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);
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;
}
// 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;
(*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
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.
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
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.