Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Unified Diff: pkg/analyzer/test/src/task/strong/checker_test.dart

Issue 1663533002: fixes #25640, errors on function downcasts when we know it's an exact type (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/test/src/task/strong/checker_test.dart
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 65de58df5c6d29cac67fa8d1e865ee8a4cfa1a46..bc62a4e4f00415064fb85d83d5da3a0e07a3c4cf 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -283,8 +283,9 @@ void main() {
'''
});
- testChecker('Ground type subtyping: dynamic is top', {
- '/main.dart': '''
+ group('Ground type subtyping:', () {
+ testChecker('dynamic is top', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -305,10 +306,10 @@ void main() {
y = b;
}
'''
- });
+ });
- testChecker('Ground type subtyping: dynamic downcasts', {
- '/main.dart': '''
+ testChecker('dynamic downcasts', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -329,10 +330,10 @@ void main() {
b = /*info:DYNAMIC_CAST*/y;
}
'''
- });
+ });
- testChecker('Ground type subtyping: assigning a class', {
- '/main.dart': '''
+ testChecker('assigning a class', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -354,10 +355,10 @@ void main() {
b = /*info:DOWN_CAST_IMPLICIT*/a;
}
'''
- });
+ });
- testChecker('Ground type subtyping: assigning a subclass', {
- '/main.dart': '''
+ testChecker('assigning a subclass', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -382,10 +383,10 @@ void main() {
c = /*severe:STATIC_TYPE_ERROR*/b;
}
'''
- });
+ });
- testChecker('Ground type subtyping: interfaces', {
- '/main.dart': '''
+ testChecker('interfaces', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -423,10 +424,12 @@ void main() {
}
}
'''
+ });
});
- testChecker('Function typing and subtyping: int and object', {
- '/main.dart': '''
+ group('Function typing and subtyping:', () {
+ testChecker('int and object', {
+ '/main.dart': '''
typedef Object Top(int x); // Top of the lattice
typedef int Left(int x); // Left branch
@@ -434,13 +437,20 @@ void main() {
typedef Object Right(Object x); // Right branch
typedef int Bot(Object x); // Bottom of the lattice
- Object top(int x) => x;
- int left(int x) => x;
- Object right(Object x) => x;
+ Object globalTop(int x) => x;
+ int globalLeft(int x) => x;
+ Object globalRight(Object x) => x;
int _bot(Object x) => /*info:DOWN_CAST_IMPLICIT*/x;
- int bot(Object x) => x as int;
+ int globalBot(Object x) => x as int;
void main() {
+ // Note: use locals so we only know the type, not that it's a specific
+ // function declaration. (we can issue better errors in that case.)
+ var top = globalTop;
+ var left = globalLeft;
+ var right = globalRight;
+ var bot = globalBot;
vsm 2016/02/03 23:52:00 Perhaps a test to cover the static method case (er
Jennifer Messerly 2016/02/04 00:41:30 instance methods are covered by this test (line 16
+
{ // Check typedef equality
Left f = left;
Left2 g = f;
@@ -475,10 +485,10 @@ void main() {
}
}
'''
- });
+ });
- testChecker('Function typing and subtyping: classes', {
- '/main.dart': '''
+ testChecker('classes', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -509,31 +519,31 @@ void main() {
}
{
Left f;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
vsm 2016/02/03 23:52:00 nice!
f = left;
- f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
+ f = /*severe:STATIC_TYPE_ERROR*/right;
f = bot;
}
{
Right f;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
f = right;
f = bot;
}
{
Bot f;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left;
- f = /*warning:DOWN_CAST_COMPOSITE*/right;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ f = /*severe:STATIC_TYPE_ERROR*/right;
f = bot;
}
}
'''
- });
+ });
- testChecker('Function typing and subtyping: dynamic', {
- '/main.dart': '''
+ testChecker('dynamic', {
+ '/main.dart': '''
class A {}
@@ -557,31 +567,31 @@ void main() {
}
{
Left f;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
f = left;
- f = /*warning:DOWN_CAST_COMPOSITE*/right;
+ f = /*severe:STATIC_TYPE_ERROR*/right;
f = bot;
}
{
Right f;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
f = right;
f = bot;
}
{
Bottom f;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left;
- f = /*warning:DOWN_CAST_COMPOSITE*/right;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ f = /*severe:STATIC_TYPE_ERROR*/right;
f = bot;
}
}
'''
- });
+ });
- testChecker('Function typing and subtyping: function literal variance', {
- '/main.dart': '''
+ testChecker('function literal variance', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -603,31 +613,31 @@ void main() {
}
{
Function2<B, B> f;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
f = left;
- f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
+ f = /*severe:STATIC_TYPE_ERROR*/right;
f = bot;
}
{
Function2<A, A> f;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
f = right;
f = bot;
}
{
Function2<A, B> f;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left;
- f = /*warning:DOWN_CAST_COMPOSITE*/right;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ f = /*severe:STATIC_TYPE_ERROR*/right;
f = bot;
}
}
'''
- });
+ });
- testChecker('Function typing and subtyping: function variable variance', {
- '/main.dart': '''
+ testChecker('function variable variance', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -663,10 +673,10 @@ void main() {
}
}
'''
- });
+ });
- testChecker('Function typing and subtyping: higher order function literals', {
- '/main.dart': '''
+ testChecker('higher order function literals 1', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -682,12 +692,99 @@ void main() {
AToB _bot(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f;
AToB bot(BToA f) => f as AToB;
Jennifer Messerly 2016/02/02 22:15:05 it's hard to see in the diff, but the original cod
+ void main() {
+ {
+ Function2<AToB, BToA> f; // Top
+ f = top;
+ f = left;
+ f = right;
+ f = bot;
+ }
+ {
+ Function2<AToB, AToB> f; // Left
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = left;
+ f = /*severe:STATIC_TYPE_ERROR*/right;
+ f = bot;
+ }
+ {
+ Function2<BToA, BToA> f; // Right
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ f = right;
+ f = bot;
+ }
+ {
+ Function2<BToA, AToB> f; // Bot
+ f = bot;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ }
+ }
+ '''
+ });
+
+ testChecker('higher order function literals 2', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+
+ typedef T Function2<S, T>(S z);
+
+ typedef A BToA(B x); // Top of the base lattice
+ typedef B AToB(A x); // Bot of the base lattice
+
Function2<B, A> top(AToB f) => f;
Function2<A, B> left(AToB f) => f;
Function2<B, A> right(BToA f) => f;
Function2<A, B> _bot(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f;
Function2<A, B> bot(BToA f) => f as Function2<A, B>;
+ void main() {
+ {
+ Function2<AToB, BToA> f; // Top
+ f = top;
+ f = left;
+ f = right;
+ f = bot;
+ }
+ {
+ Function2<AToB, AToB> f; // Left
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = left;
+ f = /*severe:STATIC_TYPE_ERROR*/right;
+ f = bot;
+ }
+ {
+ Function2<BToA, BToA> f; // Right
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ f = right;
+ f = bot;
+ }
+ {
+ Function2<BToA, AToB> f; // Bot
+ f = bot;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ }
+ }
+ '''
+ });
+
+ testChecker('higher order function literals 3', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+
+ typedef T Function2<S, T>(S z);
+
+ typedef A BToA(B x); // Top of the base lattice
+ typedef B AToB(A x); // Bot of the base lattice
BToA top(Function2<A, B> f) => f;
AToB left(Function2<A, B> f) => f;
@@ -705,32 +802,31 @@ void main() {
}
{
Function2<AToB, AToB> f; // Left
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
f = left;
- f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
+ f = /*severe:STATIC_TYPE_ERROR*/right;
f = bot;
}
{
Function2<BToA, BToA> f; // Right
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
f = right;
f = bot;
}
{
Function2<BToA, AToB> f; // Bot
f = bot;
- f = /*warning:DOWN_CAST_COMPOSITE*/left;
- f = /*warning:DOWN_CAST_COMPOSITE*/top;
- f = /*warning:DOWN_CAST_COMPOSITE*/left;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
+ f = /*severe:STATIC_TYPE_ERROR*/top;
+ f = /*severe:STATIC_TYPE_ERROR*/left;
}
}
'''
- });
+ });
- testChecker(
- 'Function typing and subtyping: higher order function variables', {
- '/main.dart': '''
+ testChecker('higher order function variables', {
+ '/main.dart': '''
class A {}
class B extends A {}
@@ -768,10 +864,10 @@ void main() {
}
}
'''
- });
+ });
- testChecker('Function typing and subtyping: named and optional parameters', {
- '/main.dart': '''
+ testChecker('named and optional parameters', {
+ '/main.dart': '''
class A {}
@@ -887,10 +983,10 @@ void main() {
nnn = nnn;
}
'''
- });
+ });
- testChecker('Function subtyping: objects with call methods', {
- '/main.dart': '''
+ testChecker('Function subtyping: objects with call methods', {
+ '/main.dart': '''
typedef int I2I(int x);
typedef num N2N(num x);
@@ -908,7 +1004,7 @@ void main() {
f = new A();
f = /*severe:STATIC_TYPE_ERROR*/new B();
f = i2i;
- f = /*warning:DOWN_CAST_COMPOSITE*/n2n;
+ f = /*severe:STATIC_TYPE_ERROR*/n2n;
f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
}
@@ -916,7 +1012,7 @@ void main() {
N2N f;
f = /*severe:STATIC_TYPE_ERROR*/new A();
f = new B();
- f = /*warning:DOWN_CAST_COMPOSITE*/i2i;
+ f = /*severe:STATIC_TYPE_ERROR*/i2i;
f = n2n;
f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
@@ -950,26 +1046,27 @@ void main() {
}
}
'''
- });
+ });
- testChecker('Function typing and subtyping: void', {
- '/main.dart': '''
+ testChecker('void', {
+ '/main.dart': '''
class A {
void bar() => null;
void foo() => bar; // allowed
}
'''
- });
+ });
- testChecker('Function subtyping: uninferred closure', {
- '/main.dart': '''
+ testChecker('uninferred closure', {
+ '/main.dart': '''
typedef num Num2Num(num x);
void main() {
Num2Num g = /*info:INFERRED_TYPE_CLOSURE,severe:STATIC_TYPE_ERROR*/(int x) { return x; };
print(g(42));
}
'''
+ });
});
testChecker('Relaxed casts', {
@@ -1416,7 +1513,7 @@ void main() {
});
testChecker('generic function wrong number of arguments', {
- '/main.dart': r'''
+ '/main.dart': r'''
/*=T*/ foo/*<T>*/(/*=T*/ x, /*=T*/ y) => x;
/*=T*/ bar/*<T>*/({/*=T*/ x, /*=T*/ y}) => x;

Powered by Google App Engine
This is Rietveld 408576698