Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 27c50ae

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Implement factor() operation from flow analysis.
Change-Id: If2e23c3b850974d9190b90b287b811baf3121739 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/138269 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 81bc629 commit 27c50ae

File tree

3 files changed

+181
-0
lines changed

3 files changed

+181
-0
lines changed

pkg/analyzer/lib/src/generated/type_system.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,6 +1799,57 @@ class TypeSystemImpl extends TypeSystem {
17991799
}
18001800
}
18011801

1802+
/// Defines the "remainder" of `T` when `S` has been removed from
1803+
/// consideration by an instance check. This operation is used for type
1804+
/// promotion during flow analysis.
1805+
DartType factor(DartType T, DartType S) {
1806+
// * If T <: S then Never
1807+
if (isSubtypeOf2(T, S)) {
1808+
return NeverTypeImpl.instance;
1809+
}
1810+
1811+
var T_nullability = T.nullabilitySuffix;
1812+
1813+
// * Else if T is R? and Null <: S then factor(R, S)
1814+
// * Else if T is R? then factor(R, S)?
1815+
if (T_nullability == NullabilitySuffix.question) {
1816+
var R = (T as TypeImpl).withNullability(NullabilitySuffix.none);
1817+
var factor_RS = factor(R, S) as TypeImpl;
1818+
if (isSubtypeOf2(nullNone, S)) {
1819+
return factor_RS;
1820+
} else {
1821+
return factor_RS.withNullability(NullabilitySuffix.question);
1822+
}
1823+
}
1824+
1825+
// * Else if T is R* and Null <: S then factor(R, S)
1826+
// * Else if T is R* then factor(R, S)*
1827+
if (T_nullability == NullabilitySuffix.star) {
1828+
var R = (T as TypeImpl).withNullability(NullabilitySuffix.none);
1829+
var factor_RS = factor(R, S) as TypeImpl;
1830+
if (isSubtypeOf2(nullNone, S)) {
1831+
return factor_RS;
1832+
} else {
1833+
return factor_RS.withNullability(NullabilitySuffix.star);
1834+
}
1835+
}
1836+
1837+
// * Else if T is FutureOr<R> and Future<R> <: S then factor(R, S)
1838+
// * Else if T is FutureOr<R> and R <: S then factor(Future<R>, S)
1839+
if (T is InterfaceType && T.isDartAsyncFutureOr) {
1840+
var R = T.typeArguments[0];
1841+
var future_R = typeProvider.futureType2(R);
1842+
if (isSubtypeOf2(future_R, S)) {
1843+
return factor(R, S);
1844+
}
1845+
if (isSubtypeOf2(R, S)) {
1846+
return factor(future_R, S);
1847+
}
1848+
}
1849+
1850+
return T;
1851+
}
1852+
18021853
/// Given a type t, if t is an interface type with a call method
18031854
/// defined, return the function type for the call method, otherwise
18041855
/// return null.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright (c) 2020, 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+
import 'package:analyzer/dart/analysis/features.dart';
6+
import 'package:analyzer/dart/element/type.dart';
7+
import 'package:analyzer/dart/element/type_provider.dart';
8+
import 'package:analyzer/src/dart/element/type.dart';
9+
import 'package:analyzer/src/generated/resolver.dart' show TypeSystemImpl;
10+
import 'package:test/test.dart';
11+
import 'package:test_reflective_loader/test_reflective_loader.dart';
12+
13+
import '../../../generated/elements_types_mixin.dart';
14+
import '../../../generated/test_analysis_context.dart';
15+
16+
main() {
17+
defineReflectiveSuite(() {
18+
defineReflectiveTests(FactorTypeTest);
19+
});
20+
}
21+
22+
@reflectiveTest
23+
class FactorTypeTest with ElementsTypesMixin {
24+
@override
25+
TypeProvider typeProvider;
26+
27+
TypeSystemImpl typeSystem;
28+
29+
FeatureSet get testFeatureSet {
30+
return FeatureSet.forTesting(
31+
additionalFeatures: [Feature.non_nullable],
32+
);
33+
}
34+
35+
void setUp() {
36+
var analysisContext = TestAnalysisContext(
37+
featureSet: testFeatureSet,
38+
);
39+
typeProvider = analysisContext.typeProviderNonNullableByDefault;
40+
typeSystem = analysisContext.typeSystemNonNullableByDefault;
41+
}
42+
43+
void test_futureOr() {
44+
_check(futureOrNone(intNone), intNone, 'Future<int>');
45+
_check(futureOrNone(intNone), futureNone(intNone), 'int');
46+
47+
_check(futureOrNone(intQuestion), intNone, 'FutureOr<int?>');
48+
_check(futureOrNone(intQuestion), futureNone(intNone), 'FutureOr<int?>');
49+
_check(futureOrNone(intQuestion), intQuestion, 'Future<int?>');
50+
_check(futureOrNone(intQuestion), futureNone(intQuestion), 'int?');
51+
_check(futureOrNone(intQuestion), intStar, 'Future<int?>');
52+
_check(futureOrNone(intQuestion), futureNone(intStar), 'int?');
53+
54+
_check(futureOrNone(intNone), numNone, 'Future<int>');
55+
_check(futureOrNone(intNone), futureNone(numNone), 'int');
56+
}
57+
58+
void test_object() {
59+
_check(objectNone, objectNone, 'Never');
60+
_check(objectNone, objectQuestion, 'Never');
61+
_check(objectNone, objectStar, 'Never');
62+
63+
_check(objectNone, intNone, 'Object');
64+
_check(objectNone, intQuestion, 'Object');
65+
_check(objectNone, intStar, 'Object');
66+
67+
_check(objectQuestion, objectNone, 'Never?');
68+
_check(objectQuestion, objectQuestion, 'Never');
69+
_check(objectQuestion, objectStar, 'Never');
70+
71+
_check(objectQuestion, intNone, 'Object?');
72+
_check(objectQuestion, intQuestion, 'Object');
73+
_check(objectQuestion, intStar, 'Object');
74+
}
75+
76+
test_subtype() {
77+
_check(intNone, intNone, 'Never');
78+
_check(intNone, intQuestion, 'Never');
79+
_check(intNone, intStar, 'Never');
80+
81+
_check(intQuestion, intNone, 'Never?');
82+
_check(intQuestion, intQuestion, 'Never');
83+
_check(intQuestion, intStar, 'Never');
84+
85+
_check(intStar, intNone, 'Never');
86+
_check(intStar, intQuestion, 'Never');
87+
_check(intStar, intStar, 'Never');
88+
89+
_check(intNone, numNone, 'Never');
90+
_check(intNone, numQuestion, 'Never');
91+
_check(intNone, numStar, 'Never');
92+
93+
_check(intQuestion, numNone, 'Never?');
94+
_check(intQuestion, numQuestion, 'Never');
95+
_check(intQuestion, numStar, 'Never');
96+
97+
_check(intStar, numNone, 'Never');
98+
_check(intStar, numQuestion, 'Never');
99+
_check(intStar, numStar, 'Never');
100+
101+
_check(intNone, nullNone, 'int');
102+
_check(intQuestion, nullNone, 'int');
103+
_check(intStar, nullNone, 'int');
104+
105+
_check(intNone, stringNone, 'int');
106+
_check(intQuestion, stringNone, 'int?');
107+
_check(intStar, stringNone, 'int*');
108+
109+
_check(intNone, stringQuestion, 'int');
110+
_check(intQuestion, stringQuestion, 'int');
111+
_check(intStar, stringQuestion, 'int');
112+
113+
_check(intNone, stringStar, 'int');
114+
_check(intQuestion, stringStar, 'int');
115+
_check(intStar, stringStar, 'int');
116+
}
117+
118+
void _check(DartType T, DartType S, String expectedStr) {
119+
var result = typeSystem.factor(T, S);
120+
var resultStr = _typeString(result);
121+
122+
expect(resultStr, expectedStr);
123+
}
124+
125+
String _typeString(TypeImpl type) {
126+
return type.getDisplayString(withNullability: true);
127+
}
128+
}

pkg/analyzer/test/src/dart/element/test_all.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:test_reflective_loader/test_reflective_loader.dart';
66

77
import 'element_test.dart' as element;
8+
import 'factor_type_test.dart' as factor_type;
89
import 'function_type_test.dart' as function_type;
910
import 'inheritance_manager3_test.dart' as inheritance_manager3;
1011
import 'least_upper_bound_helper_test.dart' as least_upper_bound_helper;
@@ -23,6 +24,7 @@ import 'upper_lower_bound_test.dart' as upper_bound;
2324
main() {
2425
defineReflectiveSuite(() {
2526
element.main();
27+
factor_type.main();
2628
function_type.main();
2729
inheritance_manager3.main();
2830
least_upper_bound_helper.main();

0 commit comments

Comments
 (0)