Skip to content

Commit d039e28

Browse files
alexmarkovCommit Queue
authored andcommitted
[tfa,aot,dart2wasm] More precise intersection of a wide cone type with an empty cone type
When cone type has a large number of allocated subtypes, TFA uses symbolic wide cone type as a faster approximation to speed up the analysis. Intersection of wide cone type C1+ with cone type C2+ when there is no subtyping relation between C1 and C2 results in approximate type C1+. As a result, analysis may fail to determine that certain type test will never succeed. This change improves precision of cone and wide cone intersections and unions in case cone type has an empty specialization (no allocated subtypes). TEST=pkg/vm/testcases/transformations/type_flow/transformer/regress_60733.dart Fixes #60733 Change-Id: I51287d38a9e5f3c0ce88dab358d0825843a0de03 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/428840 Reviewed-by: Slava Egorov <[email protected]> Reviewed-by: Martin Kustermann <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent 630a3aa commit d039e28

File tree

4 files changed

+108
-3
lines changed

4 files changed

+108
-3
lines changed

pkg/vm/lib/transformations/type_flow/types.dart

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -890,10 +890,12 @@ class ConeType extends Type {
890890
if (this == other) {
891891
return this;
892892
}
893-
if (other.cls.isSubtypeOf(this.cls)) {
893+
if (other.hasEmptySpecialization(typeHierarchy) ||
894+
other.cls.isSubtypeOf(this.cls)) {
894895
return this;
895896
}
896-
if (this.cls.isSubtypeOf(other.cls)) {
897+
if (this.hasEmptySpecialization(typeHierarchy) ||
898+
this.cls.isSubtypeOf(other.cls)) {
897899
return other;
898900
}
899901
} else if (other is ConcreteType) {
@@ -916,6 +918,10 @@ class ConeType extends Type {
916918
if (this == other) {
917919
return this;
918920
}
921+
if (this.hasEmptySpecialization(typeHierarchy) ||
922+
other.hasEmptySpecialization(typeHierarchy)) {
923+
return emptyType;
924+
}
919925
if (other.cls.isSubtypeOf(this.cls)) {
920926
return other;
921927
}
@@ -956,6 +962,9 @@ class WideConeType extends ConeType {
956962
identical(this, other) ||
957963
(other is WideConeType) && identical(this.cls, other.cls);
958964

965+
@override
966+
String toString() => "_T (${cls})++";
967+
959968
@override
960969
int get order => TypeOrder.WideCone.index;
961970

@@ -975,7 +984,8 @@ class WideConeType extends ConeType {
975984
return other.union(this, typeHierarchy);
976985
}
977986
if (other is ConeType) {
978-
if (other.cls.isSubtypeOf(this.cls)) {
987+
if (other.hasEmptySpecialization(typeHierarchy) ||
988+
other.cls.isSubtypeOf(this.cls)) {
979989
return this;
980990
}
981991
if (this.cls.isSubtypeOf(other.cls)) {
@@ -1013,6 +1023,9 @@ class WideConeType extends ConeType {
10131023
return other.intersection(this, typeHierarchy);
10141024
}
10151025
if (other is ConeType) {
1026+
if (other.hasEmptySpecialization(typeHierarchy)) {
1027+
return emptyType;
1028+
}
10161029
if (other.cls.isSubtypeOf(this.cls)) {
10171030
return other;
10181031
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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+
// Regression test for https://github.com/dart-lang/sdk/issues/60733.
6+
// Verifies that intersection of a wide cone with an empty cone
7+
// results in empty type.
8+
9+
// This test assumes the following low thresholds:
10+
// maxAllocatedTypesInSetSpecialization = 4,
11+
12+
class Widget {}
13+
14+
class W1 implements Widget {}
15+
16+
class W2 implements Widget {}
17+
18+
class W3 implements Widget {}
19+
20+
class W4 implements Widget {}
21+
22+
class W5 implements Widget {}
23+
24+
class _HasCreationLocation {
25+
Object? get location => 'hey';
26+
}
27+
28+
Object? _getObjectCreationLocation(Object object) {
29+
return object is _HasCreationLocation ? object.location : null;
30+
}
31+
32+
final widgets = <Widget>[W1(), W2(), W3(), W4(), W5()];
33+
34+
void main() {
35+
for (Widget w in widgets) {
36+
print(_getObjectCreationLocation(w));
37+
}
38+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
library #lib;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "dart:_internal" as _in;
5+
6+
abstract class Widget extends core::Object {
7+
}
8+
class W1 extends core::Object implements self::Widget {
9+
synthetic constructor •() → self::W1
10+
: super core::Object::•()
11+
;
12+
}
13+
class W2 extends core::Object implements self::Widget {
14+
synthetic constructor •() → self::W2
15+
: super core::Object::•()
16+
;
17+
}
18+
class W3 extends core::Object implements self::Widget {
19+
synthetic constructor •() → self::W3
20+
: super core::Object::•()
21+
;
22+
}
23+
class W4 extends core::Object implements self::Widget {
24+
synthetic constructor •() → self::W4
25+
: super core::Object::•()
26+
;
27+
}
28+
class W5 extends core::Object implements self::Widget {
29+
synthetic constructor •() → self::W5
30+
: super core::Object::•()
31+
;
32+
}
33+
34+
[@vm.inferred-type.metadata=dart.core::_GrowableList<#lib::Widget>]
35+
static final field core::List<self::Widget> widgets = [@vm.inferred-type.metadata=dart.core::_GrowableList<#lib::Widget>] core::_GrowableList::_literal5<self::Widget>(new self::W1::•(), new self::W2::•(), new self::W3::•(), new self::W4::•(), new self::W5::•());
36+
37+
[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)]
38+
static method _getObjectCreationLocation() → core::Object? {
39+
return _in::unsafeCast<core::Object?>(null);
40+
}
41+
42+
[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)]
43+
static method main() → void {
44+
{
45+
synthesized core::Iterator<self::Widget> :sync-for-iterator = [@vm.direct-call.metadata=dart.core::_GrowableList.iterator] [@vm.inferred-type.metadata=dart._internal::ListIterator<#lib::Widget>] [@vm.inferred-type.metadata=dart.core::_GrowableList<#lib::Widget>] self::widgets.{core::Iterable::iterator}{core::Iterator<self::Widget>};
46+
for (; [@vm.direct-call.metadata=dart._internal::ListIterator.moveNext] [@vm.inferred-type.metadata=dart.core::bool (skip check)] :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
47+
self::Widget w = [@vm.direct-call.metadata=dart._internal::ListIterator.current] [@vm.inferred-type.metadata=!] :sync-for-iterator.{core::Iterator::current}{self::Widget};
48+
{
49+
core::print([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::_getObjectCreationLocation());
50+
}
51+
}
52+
}
53+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--tfa.maxAllocatedTypesInSetSpecialization=4

0 commit comments

Comments
 (0)