mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 21:20:36 +00:00
[vm] Update number of parent function type arguments
Number of parent type arguments in function types is critical for instantiation and subtype checks when there are nested generic function types. So it is important to update number of parent type arguments when parent function type is updated. This change adds mechanism for updating number of parent type arguments and uses the new mechanism in 2 cases: 1) When a type parameter is substituted during type instantiation. The substituted type can have nested generic function types and it should be updated if substituted inside another generic function type. 2) When creating a constructor tear-off for a generic class. Parameter types of the constructor could have nested generic function types and they should be updated as tear-off itself is a generic function. TEST=language/function_subtype/generic_function_type_substitution_test TEST=language/regress/regress50905_test Fixes https://github.com/dart-lang/sdk/issues/50614 Fixes https://github.com/dart-lang/sdk/issues/50905 Change-Id: If13baa420939f5ac002ce32f3909953fb6998bd2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278525 Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
3157f9ff8d
commit
88400bdc42
|
@ -7289,7 +7289,8 @@ TypeArgumentsPtr TypeArguments::InstantiateFrom(
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
TrailPtr trail,
|
||||
intptr_t num_parent_type_args_adjustment) const {
|
||||
ASSERT(!IsInstantiated());
|
||||
if ((instantiator_type_arguments.IsNull() ||
|
||||
instantiator_type_arguments.Length() == Length()) &&
|
||||
|
@ -7311,7 +7312,8 @@ TypeArgumentsPtr TypeArguments::InstantiateFrom(
|
|||
if (!type.IsNull() && !type.IsInstantiated()) {
|
||||
type = type.InstantiateFrom(instantiator_type_arguments,
|
||||
function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
num_free_fun_type_params, space, trail,
|
||||
num_parent_type_args_adjustment);
|
||||
// A returned null type indicates a failed instantiation in dead code that
|
||||
// must be propagated up to the caller, the optimizing compiler.
|
||||
if (type.IsNull()) {
|
||||
|
@ -7323,6 +7325,37 @@ TypeArgumentsPtr TypeArguments::InstantiateFrom(
|
|||
return instantiated_array.ptr();
|
||||
}
|
||||
|
||||
TypeArgumentsPtr TypeArguments::UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
TypeArguments* updated_args = nullptr;
|
||||
AbstractType& type = AbstractType::Handle(zone);
|
||||
AbstractType& updated = AbstractType::Handle(zone);
|
||||
for (intptr_t i = 0, n = Length(); i < n; ++i) {
|
||||
type = TypeAt(i);
|
||||
updated =
|
||||
type.UpdateParentFunctionType(num_parent_type_args_adjustment,
|
||||
num_free_fun_type_params, space, trail);
|
||||
if (type.ptr() != updated.ptr()) {
|
||||
if (updated_args == nullptr) {
|
||||
updated_args =
|
||||
&TypeArguments::Handle(zone, TypeArguments::New(n, space));
|
||||
for (intptr_t j = 0; j < i; ++j) {
|
||||
type = TypeAt(j);
|
||||
updated_args->SetTypeAt(j, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updated_args != nullptr) {
|
||||
updated_args->SetTypeAt(i, updated);
|
||||
}
|
||||
}
|
||||
return (updated_args != nullptr) ? updated_args->ptr() : ptr();
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// A local flag used only in object_test.cc that, when true, causes a failure
|
||||
// when a cache entry for the given instantiator and function type arguments
|
||||
|
@ -9269,7 +9302,8 @@ AbstractTypePtr FunctionType::InstantiateFrom(
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
TrailPtr trail,
|
||||
intptr_t num_parent_type_args_adjustment) const {
|
||||
ASSERT(IsFinalized() || IsBeingFinalized());
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
const intptr_t num_parent_type_args = NumParentTypeArguments();
|
||||
|
@ -9293,6 +9327,12 @@ AbstractTypePtr FunctionType::InstantiateFrom(
|
|||
num_free_fun_type_params < num_parent_type_args
|
||||
? num_parent_type_args - num_free_fun_type_params
|
||||
: 0;
|
||||
|
||||
// Adjust number of parent type arguments for all nested substituted types.
|
||||
num_parent_type_args_adjustment =
|
||||
remaining_parent_type_params +
|
||||
(delete_type_parameters ? 0 : NumTypeParameters());
|
||||
|
||||
FunctionType& sig = FunctionType::Handle(
|
||||
FunctionType::New(remaining_parent_type_params, nullability(), space));
|
||||
AbstractType& type = AbstractType::Handle(zone);
|
||||
|
@ -9313,14 +9353,16 @@ AbstractTypePtr FunctionType::InstantiateFrom(
|
|||
if (!type_args.IsNull() && !type_args.IsInstantiated()) {
|
||||
type_args = type_args.InstantiateFrom(
|
||||
instantiator_type_arguments, function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
num_free_fun_type_params, space, trail,
|
||||
num_parent_type_args_adjustment);
|
||||
}
|
||||
sig_type_params.set_bounds(type_args);
|
||||
type_args = type_params.defaults();
|
||||
if (!type_args.IsNull() && !type_args.IsInstantiated()) {
|
||||
type_args = type_args.InstantiateFrom(
|
||||
instantiator_type_arguments, function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
num_free_fun_type_params, space, trail,
|
||||
num_parent_type_args_adjustment);
|
||||
}
|
||||
sig_type_params.set_defaults(type_args);
|
||||
sig.SetTypeParameters(sig_type_params);
|
||||
|
@ -9329,9 +9371,10 @@ AbstractTypePtr FunctionType::InstantiateFrom(
|
|||
|
||||
type = result_type();
|
||||
if (!type.IsInstantiated()) {
|
||||
type = type.InstantiateFrom(instantiator_type_arguments,
|
||||
function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
type =
|
||||
type.InstantiateFrom(instantiator_type_arguments,
|
||||
function_type_arguments, num_free_fun_type_params,
|
||||
space, trail, num_parent_type_args_adjustment);
|
||||
// A returned null type indicates a failed instantiation in dead code that
|
||||
// must be propagated up to the caller, the optimizing compiler.
|
||||
if (type.IsNull()) {
|
||||
|
@ -9350,7 +9393,8 @@ AbstractTypePtr FunctionType::InstantiateFrom(
|
|||
if (!type.IsInstantiated()) {
|
||||
type = type.InstantiateFrom(instantiator_type_arguments,
|
||||
function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
num_free_fun_type_params, space, trail,
|
||||
num_parent_type_args_adjustment);
|
||||
// A returned null type indicates a failed instantiation in dead code that
|
||||
// must be propagated up to the caller, the optimizing compiler.
|
||||
if (type.IsNull()) {
|
||||
|
@ -9377,6 +9421,80 @@ AbstractTypePtr FunctionType::InstantiateFrom(
|
|||
return sig.ptr();
|
||||
}
|
||||
|
||||
AbstractTypePtr FunctionType::UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
ASSERT(num_parent_type_args_adjustment > 0);
|
||||
ASSERT(IsFinalized());
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
|
||||
const intptr_t old_num_parent_type_args = NumParentTypeArguments();
|
||||
// From now on, adjust all type parameter types
|
||||
// which belong to this or nested function types.
|
||||
if (num_free_fun_type_params > old_num_parent_type_args) {
|
||||
num_free_fun_type_params = old_num_parent_type_args;
|
||||
}
|
||||
|
||||
FunctionType& new_type = FunctionType::Handle(
|
||||
zone, FunctionType::New(
|
||||
NumParentTypeArguments() + num_parent_type_args_adjustment,
|
||||
nullability(), space));
|
||||
AbstractType& type = AbstractType::Handle(zone);
|
||||
|
||||
const TypeParameters& type_params =
|
||||
TypeParameters::Handle(zone, type_parameters());
|
||||
if (!type_params.IsNull()) {
|
||||
const TypeParameters& new_type_params =
|
||||
TypeParameters::Handle(zone, TypeParameters::New());
|
||||
// No need to set names that are ignored in a signature, however, the
|
||||
// length of the names array defines the number of type parameters.
|
||||
new_type_params.set_names(Array::Handle(zone, type_params.names()));
|
||||
new_type_params.set_flags(Array::Handle(zone, type_params.flags()));
|
||||
TypeArguments& type_args = TypeArguments::Handle(zone);
|
||||
type_args = type_params.bounds();
|
||||
if (!type_args.IsNull()) {
|
||||
type_args = type_args.UpdateParentFunctionType(
|
||||
num_parent_type_args_adjustment, num_free_fun_type_params, space,
|
||||
trail);
|
||||
}
|
||||
new_type_params.set_bounds(type_args);
|
||||
type_args = type_params.defaults();
|
||||
if (!type_args.IsNull()) {
|
||||
type_args = type_args.UpdateParentFunctionType(
|
||||
num_parent_type_args_adjustment, num_free_fun_type_params, space,
|
||||
trail);
|
||||
}
|
||||
new_type_params.set_defaults(type_args);
|
||||
new_type.SetTypeParameters(new_type_params);
|
||||
}
|
||||
|
||||
type = result_type();
|
||||
type = type.UpdateParentFunctionType(num_parent_type_args_adjustment,
|
||||
num_free_fun_type_params, space, trail);
|
||||
new_type.set_result_type(type);
|
||||
|
||||
const intptr_t num_params = NumParameters();
|
||||
new_type.set_num_implicit_parameters(num_implicit_parameters());
|
||||
new_type.set_num_fixed_parameters(num_fixed_parameters());
|
||||
new_type.SetNumOptionalParameters(NumOptionalParameters(),
|
||||
HasOptionalPositionalParameters());
|
||||
new_type.set_parameter_types(Array::Handle(Array::New(num_params, space)));
|
||||
for (intptr_t i = 0; i < num_params; i++) {
|
||||
type = ParameterTypeAt(i);
|
||||
type =
|
||||
type.UpdateParentFunctionType(num_parent_type_args_adjustment,
|
||||
num_free_fun_type_params, space, trail);
|
||||
new_type.SetParameterTypeAt(i, type);
|
||||
}
|
||||
new_type.set_named_parameter_names(
|
||||
Array::Handle(zone, named_parameter_names()));
|
||||
new_type.SetIsFinalized();
|
||||
|
||||
return new_type.ptr();
|
||||
}
|
||||
|
||||
// Checks if the type of the specified parameter of this signature is a
|
||||
// supertype of the type of the specified parameter of the other signature
|
||||
// (i.e. check parameter contravariance).
|
||||
|
@ -9880,13 +9998,16 @@ FunctionPtr Function::ImplicitClosureFunction() const {
|
|||
const auto& instantiator_type_args = TypeArguments::Handle(
|
||||
zone, AbstractType::Handle(zone, closure_signature.result_type())
|
||||
.arguments());
|
||||
const intptr_t num_type_args = closure_signature.NumTypeArguments();
|
||||
auto& param_type = AbstractType::Handle(zone);
|
||||
for (intptr_t i = kClosure; i < num_params; ++i) {
|
||||
param_type = closure_signature.ParameterTypeAt(i);
|
||||
param_type = param_type.UpdateParentFunctionType(num_type_args, kAllFree,
|
||||
Heap::kOld);
|
||||
if (!param_type.IsInstantiated()) {
|
||||
param_type = param_type.InstantiateFrom(instantiator_type_args,
|
||||
Object::null_type_arguments(),
|
||||
kAllFree, Heap::kOld);
|
||||
param_type = param_type.InstantiateFrom(
|
||||
instantiator_type_args, Object::null_type_arguments(),
|
||||
kNoneFree /* avoid truncating parent type args */, Heap::kOld);
|
||||
closure_signature.SetParameterTypeAt(i, param_type);
|
||||
}
|
||||
}
|
||||
|
@ -20701,7 +20822,8 @@ AbstractTypePtr AbstractType::InstantiateFrom(
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
TrailPtr trail,
|
||||
intptr_t num_parent_type_args_adjustment) const {
|
||||
// All subclasses should implement this appropriately, so the only value that
|
||||
// should reach this implementation should be the null value.
|
||||
ASSERT(IsNull());
|
||||
|
@ -20710,6 +20832,15 @@ AbstractTypePtr AbstractType::InstantiateFrom(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
AbstractTypePtr AbstractType::UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AbstractTypePtr AbstractType::Canonicalize(Thread* thread,
|
||||
TrailPtr trail) const {
|
||||
// All subclasses should implement this appropriately, so the only value that
|
||||
|
@ -21522,7 +21653,8 @@ AbstractTypePtr Type::InstantiateFrom(
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
TrailPtr trail,
|
||||
intptr_t num_parent_type_args_adjustment) const {
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
ASSERT(IsFinalized() || IsBeingFinalized());
|
||||
ASSERT(!IsInstantiated());
|
||||
|
@ -21534,7 +21666,7 @@ AbstractTypePtr Type::InstantiateFrom(
|
|||
ASSERT(type_arguments.Length() == cls.NumTypeArguments());
|
||||
type_arguments = type_arguments.InstantiateFrom(
|
||||
instantiator_type_arguments, function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
num_free_fun_type_params, space, trail, num_parent_type_args_adjustment);
|
||||
// A returned empty_type_arguments indicates a failed instantiation in dead
|
||||
// code that must be propagated up to the caller, the optimizing compiler.
|
||||
if (type_arguments.ptr() == Object::empty_type_arguments().ptr()) {
|
||||
|
@ -21555,6 +21687,32 @@ AbstractTypePtr Type::InstantiateFrom(
|
|||
return instantiated_type.NormalizeFutureOrType(space);
|
||||
}
|
||||
|
||||
AbstractTypePtr Type::UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
ASSERT(IsFinalized());
|
||||
ASSERT(num_parent_type_args_adjustment > 0);
|
||||
if (arguments() == Object::null()) {
|
||||
return ptr();
|
||||
}
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
const auto& type_args = TypeArguments::Handle(zone, arguments());
|
||||
const auto& updated_type_args =
|
||||
TypeArguments::Handle(zone, type_args.UpdateParentFunctionType(
|
||||
num_parent_type_args_adjustment,
|
||||
num_free_fun_type_params, space, trail));
|
||||
if (type_args.ptr() == updated_type_args.ptr()) {
|
||||
return ptr();
|
||||
}
|
||||
const Class& cls = Class::Handle(zone, type_class());
|
||||
const Type& new_type = Type::Handle(
|
||||
zone, Type::New(cls, updated_type_args, nullability(), space));
|
||||
new_type.SetIsFinalized();
|
||||
return new_type.ptr();
|
||||
}
|
||||
|
||||
// Certain built-in classes are treated as syntactically equivalent.
|
||||
static classid_t NormalizeClassIdForSyntacticalTypeEquality(classid_t cid) {
|
||||
if (IsIntegerClassId(cid)) {
|
||||
|
@ -22411,7 +22569,8 @@ AbstractTypePtr TypeRef::InstantiateFrom(
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
TrailPtr trail,
|
||||
intptr_t num_parent_type_args_adjustment) const {
|
||||
TypeRef& instantiated_type_ref = TypeRef::Handle();
|
||||
instantiated_type_ref ^= OnlyBuddyInTrail(trail);
|
||||
if (!instantiated_type_ref.IsNull()) {
|
||||
|
@ -22425,7 +22584,7 @@ AbstractTypePtr TypeRef::InstantiateFrom(
|
|||
AbstractType& instantiated_ref_type = AbstractType::Handle();
|
||||
instantiated_ref_type = ref_type.InstantiateFrom(
|
||||
instantiator_type_arguments, function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
num_free_fun_type_params, space, trail, num_parent_type_args_adjustment);
|
||||
// A returned null type indicates a failed instantiation in dead code that
|
||||
// must be propagated up to the caller, the optimizing compiler.
|
||||
if (instantiated_ref_type.IsNull()) {
|
||||
|
@ -22439,6 +22598,35 @@ AbstractTypePtr TypeRef::InstantiateFrom(
|
|||
return instantiated_type_ref.ptr();
|
||||
}
|
||||
|
||||
AbstractTypePtr TypeRef::UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
ASSERT(IsFinalized());
|
||||
ASSERT(num_parent_type_args_adjustment > 0);
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
TypeRef& new_type_ref = TypeRef::Handle(zone);
|
||||
new_type_ref ^= OnlyBuddyInTrail(trail);
|
||||
if (!new_type_ref.IsNull()) {
|
||||
return new_type_ref.ptr();
|
||||
}
|
||||
new_type_ref = TypeRef::New();
|
||||
AddOnlyBuddyToTrail(&trail, new_type_ref);
|
||||
|
||||
AbstractType& ref_type = AbstractType::Handle(type());
|
||||
ASSERT(!ref_type.IsNull() && !ref_type.IsTypeRef());
|
||||
|
||||
const auto& updated_ref_type =
|
||||
AbstractType::Handle(zone, ref_type.UpdateParentFunctionType(
|
||||
num_parent_type_args_adjustment,
|
||||
num_free_fun_type_params, space, trail));
|
||||
ASSERT(!updated_ref_type.IsTypeRef());
|
||||
new_type_ref.set_type(updated_ref_type);
|
||||
|
||||
return new_type_ref.ptr();
|
||||
}
|
||||
|
||||
void TypeRef::set_type(const AbstractType& value) const {
|
||||
ASSERT(!value.IsTypeRef());
|
||||
if (value.IsNull()) {
|
||||
|
@ -22743,8 +22931,10 @@ AbstractTypePtr TypeParameter::InstantiateFrom(
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
TrailPtr trail,
|
||||
intptr_t num_parent_type_args_adjustment) const {
|
||||
AbstractType& result = AbstractType::Handle();
|
||||
bool substituted = false;
|
||||
if (IsFunctionTypeParameter()) {
|
||||
ASSERT(IsFinalized());
|
||||
if (index() >= num_free_fun_type_params) {
|
||||
|
@ -22755,7 +22945,8 @@ AbstractTypePtr TypeParameter::InstantiateFrom(
|
|||
if (!upper_bound.IsInstantiated()) {
|
||||
upper_bound = upper_bound.InstantiateFrom(
|
||||
instantiator_type_arguments, function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
num_free_fun_type_params, space, trail,
|
||||
num_parent_type_args_adjustment);
|
||||
}
|
||||
if ((upper_bound.IsTypeRef() &&
|
||||
TypeRef::Cast(upper_bound).type() == Type::NeverType()) ||
|
||||
|
@ -22774,6 +22965,7 @@ AbstractTypePtr TypeParameter::InstantiateFrom(
|
|||
return Type::DynamicType();
|
||||
} else {
|
||||
result = function_type_arguments.TypeAt(index());
|
||||
substituted = true;
|
||||
ASSERT(!result.IsTypeParameter());
|
||||
}
|
||||
} else {
|
||||
|
@ -22792,15 +22984,49 @@ AbstractTypePtr TypeParameter::InstantiateFrom(
|
|||
return AbstractType::null();
|
||||
}
|
||||
result = instantiator_type_arguments.TypeAt(index());
|
||||
substituted = true;
|
||||
// Instantiating a class type parameter cannot result in a
|
||||
// function type parameter.
|
||||
// Bounds of class type parameters are ignored in the VM.
|
||||
}
|
||||
result = result.SetInstantiatedNullability(*this, space);
|
||||
if (substituted && (num_parent_type_args_adjustment != 0)) {
|
||||
// This type parameter is used inside a generic function type.
|
||||
// A type being substituted can have nested function types,
|
||||
// whose number of parent function type arguments should be adjusted
|
||||
// after the substitution.
|
||||
result = result.UpdateParentFunctionType(num_parent_type_args_adjustment,
|
||||
kAllFree, space);
|
||||
}
|
||||
// Canonicalization is not part of instantiation.
|
||||
return result.NormalizeFutureOrType(space);
|
||||
}
|
||||
|
||||
AbstractTypePtr TypeParameter::UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
ASSERT(IsFinalized());
|
||||
ASSERT(num_parent_type_args_adjustment > 0);
|
||||
if (IsFunctionTypeParameter() && (index() >= num_free_fun_type_params)) {
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
auto& new_tp = TypeParameter::Handle(zone);
|
||||
new_tp ^= Object::Clone(*this, space);
|
||||
new_tp.set_base(base() + num_parent_type_args_adjustment);
|
||||
new_tp.set_index(index() + num_parent_type_args_adjustment);
|
||||
auto& type = AbstractType::Handle(zone, bound());
|
||||
type =
|
||||
type.UpdateParentFunctionType(num_parent_type_args_adjustment,
|
||||
num_free_fun_type_params, space, trail);
|
||||
new_tp.set_bound(type);
|
||||
ASSERT(new_tp.IsFinalized());
|
||||
return new_tp.ptr();
|
||||
} else {
|
||||
return ptr();
|
||||
}
|
||||
}
|
||||
|
||||
AbstractTypePtr TypeParameter::Canonicalize(Thread* thread,
|
||||
TrailPtr trail) const {
|
||||
ASSERT(IsFinalized());
|
||||
|
@ -27904,7 +28130,8 @@ AbstractTypePtr RecordType::InstantiateFrom(
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
TrailPtr trail,
|
||||
intptr_t num_parent_type_args_adjustment) const {
|
||||
ASSERT(IsFinalized() || IsBeingFinalized());
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
|
||||
|
@ -27918,7 +28145,8 @@ AbstractTypePtr RecordType::InstantiateFrom(
|
|||
if (!type.IsInstantiated()) {
|
||||
type = type.InstantiateFrom(instantiator_type_arguments,
|
||||
function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
num_free_fun_type_params, space, trail,
|
||||
num_parent_type_args_adjustment);
|
||||
// A returned null type indicates a failed instantiation in dead code that
|
||||
// must be propagated up to the caller, the optimizing compiler.
|
||||
if (type.IsNull()) {
|
||||
|
@ -27943,6 +28171,45 @@ AbstractTypePtr RecordType::InstantiateFrom(
|
|||
return rec.ptr();
|
||||
}
|
||||
|
||||
AbstractTypePtr RecordType::UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail) const {
|
||||
ASSERT(IsFinalized());
|
||||
ASSERT(num_parent_type_args_adjustment > 0);
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
const auto& types = Array::Handle(zone, field_types());
|
||||
Array* updated_types = nullptr;
|
||||
auto& type = AbstractType::Handle(zone);
|
||||
auto& updated = AbstractType::Handle(zone);
|
||||
for (intptr_t i = 0, n = NumFields(); i < n; ++i) {
|
||||
type ^= types.At(i);
|
||||
updated =
|
||||
type.UpdateParentFunctionType(num_parent_type_args_adjustment,
|
||||
num_free_fun_type_params, space, trail);
|
||||
if (type.ptr() != updated.ptr()) {
|
||||
if (updated_types == nullptr) {
|
||||
updated_types = &Array::Handle(zone, Array::New(n, space));
|
||||
for (intptr_t j = 0; j < i; ++j) {
|
||||
type ^= types.At(j);
|
||||
updated_types->SetAt(j, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updated_types != nullptr) {
|
||||
updated_types->SetAt(i, updated);
|
||||
}
|
||||
}
|
||||
if (updated_types == nullptr) {
|
||||
return ptr();
|
||||
}
|
||||
const auto& new_rt = RecordType::Handle(
|
||||
zone, RecordType::New(shape(), *updated_types, nullability(), space));
|
||||
new_rt.SetIsFinalized();
|
||||
return new_rt.ptr();
|
||||
}
|
||||
|
||||
bool RecordType::IsSubtypeOf(const RecordType& other, Heap::Space space) const {
|
||||
if (ptr() == other.ptr()) {
|
||||
return true;
|
||||
|
|
|
@ -8118,6 +8118,15 @@ class TypeArguments : public Instance {
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr,
|
||||
intptr_t num_parent_type_args_adjustment = 0) const;
|
||||
|
||||
// Update number of parent function type arguments for
|
||||
// all elements of this vector.
|
||||
TypeArgumentsPtr UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr) const;
|
||||
|
||||
// Runtime instantiation with canonicalization. Not to be used during type
|
||||
|
@ -8465,6 +8474,21 @@ class AbstractType : public Instance {
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr,
|
||||
intptr_t num_parent_type_args_adjustment = 0) const;
|
||||
|
||||
// Update number of parent function type arguments for the
|
||||
// nested function types and their type parameters.
|
||||
//
|
||||
// This adjustment is needed when nesting one generic function type
|
||||
// inside another.
|
||||
// Number of parent function type arguments is adjusted by
|
||||
// [num_parent_type_args_adjustment].
|
||||
// Type parameters up to [num_free_fun_type_params] are not adjusted.
|
||||
virtual AbstractTypePtr UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr) const;
|
||||
|
||||
// Caller must hold IsolateGroup::constant_canonicalization_mutex_.
|
||||
|
@ -8754,7 +8778,15 @@ class Type : public AbstractType {
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr,
|
||||
intptr_t num_parent_type_args_adjustment = 0) const;
|
||||
|
||||
virtual AbstractTypePtr UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr) const;
|
||||
|
||||
virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const;
|
||||
#if defined(DEBUG)
|
||||
// Check if type is canonical.
|
||||
|
@ -8894,7 +8926,15 @@ class FunctionType : public AbstractType {
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr,
|
||||
intptr_t num_parent_type_args_adjustment = 0) const;
|
||||
|
||||
virtual AbstractTypePtr UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr) const;
|
||||
|
||||
virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const;
|
||||
#if defined(DEBUG)
|
||||
// Check if type is canonical.
|
||||
|
@ -9173,7 +9213,15 @@ class TypeRef : public AbstractType {
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr,
|
||||
intptr_t num_parent_type_args_adjustment = 0) const;
|
||||
|
||||
virtual AbstractTypePtr UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr) const;
|
||||
|
||||
virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const;
|
||||
#if defined(DEBUG)
|
||||
// Check if typeref is canonical.
|
||||
|
@ -9258,7 +9306,15 @@ class TypeParameter : public AbstractType {
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr,
|
||||
intptr_t num_parent_type_args_adjustment = 0) const;
|
||||
|
||||
virtual AbstractTypePtr UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr) const;
|
||||
|
||||
virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const;
|
||||
#if defined(DEBUG)
|
||||
// Check if type parameter is canonical.
|
||||
|
@ -10964,7 +11020,15 @@ class RecordType : public AbstractType {
|
|||
const TypeArguments& function_type_arguments,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr,
|
||||
intptr_t num_parent_type_args_adjustment = 0) const;
|
||||
|
||||
virtual AbstractTypePtr UpdateParentFunctionType(
|
||||
intptr_t num_parent_type_args_adjustment,
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr) const;
|
||||
|
||||
virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const;
|
||||
#if defined(DEBUG)
|
||||
// Check if type is canonical.
|
||||
|
|
48
tests/language/regress/regress50905_test.dart
Normal file
48
tests/language/regress/regress50905_test.dart
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Verifies that constructor tear-off of a generic class
|
||||
// has a correct type and can be called via Function.apply.
|
||||
//
|
||||
// Regression test for https://github.com/dart-lang/sdk/issues/50905.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
class A<T> {
|
||||
A({required T Function() x}) {
|
||||
Expect.equals(f1, x);
|
||||
}
|
||||
}
|
||||
|
||||
class B<T> {
|
||||
B({required Map<S, T> Function<S>() x}) {
|
||||
Expect.equals(f2, x);
|
||||
}
|
||||
}
|
||||
|
||||
int f1() => 0;
|
||||
Map<U, int> f2<U>() => {};
|
||||
|
||||
A<V> t1<V>({required V Function() x}) => throw 'unused';
|
||||
A<int> t2({required int Function() x}) => throw 'unused';
|
||||
B<V> t3<V>({required Map<U, V> Function<U>() x}) => throw 'unused';
|
||||
B<int> t4({required Map<U, int> Function<U>() x}) => throw 'unused';
|
||||
|
||||
void main() {
|
||||
Function c1 = A.new;
|
||||
Expect.equals(t1.runtimeType.toString(), c1.runtimeType.toString());
|
||||
|
||||
Function c2 = A<int>.new;
|
||||
Expect.equals(t2.runtimeType.toString(), c2.runtimeType.toString());
|
||||
final o2 = Function.apply(c2, [], {#x: f1});
|
||||
Expect.isTrue(o2 is A<int>);
|
||||
|
||||
Function c3 = B.new;
|
||||
Expect.equals(t3.runtimeType.toString(), c3.runtimeType.toString());
|
||||
|
||||
Function c4 = B<int>.new;
|
||||
Expect.equals(t4.runtimeType.toString(), c4.runtimeType.toString());
|
||||
final o4 = Function.apply(c4, [], {#x: f2});
|
||||
Expect.isTrue(o4 is B<int>);
|
||||
}
|
Loading…
Reference in a new issue