compiler: cast comparison function result to expected bool type

Otherwise cases like
    type mybool bool
    var b mybool = [10]string{} == [10]string{}
get an incorrect type checking error.

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/274446
This commit is contained in:
Ian Lance Taylor 2020-12-02 18:11:00 -08:00
parent cd34d5f2c4
commit 17c9cf3c17
3 changed files with 48 additions and 5 deletions

View File

@ -1,4 +1,4 @@
5364d15082de77d2759a01f254208d4cb4f579e3
b3a0b068f7fa2d65ba781271b2c0479d103b7d7b
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -6287,8 +6287,21 @@ Binary_expression::lower_array_comparison(Gogo* gogo,
args->push_back(this->operand_address(inserter, this->left_));
args->push_back(this->operand_address(inserter, this->right_));
Expression* ret = Expression::make_call(func, args, false, loc);
Call_expression* ce = Expression::make_call(func, args, false, loc);
// Record that this is a call to a generated equality function. We
// need to do this because a comparison returns an abstract boolean
// type, but the function necessarily returns "bool". The
// difference shows up in code like
// type mybool bool
// var b mybool = [10]string{} == [10]string{}
// The comparison function returns "bool", but since a comparison
// has an abstract boolean type we need an implicit conversion to
// "mybool". The implicit conversion is inserted in
// Call_expression::do_flatten.
ce->set_is_equal_function();
Expression* ret = ce;
if (this->op_ == OPERATOR_NOTEQ)
ret = Expression::make_unary(OPERATOR_NOT, ret, loc);
@ -11163,6 +11176,13 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*,
return ret;
}
// Add an implicit conversion to a boolean type, if needed. See the
// comment in Binary_expression::lower_array_comparison.
if (this->is_equal_function_
&& this->type_ != NULL
&& this->type_ != Type::lookup_bool_type())
return Expression::make_cast(this->type_, this, this->location());
return this;
}
@ -11938,7 +11958,7 @@ Call_expression::do_type()
// parameter types to set the types of the arguments.
void
Call_expression::do_determine_type(const Type_context*)
Call_expression::do_determine_type(const Type_context* context)
{
if (!this->determining_types())
return;
@ -11985,6 +12005,22 @@ Call_expression::do_determine_type(const Type_context*)
(*pa)->determine_type_no_context();
}
}
// If this is a call to a generated equality function, we determine
// the type based on the context. See the comment in
// Binary_expression::lower_array_comparison.
if (this->is_equal_function_
&& !context->may_be_abstract
&& context->type != NULL
&& context->type->is_boolean_type()
&& context->type != Type::lookup_bool_type())
{
go_assert(this->type_ == NULL
|| this->type_ == Type::lookup_bool_type()
|| this->type_ == context->type
|| this->type_->is_error());
this->type_ = context->type;
}
}
// Called when determining types for a Call_expression. Return true

View File

@ -2326,8 +2326,8 @@ class Call_expression : public Expression
fn_(fn), args_(args), type_(NULL), call_(NULL), call_temp_(NULL)
, expected_result_count_(0), is_varargs_(is_varargs),
varargs_are_lowered_(false), types_are_determined_(false),
is_deferred_(false), is_concurrent_(false), issued_error_(false),
is_multi_value_arg_(false), is_flattened_(false)
is_deferred_(false), is_concurrent_(false), is_equal_function_(false),
issued_error_(false), is_multi_value_arg_(false), is_flattened_(false)
{ }
// The function to call.
@ -2408,6 +2408,11 @@ class Call_expression : public Expression
set_is_concurrent()
{ this->is_concurrent_ = true; }
// Note that this is a call to a generated equality function.
void
set_is_equal_function()
{ this->is_equal_function_ = true; }
// We have found an error with this call expression; return true if
// we should report it.
bool
@ -2545,6 +2550,8 @@ class Call_expression : public Expression
bool is_deferred_;
// True if the call is an argument to a go statement.
bool is_concurrent_;
// True if this is a call to a generated equality function.
bool is_equal_function_;
// True if we reported an error about a mismatch between call
// results and uses. This is to avoid producing multiple errors
// when there are multiple Call_result_expressions.