Skip to content

Commit 33cabf4

Browse files
creliercommit-bot@chromium.org
authored andcommitted
[VM/runtime] Allow generic function types as type arguments in the VM.
Type parameter scopes were not set properly when loading bounds with generic function types from kernel file. The trail to avoid infinite recursion while comparing type parameter bounds was not used properly. Fixes #45313 Fixes #45322 Fixes #44930 TEST=regression tests added Change-Id: I096b7d8c22aa5b3a3a9e12a59b1417388ff5171f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/191465 Commit-Queue: Régis Crelier <[email protected]> Reviewed-by: Siva Annamalai <[email protected]> Reviewed-by: Alexander Markov <[email protected]>
1 parent 1a7d39b commit 33cabf4

File tree

5 files changed

+74
-16
lines changed

5 files changed

+74
-16
lines changed

runtime/vm/compiler/frontend/kernel_translation_helper.cc

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3054,22 +3054,26 @@ void TypeTranslator::BuildFunctionType(bool simple) {
30543054

30553055
// Suspend finalization of types inside this one. They will be finalized after
30563056
// the whole function type is constructed.
3057-
//
3058-
// TODO(31213): Test further when nested generic function types
3059-
// are supported by fasta.
30603057
bool finalize = finalize_;
30613058
finalize_ = false;
3059+
intptr_t type_parameter_count = 0;
30623060

30633061
if (!simple) {
3062+
type_parameter_count = helper_->ReadListLength();
30643063
LoadAndSetupTypeParameters(
30653064
active_class_, Object::null_function(), Object::null_class(), signature,
3066-
helper_->ReadListLength(), active_class_->klass->nnbd_mode());
3065+
type_parameter_count, active_class_->klass->nnbd_mode());
30673066
}
30683067

30693068
ActiveTypeParametersScope scope(
30703069
active_class_, &signature,
30713070
TypeArguments::Handle(Z, signature.type_parameters()), Z);
30723071

3072+
if (!simple) {
3073+
LoadAndSetupBounds(active_class_, Object::null_function(),
3074+
Object::null_class(), signature, type_parameter_count);
3075+
}
3076+
30733077
intptr_t required_count;
30743078
intptr_t all_count;
30753079
intptr_t positional_count;
@@ -3324,7 +3328,6 @@ void TypeTranslator::LoadAndSetupTypeParameters(
33243328
? Nullability::kNonNullable
33253329
: Nullability::kLegacy;
33263330

3327-
// Step a)
33283331
// - Create array of [TypeParameter] objects (without bound).
33293332
// - Create array of [String] objects.
33303333
type_parameters = TypeArguments::New(type_parameter_count);
@@ -3354,20 +3357,35 @@ void TypeTranslator::LoadAndSetupTypeParameters(
33543357
} else {
33553358
name = H.DartIdentifier(lib, helper.name_index_).ptr();
33563359
}
3360+
// Bounds are filled later in LoadAndSetupBounds as bound types may
3361+
// reference type parameters which are not created yet.
33573362
parameter = TypeParameter::New(
33583363
parameterized_class, offset, offset + i, name, null_bound,
33593364
helper.IsGenericCovariantImpl(), nullability);
33603365
type_parameters.SetTypeAt(i, parameter);
33613366
}
33623367
}
3368+
}
33633369

