mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:49:43 +00:00
[vm] Fix equality of uninstantiated generic closures
Equality of uninstantiated generic closures should match equality of corresponding instantiated generic closures. We cannot use identity for equality of instantiated generic closures as distinct instantiations of the same generic closure should be equal. So, identity shouldn't be used for uninstantiated generic closures neither. This change fixes equality for uninstantiated generic closures and also updates closure hashCode correspondingly. TEST=language/closure/instantiation_closure_equality_test TEST=co19/LanguageFeatures/Constructor-tear-offs/equality_* Fixes https://github.com/dart-lang/sdk/issues/51660 Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-nnbd-linux-release-x64-try Change-Id: Ieafc052de4a4f5f9ffcd2d9d26cb36a209c0e127 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287581 Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
18d414d24d
commit
8ff777e61f
|
@ -44,7 +44,7 @@ static bool ClosureEqualsHelper(Zone* zone,
|
|||
const auto& func_b = Function::Handle(zone, other_closure.function());
|
||||
// Check that functions match.
|
||||
if (func_a.ptr() != func_b.ptr()) {
|
||||
// Closure functions that are not implicit closures (tear-offs) are unique.
|
||||
// Non-implicit closures taken from different functions are not equal.
|
||||
if (!func_a.IsImplicitClosureFunction() ||
|
||||
!func_b.IsImplicitClosureFunction()) {
|
||||
return false;
|
||||
|
@ -80,17 +80,27 @@ static bool ClosureEqualsHelper(Zone* zone,
|
|||
const Context& context_b = Context::Handle(zone, other_closure.context());
|
||||
return context_a.At(0) == context_b.At(0);
|
||||
}
|
||||
} else {
|
||||
// Non-identical closures which are not tear-offs can be equal only if
|
||||
// they are different instantiations of the same generic closure.
|
||||
if (!func_a.IsGeneric() || receiver.IsGeneric() ||
|
||||
(receiver.context() != other_closure.context()) ||
|
||||
} else if (func_a.IsGeneric()) {
|
||||
// Additional constraints for closures of generic functions:
|
||||
// (1) Different instantiations of the same generic closure
|
||||
// with the same type arguments should be equal.
|
||||
// This means that instantiated generic closures are not unique
|
||||
// and equality of instantiated generic closures should not be
|
||||
// based on identity.
|
||||
// (2) Instantiations of non-equal generic closures should be non-equal.
|
||||
// This means that equality of non-instantiated generic closures
|
||||
// should not be based on identity too as it won't match equality
|
||||
// after instantiation.
|
||||
if ((receiver.context() != other_closure.context()) ||
|
||||
(receiver.instantiator_type_arguments() !=
|
||||
other_closure.instantiator_type_arguments()) ||
|
||||
(receiver.function_type_arguments() !=
|
||||
other_closure.function_type_arguments())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Closures of non-generic functions are unique.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26529,24 +26529,26 @@ uword Closure::ComputeHash() const {
|
|||
Zone* zone = thread->zone();
|
||||
const Function& func = Function::Handle(zone, function());
|
||||
uint32_t result = 0;
|
||||
if (func.IsImplicitInstanceClosureFunction()) {
|
||||
// Implicit instance closures are not unique, so combine function's hash
|
||||
// code, delayed type arguments hash code (if generic), and identityHashCode
|
||||
// of cached receiver.
|
||||
if (func.IsImplicitClosureFunction() || func.IsGeneric()) {
|
||||
// Combine function's hash code, delayed type arguments hash code
|
||||
// (if generic), and identityHashCode of cached receiver (if implicit
|
||||
// instance closure).
|
||||
result = static_cast<uint32_t>(func.Hash());
|
||||
if (func.IsGeneric()) {
|
||||
const TypeArguments& delayed_type_args =
|
||||
TypeArguments::Handle(zone, delayed_type_arguments());
|
||||
result = CombineHashes(result, delayed_type_args.Hash());
|
||||
}
|
||||
const Context& context = Context::Handle(zone, this->context());
|
||||
const Instance& receiver =
|
||||
Instance::Handle(zone, Instance::RawCast(context.At(0)));
|
||||
const Integer& receiverHash =
|
||||
Integer::Handle(zone, receiver.IdentityHashCode(thread));
|
||||
result = CombineHashes(result, receiverHash.AsTruncatedUint32Value());
|
||||
if (func.IsImplicitInstanceClosureFunction()) {
|
||||
const Context& context = Context::Handle(zone, this->context());
|
||||
const Instance& receiver =
|
||||
Instance::Handle(zone, Instance::RawCast(context.At(0)));
|
||||
const Integer& receiverHash =
|
||||
Integer::Handle(zone, receiver.IdentityHashCode(thread));
|
||||
result = CombineHashes(result, receiverHash.AsTruncatedUint32Value());
|
||||
}
|
||||
} else {
|
||||
// Explicit closures and implicit static closures are unique,
|
||||
// Non-implicit closures of non-generic functions are unique,
|
||||
// so identityHashCode of closure object is good enough.
|
||||
const Integer& identityHash =
|
||||
Integer::Handle(zone, this->IdentityHashCode(thread));
|
||||
|
|
Loading…
Reference in a new issue