Skip to content

Commit 9da8970

Browse files
author
John Messerly
committed
fix #25486, promote from dynamic in strong mode
[email protected] Review URL: https://codereview.chromium.org/1585323003 .
1 parent 4d3d65b commit 9da8970

File tree

4 files changed

+95
-19
lines changed

4 files changed

+95
-19
lines changed

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

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9723,24 +9723,17 @@ class ResolverVisitor extends ScopedVisitor {
97239723
return;
97249724
}
97259725
// prepare current variable type
9726-
DartType type = _promoteManager.getType(element);
9727-
if (type == null) {
9728-
type = expression.staticType;
9729-
}
9730-
// Declared type should not be "dynamic".
9731-
if (type == null || type.isDynamic) {
9732-
return;
9733-
}
9734-
// Promoted type should not be "dynamic".
9735-
if (potentialType == null || potentialType.isDynamic) {
9736-
return;
9737-
}
9738-
// Promoted type should be more specific than declared.
9739-
if (!potentialType.isMoreSpecificThan(type)) {
9740-
return;
9726+
DartType type = _promoteManager.getType(element) ??
9727+
expression.staticType ??
9728+
DynamicTypeImpl.instance;
9729+
9730+
potentialType ??= DynamicTypeImpl.instance;
9731+
9732+
// Check if we can promote to potentialType from type.
9733+
if (typeSystem.canPromoteToType(potentialType, type)) {
9734+
// Do promote type of variable.
9735+
_promoteManager.setType(element, potentialType);
97419736
}
9742-
// Do promote type of variable.
9743-
_promoteManager.setType(element, potentialType);
97449737
}
97459738
}
97469739

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ class StrongTypeSystemImpl implements TypeSystem {
2929
return ft.parameters.any((p) => predicate(p.type));
3030
}
3131

32+
@override
33+
bool canPromoteToType(DartType to, DartType from) => isSubtypeOf(to, from);
34+
3235
/**
3336
* Given a type t, if t is an interface type with a call method
3437
* defined, return the function type for the call method, otherwise
@@ -562,6 +565,16 @@ class StrongTypeSystemImpl implements TypeSystem {
562565
* pluggable.
563566
*/
564567
abstract class TypeSystem {
568+
/**
569+
* Returns `true` if we can promote to the first type from the second type.
570+
*
571+
* In the standard Dart type system, it is not possible to promote from or to
572+
* `dynamic`, and we must be promoting to a more specific type.
573+
*
574+
* In strong mode, this is equivalent to [isSubtypeOf].
575+
*/
576+
bool canPromoteToType(DartType to, DartType from);
577+
565578
/**
566579
* Compute the least upper bound of two types.
567580
*/
@@ -605,6 +618,14 @@ abstract class TypeSystem {
605618
class TypeSystemImpl implements TypeSystem {
606619
TypeSystemImpl();
607620

621+
@override
622+
bool canPromoteToType(DartType to, DartType from) {
623+
// Declared type should not be "dynamic".
624+
// Promoted type should not be "dynamic".
625+
// Promoted type should be more specific than declared.
626+
return !from.isDynamic && !to.isDynamic && to.isMoreSpecificThan(from);
627+
}
628+
608629
@override
609630
DartType getLeastUpperBound(
610631
TypeProvider typeProvider, DartType type1, DartType type2) {

pkg/analyzer/test/generated/resolver_test.dart

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2276,6 +2276,44 @@ class C {
22762276
}
22772277
}
22782278

2279+
/**
2280+
* Tests for generic method and function resolution that do not use strong mode.
2281+
*/
2282+
@reflectiveTest
2283+
class GenericMethodResolverTest extends _StaticTypeAnalyzer2TestShared {
2284+
void setUp() {
2285+
super.setUp();
2286+
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
2287+
options.enableGenericMethods = true;
2288+
resetWithOptions(options);
2289+
}
2290+
2291+
void test_genericMethod_propagatedType_promotion() {
2292+
// Regression test for:
2293+
// https://github.com/dart-lang/sdk/issues/25340
2294+
//
2295+
// Note, after https://github.com/dart-lang/sdk/issues/25486 the original
2296+
// strong mode example won't work, as we now compute a static type and
2297+
// therefore discard the propagated type.
2298+
//
2299+
// So this test does not use strong mode.
2300+
_resolveTestUnit(r'''
2301+
abstract class Iter {
2302+
List<S> map<S>(S f(x));
2303+
}
2304+
class C {}
2305+
C toSpan(dynamic element) {
2306+
if (element is Iter) {
2307+
var y = element.map(toSpan);
2308+
}
2309+
return null;
2310+
}''');
2311+
SimpleIdentifier y = _findIdentifier('y = ');
2312+
expect(y.staticType.toString(), 'dynamic');
2313+
expect(y.propagatedType.toString(), 'List<dynamic>');
2314+
}
2315+
}
2316+
22792317
@reflectiveTest
22802318
class HintCodeTest extends ResolverTestCase {
22812319
void fail_deadCode_statementAfterRehrow() {
@@ -13596,6 +13634,11 @@ class D extends C {
1359613634
void test_genericMethod_propagatedType_promotion() {
1359713635
// Regression test for:
1359813636
// https://github.com/dart-lang/sdk/issues/25340
13637+
13638+
// Note, after https://github.com/dart-lang/sdk/issues/25486 the original
13639+
// example won't work, as we now compute a static type and therefore discard
13640+
// the propagated type. So a new test was created that doesn't run under
13641+
// strong mode.
1359913642
_resolveTestUnit(r'''
1360013643
abstract class Iter {
1360113644
List/*<S>*/ map/*<S>*/(/*=S*/ f(x));
@@ -13608,8 +13651,8 @@ C toSpan(dynamic element) {
1360813651
return null;
1360913652
}''');
1361013653
SimpleIdentifier y = _findIdentifier('y = ');
13611-
expect(y.staticType.toString(), 'dynamic');
13612-
expect(y.propagatedType.toString(), 'List<dynamic>');
13654+
expect(y.staticType.toString(), 'List<C>');
13655+
expect(y.propagatedType, isNull);
1361313656
}
1361413657

1361513658
void test_genericMethod_tearoff() {

pkg/analyzer/test/src/task/strong/checker_test.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,25 @@ void main() {
14321432
'''
14331433
});
14341434

1435+
testChecker('type promotion from dynamic', {
1436+
'/main.dart': r'''
1437+
f() {
1438+
dynamic x;
1439+
if (x is int) {
1440+
int y = x;
1441+
String z = /*severe:STATIC_TYPE_ERROR*/x;
1442+
}
1443+
}
1444+
g() {
1445+
Object x;
1446+
if (x is int) {
1447+
int y = x;
1448+
String z = /*severe:STATIC_TYPE_ERROR*/x;
1449+
}
1450+
}
1451+
'''
1452+
});
1453+
14351454
testChecker('unary operators', {
14361455
'/main.dart': '''
14371456
class A {

0 commit comments

Comments
 (0)