Skip to content

Commit dc2a0aa

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[cfe] Always query for ranked superclass info in least upper bound
Previously, the info was inconsistently queried, leading to nondeterministic behaviors. Closes #61791 Change-Id: I5d47d0f29b0e78d2834ae3c5793fd05171cf9156 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/457360 Commit-Queue: Chloe Stefantsova <[email protected]> Reviewed-by: Johnni Winther <[email protected]> Auto-Submit: Chloe Stefantsova <[email protected]>
1 parent b1c6707 commit dc2a0aa

9 files changed

+200
-13
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) 2025, 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+
class A {}
6+
7+
extension type E1(A a) implements A {}
8+
9+
class B extends A {}
10+
11+
extension type E2(B b) implements B, E1 {}
12+
13+
test(E2 e) {
14+
var list1 = ["", e];
15+
var list2 = ["", e];
16+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class A extends core::Object {
6+
synthetic constructor •() → self::A
7+
: super core::Object::•()
8+
;
9+
}
10+
class B extends self::A {
11+
synthetic constructor •() → self::B
12+
: super self::A::•()
13+
;
14+
}
15+
extension type E1(self::A a) implements self::A {
16+
abstract extension-type-member representation-field get a() → self::A;
17+
constructor • = self::E1|constructor#;
18+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
19+
}
20+
extension type E2(self::B b) implements self::B, self::E1 /* erasure=self::A */ {
21+
abstract extension-type-member representation-field get b() → self::B;
22+
constructor • = self::E2|constructor#;
23+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
24+
}
25+
static extension-type-member method E1|constructor#(self::A a) → self::E1 /* erasure=self::A */ {
26+
lowered final self::E1 /* erasure=self::A */ #this = a;
27+
return #this;
28+
}
29+
static extension-type-member synthetic method E1|constructor#_#new#tearOff(self::A a) → self::E1 /* erasure=self::A */
30+
return self::E1|constructor#(a);
31+
static extension-type-member method E2|constructor#(self::B b) → self::E2 /* erasure=self::B */ {
32+
lowered final self::E2 /* erasure=self::B */ #this = b;
33+
return #this;
34+
}
35+
static extension-type-member synthetic method E2|constructor#_#new#tearOff(self::B b) → self::E2 /* erasure=self::B */
36+
return self::E2|constructor#(b);
37+
static method test(self::E2 /* erasure=self::B */ e) → dynamic {
38+
core::List<core::Object> list1 = <core::Object>["", e];
39+
core::List<core::Object> list2 = <core::Object>["", e];
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class A extends core::Object {
6+
synthetic constructor •() → self::A
7+
: super core::Object::•()
8+
;
9+
}
10+
class B extends self::A {
11+
synthetic constructor •() → self::B
12+
: super self::A::•()
13+
;
14+
}
15+
extension type E1(self::A a) implements self::A {
16+
abstract extension-type-member representation-field get a() → self::A;
17+
constructor • = self::E1|constructor#;
18+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
19+
}
20+
extension type E2(self::B b) implements self::B, self::E1 /* erasure=self::A */ {
21+
abstract extension-type-member representation-field get b() → self::B;
22+
constructor • = self::E2|constructor#;
23+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
24+
}
25+
static extension-type-member method E1|constructor#(self::A a) → self::E1 /* erasure=self::A */ {
26+
lowered final self::E1 /* erasure=self::A */ #this = a;
27+
return #this;
28+
}
29+
static extension-type-member synthetic method E1|constructor#_#new#tearOff(self::A a) → self::E1 /* erasure=self::A */
30+
return self::E1|constructor#(a);
31+
static extension-type-member method E2|constructor#(self::B b) → self::E2 /* erasure=self::B */ {
32+
lowered final self::E2 /* erasure=self::B */ #this = b;
33+
return #this;
34+
}
35+
static extension-type-member synthetic method E2|constructor#_#new#tearOff(self::B b) → self::E2 /* erasure=self::B */
36+
return self::E2|constructor#(b);
37+
static method test(self::E2 /* erasure=self::B */ e) → dynamic {
38+
core::List<core::Object> list1 = <core::Object>["", e];
39+
core::List<core::Object> list2 = <core::Object>["", e];
40+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class A extends core::Object {
6+
synthetic constructor •() → self::A
7+
;
8+
}
9+
class B extends self::A {
10+
synthetic constructor •() → self::B
11+
;
12+
}
13+
extension type E1(self::A a) implements self::A {
14+
abstract extension-type-member representation-field get a() → self::A;
15+
constructor • = self::E1|constructor#;
16+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
17+
}
18+
extension type E2(self::B b) implements self::B, self::E1 /* erasure=self::A */ {
19+
abstract extension-type-member representation-field get b() → self::B;
20+
constructor • = self::E2|constructor#;
21+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
22+
}
23+
static extension-type-member method E1|constructor#(self::A a) → self::E1 /* erasure=self::A */
24+
;
25+
static extension-type-member synthetic method E1|constructor#_#new#tearOff(self::A a) → self::E1 /* erasure=self::A */
26+
return self::E1|constructor#(a);
27+
static extension-type-member method E2|constructor#(self::B b) → self::E2 /* erasure=self::B */
28+
;
29+
static extension-type-member synthetic method E2|constructor#_#new#tearOff(self::B b) → self::E2 /* erasure=self::B */
30+
return self::E2|constructor#(b);
31+
static method test(self::E2 /* erasure=self::B */ e) → dynamic
32+
;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class A extends core::Object {
6+
synthetic constructor •() → self::A
7+
: super core::Object::•()
8+
;
9+
}
10+
class B extends self::A {
11+
synthetic constructor •() → self::B
12+
: super self::A::•()
13+
;
14+
}
15+
extension type E1(self::A a) implements self::A {
16+
abstract extension-type-member representation-field get a() → self::A;
17+
constructor • = self::E1|constructor#;
18+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
19+
}
20+
extension type E2(self::B b) implements self::B, self::E1 /* erasure=self::A */ {
21+
abstract extension-type-member representation-field get b() → self::B;
22+
constructor • = self::E2|constructor#;
23+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
24+
}
25+
static extension-type-member method E1|constructor#(self::A a) → self::E1 /* erasure=self::A */ {
26+
lowered final self::E1 /* erasure=self::A */ #this = a;
27+
return #this;
28+
}
29+
static extension-type-member synthetic method E1|constructor#_#new#tearOff(self::A a) → self::E1 /* erasure=self::A */
30+
return self::E1|constructor#(a);
31+
static extension-type-member method E2|constructor#(self::B b) → self::E2 /* erasure=self::B */ {
32+
lowered final self::E2 /* erasure=self::B */ #this = b;
33+
return #this;
34+
}
35+
static extension-type-member synthetic method E2|constructor#_#new#tearOff(self::B b) → self::E2 /* erasure=self::B */
36+
return self::E2|constructor#(b);
37+
static method test(self::E2 /* erasure=self::B */ e) → dynamic {
38+
core::List<core::Object> list1 = core::_GrowableList::_literal2<core::Object>("", e);
39+
core::List<core::Object> list2 = core::_GrowableList::_literal2<core::Object>("", e);
40+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class A {}
2+
3+
extension type E1(A a) implements A {}
4+
5+
class B extends A {}
6+
7+
extension type E2(B b) implements B, E1 {}
8+
9+
test(E2 e) {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class A {}
2+
3+
class B extends A {}
4+
5+
extension type E1(A a) implements A {}
6+
7+
extension type E2(B b) implements B, E1 {}
8+
9+
test(E2 e) {}

pkg/kernel/lib/class_hierarchy.dart

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -762,10 +762,12 @@ class ClosedWorldClassHierarchy
762762
}
763763

764764
List<_ClassInfo> _getRankedSuperclassInfos(_ClassInfo info) {
765-
if (info.leastUpperBoundInfos != null) return info.leastUpperBoundInfos!;
765+
if (info._rankedSuperclassInfos != null) {
766+
return info._rankedSuperclassInfos!;
767+
}
766768
_LubHeap heap = new _LubHeap()..add(info);
767769
List<_ClassInfo> chain = <_ClassInfo>[];
768-
info.leastUpperBoundInfos = chain;
770+
info._rankedSuperclassInfos = chain;
769771
_ClassInfo? lastInfo = null;
770772
while (heap.isNotEmpty) {
771773
_ClassInfo nextInfo = heap.remove();
@@ -792,18 +794,16 @@ class ClosedWorldClassHierarchy
792794

793795
List<_ClassInfo> _getCombinedRankedSuperclassInfosFromList(
794796
List<_ClassInfo> infos) {
795-
if (infos.length == 1 && infos.single.leastUpperBoundInfos != null) {
796-
return infos.single.leastUpperBoundInfos!;
797+
if (infos.length == 1 && infos.single._rankedSuperclassInfos != null) {
798+
return infos.single._rankedSuperclassInfos!;
797799
}
798800

799801
_LubHeap heap = new _LubHeap();
800802
for (_ClassInfo info in infos) {
801803
heap.add(info);
802-
if (info.leastUpperBoundInfos == null) {
803-
List<_ClassInfo> chainForInfo = _getRankedSuperclassInfos(info);
804-
for (_ClassInfo fromChain in chainForInfo) {
805-
heap.add(fromChain);
806-
}
804+
List<_ClassInfo> chainForInfo = _getRankedSuperclassInfos(info);
805+
for (_ClassInfo fromChain in chainForInfo) {
806+
heap.add(fromChain);
807807
}
808808
}
809809

@@ -1857,7 +1857,8 @@ class _ClassInfo {
18571857
late final Uint32List superclassIntervalList;
18581858
late final Uint32List supertypeIntervalList;
18591859

1860-
List<_ClassInfo>? leastUpperBoundInfos;
1860+
/// Cached result of [ClosedWorldClassHierarchy._getRankedSuperclassInfos].
1861+
List<_ClassInfo>? _rankedSuperclassInfos;
18611862

18621863
/// Maps generic supertype classes to the instantiations implemented by this
18631864
/// class.

pkg/kernel/lib/src/standard_bounds.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -893,19 +893,19 @@ mixin StandardBounds {
893893

894894
int computeExtensionTypeDeclarationDepth(
895895
ExtensionTypeDeclaration extensionTypeDeclaration,
896-
List<InterfaceType> superInterfaceType) {
896+
List<InterfaceType> superInterfaceTypes) {
897897
int? depth = extensionTypeDeclarationDepth[extensionTypeDeclaration];
898898
if (depth == null) {
899899
int maxDepth = 0;
900900
for (DartType implemented in extensionTypeDeclaration.implements) {
901901
if (implemented is ExtensionType) {
902902
int supertypeDepth = computeExtensionTypeDeclarationDepth(
903-
implemented.extensionTypeDeclaration, superInterfaceType);
903+
implemented.extensionTypeDeclaration, superInterfaceTypes);
904904
if (supertypeDepth >= maxDepth) {
905905
maxDepth = supertypeDepth + 1;
906906
}
907907
} else if (implemented is InterfaceType) {
908-
superInterfaceType.add(implemented);
908+
superInterfaceTypes.add(implemented);
909909
}
910910
}
911911
depth = extensionTypeDeclarationDepth[extensionTypeDeclaration] =

0 commit comments

Comments
 (0)