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

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

Issue 1521693002: Roll Observatory deps (charted -> ^0.3.0) (Closed) Base URL: https://chromium.googlesource.com/external/github.com/dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years 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: packages/analyzer/test/src/task/strong/checker_test.dart
diff --git a/packages/analyzer/test/src/task/strong/checker_test.dart b/packages/analyzer/test/src/task/strong/checker_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..874916c36781679c278cdac76f752f343ef4cda6
--- /dev/null
+++ b/packages/analyzer/test/src/task/strong/checker_test.dart
@@ -0,0 +1,2311 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(jmesserly): this file needs to be refactored, it's a port from
+// package:dev_compiler's tests
+/// General type checking tests
+library test.src.task.strong.checker_test;
+
+import 'package:unittest/unittest.dart';
+
+import 'strong_test_helper.dart';
+
+void main() {
+ testChecker('ternary operator', {
+ '/main.dart': '''
+ abstract class Comparable<T> {
+ int compareTo(T other);
+ static int compare(Comparable a, Comparable b) => a.compareTo(b);
+ }
+ typedef int Comparator<T>(T a, T b);
+
+ typedef bool _Predicate<T>(T value);
+
+ class SplayTreeMap<K, V> {
+ Comparator<K> _comparator;
+ _Predicate _validKey;
+
+ // Initializing _comparator needs a cast, since K may not always be
+ // Comparable.
+ // Initializing _validKey shouldn't need a cast. Currently
+ // it requires inference to work because of dartbug.com/23381
+ SplayTreeMap([int compare(K key1, K key2),
+ bool isValidKey(potentialKey)]) {
+ : _comparator = /*warning:DownCastComposite*/(compare == null) ? Comparable.compare : compare,
+ _validKey = /*info:InferredType should be pass*/(isValidKey != null) ? isValidKey : ((v) => true);
+ _Predicate<Object> _v = /*warning:DownCastComposite*/(isValidKey != null) ? isValidKey : ((v) => true);
+ _v = /*info:InferredType should be pass*/(isValidKey != null) ? _v : ((v) => true);
+ }
+ }
+ void main() {
+ Object obj = 42;
+ dynamic dyn = 42;
+ int i = 42;
+
+ // Check the boolean conversion of the condition.
+ print((/*severe:StaticTypeError*/i) ? false : true);
+ print((/*info:DownCastImplicit*/obj) ? false : true);
+ print((/*info:DynamicCast*/dyn) ? false : true);
+ }
+ '''
+ });
+
+ testChecker('if/for/do/while statements use boolean conversion', {
+ '/main.dart': '''
+ main() {
+ dynamic d = 42;
+ Object obj = 42;
+ int i = 42;
+ bool b = false;
+
+ if (b) {}
+ if (/*info:DynamicCast*/dyn) {}
+ if (/*info:DownCastImplicit*/obj) {}
+ if (/*severe:StaticTypeError*/i) {}
+
+ while (b) {}
+ while (/*info:DynamicCast*/dyn) {}
+ while (/*info:DownCastImplicit*/obj) {}
+ while (/*severe:StaticTypeError*/i) {}
+
+ do {} while (b);
+ do {} while (/*info:DynamicCast*/dyn);
+ do {} while (/*info:DownCastImplicit*/obj);
+ do {} while (/*severe:StaticTypeError*/i);
+
+ for (;b;) {}
+ for (;/*info:DynamicCast*/dyn;) {}
+ for (;/*info:DownCastImplicit*/obj;) {}
+ for (;/*severe:StaticTypeError*/i;) {}
+ }
+ '''
+ });
+
+ testChecker('dynamic invocation', {
+ '/main.dart': '''
+
+ class A {
+ dynamic call(dynamic x) => x;
+ }
+ class B extends A {
+ int call(int x) => x;
+ double col(double x) => x;
+ }
+ void main() {
+ {
+ B f = new B();
+ int x;
+ double y;
+ // The analyzer has what I believe is a bug (dartbug.com/23252) which
+ // causes the return type of calls to f to be treated as dynamic.
+ x = /*info:DynamicCast should be pass*/f(3);
+ x = /*severe:StaticTypeError*/f.col(3.0);
+ y = /*info:DynamicCast should be severe:StaticTypeError*/f(3);
+ y = f.col(3.0);
+ f(/*severe:StaticTypeError*/3.0);
+ f.col(/*severe:StaticTypeError*/3);
+ }
+ {
+ Function f = new B();
+ int x;
+ double y;
+ x = /*info:DynamicCast, info:DynamicInvoke*/f(3);
+ x = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0);
+ y = /*info:DynamicCast, info:DynamicInvoke*/f(3);
+ y = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0);
+ (/*info:DynamicInvoke*/f(3.0));
+ (/*info:DynamicInvoke*/f.col(3));
+ }
+ {
+ A f = new B();
+ int x;
+ double y;
+ x = /*info:DynamicCast, info:DynamicInvoke*/f(3);
+ y = /*info:DynamicCast, info:DynamicInvoke*/f(3);
+ (/*info:DynamicInvoke*/f(3.0));
+ }
+ }
+ '''
+ });
+
+ testChecker('conversion and dynamic invoke', {
+ '/helper.dart': '''
+ dynamic toString = (int x) => x + 42;
+ dynamic hashCode = "hello";
+ ''',
+ '/main.dart': '''
+ import 'helper.dart' as helper;
+
+ class A {
+ String x = "hello world";
+
+ void baz1(y) => x + /*info:DynamicCast*/y;
+ static baz2(y) => /*info:DynamicInvoke*/y + y;
+ }
+
+ void foo(String str) {
+ print(str);
+ }
+
+ class B {
+ String toString([int arg]) => arg.toString();
+ }
+
+ void bar(a) {
+ foo(/*info:DynamicCast,info:DynamicInvoke*/a.x);
+ }
+
+ baz() => new B();
+
+ typedef DynFun(x);
+ typedef StrFun(String x);
+
+ var bar1 = bar;
+
+ void main() {
+ var a = new A();
+ bar(a);
+ (/*info:DynamicInvoke*/bar1(a));
+ var b = bar;
+ (/*info:DynamicInvoke*/b(a));
+ var f1 = foo;
+ f1("hello");
+ dynamic f2 = foo;
+ (/*info:DynamicInvoke*/f2("hello"));
+ DynFun f3 = foo;
+ (/*info:DynamicInvoke*/f3("hello"));
+ (/*info:DynamicInvoke*/f3(42));
+ StrFun f4 = foo;
+ f4("hello");
+ a.baz1("hello");
+ var b1 = a.baz1;
+ (/*info:DynamicInvoke*/b1("hello"));
+ A.baz2("hello");
+ var b2 = A.baz2;
+ (/*info:DynamicInvoke*/b2("hello"));
+
+ dynamic a1 = new B();
+ (/*info:DynamicInvoke*/a1.x);
+ a1.toString();
+ (/*info:DynamicInvoke*/a1.toString(42));
+ var toStringClosure = a1.toString;
+ (/*info:DynamicInvoke*/a1.toStringClosure());
+ (/*info:DynamicInvoke*/a1.toStringClosure(42));
+ (/*info:DynamicInvoke*/a1.toStringClosure("hello"));
+ a1.hashCode;
+
+ dynamic toString = () => null;
+ (/*info:DynamicInvoke*/toString());
+
+ (/*info:DynamicInvoke*/helper.toString());
+ var toStringClosure2 = helper.toString;
+ (/*info:DynamicInvoke*/toStringClosure2());
+ int hashCode = /*info:DynamicCast*/helper.hashCode;
+
+ baz().toString();
+ baz().hashCode;
+ }
+ '''
+ });
+
+ testChecker('Constructors', {
+ '/main.dart': '''
+ const num z = 25;
+ Object obj = "world";
+
+ class A {
+ int x;
+ String y;
+
+ A(this.x) : this.y = /*severe:StaticTypeError*/42;
+
+ A.c1(p): this.x = /*info:DownCastImplicit*/z, this.y = /*info:DynamicCast*/p;
+
+ A.c2(this.x, this.y);
+
+ A.c3(/*severe:InvalidParameterDeclaration*/num this.x, String this.y);
+ }
+
+ class B extends A {
+ B() : super(/*severe:StaticTypeError*/"hello");
+
+ B.c2(int x, String y) : super.c2(/*severe:StaticTypeError*/y,
+ /*severe:StaticTypeError*/x);
+
+ B.c3(num x, Object y) : super.c3(x, /*info:DownCastImplicit*/y);
+ }
+
+ void main() {
+ A a = new A.c2(/*info:DownCastImplicit*/z, /*severe:StaticTypeError*/z);
+ var b = new B.c2(/*severe:StaticTypeError*/"hello", /*info:DownCastImplicit*/obj);
+ }
+ '''
+ });
+
+ testChecker('Unbound variable', {
+ '/main.dart': '''
+ void main() {
+ dynamic y = /*pass should be severe:StaticTypeError*/unboundVariable;
+ }
+ '''
+ });
+
+ testChecker('Unbound type name', {
+ '/main.dart': '''
+ void main() {
+ /*pass should be severe:StaticTypeError*/AToB y;
+ }
+ '''
+ });
+
+ testChecker('Ground type subtyping: dynamic is top', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+
+ void main() {
+ dynamic y;
+ Object o;
+ int i = 0;
+ double d = 0.0;
+ num n;
+ A a;
+ B b;
+ y = o;
+ y = i;
+ y = d;
+ y = n;
+ y = a;
+ y = b;
+ }
+ '''
+ });
+
+ testChecker('Ground type subtyping: dynamic downcasts', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+
+ void main() {
+ dynamic y;
+ Object o;
+ int i = 0;
+ double d = 0.0;
+ num n;
+ A a;
+ B b;
+ o = y;
+ i = /*info:DynamicCast*/y;
+ d = /*info:DynamicCast*/y;
+ n = /*info:DynamicCast*/y;
+ a = /*info:DynamicCast*/y;
+ b = /*info:DynamicCast*/y;
+ }
+ '''
+ });
+
+ testChecker('Ground type subtyping: assigning a class', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+
+ void main() {
+ dynamic y;
+ Object o;
+ int i = 0;
+ double d = 0.0;
+ num n;
+ A a;
+ B b;
+ y = a;
+ o = a;
+ i = /*severe:StaticTypeError*/a;
+ d = /*severe:StaticTypeError*/a;
+ n = /*severe:StaticTypeError*/a;
+ a = a;
+ b = /*info:DownCastImplicit*/a;
+ }
+ '''
+ });
+
+ testChecker('Ground type subtyping: assigning a subclass', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+ class C extends A {}
+
+ void main() {
+ dynamic y;
+ Object o;
+ int i = 0;
+ double d = 0.0;
+ num n;
+ A a;
+ B b;
+ C c;
+ y = b;
+ o = b;
+ i = /*severe:StaticTypeError*/b;
+ d = /*severe:StaticTypeError*/b;
+ n = /*severe:StaticTypeError*/b;
+ a = b;
+ b = b;
+ c = /*severe:StaticTypeError*/b;
+ }
+ '''
+ });
+
+ testChecker('Ground type subtyping: interfaces', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+ class C extends A {}
+ class D extends B implements C {}
+
+ void main() {
+ A top;
+ B left;
+ C right;
+ D bot;
+ {
+ top = top;
+ top = left;
+ top = right;
+ top = bot;
+ }
+ {
+ left = /*info:DownCastImplicit*/top;
+ left = left;
+ left = /*severe:StaticTypeError*/right;
+ left = bot;
+ }
+ {
+ right = /*info:DownCastImplicit*/top;
+ right = /*severe:StaticTypeError*/left;
+ right = right;
+ right = bot;
+ }
+ {
+ bot = /*info:DownCastImplicit*/top;
+ bot = /*info:DownCastImplicit*/left;
+ bot = /*info:DownCastImplicit*/right;
+ bot = bot;
+ }
+ }
+ '''
+ });
+
+ testChecker('Function typing and subtyping: int and object', {
+ '/main.dart': '''
+
+ typedef Object Top(int x); // Top of the lattice
+ typedef int Left(int x); // Left branch
+ typedef int Left2(int x); // Left branch
+ 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;
+ int _bot(Object x) => /*info:DownCastImplicit*/x;
+ int bot(Object x) => x as int;
+
+ void main() {
+ { // Check typedef equality
+ Left f = left;
+ Left2 g = f;
+ }
+ {
+ Top f;
+ f = top;
+ f = left;
+ f = right;
+ f = bot;
+ }
+ {
+ Left f;
+ f = /*warning:DownCastComposite*/top;
+ f = left;
+ f = /*warning:DownCastComposite*/right; // Should we reject this?
+ f = bot;
+ }
+ {
+ Right f;
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left; // Should we reject this?
+ f = right;
+ f = bot;
+ }
+ {
+ Bot f;
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left;
+ f = /*warning:DownCastComposite*/right;
+ f = bot;
+ }
+ }
+ '''
+ });
+
+ testChecker('Function typing and subtyping: classes', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+
+ typedef A Top(B x); // Top of the lattice
+ typedef B Left(B x); // Left branch
+ typedef B Left2(B x); // Left branch
+ typedef A Right(A x); // Right branch
+ typedef B Bot(A x); // Bottom of the lattice
+
+ B left(B x) => x;
+ B _bot(A x) => /*info:DownCastImplicit*/x;
+ B bot(A x) => x as B;
+ A top(B x) => x;
+ A right(A x) => x;
+
+ void main() {
+ { // Check typedef equality
+ Left f = left;
+ Left2 g = f;
+ }
+ {
+ Top f;
+ f = top;
+ f = left;
+ f = right;
+ f = bot;
+ }
+ {
+ Left f;
+ f = /*warning:DownCastComposite*/top;
+ f = left;
+ f = /*warning:DownCastComposite*/right; // Should we reject this?
+ f = bot;
+ }
+ {
+ Right f;
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left; // Should we reject this?
+ f = right;
+ f = bot;
+ }
+ {
+ Bot f;
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left;
+ f = /*warning:DownCastComposite*/right;
+ f = bot;
+ }
+ }
+ '''
+ });
+
+ testChecker('Function typing and subtyping: dynamic', {
+ '/main.dart': '''
+
+ class A {}
+
+ typedef dynamic Top(dynamic x); // Top of the lattice
+ typedef dynamic Left(A x); // Left branch
+ typedef A Right(dynamic x); // Right branch
+ typedef A Bottom(A x); // Bottom of the lattice
+
+ dynamic left(A x) => x;
+ A bot(A x) => x;
+ dynamic top(dynamic x) => x;
+ A right(dynamic x) => /*info:DynamicCast*/x;
+
+ void main() {
+ {
+ Top f;
+ f = top;
+ f = left;
+ f = right;
+ f = bot;
+ }
+ {
+ Left f;
+ f = /*warning:DownCastComposite*/top;
+ f = left;
+ f = /*warning:DownCastComposite*/right;
+ f = bot;
+ }
+ {
+ Right f;
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left;
+ f = right;
+ f = bot;
+ }
+ {
+ Bottom f;
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left;
+ f = /*warning:DownCastComposite*/right;
+ f = bot;
+ }
+ }
+ '''
+ });
+
+ testChecker('Function typing and subtyping: function literal variance', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+
+ typedef T Function2<S, T>(S z);
+
+ A top(B x) => x;
+ B left(B x) => x;
+ A right(A x) => x;
+ B bot(A x) => x as B;
+
+ void main() {
+ {
+ Function2<B, A> f;
+ f = top;
+ f = left;
+ f = right;
+ f = bot;
+ }
+ {
+ Function2<B, B> f;
+ f = /*warning:DownCastComposite*/top;
+ f = left;
+ f = /*warning:DownCastComposite*/right; // Should we reject this?
+ f = bot;
+ }
+ {
+ Function2<A, A> f;
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left; // Should we reject this?
+ f = right;
+ f = bot;
+ }
+ {
+ Function2<A, B> f;
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left;
+ f = /*warning:DownCastComposite*/right;
+ f = bot;
+ }
+ }
+ '''
+ });
+
+ testChecker('Function typing and subtyping: function variable variance', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+
+ typedef T Function2<S, T>(S z);
+
+ void main() {
+ {
+ Function2<B, A> top;
+ Function2<B, B> left;
+ Function2<A, A> right;
+ Function2<A, B> bot;
+
+ top = right;
+ top = bot;
+ top = top;
+ top = left;
+
+ left = /*warning:DownCastComposite*/top;
+ left = left;
+ left = /*warning:DownCastComposite*/right; // Should we reject this?
+ left = bot;
+
+ right = /*warning:DownCastComposite*/top;
+ right = /*warning:DownCastComposite*/left; // Should we reject this?
+ right = right;
+ right = bot;
+
+ bot = /*warning:DownCastComposite*/top;
+ bot = /*warning:DownCastComposite*/left;
+ bot = /*warning:DownCastComposite*/right;
+ bot = bot;
+ }
+ }
+ '''
+ });
+
+ testChecker('Function typing and subtyping: higher order function literals', {
+ '/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(AToB f) => f;
+ AToB left(AToB f) => f;
+ BToA right(BToA f) => f;
+ AToB _bot(BToA f) => /*warning:DownCastComposite*/f;
+ AToB bot(BToA f) => f as AToB;
+
+ 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:DownCastComposite*/f;
+ Function2<A, B> bot(BToA f) => f as Function2<A, B>;
+
+
+ BToA top(Function2<A, B> f) => f;
+ AToB left(Function2<A, B> f) => f;
+ BToA right(Function2<B, A> f) => f;
+ AToB _bot(Function2<B, A> f) => /*warning:DownCastComposite*/f;
+ AToB bot(Function2<B, A> f) => f as AToB;
+
+ void main() {
+ {
+ Function2<AToB, BToA> f; // Top
+ f = top;
+ f = left;
+ f = right;
+ f = bot;
+ }
+ {
+ Function2<AToB, AToB> f; // Left
+ f = /*warning:DownCastComposite*/top;
+ f = left;
+ f = /*warning:DownCastComposite*/right; // Should we reject this?
+ f = bot;
+ }
+ {
+ Function2<BToA, BToA> f; // Right
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left; // Should we reject this?
+ f = right;
+ f = bot;
+ }
+ {
+ Function2<BToA, AToB> f; // Bot
+ f = bot;
+ f = /*warning:DownCastComposite*/left;
+ f = /*warning:DownCastComposite*/top;
+ f = /*warning:DownCastComposite*/left;
+ }
+ }
+ '''
+ });
+
+ testChecker(
+ 'Function typing and subtyping: higher order function variables', {
+ '/main.dart': '''
+
+ class A {}
+ class B extends A {}
+
+ typedef T Function2<S, T>(S z);
+
+ void main() {
+ {
+ Function2<Function2<A, B>, Function2<B, A>> top;
+ Function2<Function2<B, A>, Function2<B, A>> right;
+ Function2<Function2<A, B>, Function2<A, B>> left;
+ Function2<Function2<B, A>, Function2<A, B>> bot;
+
+ top = right;
+ top = bot;
+ top = top;
+ top = left;
+
+ left = /*warning:DownCastComposite*/top;
+ left = left;
+ left =
+ /*warning:DownCastComposite should be severe:StaticTypeError*/right;
+ left = bot;
+
+ right = /*warning:DownCastComposite*/top;
+ right =
+ /*warning:DownCastComposite should be severe:StaticTypeError*/left;
+ right = right;
+ right = bot;
+
+ bot = /*warning:DownCastComposite*/top;
+ bot = /*warning:DownCastComposite*/left;
+ bot = /*warning:DownCastComposite*/right;
+ bot = bot;
+ }
+ }
+ '''
+ });
+
+ testChecker('Function typing and subtyping: named and optional parameters', {
+ '/main.dart': '''
+
+ class A {}
+
+ typedef A FR(A x);
+ typedef A FO([A x]);
+ typedef A FN({A x});
+ typedef A FRR(A x, A y);
+ typedef A FRO(A x, [A y]);
+ typedef A FRN(A x, {A n});
+ typedef A FOO([A x, A y]);
+ typedef A FNN({A x, A y});
+ typedef A FNNN({A z, A y, A x});
+
+ void main() {
+ FR r;
+ FO o;
+ FN n;
+ FRR rr;
+ FRO ro;
+ FRN rn;
+ FOO oo;
+ FNN nn;
+ FNNN nnn;
+
+ r = r;
+ r = o;
+ r = /*severe:StaticTypeError*/n;
+ r = /*severe:StaticTypeError*/rr;
+ r = ro;
+ r = rn;
+ r = oo;
+ r = /*severe:StaticTypeError*/nn;
+ r = /*severe:StaticTypeError*/nnn;
+
+ o = /*warning:DownCastComposite*/r;
+ o = o;
+ o = /*severe:StaticTypeError*/n;
+ o = /*severe:StaticTypeError*/rr;
+ o = /*severe:StaticTypeError*/ro;
+ o = /*severe:StaticTypeError*/rn;
+ o = oo;
+ o = /*severe:StaticTypeError*/nn
+ o = /*severe:StaticTypeError*/nnn;
+
+ n = /*severe:StaticTypeError*/r;
+ n = /*severe:StaticTypeError*/o;
+ n = n;
+ n = /*severe:StaticTypeError*/rr;
+ n = /*severe:StaticTypeError*/ro;
+ n = /*severe:StaticTypeError*/rn;
+ n = /*severe:StaticTypeError*/oo;
+ n = nn;
+ n = nnn;
+
+ rr = /*severe:StaticTypeError*/r;
+ rr = /*severe:StaticTypeError*/o;
+ rr = /*severe:StaticTypeError*/n;
+ rr = rr;
+ rr = ro;
+ rr = /*severe:StaticTypeError*/rn;
+ rr = oo;
+ rr = /*severe:StaticTypeError*/nn;
+ rr = /*severe:StaticTypeError*/nnn;
+
+ ro = /*warning:DownCastComposite*/r;
+ ro = /*severe:StaticTypeError*/o;
+ ro = /*severe:StaticTypeError*/n;
+ ro = /*warning:DownCastComposite*/rr;
+ ro = ro;
+ ro = /*severe:StaticTypeError*/rn;
+ ro = oo;
+ ro = /*severe:StaticTypeError*/nn;
+ ro = /*severe:StaticTypeError*/nnn;
+
+ rn = /*warning:DownCastComposite*/r;
+ rn = /*severe:StaticTypeError*/o;
+ rn = /*severe:StaticTypeError*/n;
+ rn = /*severe:StaticTypeError*/rr;
+ rn = /*severe:StaticTypeError*/ro;
+ rn = rn;
+ rn = /*severe:StaticTypeError*/oo;
+ rn = /*severe:StaticTypeError*/nn;
+ rn = /*severe:StaticTypeError*/nnn;
+
+ oo = /*warning:DownCastComposite*/r;
+ oo = /*warning:DownCastComposite*/o;
+ oo = /*severe:StaticTypeError*/n;
+ oo = /*warning:DownCastComposite*/rr;
+ oo = /*warning:DownCastComposite*/ro;
+ oo = /*severe:StaticTypeError*/rn;
+ oo = oo;
+ oo = /*severe:StaticTypeError*/nn;
+ oo = /*severe:StaticTypeError*/nnn;
+
+ nn = /*severe:StaticTypeError*/r;
+ nn = /*severe:StaticTypeError*/o;
+ nn = /*warning:DownCastComposite*/n;
+ nn = /*severe:StaticTypeError*/rr;
+ nn = /*severe:StaticTypeError*/ro;
+ nn = /*severe:StaticTypeError*/rn;
+ nn = /*severe:StaticTypeError*/oo;
+ nn = nn;
+ nn = nnn;
+
+ nnn = /*severe:StaticTypeError*/r;
+ nnn = /*severe:StaticTypeError*/o;
+ nnn = /*warning:DownCastComposite*/n;
+ nnn = /*severe:StaticTypeError*/rr;
+ nnn = /*severe:StaticTypeError*/ro;
+ nnn = /*severe:StaticTypeError*/rn;
+ nnn = /*severe:StaticTypeError*/oo;
+ nnn = /*warning:DownCastComposite*/nn;
+ nnn = nnn;
+ }
+ '''
+ });
+
+ testChecker('Function subtyping: objects with call methods', {
+ '/main.dart': '''
+
+ typedef int I2I(int x);
+ typedef num N2N(num x);
+ class A {
+ int call(int x) => x;
+ }
+ class B {
+ num call(num x) => x;
+ }
+ int i2i(int x) => x;
+ num n2n(num x) => x;
+ void main() {
+ {
+ I2I f;
+ f = new A();
+ f = /*severe:StaticTypeError*/new B();
+ f = i2i;
+ f = /*warning:DownCastComposite*/n2n;
+ f = /*warning:DownCastComposite*/i2i as Object;
+ f = /*warning:DownCastComposite*/n2n as Function;
+ }
+ {
+ N2N f;
+ f = /*severe:StaticTypeError*/new A();
+ f = new B();
+ f = /*warning:DownCastComposite*/i2i;
+ f = n2n;
+ f = /*warning:DownCastComposite*/i2i as Object;
+ f = /*warning:DownCastComposite*/n2n as Function;
+ }
+ {
+ A f;
+ f = new A();
+ f = /*severe:StaticTypeError*/new B();
+ f = /*severe:StaticTypeError*/i2i;
+ f = /*severe:StaticTypeError*/n2n;
+ f = /*info:DownCastImplicit*/i2i as Object;
+ f = /*info:DownCastImplicit*/n2n as Function;
+ }
+ {
+ B f;
+ f = /*severe:StaticTypeError*/new A();
+ f = new B();
+ f = /*severe:StaticTypeError*/i2i;
+ f = /*severe:StaticTypeError*/n2n;
+ f = /*info:DownCastImplicit*/i2i as Object;
+ f = /*info:DownCastImplicit*/n2n as Function;
+ }
+ {
+ Function f;
+ f = new A();
+ f = new B();
+ f = i2i;
+ f = n2n;
+ f = /*info:DownCastImplicit*/i2i as Object;
+ f = (n2n as Function);
+ }
+ }
+ '''
+ });
+
+ testChecker('Function typing and subtyping: void', {
+ '/main.dart': '''
+
+ class A {
+ void bar() => null;
+ void foo() => bar; // allowed
+ }
+ '''
+ });
+
+ testChecker('Relaxed casts', {
+ '/main.dart': '''
+
+ class A {}
+
+ class L<T> {}
+ class M<T> extends L<T> {}
+ // L<dynamic|Object>
+ // / \
+ // M<dynamic|Object> L<A>
+ // \ /
+ // M<A>
+ // In normal Dart, there are additional edges
+ // from M<A> to M<dynamic>
+ // from L<A> to M<dynamic>
+ // from L<A> to L<dynamic>
+ void main() {
+ L lOfDs;
+ L<Object> lOfOs;
+ L<A> lOfAs;
+
+ M mOfDs;
+ M<Object> mOfOs;
+ M<A> mOfAs;
+
+ {
+ lOfDs = mOfDs;
+ lOfDs = mOfOs;
+ lOfDs = mOfAs;
+ lOfDs = lOfDs;
+ lOfDs = lOfOs;
+ lOfDs = lOfAs;
+ }
+ {
+ lOfOs = mOfDs;
+ lOfOs = mOfOs;
+ lOfOs = mOfAs;
+ lOfOs = lOfDs;
+ lOfOs = lOfOs;
+ lOfOs = lOfAs;
+ }
+ {
+ lOfAs = /*warning:DownCastComposite*/mOfDs;
+ lOfAs = /*severe:StaticTypeError*/mOfOs;
+ lOfAs = mOfAs;
+ lOfAs = /*warning:DownCastComposite*/lOfDs;
+ lOfAs = /*warning:DownCastComposite*/lOfOs;
+ lOfAs = lOfAs;
+ }
+ {
+ mOfDs = mOfDs;
+ mOfDs = mOfOs;
+ mOfDs = mOfAs;
+ mOfDs = /*info:DownCastImplicit*/lOfDs;
+ mOfDs = /*info:DownCastImplicit*/lOfOs;
+ mOfDs = /*info:DownCastImplicit*/lOfAs;
+ }
+ {
+ mOfOs = mOfDs;
+ mOfOs = mOfOs;
+ mOfOs = mOfAs;
+ mOfOs = /*info:DownCastImplicit*/lOfDs;
+ mOfOs = /*info:DownCastImplicit*/lOfOs;
+ mOfOs = /*severe:StaticTypeError*/lOfAs;
+ }
+ {
+ mOfAs = /*warning:DownCastComposite*/mOfDs;
+ mOfAs = /*warning:DownCastComposite*/mOfOs;
+ mOfAs = mOfAs;
+ mOfAs = /*warning:DownCastComposite*/lOfDs;
+ mOfAs = /*warning:DownCastComposite*/lOfOs;
+ mOfAs = /*warning:DownCastComposite*/lOfAs;
+ }
+
+ }
+ '''
+ });
+
+ testChecker('Type checking literals', {
+ '/main.dart': '''
+ test() {
+ num n = 3;
+ int i = 3;
+ String s = "hello";
+ {
+ List<int> l = <int>[i];
+ l = <int>[/*severe:StaticTypeError*/s];
+ l = <int>[/*info:DownCastImplicit*/n];
+ l = <int>[i, /*info:DownCastImplicit*/n, /*severe:StaticTypeError*/s];
+ }
+ {
+ List l = [i];
+ l = [s];
+ l = [n];
+ l = [i, n, s];
+ }
+ {
+ Map<String, int> m = <String, int>{s: i};
+ m = <String, int>{s: /*severe:StaticTypeError*/s};
+ m = <String, int>{s: /*info:DownCastImplicit*/n};
+ m = <String, int>{s: i,
+ s: /*info:DownCastImplicit*/n,
+ s: /*severe:StaticTypeError*/s};
+ }
+ // TODO(leafp): We can't currently test for key errors since the
+ // error marker binds to the entire entry.
+ {
+ Map m = {s: i};
+ m = {s: s};
+ m = {s: n};
+ m = {s: i,
+ s: n,
+ s: s};
+ m = {i: s,
+ n: s,
+ s: s};
+ }
+ }
+ '''
+ });
+
+ testChecker('casts in constant contexts', {
+ '/main.dart': '''
+ class A {
+ static const num n = 3.0;
+ static const int i = /*info:AssignmentCast*/n;
+ final int fi;
+ const A(num a) : this.fi = /*info:DownCastImplicit*/a;
+ }
+ class B extends A {
+ const B(Object a) : super(/*info:DownCastImplicit*/a);
+ }
+ void foo(Object o) {
+ var a = const A(/*info:DownCastImplicit*/o);
+ }
+ '''
+ });
+
+ testChecker('casts in conditionals', {
+ '/main.dart': '''
+ main() {
+ bool b = true;
+ num x = b ? 1 : 2.3;
+ int y = /*info:AssignmentCast*/b ? 1 : 2.3;
+ String z = !b ? "hello" : null;
+ z = b ? null : "hello";
+ }
+ '''
+ });
+
+ testChecker('redirecting constructor', {
+ '/main.dart': '''
+ class A {
+ A(A x) {}
+ A.two() : this(/*severe:StaticTypeError*/3);
+ }
+ '''
+ });
+
+ testChecker('super constructor', {
+ '/main.dart': '''
+ class A { A(A x) {} }
+ class B extends A {
+ B() : super(/*severe:StaticTypeError*/3);
+ }
+ '''
+ });
+
+ testChecker('field/field override', {
+ '/main.dart': '''
+ class A {}
+ class B extends A {}
+ class C extends B {}
+
+ class Base {
+ B f1;
+ B f2;
+ B f3;
+ B f4;
+ }
+
+ class Child extends Base {
+ /*severe:InvalidMethodOverride*/A f1; // invalid for getter
+ /*severe:InvalidMethodOverride*/C f2; // invalid for setter
+ var f3;
+ /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/dynamic f4;
+ }
+ '''
+ });
+
+ testChecker('getter/getter override', {
+ '/main.dart': '''
+ class A {}
+ class B extends A {}
+ class C extends B {}
+
+ abstract class Base {
+ B get f1;
+ B get f2;
+ B get f3;
+ B get f4;
+ }
+
+ class Child extends Base {
+ /*severe:InvalidMethodOverride*/A get f1 => null;
+ C get f2 => null;
+ get f3 => null;
+ /*severe:InvalidMethodOverride*/dynamic get f4 => null;
+ }
+ '''
+ });
+
+ testChecker('field/getter override', {
+ '/main.dart': '''
+ class A {}
+ class B extends A {}
+ class C extends B {}
+
+ abstract class Base {
+ B f1;
+ B f2;
+ B f3;
+ B f4;
+ }
+
+ class Child extends Base {
+ /*severe:InvalidMethodOverride*/A get f1 => null;
+ C get f2 => null;
+ get f3 => null;
+ /*severe:InvalidMethodOverride*/dynamic get f4 => null;
+ }
+ '''
+ });
+
+ testChecker('setter/setter override', {
+ '/main.dart': '''
+ class A {}
+ class B extends A {}
+ class C extends B {}
+
+ abstract class Base {
+ void set f1(B value);
+ void set f2(B value);
+ void set f3(B value);
+ void set f4(B value);
+ void set f5(B value);
+ }
+
+ class Child extends Base {
+ void set f1(A value) {}
+ /*severe:InvalidMethodOverride*/void set f2(C value) {}
+ void set f3(value) {}
+ /*severe:InvalidMethodOverride*/void set f4(dynamic value) {}
+ set f5(B value) {}
+ }
+ '''
+ });
+
+ testChecker('field/setter override', {
+ '/main.dart': '''
+ class A {}
+ class B extends A {}
+ class C extends B {}
+
+ class Base {
+ B f1;
+ B f2;
+ B f3;
+ B f4;
+ B f5;
+ }
+
+ class Child extends Base {
+ B get f1 => null;
+ B get f2 => null;
+ B get f3 => null;
+ B get f4 => null;
+ B get f5 => null;
+
+ void set f1(A value) {}
+ /*severe:InvalidMethodOverride*/void set f2(C value) {}
+ void set f3(value) {}
+ /*severe:InvalidMethodOverride*/void set f4(dynamic value) {}
+ set f5(B value) {}
+ }
+ '''
+ });
+
+ testChecker('method override', {
+ '/main.dart': '''
+ class A {}
+ class B extends A {}
+ class C extends B {}
+
+ class Base {
+ B m1(B a);
+ B m2(B a);
+ B m3(B a);
+ B m4(B a);
+ B m5(B a);
+ B m6(B a);
+ }
+
+ class Child extends Base {
+ /*severe:InvalidMethodOverride*/A m1(A value) {}
+ /*severe:InvalidMethodOverride*/C m2(C value) {}
+ /*severe:InvalidMethodOverride*/A m3(C value) {}
+ C m4(A value) {}
+ m5(value) {}
+ /*severe:InvalidMethodOverride*/dynamic m6(dynamic value) {}
+ }
+ '''
+ });
+
+ testChecker('unary operators', {
+ '/main.dart': '''
+ class A {
+ A operator ~() {}
+ A operator +(int x) {}
+ A operator -(int x) {}
+ A operator -() {}
+ }
+
+ foo() => new A();
+
+ test() {
+ A a = new A();
+ var c = foo();
+
+ ~a;
+ (/*info:DynamicInvoke*/~d);
+
+ !/*severe:StaticTypeError*/a;
+ !/*info:DynamicCast*/d;
+
+ -a;
+ (/*info:DynamicInvoke*/-d);
+
+ ++a;
+ --a;
+ (/*info:DynamicInvoke*/++d);
+ (/*info:DynamicInvoke*/--d);
+
+ a++;
+ a--;
+ (/*info:DynamicInvoke*/d++);
+ (/*info:DynamicInvoke*/d--);
+ }'''
+ });
+
+ testChecker('binary and index operators', {
+ '/main.dart': '''
+ class A {
+ A operator *(B b) {}
+ A operator /(B b) {}
+ A operator ~/(B b) {}
+ A operator %(B b) {}
+ A operator +(B b) {}
+ A operator -(B b) {}
+ A operator <<(B b) {}
+ A operator >>(B b) {}
+ A operator &(B b) {}
+ A operator ^(B b) {}
+ A operator |(B b) {}
+ A operator[](B b) {}
+ }
+
+ class B {
+ A operator -(B b) {}
+ }
+
+ foo() => new A();
+
+ test() {
+ A a = new A();
+ B b = new B();
+ var c = foo();
+ a = a * b;
+ a = a * /*info:DynamicCast*/c;
+ a = a / b;
+ a = a ~/ b;
+ a = a % b;
+ a = a + b;
+ a = a + /*severe:StaticTypeError*/a;
+ a = a - b;
+ b = /*severe:StaticTypeError*/b - b;
+ a = a << b;
+ a = a >> b;
+ a = a & b;
+ a = a ^ b;
+ a = a | b;
+ c = (/*info:DynamicInvoke*/c + b);
+
+ String x = 'hello';
+ int y = 42;
+ x = x + x;
+ x = x + /*info:DynamicCast*/c;
+ x = x + /*severe:StaticTypeError*/y;
+
+ bool p = true;
+ p = p && p;
+ p = p && /*info:DynamicCast*/c;
+ p = (/*info:DynamicCast*/c) && p;
+ p = (/*info:DynamicCast*/c) && /*info:DynamicCast*/c;
+ p = (/*severe:StaticTypeError*/y) && p;
+ p = c == y;
+
+ a = a[b];
+ a = a[/*info:DynamicCast*/c];
+ c = (/*info:DynamicInvoke*/c[b]);
+ a[/*severe:StaticTypeError*/y];
+ }
+ '''
+ });
+
+ testChecker('compound assignments', {
+ '/main.dart': '''
+ class A {
+ A operator *(B b) {}
+ A operator /(B b) {}
+ A operator ~/(B b) {}
+ A operator %(B b) {}
+ A operator +(B b) {}
+ A operator -(B b) {}
+ A operator <<(B b) {}
+ A operator >>(B b) {}
+ A operator &(B b) {}
+ A operator ^(B b) {}
+ A operator |(B b) {}
+ D operator [](B index) {}
+ void operator []=(B index, D value) {}
+ }
+
+ class B {
+ A operator -(B b) {}
+ }
+
+ class D {
+ D operator +(D d) {}
+ }
+
+ foo() => new A();
+
+ test() {
+ int x = 0;
+ x += 5;
+ (/*severe:StaticTypeError*/x += 3.14);
+
+ double y = 0.0;
+ y += 5;
+ y += 3.14;
+
+ num z = 0;
+ z += 5;
+ z += 3.14;
+
+ x = /*info:DownCastImplicit*/x + z;
+ x += /*info:DownCastImplicit*/z;
+ y = /*info:DownCastImplicit*/y + z;
+ y += /*info:DownCastImplicit*/z;
+
+ dynamic w = 42;
+ x += /*info:DynamicCast*/w;
+ y += /*info:DynamicCast*/w;
+ z += /*info:DynamicCast*/w;
+
+ A a = new A();
+ B b = new B();
+ var c = foo();
+ a = a * b;
+ a *= b;
+ a *= /*info:DynamicCast*/c;
+ a /= b;
+ a ~/= b;
+ a %= b;
+ a += b;
+ a += /*severe:StaticTypeError*/a;
+ a -= b;
+ (/*severe:StaticTypeError*/b -= b);
+ a <<= b;
+ a >>= b;
+ a &= b;
+ a ^= b;
+ a |= b;
+ (/*info:DynamicInvoke*/c += b);
+
+ var d = new D();
+ a[b] += d;
+ a[/*info:DynamicCast*/c] += d;
+ a[/*severe:StaticTypeError*/z] += d;
+ a[b] += /*info:DynamicCast*/c;
+ a[b] += /*severe:StaticTypeError*/z;
+ (/*info:DynamicInvoke*/(/*info:DynamicInvoke*/c[b]) += d);
+ }
+ '''
+ });
+
+ testChecker('super call placement', {
+ '/main.dart': '''
+ class Base {
+ var x;
+ Base() : x = print('Base.1') { print('Base.2'); }
+ }
+
+ class Derived extends Base {
+ var y, z;
+ Derived()
+ : y = print('Derived.1'),
+ /*severe:InvalidSuperInvocation*/super(),
+ z = print('Derived.2') {
+ print('Derived.3');
+ }
+ }
+
+ class Valid extends Base {
+ var y, z;
+ Valid()
+ : y = print('Valid.1'),
+ z = print('Valid.2'),
+ super() {
+ print('Valid.3');
+ }
+ }
+
+ class AlsoValid extends Base {
+ AlsoValid() : super();
+ }
+
+ main() => new Derived();
+ '''
+ });
+
+ testChecker('for loop variable', {
+ '/main.dart': '''
+ foo() {
+ for (int i = 0; i < 10; i++) {
+ i = /*severe:StaticTypeError*/"hi";
+ }
+ }
+ bar() {
+ for (var i = 0; i < 10; i++) {
+ int j = i + 1;
+ }
+ }
+ '''
+ });
+
+ group('invalid overrides', () {
+ testChecker('child override', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ class Base {
+ A f;
+ }
+
+ class T1 extends Base {
+ /*severe:InvalidMethodOverride*/B get f => null;
+ }
+
+ class T2 extends Base {
+ /*severe:InvalidMethodOverride*/set f(B b) => null;
+ }
+
+ class T3 extends Base {
+ /*severe:InvalidMethodOverride*/final B f;
+ }
+ class T4 extends Base {
+ // two: one for the getter one for the setter.
+ /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/B f;
+ }
+ '''
+ });
+
+ testChecker('child override 2', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ class Base {
+ m(A a) {}
+ }
+
+ class Test extends Base {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+ testChecker('grandchild override', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ class Grandparent {
+ m(A a) {}
+ }
+ class Parent extends Grandparent {
+ }
+
+ class Test extends Parent {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+
+ testChecker('double override', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ class Grandparent {
+ m(A a) {}
+ }
+ class Parent extends Grandparent {
+ m(A a) {}
+ }
+
+ class Test extends Parent {
+ // Reported only once
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+
+ testChecker('double override 2', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ class Grandparent {
+ m(A a) {}
+ }
+ class Parent extends Grandparent {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+
+ class Test extends Parent {
+ m(B a) {}
+ }
+ '''
+ });
+
+ testChecker('mixin override to base', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ class Base {
+ m(A a) {}
+ }
+
+ class M1 {
+ m(B a) {}
+ }
+
+ class M2 {}
+
+ class T1 extends Base with /*severe:InvalidMethodOverride*/M1 {}
+ class T2 extends Base with /*severe:InvalidMethodOverride*/M1, M2 {}
+ class T3 extends Base with M2, /*severe:InvalidMethodOverride*/M1 {}
+ '''
+ });
+
+ testChecker('mixin override to mixin', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ class Base {
+ }
+
+ class M1 {
+ m(B a) {}
+ }
+
+ class M2 {
+ m(A a) {}
+ }
+
+ class T1 extends Base with M1, /*severe:InvalidMethodOverride*/M2 {}
+ '''
+ });
+
+ // This is a regression test for a bug in an earlier implementation were
+ // names were hiding errors if the first mixin override looked correct,
+ // but subsequent ones did not.
+ testChecker('no duplicate mixin override', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ class Base {
+ m(A a) {}
+ }
+
+ class M1 {
+ m(A a) {}
+ }
+
+ class M2 {
+ m(B a) {}
+ }
+
+ class M3 {
+ m(B a) {}
+ }
+
+ class T1 extends Base
+ with M1, /*severe:InvalidMethodOverride*/M2, M3 {}
+ '''
+ });
+
+ testChecker('class override of interface', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I {
+ m(A a);
+ }
+
+ class T1 implements I {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+
+ testChecker('base class override to child interface', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I {
+ m(A a);
+ }
+
+ class Base {
+ m(B a) {}
+ }
+
+
+ class T1 /*severe:InvalidMethodOverride*/extends Base implements I {
+ }
+ '''
+ });
+
+ testChecker('mixin override of interface', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I {
+ m(A a);
+ }
+
+ class M {
+ m(B a) {}
+ }
+
+ class T1 extends Object with /*severe:InvalidMethodOverride*/M
+ implements I {}
+ '''
+ });
+
+ // This is a case were it is incorrect to say that the base class
+ // incorrectly overrides the interface.
+ testChecker(
+ 'no errors if subclass correctly overrides base and interface', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ class Base {
+ m(A a) {}
+ }
+
+ class I1 {
+ m(B a) {}
+ }
+
+ class T1 /*severe:InvalidMethodOverride*/extends Base
+ implements I1 {}
+
+ class T2 extends Base implements I1 {
+ /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {}
+ }
+
+ class T3 extends Object with /*severe:InvalidMethodOverride*/Base
+ implements I1 {}
+
+ class T4 extends Object with Base implements I1 {
+ /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {}
+ }
+ '''
+ });
+ });
+
+ group('class override of grand interface', () {
+ testChecker('interface of interface of child', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+ abstract class I2 implements I1 {}
+
+ class T1 implements I2 {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+ testChecker('superclass of interface of child', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+ abstract class I2 extends I1 {}
+
+ class T1 implements I2 {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+ testChecker('mixin of interface of child', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class M1 {
+ m(A a);
+ }
+ abstract class I2 extends Object with M1 {}
+
+ class T1 implements I2 {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+ testChecker('interface of abstract superclass', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+ abstract class Base implements I1 {}
+
+ class T1 extends Base {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+ testChecker('interface of concrete superclass', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+
+ // See issue #25
+ /*pass should be warning:AnalyzerError*/class Base implements I1 {
+ }
+
+ class T1 extends Base {
+ // not reported technically because if the class is concrete,
+ // it should implement all its interfaces and hence it is
+ // sufficient to check overrides against it.
+ m(B a) {}
+ }
+ '''
+ });
+ });
+
+ group('mixin override of grand interface', () {
+ testChecker('interface of interface of child', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+ abstract class I2 implements I1 {}
+
+ class M {
+ m(B a) {}
+ }
+
+ class T1 extends Object with /*severe:InvalidMethodOverride*/M
+ implements I2 {
+ }
+ '''
+ });
+ testChecker('superclass of interface of child', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+ abstract class I2 extends I1 {}
+
+ class M {
+ m(B a) {}
+ }
+
+ class T1 extends Object with /*severe:InvalidMethodOverride*/M
+ implements I2 {
+ }
+ '''
+ });
+ testChecker('mixin of interface of child', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class M1 {
+ m(A a);
+ }
+ abstract class I2 extends Object with M1 {}
+
+ class M {
+ m(B a) {}
+ }
+
+ class T1 extends Object with /*severe:InvalidMethodOverride*/M
+ implements I2 {
+ }
+ '''
+ });
+ testChecker('interface of abstract superclass', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+ abstract class Base implements I1 {}
+
+ class M {
+ m(B a) {}
+ }
+
+ class T1 extends Base with /*severe:InvalidMethodOverride*/M {
+ }
+ '''
+ });
+ testChecker('interface of concrete superclass', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+
+ // See issue #25
+ /*pass should be warning:AnalyzerError*/class Base implements I1 {
+ }
+
+ class M {
+ m(B a) {}
+ }
+
+ class T1 extends Base with M {
+ }
+ '''
+ });
+ });
+
+ group('superclass override of grand interface', () {
+ testChecker('interface of interface of child', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+ abstract class I2 implements I1 {}
+
+ class Base {
+ m(B a) {}
+ }
+
+ class T1 /*severe:InvalidMethodOverride*/extends Base
+ implements I2 {
+ }
+ '''
+ });
+ testChecker('superclass of interface of child', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+ abstract class I2 extends I1 {}
+
+ class Base {
+ m(B a) {}
+ }
+
+ class T1 /*severe:InvalidMethodOverride*/extends Base
+ implements I2 {
+ }
+ '''
+ });
+ testChecker('mixin of interface of child', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class M1 {
+ m(A a);
+ }
+ abstract class I2 extends Object with M1 {}
+
+ class Base {
+ m(B a) {}
+ }
+
+ class T1 /*severe:InvalidMethodOverride*/extends Base
+ implements I2 {
+ }
+ '''
+ });
+ testChecker('interface of abstract superclass', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+
+ abstract class Base implements I1 {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+
+ class T1 extends Base {
+ // we consider the base class incomplete because it is
+ // abstract, so we report the error here too.
+ // TODO(sigmund): consider tracking overrides in a fine-grain
+ // manner, then this and the double-overrides would not be
+ // reported.
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+ testChecker('interface of concrete superclass', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+
+ class Base implements I1 {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+
+ class T1 extends Base {
+ m(B a) {}
+ }
+ '''
+ });
+ });
+
+ group('no duplicate reports from overriding interfaces', () {
+ testChecker('type overrides same method in multiple interfaces', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+ abstract class I2 implements I1 {
+ m(A a);
+ }
+
+ class Base {
+ }
+
+ class T1 implements I2 {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+ '''
+ });
+
+ testChecker('type and base type override same method in interface', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+
+ class Base {
+ m(B a);
+ }
+
+ // Note: no error reported in `extends Base` to avoid duplicating
+ // the error in T1.
+ class T1 extends Base implements I1 {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+
+ // If there is no error in the class, we do report the error at
+ // the base class:
+ class T2 /*severe:InvalidMethodOverride*/extends Base
+ implements I1 {
+ }
+ '''
+ });
+
+ testChecker('type and mixin override same method in interface', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+
+ class M {
+ m(B a);
+ }
+
+ class T1 extends Object with M implements I1 {
+ /*severe:InvalidMethodOverride*/m(B a) {}
+ }
+
+ class T2 extends Object with /*severe:InvalidMethodOverride*/M
+ implements I1 {
+ }
+ '''
+ });
+
+ testChecker('two grand types override same method in interface', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+
+ class Grandparent {
+ m(B a) {}
+ }
+
+ class Parent1 extends Grandparent {
+ m(B a) {}
+ }
+ class Parent2 extends Grandparent {
+ }
+
+ // Note: otherwise both errors would be reported on this line
+ class T1 /*severe:InvalidMethodOverride*/extends Parent1
+ implements I1 {
+ }
+ class T2 /*severe:InvalidMethodOverride*/extends Parent2
+ implements I1 {
+ }
+ '''
+ });
+
+ testChecker('two mixins override same method in interface', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+
+ class M1 {
+ m(B a) {}
+ }
+
+ class M2 {
+ m(B a) {}
+ }
+
+ // Here we want to report both, because the error location is
+ // different.
+ // TODO(sigmund): should we merge these as well?
+ class T1 extends Object
+ with /*severe:InvalidMethodOverride*/M1
+ with /*severe:InvalidMethodOverride*/M2
+ implements I1 {
+ }
+ '''
+ });
+
+ testChecker('base type and mixin override same method in interface', {
+ '/main.dart': '''
+ class A {}
+ class B {}
+
+ abstract class I1 {
+ m(A a);
+ }
+
+ class Base {
+ m(B a) {}
+ }
+
+ class M {
+ m(B a) {}
+ }
+
+ // Here we want to report both, because the error location is
+ // different.
+ // TODO(sigmund): should we merge these as well?
+ class T1 /*severe:InvalidMethodOverride*/extends Base
+ with /*severe:InvalidMethodOverride*/M
+ implements I1 {
+ }
+ '''
+ });
+ });
+
+ testChecker('invalid runtime checks', {
+ '/main.dart': '''
+ typedef int I2I(int x);
+ typedef int D2I(x);
+ typedef int II2I(int x, int y);
+ typedef int DI2I(x, int y);
+ typedef int ID2I(int x, y);
+ typedef int DD2I(x, y);
+
+ typedef I2D(int x);
+ typedef D2D(x);
+ typedef II2D(int x, int y);
+ typedef DI2D(x, int y);
+ typedef ID2D(int x, y);
+ typedef DD2D(x, y);
+
+ int foo(int x) => x;
+ int bar(int x, int y) => x + y;
+
+ void main() {
+ bool b;
+ b = /*info:NonGroundTypeCheckInfo*/foo is I2I;
+ b = /*info:NonGroundTypeCheckInfo*/foo is D2I;
+ b = /*info:NonGroundTypeCheckInfo*/foo is I2D;
+ b = foo is D2D;
+
+ b = /*info:NonGroundTypeCheckInfo*/bar is II2I;
+ b = /*info:NonGroundTypeCheckInfo*/bar is DI2I;
+ b = /*info:NonGroundTypeCheckInfo*/bar is ID2I;
+ b = /*info:NonGroundTypeCheckInfo*/bar is II2D;
+ b = /*info:NonGroundTypeCheckInfo*/bar is DD2I;
+ b = /*info:NonGroundTypeCheckInfo*/bar is DI2D;
+ b = /*info:NonGroundTypeCheckInfo*/bar is ID2D;
+ b = bar is DD2D;
+
+ // For as, the validity of checks is deferred to runtime.
+ Function f;
+ f = foo as I2I;
+ f = foo as D2I;
+ f = foo as I2D;
+ f = foo as D2D;
+
+ f = bar as II2I;
+ f = bar as DI2I;
+ f = bar as ID2I;
+ f = bar as II2D;
+ f = bar as DD2I;
+ f = bar as DI2D;
+ f = bar as ID2D;
+ f = bar as DD2D;
+ }
+ '''
+ });
+
+ group('function modifiers', () {
+ testChecker('async', {
+ '/main.dart': '''
+ import 'dart:async';
+ import 'dart:math' show Random;
+
+ dynamic x;
+
+ foo1() async => x;
+ Future foo2() async => x;
+ Future<int> foo3() async => (/*info:DynamicCast*/x);
+ Future<int> foo4() async => (/*severe:StaticTypeError*/new Future<int>.value(/*info:DynamicCast*/x));
+
+ bar1() async { return x; }
+ Future bar2() async { return x; }
+ Future<int> bar3() async { return (/*info:DynamicCast*/x); }
+ Future<int> bar4() async { return (/*severe:StaticTypeError*/new Future<int>.value(/*info:DynamicCast*/x)); }
+
+ int y;
+ Future<int> z;
+
+ void baz() async {
+ int a = /*info:DynamicCast*/await x;
+ int b = await y;
+ int c = await z;
+ String d = /*severe:StaticTypeError*/await z;
+ }
+
+ Future<bool> get issue_264 async {
+ await 42;
+ if (new Random().nextBool()) {
+ return true;
+ } else {
+ return /*severe:StaticTypeError*/new Future<bool>.value(false);
+ }
+ }
+ '''
+ });
+
+ testChecker('async*', {
+ '/main.dart': '''
+ import 'dart:async';
+
+ dynamic x;
+
+ bar1() async* { yield x; }
+ Stream bar2() async* { yield x; }
+ Stream<int> bar3() async* { yield (/*info:DynamicCast*/x); }
+ Stream<int> bar4() async* { yield (/*severe:StaticTypeError*/new Stream<int>()); }
+
+ baz1() async* { yield* (/*info:DynamicCast*/x); }
+ Stream baz2() async* { yield* (/*info:DynamicCast*/x); }
+ Stream<int> baz3() async* { yield* (/*warning:DownCastComposite*/x); }
+ Stream<int> baz4() async* { yield* new Stream<int>(); }
+ Stream<int> baz5() async* { yield* (/*info:InferredTypeAllocation*/new Stream()); }
+ '''
+ });
+
+ testChecker('sync*', {
+ '/main.dart': '''
+ import 'dart:async';
+
+ dynamic x;
+
+ bar1() sync* { yield x; }
+ Iterable bar2() sync* { yield x; }
+ Iterable<int> bar3() sync* { yield (/*info:DynamicCast*/x); }
+ Iterable<int> bar4() sync* { yield (/*severe:StaticTypeError*/new Iterable<int>()); }
+
+ baz1() sync* { yield* (/*info:DynamicCast*/x); }
+ Iterable baz2() sync* { yield* (/*info:DynamicCast*/x); }
+ Iterable<int> baz3() sync* { yield* (/*warning:DownCastComposite*/x); }
+ Iterable<int> baz4() sync* { yield* new Iterable<int>(); }
+ Iterable<int> baz5() sync* { yield* (/*info:InferredTypeAllocation*/new Iterable()); }
+ '''
+ });
+ });
+}
« no previous file with comments | « packages/analyzer/test/src/task/html_test.dart ('k') | packages/analyzer/test/src/task/strong/inferred_type_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698