Skip to content

Commit ff363b5

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Avoid false positives on extension type depending on itself
Closes #54169 Part of #49731 Change-Id: Ia4a8a2237785b0876461473f98af89b82ccc10eb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/338601 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 08d7e0a commit ff363b5

19 files changed

+382
-3
lines changed

pkg/front_end/lib/src/fasta/source/source_extension_type_declaration_builder.dart

+13-3
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ class SourceExtensionTypeDeclarationBuilder
262262
if (representationFieldBuilder != null) {
263263
TypeBuilder typeBuilder = representationFieldBuilder!.type;
264264
if (typeBuilder.isExplicit) {
265-
if (_checkRepresentationDependency(typeBuilder, {this}, {})) {
265+
if (_checkRepresentationDependency(typeBuilder, this, {this}, {})) {
266266
representationType = const InvalidType();
267267
} else {
268268
representationType =
@@ -309,6 +309,7 @@ class SourceExtensionTypeDeclarationBuilder
309309

310310
bool _checkRepresentationDependency(
311311
TypeBuilder? typeBuilder,
312+
ExtensionTypeDeclarationBuilder rootExtensionTypeDeclaration,
312313
Set<ExtensionTypeDeclarationBuilder> seenExtensionTypeDeclarations,
313314
Set<TypeAliasBuilder> usedTypeAliasBuilders) {
314315
TypeBuilder? unaliased = typeBuilder?.unalias(
@@ -322,7 +323,9 @@ class SourceExtensionTypeDeclarationBuilder
322323
typeArguments: List<TypeBuilder>? arguments
323324
):
324325
if (declaration is ExtensionTypeDeclarationBuilder) {
325-
if (!seenExtensionTypeDeclarations.add(declaration)) {
326+
bool declarationSeenFirstTime =
327+
seenExtensionTypeDeclarations.add(declaration);
328+
if (declaration == rootExtensionTypeDeclaration) {
326329
List<LocatedMessage> context = [];
327330
for (ExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder
328331
in seenExtensionTypeDeclarations) {
@@ -349,9 +352,10 @@ class SourceExtensionTypeDeclarationBuilder
349352
} else {
350353
TypeBuilder? representationTypeBuilder =
351354
declaration.declaredRepresentationTypeBuilder;
352-
if (representationTypeBuilder != null) {
355+
if (declarationSeenFirstTime && representationTypeBuilder != null) {
353356
if (_checkRepresentationDependency(
354357
representationTypeBuilder,
358+
rootExtensionTypeDeclaration,
355359
seenExtensionTypeDeclarations.toSet(),
356360
usedTypeAliasBuilders.toSet())) {
357361
return true;
@@ -363,6 +367,7 @@ class SourceExtensionTypeDeclarationBuilder
363367
for (TypeBuilder typeArgument in arguments) {
364368
if (_checkRepresentationDependency(
365369
typeArgument,
370+
rootExtensionTypeDeclaration,
366371
seenExtensionTypeDeclarations.toSet(),
367372
usedTypeAliasBuilders.toSet())) {
368373
return true;
@@ -376,6 +381,7 @@ class SourceExtensionTypeDeclarationBuilder
376381
):
377382
if (_checkRepresentationDependency(
378383
returnType,
384+
rootExtensionTypeDeclaration,
379385
seenExtensionTypeDeclarations.toSet(),
380386
usedTypeAliasBuilders.toSet())) {
381387
return true;
@@ -384,6 +390,7 @@ class SourceExtensionTypeDeclarationBuilder
384390
for (ParameterBuilder formal in formals) {
385391
if (_checkRepresentationDependency(
386392
formal.type,
393+
rootExtensionTypeDeclaration,
387394
seenExtensionTypeDeclarations.toSet(),
388395
usedTypeAliasBuilders.toSet())) {
389396
return true;
@@ -395,6 +402,7 @@ class SourceExtensionTypeDeclarationBuilder
395402
TypeBuilder? bound = typeVariable.bound;
396403
if (_checkRepresentationDependency(
397404
bound,
405+
rootExtensionTypeDeclaration,
398406
seenExtensionTypeDeclarations.toSet(),
399407
usedTypeAliasBuilders.toSet())) {
400408
return true;
@@ -409,6 +417,7 @@ class SourceExtensionTypeDeclarationBuilder
409417
for (RecordTypeFieldBuilder field in positionalFields) {
410418
if (_checkRepresentationDependency(
411419
field.type,
420+
rootExtensionTypeDeclaration,
412421
seenExtensionTypeDeclarations.toSet(),
413422
usedTypeAliasBuilders.toSet())) {
414423
return true;
@@ -419,6 +428,7 @@ class SourceExtensionTypeDeclarationBuilder
419428
for (RecordTypeFieldBuilder field in namedFields) {
420429
if (_checkRepresentationDependency(
421430
field.type,
431+
rootExtensionTypeDeclaration,
422432
seenExtensionTypeDeclarations.toSet(),
423433
usedTypeAliasBuilders.toSet())) {
424434
return true;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2023, 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+
extension type E1<X>(X it) {}
6+
typedef F<X> = X;
7+
extension type E2<X>(E1<F<E1<X>>> it) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F<X extends core::Object? = dynamic> = X%;
6+
extension type E1<X extends core::Object? = dynamic>(X% it) {
7+
abstract extension-type-member representation-field get it() → X%;
8+
constructor • = self::E1|constructor#;
9+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
10+
}
11+
extension type E2<X extends core::Object? = dynamic>(self::E1<self::E1<X%>% /* = X% */>% /* = X% */ it) {
12+
abstract extension-type-member representation-field get it() → self::E1<self::E1<X%>% /* = X% */>% /* = X% */;
13+
constructor • = self::E2|constructor#;
14+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
15+
}
16+
static extension-type-member method E1|constructor#<X extends core::Object? = dynamic>(self::E1|constructor#::X% it) → self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ {
17+
lowered final self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ #this = it;
18+
return #this;
19+
}
20+
static extension-type-member method E1|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1|constructor#_#new#tearOff::X% it) → self::E1<self::E1|constructor#_#new#tearOff::X%>% /* = self::E1|constructor#_#new#tearOff::X% */
21+
return self::E1|constructor#<self::E1|constructor#_#new#tearOff::X%>(it);
22+
static extension-type-member method E2|constructor#<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#::X%>% /* = self::E2|constructor#::X% */>% /* = self::E2|constructor#::X% */ it) → self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ {
23+
lowered final self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ #this = it;
24+
return #this;
25+
}
26+
static extension-type-member method E2|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */>% /* = self::E2|constructor#_#new#tearOff::X% */ it) → self::E2<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */
27+
return self::E2|constructor#<self::E2|constructor#_#new#tearOff::X%>(it);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F<X extends core::Object? = dynamic> = X%;
6+
extension type E1<X extends core::Object? = dynamic>(X% it) {
7+
abstract extension-type-member representation-field get it() → X%;
8+
constructor • = self::E1|constructor#;
9+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
10+
}
11+
extension type E2<X extends core::Object? = dynamic>(self::E1<self::E1<X%>% /* = X% */>% /* = X% */ it) {
12+
abstract extension-type-member representation-field get it() → self::E1<self::E1<X%>% /* = X% */>% /* = X% */;
13+
constructor • = self::E2|constructor#;
14+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
15+
}
16+
static extension-type-member method E1|constructor#<X extends core::Object? = dynamic>(self::E1|constructor#::X% it) → self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ {
17+
lowered final self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ #this = it;
18+
return #this;
19+
}
20+
static extension-type-member method E1|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1|constructor#_#new#tearOff::X% it) → self::E1<self::E1|constructor#_#new#tearOff::X%>% /* = self::E1|constructor#_#new#tearOff::X% */
21+
return self::E1|constructor#<self::E1|constructor#_#new#tearOff::X%>(it);
22+
static extension-type-member method E2|constructor#<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#::X%>% /* = self::E2|constructor#::X% */>% /* = self::E2|constructor#::X% */ it) → self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ {
23+
lowered final self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ #this = it;
24+
return #this;
25+
}
26+
static extension-type-member method E2|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */>% /* = self::E2|constructor#_#new#tearOff::X% */ it) → self::E2<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */
27+
return self::E2|constructor#<self::E2|constructor#_#new#tearOff::X%>(it);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
extension type E1<X>(X it) {}
2+
typedef F<X> = X;
3+
extension type E2<X>(E1<F<E1<X>>> it) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
extension type E1<X>(X it) {}
2+
extension type E2<X>(E1<F<E1<X>>> it) {}
3+
typedef F<X> = X;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F<X extends core::Object? = dynamic> = X%;
6+
extension type E1<X extends core::Object? = dynamic>(X% it) {
7+
abstract extension-type-member representation-field get it() → X%;
8+
constructor • = self::E1|constructor#;
9+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
10+
}
11+
extension type E2<X extends core::Object? = dynamic>(self::E1<self::E1<X%>% /* = X% */>% /* = X% */ it) {
12+
abstract extension-type-member representation-field get it() → self::E1<self::E1<X%>% /* = X% */>% /* = X% */;
13+
constructor • = self::E2|constructor#;
14+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
15+
}
16+
static extension-type-member method E1|constructor#<X extends core::Object? = dynamic>(self::E1|constructor#::X% it) → self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ {
17+
lowered final self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ #this = it;
18+
return #this;
19+
}
20+
static extension-type-member method E1|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1|constructor#_#new#tearOff::X% it) → self::E1<self::E1|constructor#_#new#tearOff::X%>% /* = self::E1|constructor#_#new#tearOff::X% */
21+
return self::E1|constructor#<self::E1|constructor#_#new#tearOff::X%>(it);
22+
static extension-type-member method E2|constructor#<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#::X%>% /* = self::E2|constructor#::X% */>% /* = self::E2|constructor#::X% */ it) → self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ {
23+
lowered final self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ #this = it;
24+
return #this;
25+
}
26+
static extension-type-member method E2|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */>% /* = self::E2|constructor#_#new#tearOff::X% */ it) → self::E2<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */
27+
return self::E2|constructor#<self::E2|constructor#_#new#tearOff::X%>(it);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F<X extends core::Object? = dynamic> = X%;
6+
extension type E1<X extends core::Object? = dynamic>(X% it) {
7+
abstract extension-type-member representation-field get it() → X%;
8+
constructor • = self::E1|constructor#;
9+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
10+
}
11+
extension type E2<X extends core::Object? = dynamic>(self::E1<self::E1<X%>% /* = X% */>% /* = X% */ it) {
12+
abstract extension-type-member representation-field get it() → self::E1<self::E1<X%>% /* = X% */>% /* = X% */;
13+
constructor • = self::E2|constructor#;
14+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
15+
}
16+
static extension-type-member method E1|constructor#<X extends core::Object? = dynamic>(self::E1|constructor#::X% it) → self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ {
17+
lowered final self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ #this = it;
18+
return #this;
19+
}
20+
static extension-type-member method E1|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1|constructor#_#new#tearOff::X% it) → self::E1<self::E1|constructor#_#new#tearOff::X%>% /* = self::E1|constructor#_#new#tearOff::X% */
21+
return self::E1|constructor#<self::E1|constructor#_#new#tearOff::X%>(it);
22+
static extension-type-member method E2|constructor#<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#::X%>% /* = self::E2|constructor#::X% */>% /* = self::E2|constructor#::X% */ it) → self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ {
23+
lowered final self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ #this = it;
24+
return #this;
25+
}
26+
static extension-type-member method E2|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */>% /* = self::E2|constructor#_#new#tearOff::X% */ it) → self::E2<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */
27+
return self::E2|constructor#<self::E2|constructor#_#new#tearOff::X%>(it);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F<X extends core::Object? = dynamic> = X%;
6+
extension type E1<X extends core::Object? = dynamic>(X% it) {
7+
abstract extension-type-member representation-field get it() → X%;
8+
constructor • = self::E1|constructor#;
9+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
10+
}
11+
extension type E2<X extends core::Object? = dynamic>(self::E1<self::E1<X%>% /* = X% */>% /* = X% */ it) {
12+
abstract extension-type-member representation-field get it() → self::E1<self::E1<X%>% /* = X% */>% /* = X% */;
13+
constructor • = self::E2|constructor#;
14+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
15+
}
16+
static extension-type-member method E1|constructor#<X extends core::Object? = dynamic>(self::E1|constructor#::X% it) → self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */
17+
;
18+
static extension-type-member method E1|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1|constructor#_#new#tearOff::X% it) → self::E1<self::E1|constructor#_#new#tearOff::X%>% /* = self::E1|constructor#_#new#tearOff::X% */
19+
return self::E1|constructor#<self::E1|constructor#_#new#tearOff::X%>(it);
20+
static extension-type-member method E2|constructor#<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#::X%>% /* = self::E2|constructor#::X% */>% /* = self::E2|constructor#::X% */ it) → self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */
21+
;
22+
static extension-type-member method E2|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */>% /* = self::E2|constructor#_#new#tearOff::X% */ it) → self::E2<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */
23+
return self::E2|constructor#<self::E2|constructor#_#new#tearOff::X%>(it);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F<X extends core::Object? = dynamic> = X%;
6+
extension type E1<X extends core::Object? = dynamic>(X% it) {
7+
abstract extension-type-member representation-field get it() → X%;
8+
constructor • = self::E1|constructor#;
9+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
10+
}
11+
extension type E2<X extends core::Object? = dynamic>(self::E1<self::E1<X%>% /* = X% */>% /* = X% */ it) {
12+
abstract extension-type-member representation-field get it() → self::E1<self::E1<X%>% /* = X% */>% /* = X% */;
13+
constructor • = self::E2|constructor#;
14+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
15+
}
16+
static extension-type-member method E1|constructor#<X extends core::Object? = dynamic>(self::E1|constructor#::X% it) → self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ {
17+
lowered final self::E1<self::E1|constructor#::X%> /* = self::E1|constructor#::X% */ #this = it;
18+
return #this;
19+
}
20+
static extension-type-member method E1|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1|constructor#_#new#tearOff::X% it) → self::E1<self::E1|constructor#_#new#tearOff::X%>% /* = self::E1|constructor#_#new#tearOff::X% */
21+
return self::E1|constructor#<self::E1|constructor#_#new#tearOff::X%>(it);
22+
static extension-type-member method E2|constructor#<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#::X%>% /* = self::E2|constructor#::X% */>% /* = self::E2|constructor#::X% */ it) → self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ {
23+
lowered final self::E2<self::E2|constructor#::X%> /* = self::E2|constructor#::X% */ #this = it;
24+
return #this;
25+
}
26+
static extension-type-member method E2|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E1<self::E1<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */>% /* = self::E2|constructor#_#new#tearOff::X% */ it) → self::E2<self::E2|constructor#_#new#tearOff::X%>% /* = self::E2|constructor#_#new#tearOff::X% */
27+
return self::E2|constructor#<self::E2|constructor#_#new#tearOff::X%>(it);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) 2023, 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+
extension type ET1(ET2 it) {}
6+
extension type ET2(ET2 it) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/extension_types/issue54169_2.dart:6:20: Error: An extension type can't depend on itself through its representation type.
6+
// extension type ET2(ET2 it) {}
7+
// ^
8+
//
9+
import self as self;
10+
11+
extension type ET1(self::ET2 /* = invalid-type */ it) {
12+
abstract extension-type-member representation-field get it() → self::ET2 /* = invalid-type */;
13+
constructor • = self::ET1|constructor#;
14+
constructor tearoff • = self::ET1|constructor#_#new#tearOff;
15+
}
16+
extension type ET2(invalid-type it) {
17+
abstract extension-type-member representation-field get it() → self::ET2 /* = invalid-type */;
18+
constructor • = self::ET2|constructor#;
19+
constructor tearoff • = self::ET2|constructor#_#new#tearOff;
20+
}
21+
static extension-type-member method ET1|constructor#(self::ET2 /* = invalid-type */ it) → self::ET1 /* = invalid-type */ {
22+
lowered final self::ET1 /* = invalid-type */ #this = it;
23+
return #this;
24+
}
25+
static extension-type-member method ET1|constructor#_#new#tearOff(self::ET2 /* = invalid-type */ it) → self::ET1 /* = invalid-type */
26+
return self::ET1|constructor#(it);
27+
static extension-type-member method ET2|constructor#(self::ET2 /* = invalid-type */ it) → self::ET2 /* = invalid-type */ {
28+
lowered final self::ET2 /* = invalid-type */ #this = it;
29+
return #this;
30+
}
31+
static extension-type-member method ET2|constructor#_#new#tearOff(self::ET2 /* = invalid-type */ it) → self::ET2 /* = invalid-type */
32+
return self::ET2|constructor#(it);

0 commit comments

Comments
 (0)