diff mbox

Go patch committed: Error if type switch case can not match

Message ID mcrk44gwuld.fsf@dhcp-172-18-216-180.mtv.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor Jan. 24, 2012, 11:26 p.m. UTC
This patch to the Go frontend adds in an error if a case in a type
switch can not match the type of the switch value, because the case type
does not implement methods of the switch value.  Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

diff -r b4d67f01b439 go/statements.cc
--- a/go/statements.cc	Tue Jan 24 14:32:07 2012 -0800
+++ b/go/statements.cc	Tue Jan 24 15:22:44 2012 -0800
@@ -3940,7 +3940,8 @@ 
 // statements.
 
 void
-Type_case_clauses::Type_case_clause::lower(Block* b,
+Type_case_clauses::Type_case_clause::lower(Type* switch_val_type,
+					   Block* b,
 					   Temporary_statement* descriptor_temp,
 					   Unnamed_label* break_label,
 					   Unnamed_label** stmts_label) const
@@ -3952,6 +3953,20 @@ 
     {
       Type* type = this->type_;
 
+      std::string reason;
+      if (switch_val_type->interface_type() != NULL
+	  && !type->is_nil_constant_as_type()
+	  && type->interface_type() == NULL
+	  && !switch_val_type->interface_type()->implements_interface(type,
+								      &reason))
+	{
+	  if (reason.empty())
+	    error_at(this->location_, "impossible type switch case");
+	  else
+	    error_at(this->location_, "impossible type switch case (%s)",
+		     reason.c_str());
+	}
+
       Expression* ref = Expression::make_temporary_reference(descriptor_temp,
 							     loc);
 
@@ -4102,7 +4117,8 @@ 
 // BREAK_LABEL is the label at the end of the type switch.
 
 void
-Type_case_clauses::lower(Block* b, Temporary_statement* descriptor_temp,
+Type_case_clauses::lower(Type* switch_val_type, Block* b,
+			 Temporary_statement* descriptor_temp,
 			 Unnamed_label* break_label) const
 {
   const Type_case_clause* default_case = NULL;
@@ -4113,7 +4129,8 @@ 
        ++p)
     {
       if (!p->is_default())
-	p->lower(b, descriptor_temp, break_label, &stmts_label);
+	p->lower(switch_val_type, b, descriptor_temp, break_label,
+		 &stmts_label);
       else
 	{
 	  // We are generating a series of tests, which means that we
@@ -4124,7 +4141,8 @@ 
   go_assert(stmts_label == NULL);
 
   if (default_case != NULL)
-    default_case->lower(b, descriptor_temp, break_label, NULL);
+    default_case->lower(switch_val_type, b, descriptor_temp, break_label,
+			NULL);
 }
 
 // Dump the AST representation for case clauses (from a switch statement)
@@ -4222,7 +4240,7 @@ 
     }
 
   if (this->clauses_ != NULL)
-    this->clauses_->lower(b, descriptor_temp, this->break_label());
+    this->clauses_->lower(val_type, b, descriptor_temp, this->break_label());
 
   Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
   b->add_statement(s);
diff -r b4d67f01b439 go/statements.h
--- a/go/statements.h	Tue Jan 24 14:32:07 2012 -0800
+++ b/go/statements.h	Tue Jan 24 15:22:44 2012 -0800
@@ -1441,7 +1441,7 @@ 
 
   // Lower to if and goto statements.
   void
-  lower(Block*, Temporary_statement* descriptor_temp,
+  lower(Type*, Block*, Temporary_statement* descriptor_temp,
 	Unnamed_label* break_label) const;
 
   // Dump the AST representation to a dump context.
@@ -1485,7 +1485,7 @@ 
 
     // Lower to if and goto statements.
     void
-    lower(Block*, Temporary_statement* descriptor_temp,
+    lower(Type*, Block*, Temporary_statement* descriptor_temp,
 	  Unnamed_label* break_label, Unnamed_label** stmts_label) const;
 
     // Dump the AST representation to a dump context.