Push hash table identity check down to subtypes.
From-SVN: r167870
This commit is contained in:
parent
53f672caaa
commit
50ba28bb63
|
@ -6172,7 +6172,7 @@ Bound_method_expression::do_check_types(Gogo*)
|
|||
? this->expr_type_
|
||||
: this->expr_->type());
|
||||
etype = etype->deref();
|
||||
if (!Type::are_identical(rtype, etype, NULL))
|
||||
if (!Type::are_identical(rtype, etype, true, NULL))
|
||||
this->report_error(_("method type does not match object type"));
|
||||
}
|
||||
}
|
||||
|
@ -6849,7 +6849,7 @@ Builtin_call_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
|
|||
bool ret = false;
|
||||
Type* itype;
|
||||
if (args->back()->float_constant_value(i, &itype)
|
||||
&& Type::are_identical(rtype, itype, NULL))
|
||||
&& Type::are_identical(rtype, itype, false, NULL))
|
||||
{
|
||||
mpfr_set(real, r, GMP_RNDN);
|
||||
mpfr_set(imag, i, GMP_RNDN);
|
||||
|
@ -7228,7 +7228,7 @@ Builtin_call_expression::do_check_types(Gogo*)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!Type::are_identical(e1, e2, NULL))
|
||||
if (!Type::are_identical(e1, e2, true, NULL))
|
||||
this->report_error(_("element types must be the same"));
|
||||
}
|
||||
break;
|
||||
|
@ -7282,7 +7282,7 @@ Builtin_call_expression::do_check_types(Gogo*)
|
|||
|| args->back()->type()->is_error_type())
|
||||
this->set_is_error();
|
||||
else if (!Type::are_identical(args->front()->type(),
|
||||
args->back()->type(), NULL))
|
||||
args->back()->type(), true, NULL))
|
||||
this->report_error(_("cmplx arguments must have identical types"));
|
||||
else if (args->front()->type()->float_type() == NULL)
|
||||
this->report_error(_("cmplx arguments must have "
|
||||
|
@ -8085,7 +8085,7 @@ Call_expression::is_compatible_varargs_argument(Named_object* function,
|
|||
Array_type* param_at = param_type->array_type();
|
||||
if (param_at != NULL
|
||||
&& Type::are_identical(var_at->element_type(),
|
||||
param_at->element_type(), NULL))
|
||||
param_at->element_type(), true, NULL))
|
||||
return true;
|
||||
error_at(arg->location(), "... mismatch: passing ...T as ...");
|
||||
*issued_error = true;
|
||||
|
|
|
@ -301,16 +301,19 @@ Type::do_traverse(Traverse*)
|
|||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
// Return whether two types are identical. If REASON is not NULL,
|
||||
// optionally set *REASON to the reason the types are not identical.
|
||||
// Return whether two types are identical. If ERRORS_ARE_IDENTICAL,
|
||||
// then return true for all erroneous types; this is used to avoid
|
||||
// cascading errors. If REASON is not NULL, optionally set *REASON to
|
||||
// the reason the types are not identical.
|
||||
|
||||
bool
|
||||
Type::are_identical(const Type* t1, const Type* t2, std::string* reason)
|
||||
Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical,
|
||||
std::string* reason)
|
||||
{
|
||||
if (t1 == NULL || t2 == NULL)
|
||||
{
|
||||
// Something is wrong. Return true to avoid cascading errors.
|
||||
return true;
|
||||
// Something is wrong.
|
||||
return errors_are_identical ? true : t1 == t2;
|
||||
}
|
||||
|
||||
// Skip defined forward declarations.
|
||||
|
@ -320,15 +323,18 @@ Type::are_identical(const Type* t1, const Type* t2, std::string* reason)
|
|||
if (t1 == t2)
|
||||
return true;
|
||||
|
||||
// An undefined forward declaration is an error, so we return true
|
||||
// to avoid cascading errors.
|
||||
// An undefined forward declaration is an error.
|
||||
if (t1->forward_declaration_type() != NULL
|
||||
|| t2->forward_declaration_type() != NULL)
|
||||
return true;
|
||||
return errors_are_identical;
|
||||
|
||||
// Avoid cascading errors with error types.
|
||||
if (t1->is_error_type() || t2->is_error_type())
|
||||
return true;
|
||||
{
|
||||
if (errors_are_identical)
|
||||
return true;
|
||||
return t1->is_error_type() && t2->is_error_type();
|
||||
}
|
||||
|
||||
// Get a good reason for the sink type. Note that the sink type on
|
||||
// the left hand side of an assignment is handled in are_assignable.
|
||||
|
@ -368,70 +374,45 @@ Type::are_identical(const Type* t1, const Type* t2, std::string* reason)
|
|||
case TYPE_FUNCTION:
|
||||
return t1->function_type()->is_identical(t2->function_type(),
|
||||
false,
|
||||
errors_are_identical,
|
||||
reason);
|
||||
|
||||
case TYPE_POINTER:
|
||||
return Type::are_identical(t1->points_to(), t2->points_to(), reason);
|
||||
return Type::are_identical(t1->points_to(), t2->points_to(),
|
||||
errors_are_identical, reason);
|
||||
|
||||
case TYPE_STRUCT:
|
||||
return t1->struct_type()->is_identical(t2->struct_type());
|
||||
return t1->struct_type()->is_identical(t2->struct_type(),
|
||||
errors_are_identical);
|
||||
|
||||
case TYPE_ARRAY:
|
||||
return t1->array_type()->is_identical(t2->array_type());
|
||||
return t1->array_type()->is_identical(t2->array_type(),
|
||||
errors_are_identical);
|
||||
|
||||
case TYPE_MAP:
|
||||
return t1->map_type()->is_identical(t2->map_type());
|
||||
return t1->map_type()->is_identical(t2->map_type(),
|
||||
errors_are_identical);
|
||||
|
||||
case TYPE_CHANNEL:
|
||||
return t1->channel_type()->is_identical(t2->channel_type());
|
||||
return t1->channel_type()->is_identical(t2->channel_type(),
|
||||
errors_are_identical);
|
||||
|
||||
case TYPE_INTERFACE:
|
||||
return t1->interface_type()->is_identical(t2->interface_type());
|
||||
return t1->interface_type()->is_identical(t2->interface_type(),
|
||||
errors_are_identical);
|
||||
|
||||
default:
|
||||
gcc_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if two types are identical when it comes to storing
|
||||
// them in a hash table. This differs from Type::are_identical with
|
||||
// regard to how we handle error types. We want to treat error types
|
||||
// as identical to other types when it comes to reporting
|
||||
// compatibility errors, but we want to treat them as different when
|
||||
// it comes to storing them in a hash table.
|
||||
|
||||
bool
|
||||
Type::are_identical_for_hash_table(const Type* t1, const Type *t2)
|
||||
{
|
||||
if (t1 == NULL || t2 == NULL)
|
||||
return t1 == t2;
|
||||
|
||||
t1 = t1->forwarded();
|
||||
t2 = t2->forwarded();
|
||||
|
||||
if (t1 == t2)
|
||||
return true;
|
||||
|
||||
// Undefined forward declarations are only equal to themselves.
|
||||
if (t1->forward_declaration_type() != NULL
|
||||
|| t2->forward_declaration_type() != NULL)
|
||||
return false;
|
||||
|
||||
// The error type is only equal to the error type.
|
||||
if (t1->is_error_type() || t2->is_error_type())
|
||||
return t1->is_error_type() && t2->is_error_type();
|
||||
|
||||
// Otherwise we can use the usual identity check.
|
||||
return Type::are_identical(t1, t2, NULL);
|
||||
}
|
||||
|
||||
// Return true if it's OK to have a binary operation with types LHS
|
||||
// and RHS. This is not used for shifts or comparisons.
|
||||
|
||||
bool
|
||||
Type::are_compatible_for_binop(const Type* lhs, const Type* rhs)
|
||||
{
|
||||
if (Type::are_identical(lhs, rhs, NULL))
|
||||
if (Type::are_identical(lhs, rhs, true, NULL))
|
||||
return true;
|
||||
|
||||
// A constant of abstract bool type may be mixed with any bool type.
|
||||
|
@ -513,14 +494,14 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
|
|||
}
|
||||
|
||||
// Identical types are assignable.
|
||||
if (Type::are_identical(lhs, rhs, reason))
|
||||
if (Type::are_identical(lhs, rhs, true, reason))
|
||||
return true;
|
||||
|
||||
// The types are assignable if they have identical underlying types
|
||||
// and either LHS or RHS is not a named type.
|
||||
if (((lhs->named_type() != NULL && rhs->named_type() == NULL)
|
||||
|| (rhs->named_type() != NULL && lhs->named_type() == NULL))
|
||||
&& Type::are_identical(lhs->base(), rhs->base(), reason))
|
||||
&& Type::are_identical(lhs->base(), rhs->base(), true, reason))
|
||||
return true;
|
||||
|
||||
// The types are assignable if LHS is an interface type and RHS
|
||||
|
@ -547,6 +528,7 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
|
|||
&& (lhs->named_type() == NULL || rhs->named_type() == NULL)
|
||||
&& Type::are_identical(lhs->channel_type()->element_type(),
|
||||
rhs->channel_type()->element_type(),
|
||||
true,
|
||||
reason))
|
||||
return true;
|
||||
|
||||
|
@ -609,7 +591,7 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason)
|
|||
// The types are convertible if they have identical underlying
|
||||
// types.
|
||||
if ((lhs->named_type() != NULL || rhs->named_type() != NULL)
|
||||
&& Type::are_identical(lhs->base(), rhs->base(), reason))
|
||||
&& Type::are_identical(lhs->base(), rhs->base(), true, reason))
|
||||
return true;
|
||||
|
||||
// The types are convertible if they are both unnamed pointer types
|
||||
|
@ -622,6 +604,7 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason)
|
|||
|| rhs->points_to()->named_type() != NULL)
|
||||
&& Type::are_identical(lhs->points_to()->base(),
|
||||
rhs->points_to()->base(),
|
||||
true,
|
||||
reason))
|
||||
return true;
|
||||
|
||||
|
@ -2352,7 +2335,7 @@ bool
|
|||
Function_type::is_valid_redeclaration(const Function_type* t,
|
||||
std::string* reason) const
|
||||
{
|
||||
if (!this->is_identical(t, false, reason))
|
||||
if (!this->is_identical(t, false, true, reason))
|
||||
return false;
|
||||
|
||||
// A redeclaration of a function is required to use the same names
|
||||
|
@ -2436,6 +2419,7 @@ Function_type::is_valid_redeclaration(const Function_type* t,
|
|||
|
||||
bool
|
||||
Function_type::is_identical(const Function_type* t, bool ignore_receiver,
|
||||
bool errors_are_identical,
|
||||
std::string* reason) const
|
||||
{
|
||||
if (!ignore_receiver)
|
||||
|
@ -2450,7 +2434,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
|
|||
}
|
||||
if (r1 != NULL)
|
||||
{
|
||||
if (!Type::are_identical(r1->type(), r2->type(), reason))
|
||||
if (!Type::are_identical(r1->type(), r2->type(), errors_are_identical,
|
||||
reason))
|
||||
{
|
||||
if (reason != NULL && !reason->empty())
|
||||
*reason = "receiver: " + *reason;
|
||||
|
@ -2481,7 +2466,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Type::are_identical(p1->type(), p2->type(), NULL))
|
||||
if (!Type::are_identical(p1->type(), p2->type(),
|
||||
errors_are_identical, NULL))
|
||||
{
|
||||
if (reason != NULL)
|
||||
*reason = _("different parameter types");
|
||||
|
@ -2525,7 +2511,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Type::are_identical(res1->type(), res2->type(), NULL))
|
||||
if (!Type::are_identical(res1->type(), res2->type(),
|
||||
errors_are_identical, NULL))
|
||||
{
|
||||
if (reason != NULL)
|
||||
*reason = _("different result types");
|
||||
|
@ -3445,7 +3432,8 @@ Struct_type::do_has_pointer() const
|
|||
// Whether this type is identical to T.
|
||||
|
||||
bool
|
||||
Struct_type::is_identical(const Struct_type* t) const
|
||||
Struct_type::is_identical(const Struct_type* t,
|
||||
bool errors_are_identical) const
|
||||
{
|
||||
const Struct_field_list* fields1 = this->fields();
|
||||
const Struct_field_list* fields2 = t->fields();
|
||||
|
@ -3461,7 +3449,8 @@ Struct_type::is_identical(const Struct_type* t) const
|
|||
if (pf1->field_name() != pf2->field_name())
|
||||
return false;
|
||||
if (pf1->is_anonymous() != pf2->is_anonymous()
|
||||
|| !Type::are_identical(pf1->type(), pf2->type(), NULL))
|
||||
|| !Type::are_identical(pf1->type(), pf2->type(),
|
||||
errors_are_identical, NULL))
|
||||
return false;
|
||||
if (!pf1->has_tag())
|
||||
{
|
||||
|
@ -4142,9 +4131,10 @@ Type::make_struct_type(Struct_field_list* fields,
|
|||
// Whether two array types are identical.
|
||||
|
||||
bool
|
||||
Array_type::is_identical(const Array_type* t) const
|
||||
Array_type::is_identical(const Array_type* t, bool errors_are_identical) const
|
||||
{
|
||||
if (!Type::are_identical(this->element_type(), t->element_type(), NULL))
|
||||
if (!Type::are_identical(this->element_type(), t->element_type(),
|
||||
errors_are_identical, NULL))
|
||||
return false;
|
||||
|
||||
Expression* l1 = this->length();
|
||||
|
@ -4960,10 +4950,12 @@ Map_type::do_verify()
|
|||
// Whether two map types are identical.
|
||||
|
||||
bool
|
||||
Map_type::is_identical(const Map_type* t) const
|
||||
Map_type::is_identical(const Map_type* t, bool errors_are_identical) const
|
||||
{
|
||||
return (Type::are_identical(this->key_type(), t->key_type(), NULL)
|
||||
&& Type::are_identical(this->val_type(), t->val_type(), NULL));
|
||||
return (Type::are_identical(this->key_type(), t->key_type(),
|
||||
errors_are_identical, NULL)
|
||||
&& Type::are_identical(this->val_type(), t->val_type(),
|
||||
errors_are_identical, NULL));
|
||||
}
|
||||
|
||||
// Hash code.
|
||||
|
@ -5248,9 +5240,11 @@ Channel_type::do_hash_for_method(Gogo* gogo) const
|
|||
// Whether this type is the same as T.
|
||||
|
||||
bool
|
||||
Channel_type::is_identical(const Channel_type* t) const
|
||||
Channel_type::is_identical(const Channel_type* t,
|
||||
bool errors_are_identical) const
|
||||
{
|
||||
if (!Type::are_identical(this->element_type(), t->element_type(), NULL))
|
||||
if (!Type::are_identical(this->element_type(), t->element_type(),
|
||||
errors_are_identical, NULL))
|
||||
return false;
|
||||
return (this->may_send_ == t->may_send_
|
||||
&& this->may_receive_ == t->may_receive_);
|
||||
|
@ -5666,7 +5660,8 @@ Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const
|
|||
// Whether this type is identical with T.
|
||||
|
||||
bool
|
||||
Interface_type::is_identical(const Interface_type* t) const
|
||||
Interface_type::is_identical(const Interface_type* t,
|
||||
bool errors_are_identical) const
|
||||
{
|
||||
// We require the same methods with the same types. The methods
|
||||
// have already been sorted.
|
||||
|
@ -5681,7 +5676,8 @@ Interface_type::is_identical(const Interface_type* t) const
|
|||
if (p1 == this->methods()->end())
|
||||
return false;
|
||||
if (p1->name() != p2->name()
|
||||
|| !Type::are_identical(p1->type(), p2->type(), NULL))
|
||||
|| !Type::are_identical(p1->type(), p2->type(),
|
||||
errors_are_identical, NULL))
|
||||
return false;
|
||||
}
|
||||
if (p1 != this->methods()->end())
|
||||
|
@ -5720,7 +5716,7 @@ Interface_type::is_compatible_for_assign(const Interface_type* t,
|
|||
}
|
||||
|
||||
std::string subreason;
|
||||
if (!Type::are_identical(p->type(), m->type(), &subreason))
|
||||
if (!Type::are_identical(p->type(), m->type(), true, &subreason))
|
||||
{
|
||||
if (reason != NULL)
|
||||
{
|
||||
|
@ -5855,7 +5851,7 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const
|
|||
Function_type* m_fn_type = m->type()->function_type();
|
||||
gcc_assert(p_fn_type != NULL && m_fn_type != NULL);
|
||||
std::string subreason;
|
||||
if (!p_fn_type->is_identical(m_fn_type, true, &subreason))
|
||||
if (!p_fn_type->is_identical(m_fn_type, true, true, &subreason))
|
||||
{
|
||||
if (reason != NULL)
|
||||
{
|
||||
|
|
|
@ -503,16 +503,13 @@ class Type
|
|||
verify()
|
||||
{ return this->do_verify(); }
|
||||
|
||||
// Return true if two types are identical. If this returns false,
|
||||
// Return true if two types are identical. If ERRORS_ARE_IDENTICAL,
|
||||
// returns that an erroneous type is identical to any other type;
|
||||
// this is used to avoid cascading errors. If this returns false,
|
||||
// and REASON is not NULL, it may set *REASON.
|
||||
static bool
|
||||
are_identical(const Type* lhs, const Type* rhs, std::string* reason);
|
||||
|
||||
// Return true if two types are identical when it comes to putting
|
||||
// them in a hash table. This differs from are_identical only in
|
||||
// how error types are handled.
|
||||
static bool
|
||||
are_identical_for_hash_table(const Type*, const Type*);
|
||||
are_identical(const Type* lhs, const Type* rhs, bool errors_are_identical,
|
||||
std::string* reason);
|
||||
|
||||
// Return true if two types are compatible for use in a binary
|
||||
// operation, other than a shift, comparison, or channel send. This
|
||||
|
@ -1110,7 +1107,7 @@ class Type_identical
|
|||
public:
|
||||
bool
|
||||
operator()(const Type* t1, const Type* t2) const
|
||||
{ return Type::are_identical_for_hash_table(t1, t2); }
|
||||
{ return Type::are_identical(t1, t2, false, NULL); }
|
||||
};
|
||||
|
||||
// An identifier with a type.
|
||||
|
@ -1583,7 +1580,7 @@ class Function_type : public Type
|
|||
// Whether this type is the same as T.
|
||||
bool
|
||||
is_identical(const Function_type* t, bool ignore_receiver,
|
||||
std::string*) const;
|
||||
bool errors_are_identical, std::string*) const;
|
||||
|
||||
// Record that this is a varargs function.
|
||||
void
|
||||
|
@ -1890,7 +1887,7 @@ class Struct_type : public Type
|
|||
|
||||
// Whether this type is identical with T.
|
||||
bool
|
||||
is_identical(const Struct_type* t) const;
|
||||
is_identical(const Struct_type* t, bool errors_are_identical) const;
|
||||
|
||||
// Whether this struct type has any hidden fields. This returns
|
||||
// true if any fields have hidden names, or if any non-pointer
|
||||
|
@ -2009,7 +2006,7 @@ class Array_type : public Type
|
|||
|
||||
// Whether this type is identical with T.
|
||||
bool
|
||||
is_identical(const Array_type* t) const;
|
||||
is_identical(const Array_type* t, bool errors_are_identical) const;
|
||||
|
||||
// Whether this type has any hidden fields.
|
||||
bool
|
||||
|
@ -2126,7 +2123,7 @@ class Map_type : public Type
|
|||
|
||||
// Whether this type is identical with T.
|
||||
bool
|
||||
is_identical(const Map_type* t) const;
|
||||
is_identical(const Map_type* t, bool errors_are_identical) const;
|
||||
|
||||
// Import a map type.
|
||||
static Map_type*
|
||||
|
@ -2212,7 +2209,7 @@ class Channel_type : public Type
|
|||
|
||||
// Whether this type is identical with T.
|
||||
bool
|
||||
is_identical(const Channel_type* t) const;
|
||||
is_identical(const Channel_type* t, bool errors_are_identical) const;
|
||||
|
||||
// Import a channel type.
|
||||
static Channel_type*
|
||||
|
@ -2315,7 +2312,7 @@ class Interface_type : public Type
|
|||
// Whether this type is identical with T. REASON is as in
|
||||
// implements_interface.
|
||||
bool
|
||||
is_identical(const Interface_type* t) const;
|
||||
is_identical(const Interface_type* t, bool errors_are_identical) const;
|
||||
|
||||
// Whether we can assign T to this type. is_identical is known to
|
||||
// be false.
|
||||
|
|
Loading…
Reference in New Issue