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 -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.