3364-
const FunctionType* enclosing = NULL;
3365-
if (!parameterized_signature.IsNull()) {
3366-
enclosing = &parameterized_signature;
3370+
void TypeTranslator::LoadAndSetupBounds(
3371+
ActiveClass* active_class,
3372+
const Function& function,
3373+
const Class& parameterized_class,
3374+
const FunctionType& parameterized_signature,
3375+
intptr_t type_parameter_count) {
3376+
ASSERT(parameterized_class.IsNull() != parameterized_signature.IsNull());
3377+
ASSERT(type_parameter_count >= 0);
3378+
if (type_parameter_count == 0) {
3379+
return;
33673380
}
3368-
ActiveTypeParametersScope scope(active_class, enclosing, type_parameters, Z);
33693381

3370-
// Step b) Fill in the bounds and default arguments of all [TypeParameter]s.
3382+
const TypeArguments& type_parameters =
3383+
TypeArguments::Handle(Z, !parameterized_class.IsNull()
3384+
? parameterized_class.type_parameters()
3385+
: parameterized_signature.type_parameters());
3386+
TypeParameter& parameter = TypeParameter::Handle(Z);
3387+
3388+
// Fill in the bounds and default arguments of all [TypeParameter]s.
33713389
for (intptr_t i = 0; i < type_parameter_count; i++) {
33723390
TypeParameterHelper helper(helper_);
33733391
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
@@ -3389,6 +3407,9 @@ void TypeTranslator::LoadAndSetupTypeParameters(
33893407

33903408
// Fix bounds and default arguments in all derived type parameters (with
33913409
// different nullabilities).
3410+
const intptr_t offset = !parameterized_signature.IsNull()
3411+
? parameterized_signature.NumParentTypeArguments()
3412+
: 0;
33923413
if (active_class->derived_type_parameters != nullptr) {
33933414
auto& derived = TypeParameter::Handle(Z);
33943415
auto& type = AbstractType::Handle(Z);
@@ -3535,15 +3556,22 @@ void TypeTranslator::SetupFunctionParameters(
35353556

35363557
const FunctionType& signature = FunctionType::Handle(Z, function.signature());
35373558
ASSERT(!signature.IsNull());
3559+
intptr_t type_parameter_count = 0;
35383560
if (!is_factory) {
3561+
type_parameter_count = helper_->ReadListLength();
35393562
LoadAndSetupTypeParameters(active_class_, function, Class::Handle(Z),
3540-
signature, helper_->ReadListLength(),
3563+
signature, type_parameter_count,
35413564
function.nnbd_mode());
3542-
function_node_helper->SetJustRead(FunctionNodeHelper::kTypeParameters);
35433565
}
35443566

35453567
ActiveTypeParametersScope scope(active_class_, function, &signature, Z);
35463568

3569+
if (!is_factory) {
3570+
LoadAndSetupBounds(active_class_, function, Class::Handle(Z), signature,
3571+
type_parameter_count);
3572+
function_node_helper->SetJustRead(FunctionNodeHelper::kTypeParameters);
3573+
}
3574+
35473575
function_node_helper->ReadUntilExcluding(
35483576
FunctionNodeHelper::kPositionalParameters);
35493577

runtime/vm/compiler/frontend/kernel_translation_helper.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,12 @@ class TypeTranslator {
14781478
intptr_t type_parameter_count,
14791479
const NNBDMode nnbd_mode);
14801480

1481+
void LoadAndSetupBounds(ActiveClass* active_class,
1482+
const Function& function,
1483+
const Class& parameterized_class,
1484+
const FunctionType& parameterized_signature,
1485+
intptr_t type_parameter_count);
1486+
14811487
const Type& ReceiverType(const Class& klass);
14821488

14831489
void SetupFunctionParameters(const Class& klass,

runtime/vm/kernel_loader.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,9 @@ void KernelLoader::LoadPreliminaryClass(ClassHelper* class_helper,
14241424
Object::null_function_type(),
14251425
type_parameter_count, klass->nnbd_mode());
14261426

1427+
T.LoadAndSetupBounds(&active_class_, Object::null_function(), *klass,
1428+
Object::null_function_type(), type_parameter_count);
1429+
14271430
// Set super type. Some classes (e.g., Object) do not have one.
14281431
Tag type_tag = helper_.ReadTag(); // read super class type (part 1).
14291432
if (type_tag == kSomething) {

runtime/vm/object.cc

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21117,10 +21117,12 @@ bool TypeParameter::IsEquivalent(const Instance& other,
2111721117
return false;
2111821118
}
2111921119
// Compare bounds.
21120+
if (TestAndAddBuddyToTrail(&trail, other_type_param)) {
21121+
return true;
21122+
}
2112021123
AbstractType& type = AbstractType::Handle(bound());
2112121124
AbstractType& other_type = AbstractType::Handle(other_type_param.bound());
21122-
if (!TestAndAddBuddyToTrail(&trail, other_type_param) &&
21123-
!type.IsEquivalent(other_type, kind, trail)) {
21125+
if (!type.IsEquivalent(other_type, kind, trail)) {
2112421126
return false;
2112521127
}
2112621128
if (kind == TypeEquality::kCanonical) {
@@ -21164,11 +21166,13 @@ bool TypeParameter::IsEquivalent(const Instance& other,
2116421166
}
2116521167
}
2116621168
// Compare bounds.
21169+
if (TestAndAddBuddyToTrail(&trail, other_type_param)) {
21170+
return true;
21171+
}
2116721172
AbstractType& upper_bound = AbstractType::Handle(bound());
2116821173
AbstractType& other_type_param_upper_bound =
2116921174
AbstractType::Handle(other_type_param.bound());
21170-
if (!TestAndAddBuddyToTrail(&trail, other_type_param) &&
21171-
!upper_bound.IsEquivalent(other_type_param_upper_bound, kind, trail)) {
21175+
if (!upper_bound.IsEquivalent(other_type_param_upper_bound, kind, trail)) {
2117221176
return false;
2117321177
}
2117421178
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// SharedOptions=--enable-experiment=generic-metadata
6+
7+
import "package:expect/expect.dart";
8+
9+
typedef TEST_TYPEDEF<TT extends T Function<T>(T)> = void
10+
Function<TTT extends TT>();
11+
void testme<TT extends T Function<T>(T)>() {}
12+
13+
main() {
14+
Expect.isTrue(testme is TEST_TYPEDEF);
15+
TEST_TYPEDEF ttttt = testme;
16+
Expect.isTrue(ttttt is TEST_TYPEDEF);
17+
}

0 commit comments

Comments
 (0)