| 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
|
| index 874916c36781679c278cdac76f752f343ef4cda6..9013f2121b5871f8a4c578d7762c3a64a3b1ea90 100644
|
| --- a/packages/analyzer/test/src/task/strong/checker_test.dart
|
| +++ b/packages/analyzer/test/src/task/strong/checker_test.dart
|
| @@ -2,2310 +2,3957 @@
|
| // 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;
|
| +library analyzer.test.src.task.strong.checker_test;
|
|
|
| -import 'package:unittest/unittest.dart';
|
| +import 'package:test_reflective_loader/test_reflective_loader.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;
|
| - }
|
| - }
|
| + initStrongModeTests();
|
| + defineReflectiveTests(CheckerTest);
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class CheckerTest {
|
| + void test_awaitForInCastsStreamElementToVariable() {
|
| + checkFile('''
|
| +import 'dart:async';
|
| +main() async {
|
| + // Don't choke if sequence is not stream.
|
| + await for (var i in /*error:FOR_IN_OF_INVALID_TYPE*/1234) {}
|
| +
|
| + // Dynamic cast.
|
| + await for (String /*info:DYNAMIC_CAST*/s in new Stream<dynamic>()) {}
|
| +
|
| + // Identity cast.
|
| + await for (String s in new Stream<String>()) {}
|
| +
|
| + // Untyped.
|
| + await for (var s in new Stream<String>()) {}
|
| +
|
| + // Downcast.
|
| + await for (int /*info:DOWN_CAST_IMPLICIT*/i in new Stream<num>()) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_awaitForInCastsSupertypeSequenceToStream() {
|
| + checkFile('''
|
| +main() async {
|
| + dynamic d;
|
| + await for (var i in /*info:DYNAMIC_CAST*/d) {}
|
| +
|
| + Object o;
|
| + await for (var i in /*info:DOWN_CAST_IMPLICIT*/o) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_binaryAndIndexOperators() {
|
| + checkFile('''
|
| +class A {
|
| + A operator *(B b) => null;
|
| + A operator /(B b) => null;
|
| + A operator ~/(B b) => null;
|
| + A operator %(B b) => null;
|
| + A operator +(B b) => null;
|
| + A operator -(B b) => null;
|
| + A operator <<(B b) => null;
|
| + A operator >>(B b) => null;
|
| + A operator &(B b) => null;
|
| + A operator ^(B b) => null;
|
| + A operator |(B b) => null;
|
| + A operator[](B b) => null;
|
| +}
|
| +
|
| +class B {
|
| + A operator -(B b) => null;
|
| +}
|
| +
|
| +foo() => new A();
|
| +
|
| +test() {
|
| + A a = new A();
|
| + B b = new B();
|
| + var c = foo();
|
| + a = a * b;
|
| + a = a * /*info:DYNAMIC_CAST*/c;
|
| + a = a / b;
|
| + a = a ~/ b;
|
| + a = a % b;
|
| + a = a + b;
|
| + a = a + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/a;
|
| + a = a - b;
|
| + b = /*error:INVALID_ASSIGNMENT*/b - b;
|
| + a = a << b;
|
| + a = a >> b;
|
| + a = a & b;
|
| + a = a ^ b;
|
| + a = a | b;
|
| + c = (/*info:DYNAMIC_INVOKE*/c + b);
|
| +
|
| + String x = 'hello';
|
| + int y = 42;
|
| + x = x + x;
|
| + x = x + /*info:DYNAMIC_CAST*/c;
|
| + x = x + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/y;
|
| +
|
| + bool p = true;
|
| + p = p && p;
|
| + p = p && /*info:DYNAMIC_CAST*/c;
|
| + p = (/*info:DYNAMIC_CAST*/c) && p;
|
| + p = (/*info:DYNAMIC_CAST*/c) && /*info:DYNAMIC_CAST*/c;
|
| + p = /*error:NON_BOOL_OPERAND*/y && p;
|
| + p = c == y;
|
| +
|
| + a = a[b];
|
| + a = a[/*info:DYNAMIC_CAST*/c];
|
| + c = (/*info:DYNAMIC_INVOKE*/c[b]);
|
| + a[/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/y];
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_callMethodOnFunctions() {
|
| + checkFile(r'''
|
| +void f(int x) => print(x);
|
| +main() {
|
| + f.call(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi');
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_castsInConditions() {
|
| + checkFile('''
|
| +main() {
|
| + bool b = true;
|
| + num x = b ? 1 : 2.3;
|
| + int y = /*info:ASSIGNMENT_CAST*/b ? 1 : 2.3;
|
| + String z = !b ? "hello" : null;
|
| + z = b ? null : "hello";
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_castsInConstantContexts() {
|
| + checkFile('''
|
| +class A {
|
| + static const num n = 3.0;
|
| + // The severe error is from constant evaluation where we know the
|
| + // concrete type.
|
| + static const int /*error:VARIABLE_TYPE_MISMATCH*/i = /*info:ASSIGNMENT_CAST*/n;
|
| + final int fi;
|
| + const A(num a) : this.fi = /*info:DOWN_CAST_IMPLICIT*/a;
|
| +}
|
| +class B extends A {
|
| + const B(Object a) : super(/*info:DOWN_CAST_IMPLICIT*/a);
|
| +}
|
| +void foo(Object o) {
|
| + var a = const A(/*info:DOWN_CAST_IMPLICIT, error:CONST_WITH_NON_CONSTANT_ARGUMENT, error:INVALID_CONSTANT*/o);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_classOverrideOfGrandInterface_interfaceOfAbstractSuperclass() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +abstract class Base implements I1 {}
|
| +
|
| +class T1 extends Base {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_classOverrideOfGrandInterface_interfaceOfConcreteSuperclass() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +
|
| +class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/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) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_classOverrideOfGrandInterface_interfaceOfInterfaceOfChild() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 implements I1 {}
|
| +
|
| +class T1 implements I2 {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_classOverrideOfGrandInterface_mixinOfInterfaceOfChild() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class M1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 extends Object with M1 {}
|
| +
|
| +class T1 implements I2 {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_classOverrideOfGrandInterface_superclassOfInterfaceOfChild() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 extends I1 {}
|
| +
|
| +class T1 implements I2 {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_compoundAssignments() {
|
| + checkFile('''
|
| +class A {
|
| + A operator *(B b) => null;
|
| + A operator /(B b) => null;
|
| + A operator ~/(B b) => null;
|
| + A operator %(B b) => null;
|
| + A operator +(B b) => null;
|
| + A operator -(B b) => null;
|
| + A operator <<(B b) => null;
|
| + A operator >>(B b) => null;
|
| + A operator &(B b) => null;
|
| + A operator ^(B b) => null;
|
| + A operator |(B b) => null;
|
| + D operator [](B index) => null;
|
| + void operator []=(B index, D value) => null;
|
| +}
|
| +
|
| +class B {
|
| + A operator -(B b) => null;
|
| +}
|
| +
|
| +class D {
|
| + D operator +(D d) => null;
|
| +}
|
| +
|
| +class SubA extends A {}
|
| +class SubSubA extends SubA {}
|
| +
|
| +foo() => new A();
|
| +
|
| +test() {
|
| + int x = 0;
|
| + x += 5;
|
| + x += /*error:INVALID_ASSIGNMENT*/3.14;
|
| +
|
| + double y = 0.0;
|
| + y += 5;
|
| + y += 3.14;
|
| +
|
| + num z = 0;
|
| + z += 5;
|
| + z += 3.14;
|
| +
|
| + x = /*info:DOWN_CAST_IMPLICIT*/x + z;
|
| + /*info:DOWN_CAST_IMPLICIT_ASSIGN*/x += z;
|
| + y = y + z;
|
| + y += z;
|
| +
|
| + dynamic w = 42;
|
| + /*info:DOWN_CAST_IMPLICIT_ASSIGN*/x += /*info:DYNAMIC_CAST*/w;
|
| + y += /*info:DYNAMIC_CAST*/w;
|
| + z += /*info:DYNAMIC_CAST*/w;
|
| +
|
| + A a = new A();
|
| + B b = new B();
|
| + var c = foo();
|
| + a = a * b;
|
| + a *= b;
|
| + a *= /*info:DYNAMIC_CAST*/c;
|
| + a /= b;
|
| + a ~/= b;
|
| + a %= b;
|
| + a += b;
|
| + a += /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/a;
|
| + a -= b;
|
| + b -= /*error:INVALID_ASSIGNMENT*/b;
|
| + a <<= b;
|
| + a >>= b;
|
| + a &= b;
|
| + a ^= b;
|
| + a |= b;
|
| + /*info:DYNAMIC_INVOKE*/c += b;
|
| +
|
| + SubA sa;
|
| + /*info:DOWN_CAST_IMPLICIT_ASSIGN*/sa += b;
|
| + SubSubA ssa = /*info:ASSIGNMENT_CAST,info:DOWN_CAST_IMPLICIT_ASSIGN*/sa += b;
|
| +
|
| + var d = new D();
|
| + a[b] += d;
|
| + a[/*info:DYNAMIC_CAST*/c] += d;
|
| + a[/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/z] += d;
|
| + a[b] += /*info:DYNAMIC_CAST*/c;
|
| + a[b] += /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/z;
|
| + /*info:DYNAMIC_INVOKE,info:DYNAMIC_INVOKE*/c[b] += d;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_constantGenericTypeArg_explict() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/26141
|
| + checkFile('''
|
| +abstract class Equality<R> {}
|
| +abstract class EqualityBase<R> implements Equality<R> {
|
| + final C<R> c = const C<R>();
|
| + const EqualityBase();
|
| +}
|
| +class DefaultEquality<S> extends EqualityBase<S> {
|
| + const DefaultEquality();
|
| +}
|
| +class SetEquality<T> implements Equality<T> {
|
| + final Equality<T> field = const DefaultEquality<T>();
|
| + const SetEquality([Equality<T> inner = const DefaultEquality<T>()]);
|
| +}
|
| +class C<Q> {
|
| + final List<Q> list = const <Q>[];
|
| + final Map<Q, Iterable<Q>> m = const <Q, Iterable<Q>>{};
|
| + const C();
|
| +}
|
| +main() {
|
| + const SetEquality<String>();
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_constantGenericTypeArg_infer() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/26141
|
| + checkFile('''
|
| +abstract class Equality<Q> {}
|
| +abstract class EqualityBase<R> implements Equality<R> {
|
| + final C<R> c = /*info:INFERRED_TYPE_ALLOCATION*/const C();
|
| + const EqualityBase();
|
| +}
|
| +class DefaultEquality<S> extends EqualityBase<S> {
|
| + const DefaultEquality();
|
| +}
|
| +class SetEquality<T> implements Equality<T> {
|
| + final Equality<T> field = const DefaultEquality();
|
| + const SetEquality([Equality<T> inner = const DefaultEquality()]);
|
| +}
|
| +class C<Q> {
|
| + final List<Q> list = /*info:INFERRED_TYPE_LITERAL*/const [];
|
| + final Map<Q, Iterable<Q>> m = /*info:INFERRED_TYPE_LITERAL*/const {};
|
| + const C();
|
| +}
|
| +main() {
|
| + const SetEquality<String>();
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_compoundAssignment_returnsDynamic() {
|
| + checkFile(r'''
|
| +class Foo {
|
| + operator +(other) => null;
|
| +}
|
| +
|
| +main() {
|
| + var foo = new Foo();
|
| + foo = /*info:DYNAMIC_CAST*/foo + 1;
|
| + /*info:DYNAMIC_CAST*/foo += 1;
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_constructorInvalid() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/26695
|
| + checkFile('''
|
| +class A {
|
| + B({ /*error:FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR*/this.test: 1.0 }) {}
|
| + final double test = 0.0;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_constructors() {
|
| + checkFile('''
|
| +const num z = 25;
|
| +Object obj = "world";
|
| +
|
| +class A {
|
| + int x;
|
| + String y;
|
| +
|
| + A(this.x) : this.y = /*error:FIELD_INITIALIZER_NOT_ASSIGNABLE*/42;
|
| +
|
| + A.c1(p): this.x = /*info:DOWN_CAST_IMPLICIT*/z, this.y = /*info:DYNAMIC_CAST*/p;
|
| +
|
| + A.c2(this.x, this.y);
|
| +
|
| + A.c3(/*error:INVALID_PARAMETER_DECLARATION*/num this.x, String this.y);
|
| +}
|
| +
|
| +class B extends A {
|
| + B() : super(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/"hello");
|
| +
|
| + B.c2(int x, String y) : super.c2(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/y,
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/x);
|
| +
|
| + B.c3(num x, Object y) : super.c3(x, /*info:DOWN_CAST_IMPLICIT*/y);
|
| +}
|
| +
|
| +void main() {
|
| + A a = new A.c2(/*info:DOWN_CAST_IMPLICIT*/z, /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/z);
|
| + var b = new B.c2(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/"hello", /*info:DOWN_CAST_IMPLICIT*/obj);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_conversionAndDynamicInvoke() {
|
| + addFile(
|
| '''
|
| - });
|
| -
|
| - 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 {}
|
| - '''
|
| - });
|
| +dynamic toString = (int x) => x + 42;
|
| +dynamic hashCode = "hello";
|
| +''',
|
| + name: '/helper.dart');
|
| + checkFile('''
|
| +import 'helper.dart' as helper;
|
| +
|
| +class A {
|
| + String x = "hello world";
|
| +
|
| + void baz1(y) { x + /*info:DYNAMIC_CAST*/y; }
|
| + static baz2(y) => /*info:DYNAMIC_INVOKE*/y + y;
|
| +}
|
| +
|
| +void foo(String str) {
|
| + print(str);
|
| +}
|
| +
|
| +class B {
|
| + String toString([int arg]) => arg.toString();
|
| +}
|
| +
|
| +void bar(a) {
|
| + foo(/*info:DYNAMIC_CAST,info:DYNAMIC_INVOKE*/a.x);
|
| +}
|
| +
|
| +baz() => new B();
|
| +
|
| +typedef DynFun(x);
|
| +typedef StrFun(String x);
|
| +
|
| +var bar1 = bar;
|
| +
|
| +void main() {
|
| + var a = new A();
|
| + bar(a);
|
| + (/*info:DYNAMIC_INVOKE*/bar1(a));
|
| + var b = bar;
|
| + (/*info:DYNAMIC_INVOKE*/b(a));
|
| + var f1 = foo;
|
| + f1("hello");
|
| + dynamic f2 = foo;
|
| + (/*info:DYNAMIC_INVOKE*/f2("hello"));
|
| + DynFun f3 = foo;
|
| + (/*info:DYNAMIC_INVOKE*/f3("hello"));
|
| + (/*info:DYNAMIC_INVOKE*/f3(42));
|
| + StrFun f4 = foo;
|
| + f4("hello");
|
| + a.baz1("hello");
|
| + var b1 = a.baz1;
|
| + (/*info:DYNAMIC_INVOKE*/b1("hello"));
|
| + A.baz2("hello");
|
| + var b2 = A.baz2;
|
| + (/*info:DYNAMIC_INVOKE*/b2("hello"));
|
| +
|
| + dynamic a1 = new B();
|
| + (/*info:DYNAMIC_INVOKE*/a1.x);
|
| + a1.toString();
|
| + (/*info:DYNAMIC_INVOKE*/a1.toString(42));
|
| + var toStringClosure = a1.toString;
|
| + (/*info:DYNAMIC_INVOKE*/a1.toStringClosure());
|
| + (/*info:DYNAMIC_INVOKE*/a1.toStringClosure(42));
|
| + (/*info:DYNAMIC_INVOKE*/a1.toStringClosure("hello"));
|
| + a1.hashCode;
|
| +
|
| + dynamic toString = () => null;
|
| + (/*info:DYNAMIC_INVOKE*/toString());
|
| +
|
| + (/*info:DYNAMIC_INVOKE*/helper.toString());
|
| + var toStringClosure2 = helper.toString;
|
| + (/*info:DYNAMIC_INVOKE*/toStringClosure2());
|
| + int hashCode = /*info:DYNAMIC_CAST*/helper.hashCode;
|
| +
|
| + baz().toString();
|
| + baz().hashCode;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_covariantOverride() {
|
| + _addMetaLibrary();
|
| + checkFile(r'''
|
| +import 'meta.dart';
|
| +class C {
|
| + num f(num x) => x;
|
| +}
|
| +class D extends C {
|
| + int f(@checked int x) => x;
|
| +}
|
| +class E extends D {
|
| + int f(Object x) => /*info:DOWN_CAST_IMPLICIT*/x;
|
| +}
|
| +class F extends E {
|
| + int f(@checked int x) => x;
|
| +}
|
| +class G extends E implements D {}
|
| +
|
| +class D_error extends C {
|
| + /*error:INVALID_METHOD_OVERRIDE*/int f(int x) => x;
|
| +}
|
| +class E_error extends D {
|
| + /*error:INVALID_METHOD_OVERRIDE*/int f(@checked double x) => 0;
|
| +}
|
| +class F_error extends E {
|
| + /*error:INVALID_METHOD_OVERRIDE*/int f(@checked double x) => 0;
|
| +}
|
| +class G_error extends E implements D {
|
| + /*error:INVALID_METHOD_OVERRIDE*/int f(@checked double x) => 0;
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_covariantOverride_fields() {
|
| + _addMetaLibrary();
|
| + checkFile(r'''
|
| +import 'meta.dart';
|
| +class A {
|
| + get foo => '';
|
| + set foo(_) {}
|
| +}
|
| +
|
| +class B extends A {
|
| + @checked num foo;
|
| +}
|
| +class C extends A {
|
| + @checked @virtual num foo;
|
| +}
|
| +class D extends C {
|
| + @virtual int foo;
|
| +}
|
| +class E extends D {
|
| + @virtual /*error:INVALID_METHOD_OVERRIDE*/num foo;
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_covariantOverride_leastUpperBound() {
|
| + _addMetaLibrary();
|
| + checkFile(r'''
|
| +import "meta.dart";
|
| +abstract class Top {}
|
| +abstract class Left implements Top {}
|
| +abstract class Right implements Top {}
|
| +abstract class Bottom implements Left, Right {}
|
| +
|
| +abstract class TakesLeft {
|
| + m(Left x);
|
| +}
|
| +abstract class TakesRight {
|
| + m(Right x);
|
| +}
|
| +abstract class TakesTop implements TakesLeft, TakesRight {
|
| + m(Top x); // works today
|
| +}
|
| +abstract class TakesBottom implements TakesLeft, TakesRight {
|
| + // LUB(Left, Right) == Top, so this is an implicit cast from Top to Bottom.
|
| + m(@checked Bottom x);
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_covariantOverride_markerIsInherited() {
|
| + _addMetaLibrary();
|
| + checkFile(r'''
|
| +import 'meta.dart';
|
| +class C {
|
| + num f(@checked num x) => x;
|
| +}
|
| +class D extends C {
|
| + int f(int x) => x;
|
| +}
|
| +class E extends D {
|
| + int f(Object x) => /*info:DOWN_CAST_IMPLICIT*/x;
|
| +}
|
| +class F extends E {
|
| + int f(int x) => x;
|
| +}
|
| +class G extends E implements D {}
|
| +
|
| +class D_error extends C {
|
| + /*error:INVALID_METHOD_OVERRIDE*/int f(String x) => 0;
|
| +}
|
| +class E_error extends D {
|
| + /*error:INVALID_METHOD_OVERRIDE*/int f(double x) => 0;
|
| +}
|
| +class F_error extends E {
|
| + /*error:INVALID_METHOD_OVERRIDE*/int f(double x) => 0;
|
| +}
|
| +class G_error extends E implements D {
|
| + /*error:INVALID_METHOD_OVERRIDE*/int f(double x) => 0;
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_dynamicInvocation() {
|
| + checkFile('''
|
| +typedef dynamic A(dynamic x);
|
| +class B {
|
| + int call(int x) => x;
|
| + double col(double x) => x;
|
| +}
|
| +void main() {
|
| + {
|
| + B f = new B();
|
| + int x;
|
| + double y;
|
| + x = f(3);
|
| + x = /*error:INVALID_ASSIGNMENT*/f.col(3.0);
|
| + y = /*error:INVALID_ASSIGNMENT*/f(3);
|
| + y = f.col(3.0);
|
| + f(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/3.0);
|
| + f.col(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/3);
|
| + }
|
| + {
|
| + Function f = new B();
|
| + int x;
|
| + double y;
|
| + x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
|
| + x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f.col(3.0);
|
| + y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
|
| + y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f.col(3.0);
|
| + /*info:DYNAMIC_INVOKE*/f(3.0);
|
| + // Through type propagation, we know f is actually a B, hence the
|
| + // hint.
|
| + /*info:DYNAMIC_INVOKE*/f.col(3);
|
| + }
|
| + {
|
| + A f = new B();
|
| + int x;
|
| + double y;
|
| + x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
|
| + y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
|
| + /*info:DYNAMIC_INVOKE*/f(3.0);
|
| + }
|
| + {
|
| + dynamic g = new B();
|
| + /*info:DYNAMIC_INVOKE*/g.call(32.0);
|
| + /*info:DYNAMIC_INVOKE*/g.col(42.0);
|
| + /*info:DYNAMIC_INVOKE*/g.foo(42.0);
|
| + /*info:DYNAMIC_INVOKE*/g.x;
|
| + A f = new B();
|
| + /*info:DYNAMIC_INVOKE*/f.col(42.0);
|
| + /*info:DYNAMIC_INVOKE*/f.foo(42.0);
|
| + /*info:DYNAMIC_INVOKE*/f./*error:UNDEFINED_GETTER*/x;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_factoryConstructorDowncast() {
|
| + checkFile(r'''
|
| +class Animal {
|
| + Animal();
|
| + factory Animal.cat() => new Cat();
|
| +}
|
| +
|
| +class Cat extends Animal {}
|
| +
|
| +void main() {
|
| + Cat c = /*info:ASSIGNMENT_CAST*/new Animal.cat();
|
| + c = /*error:STATIC_TYPE_ERROR*/new Animal();
|
| +}''');
|
| + }
|
| +
|
| + void test_fieldFieldOverride() {
|
| + checkFile('''
|
| +class A {}
|
| +class B extends A {}
|
| +class C extends B {}
|
| +
|
| +class Base {
|
| + B f1;
|
| + B f2;
|
| + B f3;
|
| + B f4;
|
| +}
|
| +
|
| +class Child extends Base {
|
| + /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/A f1; // invalid for getter
|
| + /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/C f2; // invalid for setter
|
| + /*error:INVALID_FIELD_OVERRIDE*/var f3;
|
| + /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/dynamic f4;
|
| +}
|
| +
|
| +class Child2 implements Base {
|
| + /*error:INVALID_METHOD_OVERRIDE*/A f1; // invalid for getter
|
| + /*error:INVALID_METHOD_OVERRIDE*/C f2; // invalid for setter
|
| + var f3;
|
| + /*error:INVALID_METHOD_OVERRIDE*/dynamic f4;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_fieldGetterOverride() {
|
| + checkFile('''
|
| +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 {
|
| + /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/A get f1 => null;
|
| + /*error:INVALID_FIELD_OVERRIDE*/C get f2 => null;
|
| + /*error:INVALID_FIELD_OVERRIDE*/get f3 => null;
|
| + /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
|
| +}
|
| +
|
| +class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR*/Child2 implements Base {
|
| + /*error:INVALID_METHOD_OVERRIDE*/A get f1 => null;
|
| + C get f2 => null;
|
| + get f3 => null;
|
| + /*error:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_fieldOverride_fuzzyArrows() {
|
| + checkFile('''
|
| +typedef void ToVoid<T>(T x);
|
| +class F {
|
| + final ToVoid<dynamic> f = null;
|
| + final ToVoid<int> g = null;
|
| +}
|
| +
|
| +class G extends F {
|
| + /*error:INVALID_FIELD_OVERRIDE*/final ToVoid<int> f = null;
|
| + /*error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/final ToVoid<dynamic> g = null;
|
| +}
|
| +
|
| +class H implements F {
|
| + final ToVoid<int> f = null;
|
| + /*error:INVALID_METHOD_OVERRIDE*/final ToVoid<dynamic> g = null;
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_fieldOverride_virtual() {
|
| + _addMetaLibrary();
|
| + checkFile(r'''
|
| +import 'meta.dart';
|
| +class C {
|
| + @virtual int x;
|
| +}
|
| +class OverrideGetter extends C {
|
| + int get x => 42;
|
| +}
|
| +class OverrideSetter extends C {
|
| + set x(int v) {}
|
| +}
|
| +class OverrideBoth extends C {
|
| + int get x => 42;
|
| + set x(int v) {}
|
| +}
|
| +class OverrideWithField extends C {
|
| + int x;
|
| +
|
| + // expose the hidden storage slot
|
| + int get superX => super.x;
|
| + set superX(int v) { super.x = v; }
|
| +}
|
| +class VirtualNotInherited extends OverrideWithField {
|
| + /*error:INVALID_FIELD_OVERRIDE*/int x;
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_fieldSetterOverride() {
|
| + checkFile('''
|
| +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 {
|
| + /*error:INVALID_FIELD_OVERRIDE*/B get f1 => null;
|
| + /*error:INVALID_FIELD_OVERRIDE*/B get f2 => null;
|
| + /*error:INVALID_FIELD_OVERRIDE*/B get f3 => null;
|
| + /*error:INVALID_FIELD_OVERRIDE*/B get f4 => null;
|
| + /*error:INVALID_FIELD_OVERRIDE*/B get f5 => null;
|
| +
|
| + /*error:INVALID_FIELD_OVERRIDE*/void set f1(A value) {}
|
| + /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
|
| + /*error:INVALID_FIELD_OVERRIDE*/void set f3(value) {}
|
| + /*error:INVALID_FIELD_OVERRIDE*/void set f4(dynamic value) {}
|
| + /*error:INVALID_FIELD_OVERRIDE*/set f5(B value) {}
|
| +}
|
| +
|
| +class Child2 implements 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) {}
|
| + /*error:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
|
| + void set f3(value) {}
|
| + void set f4(dynamic value) {}
|
| + set f5(B value) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_forInCastsIterateElementToVariable() {
|
| + checkFile('''
|
| +main() {
|
| + // Don't choke if sequence is not iterable.
|
| + for (var i in /*error:FOR_IN_OF_INVALID_TYPE*/1234) {}
|
| +
|
| + // Dynamic cast.
|
| + for (String /*info:DYNAMIC_CAST*/s in <dynamic>[]) {}
|
| +
|
| + // Identity cast.
|
| + for (String s in <String>[]) {}
|
| +
|
| + // Untyped.
|
| + for (var s in <String>[]) {}
|
| +
|
| + // Downcast.
|
| + for (int /*info:DOWN_CAST_IMPLICIT*/i in <num>[]) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_forInCastsSupertypeSequenceToIterate() {
|
| + checkFile('''
|
| +main() {
|
| + dynamic d;
|
| + for (var i in /*info:DYNAMIC_CAST*/d) {}
|
| +
|
| + Object o;
|
| + for (var i in /*info:DOWN_CAST_IMPLICIT*/o) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_forLoopVariable() {
|
| + checkFile('''
|
| +foo() {
|
| + for (int i = 0; i < 10; i++) {
|
| + i = /*error:INVALID_ASSIGNMENT*/"hi";
|
| + }
|
| +}
|
| +bar() {
|
| + for (var i = 0; i < 10; i++) {
|
| + int j = i + 1;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionModifiers_async() {
|
| + checkFile('''
|
| +import 'dart:async';
|
| +import 'dart:math' show Random;
|
| +
|
| +dynamic x;
|
| +
|
| +foo1() async => x;
|
| +Future foo2() async => x;
|
| +Future<int> foo3() async => x;
|
| +Future<int> foo4() async => new Future<int>.value(/*info:DYNAMIC_CAST*/x);
|
| +Future<int> foo5() async =>
|
| + /*error:RETURN_OF_INVALID_TYPE*/new Future<String>.value(/*info:DYNAMIC_CAST*/x);
|
| +
|
| +bar1() async { return x; }
|
| +Future bar2() async { return x; }
|
| +Future<int> bar3() async { return x; }
|
| +Future<int> bar4() async { return new Future<int>.value(/*info:DYNAMIC_CAST*/x); }
|
| +Future<int> bar5() async {
|
| + return /*error:RETURN_OF_INVALID_TYPE*/new Future<String>.value(/*info:DYNAMIC_CAST*/x);
|
| +}
|
| +
|
| +int y;
|
| +Future<int> z;
|
| +
|
| +baz() async {
|
| + int a = /*info:DYNAMIC_CAST*/await x;
|
| + int b = await y;
|
| + int c = await z;
|
| + String d = /*error:INVALID_ASSIGNMENT*/await z;
|
| +}
|
| +
|
| +Future<bool> get issue_ddc_264 async {
|
| + await 42;
|
| + if (new Random().nextBool()) {
|
| + return true;
|
| + } else {
|
| + return new Future<bool>.value(false);
|
| + }
|
| +}
|
| +
|
| +
|
| +Future<String> issue_sdk_26404() async {
|
| + return (1 > 0) ? new Future<String>.value('hello') : "world";
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionModifiers_asyncStar() {
|
| + checkFile('''
|
| +import 'dart:async';
|
| +
|
| +dynamic x;
|
| +
|
| +bar1() async* { yield x; }
|
| +Stream bar2() async* { yield x; }
|
| +Stream<int> bar3() async* { yield /*info:DYNAMIC_CAST*/x; }
|
| +Stream<int> bar4() async* { yield /*error:YIELD_OF_INVALID_TYPE*/new Stream<int>(); }
|
| +
|
| +baz1() async* { yield* /*info:DYNAMIC_CAST*/x; }
|
| +Stream baz2() async* { yield* /*info:DYNAMIC_CAST*/x; }
|
| +Stream<int> baz3() async* { yield* /*warning:DOWN_CAST_COMPOSITE*/x; }
|
| +Stream<int> baz4() async* { yield* new Stream<int>(); }
|
| +Stream<int> baz5() async* { yield* /*info:INFERRED_TYPE_ALLOCATION*/new Stream(); }
|
| +''');
|
| + }
|
| +
|
| + void test_functionModifiers_syncStar() {
|
| + checkFile('''
|
| +dynamic x;
|
| +
|
| +bar1() sync* { yield x; }
|
| +Iterable bar2() sync* { yield x; }
|
| +Iterable<int> bar3() sync* { yield /*info:DYNAMIC_CAST*/x; }
|
| +Iterable<int> bar4() sync* { yield /*error:YIELD_OF_INVALID_TYPE*/bar3(); }
|
| +
|
| +baz1() sync* { yield* /*info:DYNAMIC_CAST*/x; }
|
| +Iterable baz2() sync* { yield* /*info:DYNAMIC_CAST*/x; }
|
| +Iterable<int> baz3() sync* { yield* /*warning:DOWN_CAST_COMPOSITE*/x; }
|
| +Iterable<int> baz4() sync* { yield* bar3(); }
|
| +Iterable<int> baz5() sync* { yield* /*info:INFERRED_TYPE_ALLOCATION*/new List(); }
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_classes() {
|
| + checkFile('''
|
| +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:DOWN_CAST_IMPLICIT*/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 = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = left;
|
| + f = /*error:INVALID_ASSIGNMENT*/right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Right f;
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:INVALID_ASSIGNMENT*/left;
|
| + f = right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Bot f;
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:STATIC_TYPE_ERROR*/left;
|
| + f = /*error:STATIC_TYPE_ERROR*/right;
|
| + f = bot;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_dynamic() {
|
| + checkFile('''
|
| +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
|
| +
|
| +void main() {
|
| + Top top;
|
| + Left left;
|
| + Right right;
|
| + Bottom bot;
|
| + {
|
| + Top f;
|
| + f = top;
|
| + f = left;
|
| + f = right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Left f;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/top;
|
| + f = left;
|
| + f = /*error:INVALID_ASSIGNMENT*/right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Right f;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/top;
|
| + f = /*error:INVALID_ASSIGNMENT*/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 = bot;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_dynamic_knownFunctions() {
|
| + // Our lattice should look like this:
|
| + //
|
| + //
|
| + // Bot -> Top
|
| + // / \
|
| + // A -> Top Bot -> A
|
| + // / \ /
|
| + // Top -> Top A -> A
|
| + // \ /
|
| + // Top -> A
|
| + //
|
| + // Note that downcasts of known functions are promoted to
|
| + // static type errors, since they cannot succeed.
|
| + // This makes some of what look like downcasts turn into
|
| + // type errors below.
|
| + checkFile('''
|
| +class A {}
|
| +
|
| +typedef dynamic BotTop(dynamic x);
|
| +typedef dynamic ATop(A x);
|
| +typedef A BotA(dynamic x);
|
| +typedef A AA(A x);
|
| +typedef A TopA(Object x);
|
| +typedef dynamic TopTop(Object x);
|
| +
|
| +dynamic aTop(A x) => x;
|
| +A aa(A x) => x;
|
| +dynamic topTop(dynamic x) => x;
|
| +A topA(dynamic x) => /*info:DYNAMIC_CAST*/x;
|
| +void apply/*<T>*/(/*=T*/ f0, /*=T*/ f1, /*=T*/ f2,
|
| + /*=T*/ f3, /*=T*/ f4, /*=T*/ f5) {}
|
| +void main() {
|
| + BotTop botTop;
|
| + BotA botA;
|
| + {
|
| + BotTop f;
|
| + f = topA;
|
| + f = topTop;
|
| + f = aa;
|
| + f = aTop;
|
| + f = botA;
|
| + f = botTop;
|
| + apply/*<BotTop>*/(
|
| + topA,
|
| + topTop,
|
| + aa,
|
| + aTop,
|
| + botA,
|
| + botTop
|
| + );
|
| + apply/*<BotTop>*/(
|
| + (dynamic x) => new A(),
|
| + (dynamic x) => (x as Object),
|
| + (A x) => x,
|
| + (A x) => null,
|
| + botA,
|
| + botTop
|
| + );
|
| + }
|
| + {
|
| + ATop f;
|
| + f = topA;
|
| + f = topTop;
|
| + f = aa;
|
| + f = aTop;
|
| + f = /*error:INVALID_ASSIGNMENT*/botA;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/botTop;
|
| + apply/*<ATop>*/(
|
| + topA,
|
| + topTop,
|
| + aa,
|
| + aTop,
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + apply/*<ATop>*/(
|
| + (dynamic x) => new A(),
|
| + (dynamic x) => (x as Object),
|
| + (A x) => x,
|
| + (A x) => null,
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + }
|
| + {
|
| + BotA f;
|
| + f = topA;
|
| + f = /*error:INVALID_ASSIGNMENT*/topTop;
|
| + f = aa;
|
| + f = /*error:INVALID_ASSIGNMENT*/aTop;
|
| + f = botA;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/botTop;
|
| + apply/*<BotA>*/(
|
| + topA,
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/topTop,
|
| + aa,
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/aTop,
|
| + botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + apply/*<BotA>*/(
|
| + (dynamic x) => new A(),
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(dynamic x) => (x as Object),
|
| + (A x) => x,
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(A x) => (/*info:UNNECESSARY_CAST*/x as Object),
|
| + botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + }
|
| + {
|
| + AA f;
|
| + f = topA;
|
| + f = /*error:INVALID_ASSIGNMENT*/topTop;
|
| + f = aa;
|
| + f = /*error:STATIC_TYPE_ERROR*/aTop; // known function
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/botA;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/botTop;
|
| + apply/*<AA>*/(
|
| + topA,
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/topTop,
|
| + aa,
|
| + /*error:STATIC_TYPE_ERROR*/aTop, // known function
|
| + /*warning:DOWN_CAST_COMPOSITE*/botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + apply/*<AA>*/(
|
| + (dynamic x) => new A(),
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(dynamic x) => (x as Object),
|
| + (A x) => x,
|
| + /*error:STATIC_TYPE_ERROR*/(A x) => (/*info:UNNECESSARY_CAST*/x as Object), // known function
|
| + /*warning:DOWN_CAST_COMPOSITE*/botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + }
|
| + {
|
| + TopTop f;
|
| + f = topA;
|
| + f = topTop;
|
| + f = /*error:INVALID_ASSIGNMENT*/aa;
|
| + f = /*error:STATIC_TYPE_ERROR*/aTop; // known function
|
| + f = /*error:INVALID_ASSIGNMENT*/botA;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/botTop;
|
| + apply/*<TopTop>*/(
|
| + topA,
|
| + topTop,
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/aa,
|
| + /*error:STATIC_TYPE_ERROR*/aTop, // known function
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + apply/*<TopTop>*/(
|
| + (dynamic x) => new A(),
|
| + (dynamic x) => (x as Object),
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(A x) => x,
|
| + /*error:STATIC_TYPE_ERROR*/(A x) => (/*info:UNNECESSARY_CAST*/x as Object), // known function
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + }
|
| + {
|
| + TopA f;
|
| + f = topA;
|
| + f = /*error:STATIC_TYPE_ERROR*/topTop; // known function
|
| + f = /*error:STATIC_TYPE_ERROR*/aa; // known function
|
| + f = /*error:STATIC_TYPE_ERROR*/aTop; // known function
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/botA;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/botTop;
|
| + apply/*<TopA>*/(
|
| + topA,
|
| + /*error:STATIC_TYPE_ERROR*/topTop, // known function
|
| + /*error:STATIC_TYPE_ERROR*/aa, // known function
|
| + /*error:STATIC_TYPE_ERROR*/aTop, // known function
|
| + /*warning:DOWN_CAST_COMPOSITE*/botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + apply/*<TopA>*/(
|
| + (dynamic x) => new A(),
|
| + /*error:STATIC_TYPE_ERROR*/(dynamic x) => (x as Object), // known function
|
| + /*error:STATIC_TYPE_ERROR*/(A x) => x, // known function
|
| + /*error:STATIC_TYPE_ERROR*/(A x) => (/*info:UNNECESSARY_CAST*/x as Object), // known function
|
| + /*warning:DOWN_CAST_COMPOSITE*/botA,
|
| + /*warning:DOWN_CAST_COMPOSITE*/botTop
|
| + );
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_dynamicFunctions_clasuresAreNotFuzzy() {
|
| + // Regression test for
|
| + // https://github.com/dart-lang/sdk/issues/26118
|
| + // https://github.com/dart-lang/sdk/issues/26156
|
| + checkFile('''
|
| +void takesF(void f(int x)) {}
|
| +
|
| +typedef void TakesInt(int x);
|
| +
|
| +void update(_) {}
|
| +void updateOpt([_]) {}
|
| +void updateOptNum([num x]) {}
|
| +
|
| +class A {
|
| + TakesInt f;
|
| + A(TakesInt g) {
|
| + f = update;
|
| + f = updateOpt;
|
| + f = updateOptNum;
|
| + }
|
| + TakesInt g(bool a, bool b) {
|
| + if (a) {
|
| + return update;
|
| + } else if (b) {
|
| + return updateOpt;
|
| + } else {
|
| + return updateOptNum;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void test0() {
|
| + takesF(update);
|
| + takesF(updateOpt);
|
| + takesF(updateOptNum);
|
| + TakesInt f;
|
| + f = update;
|
| + f = updateOpt;
|
| + f = updateOptNum;
|
| + new A(update);
|
| + new A(updateOpt);
|
| + new A(updateOptNum);
|
| +}
|
| +
|
| +void test1() {
|
| + void takesF(f(int x)) => null;
|
| + takesF((dynamic y) => 3);
|
| +}
|
| +
|
| +void test2() {
|
| + int x;
|
| + int f/*<T>*/(/*=T*/ t, callback(/*=T*/ x)) { return 3; }
|
| + f(x, (y) => 3);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_functionLiteralVariance() {
|
| + checkFile('''
|
| +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; // left
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = left;
|
| + f = /*error:INVALID_ASSIGNMENT*/right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Function2<A, A> f; // right
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:INVALID_ASSIGNMENT*/left;
|
| + f = right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Function2<A, B> f;
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:STATIC_TYPE_ERROR*/left;
|
| + f = /*error:STATIC_TYPE_ERROR*/right;
|
| + f = bot;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_functionVariableVariance() {
|
| + checkFile('''
|
| +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:DOWN_CAST_COMPOSITE*/top;
|
| + left = left;
|
| + left = /*error:INVALID_ASSIGNMENT*/right;
|
| + left = bot;
|
| +
|
| + right = /*warning:DOWN_CAST_COMPOSITE*/top;
|
| + right = /*error:INVALID_ASSIGNMENT*/left;
|
| + right = right;
|
| + right = bot;
|
| +
|
| + bot = /*warning:DOWN_CAST_COMPOSITE*/top;
|
| + bot = /*warning:DOWN_CAST_COMPOSITE*/left;
|
| + bot = /*warning:DOWN_CAST_COMPOSITE*/right;
|
| + bot = bot;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_higherOrderFunctionLiteral1() {
|
| + checkFile('''
|
| +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:DOWN_CAST_COMPOSITE*/f;
|
| +AToB bot(BToA 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 = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = left;
|
| + f = /*error:INVALID_ASSIGNMENT*/right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Function2<BToA, BToA> f; // Right
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:INVALID_ASSIGNMENT*/left;
|
| + f = right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Function2<BToA, AToB> f; // Bot
|
| + f = bot;
|
| + f = /*error:STATIC_TYPE_ERROR*/left;
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:STATIC_TYPE_ERROR*/right;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_higherOrderFunctionLiteral2() {
|
| + checkFile('''
|
| +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 = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = left;
|
| + f = /*error:INVALID_ASSIGNMENT*/right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Function2<BToA, BToA> f; // Right
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:INVALID_ASSIGNMENT*/left;
|
| + f = right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Function2<BToA, AToB> f; // Bot
|
| + f = bot;
|
| + f = /*error:STATIC_TYPE_ERROR*/left;
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:STATIC_TYPE_ERROR*/right;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_higherOrderFunctionLiteral3() {
|
| + checkFile('''
|
| +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;
|
| +BToA right(Function2<B, A> f) => f;
|
| +AToB bot_(Function2<B, A> f) => /*warning:DOWN_CAST_COMPOSITE*/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 = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = left;
|
| + f = /*error:INVALID_ASSIGNMENT*/right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Function2<BToA, BToA> f; // Right
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:INVALID_ASSIGNMENT*/left;
|
| + f = right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Function2<BToA, AToB> f; // Bot
|
| + f = bot;
|
| + f = /*error:STATIC_TYPE_ERROR*/left;
|
| + f = /*error:STATIC_TYPE_ERROR*/top;
|
| + f = /*error:STATIC_TYPE_ERROR*/right;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_higherOrderFunctionVariables() {
|
| + checkFile('''
|
| +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:DOWN_CAST_COMPOSITE*/top;
|
| + left = left;
|
| + left =
|
| + /*error:INVALID_ASSIGNMENT*/right;
|
| + left = bot;
|
| +
|
| + right = /*warning:DOWN_CAST_COMPOSITE*/top;
|
| + right =
|
| + /*error:INVALID_ASSIGNMENT*/left;
|
| + right = right;
|
| + right = bot;
|
| +
|
| + bot = /*warning:DOWN_CAST_COMPOSITE*/top;
|
| + bot = /*warning:DOWN_CAST_COMPOSITE*/left;
|
| + bot = /*warning:DOWN_CAST_COMPOSITE*/right;
|
| + bot = bot;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_instanceMethodVariance() {
|
| + checkFile('''
|
| +class A {}
|
| +class B extends A {}
|
| +
|
| +class C {
|
| + A top(B x) => x;
|
| + B left(B x) => x;
|
| + A right(A x) => x;
|
| + B bot(A x) => x as B;
|
| +}
|
| +
|
| +typedef T Function2<S, T>(S z);
|
| +
|
| +void main() {
|
| + C c = new C();
|
| + {
|
| + Function2<B, A> f;
|
| + f = c.top;
|
| + f = c.left;
|
| + f = c.right;
|
| + f = c.bot;
|
| + }
|
| + {
|
| + Function2<B, B> f;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/c.top;
|
| + f = c.left;
|
| + f = /*error:INVALID_ASSIGNMENT*/c.right;
|
| + f = c.bot;
|
| + }
|
| + {
|
| + Function2<A, A> f;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/c.top;
|
| + f = /*error:INVALID_ASSIGNMENT*/c.left;
|
| + f = c.right;
|
| + f = c.bot;
|
| + }
|
| + {
|
| + Function2<A, B> f;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/c.top;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/c.left;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/c.right;
|
| + f = c.bot;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_intAndObject() {
|
| + checkFile('''
|
| +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 globalTop(int x) => x;
|
| +int globalLeft(int x) => x;
|
| +Object globalRight(Object x) => x;
|
| +int bot_(Object x) => /*info:DOWN_CAST_IMPLICIT*/x;
|
| +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;
|
| +
|
| + { // Check typedef equality
|
| + Left f = left;
|
| + Left2 g = f;
|
| + }
|
| + {
|
| + Top f;
|
| + f = top;
|
| + f = left;
|
| + f = right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Left f;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/top;
|
| + f = left;
|
| + f = /*error:INVALID_ASSIGNMENT*/right;
|
| + f = bot;
|
| + }
|
| + {
|
| + Right f;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/top;
|
| + f = /*error:INVALID_ASSIGNMENT*/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 = bot;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_namedAndOptionalParameters() {
|
| + checkFile('''
|
| +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 = /*error:INVALID_ASSIGNMENT*/n;
|
| + r = /*error:INVALID_ASSIGNMENT*/rr;
|
| + r = ro;
|
| + r = rn;
|
| + r = oo;
|
| + r = /*error:INVALID_ASSIGNMENT*/nn;
|
| + r = /*error:INVALID_ASSIGNMENT*/nnn;
|
| +
|
| + o = /*warning:DOWN_CAST_COMPOSITE*/r;
|
| + o = o;
|
| + o = /*error:INVALID_ASSIGNMENT*/n;
|
| + o = /*error:INVALID_ASSIGNMENT*/rr;
|
| + o = /*error:INVALID_ASSIGNMENT*/ro;
|
| + o = /*error:INVALID_ASSIGNMENT*/rn;
|
| + o = oo;
|
| + o = /*error:INVALID_ASSIGNMENT*/nn;
|
| + o = /*error:INVALID_ASSIGNMENT*/nnn;
|
| +
|
| + n = /*error:INVALID_ASSIGNMENT*/r;
|
| + n = /*error:INVALID_ASSIGNMENT*/o;
|
| + n = n;
|
| + n = /*error:INVALID_ASSIGNMENT*/rr;
|
| + n = /*error:INVALID_ASSIGNMENT*/ro;
|
| + n = /*error:INVALID_ASSIGNMENT*/rn;
|
| + n = /*error:INVALID_ASSIGNMENT*/oo;
|
| + n = nn;
|
| + n = nnn;
|
| +
|
| + rr = /*error:INVALID_ASSIGNMENT*/r;
|
| + rr = /*error:INVALID_ASSIGNMENT*/o;
|
| + rr = /*error:INVALID_ASSIGNMENT*/n;
|
| + rr = rr;
|
| + rr = ro;
|
| + rr = /*error:INVALID_ASSIGNMENT*/rn;
|
| + rr = oo;
|
| + rr = /*error:INVALID_ASSIGNMENT*/nn;
|
| + rr = /*error:INVALID_ASSIGNMENT*/nnn;
|
| +
|
| + ro = /*warning:DOWN_CAST_COMPOSITE*/r;
|
| + ro = /*error:INVALID_ASSIGNMENT*/o;
|
| + ro = /*error:INVALID_ASSIGNMENT*/n;
|
| + ro = /*warning:DOWN_CAST_COMPOSITE*/rr;
|
| + ro = ro;
|
| + ro = /*error:INVALID_ASSIGNMENT*/rn;
|
| + ro = oo;
|
| + ro = /*error:INVALID_ASSIGNMENT*/nn;
|
| + ro = /*error:INVALID_ASSIGNMENT*/nnn;
|
| +
|
| + rn = /*warning:DOWN_CAST_COMPOSITE*/r;
|
| + rn = /*error:INVALID_ASSIGNMENT*/o;
|
| + rn = /*error:INVALID_ASSIGNMENT*/n;
|
| + rn = /*error:INVALID_ASSIGNMENT*/rr;
|
| + rn = /*error:INVALID_ASSIGNMENT*/ro;
|
| + rn = rn;
|
| + rn = /*error:INVALID_ASSIGNMENT*/oo;
|
| + rn = /*error:INVALID_ASSIGNMENT*/nn;
|
| + rn = /*error:INVALID_ASSIGNMENT*/nnn;
|
| +
|
| + oo = /*warning:DOWN_CAST_COMPOSITE*/r;
|
| + oo = /*warning:DOWN_CAST_COMPOSITE*/o;
|
| + oo = /*error:INVALID_ASSIGNMENT*/n;
|
| + oo = /*warning:DOWN_CAST_COMPOSITE*/rr;
|
| + oo = /*warning:DOWN_CAST_COMPOSITE*/ro;
|
| + oo = /*error:INVALID_ASSIGNMENT*/rn;
|
| + oo = oo;
|
| + oo = /*error:INVALID_ASSIGNMENT*/nn;
|
| + oo = /*error:INVALID_ASSIGNMENT*/nnn;
|
| +
|
| + nn = /*error:INVALID_ASSIGNMENT*/r;
|
| + nn = /*error:INVALID_ASSIGNMENT*/o;
|
| + nn = /*warning:DOWN_CAST_COMPOSITE*/n;
|
| + nn = /*error:INVALID_ASSIGNMENT*/rr;
|
| + nn = /*error:INVALID_ASSIGNMENT*/ro;
|
| + nn = /*error:INVALID_ASSIGNMENT*/rn;
|
| + nn = /*error:INVALID_ASSIGNMENT*/oo;
|
| + nn = nn;
|
| + nn = nnn;
|
| +
|
| + nnn = /*error:INVALID_ASSIGNMENT*/r;
|
| + nnn = /*error:INVALID_ASSIGNMENT*/o;
|
| + nnn = /*warning:DOWN_CAST_COMPOSITE*/n;
|
| + nnn = /*error:INVALID_ASSIGNMENT*/rr;
|
| + nnn = /*error:INVALID_ASSIGNMENT*/ro;
|
| + nnn = /*error:INVALID_ASSIGNMENT*/rn;
|
| + nnn = /*error:INVALID_ASSIGNMENT*/oo;
|
| + nnn = /*warning:DOWN_CAST_COMPOSITE*/nn;
|
| + nnn = nnn;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_objectsWithCallMethods() {
|
| + checkFile('''
|
| +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 = /*error:INVALID_ASSIGNMENT*/new B();
|
| + f = i2i;
|
| + f = /*error:INVALID_ASSIGNMENT*/n2n;
|
| + f = /*info:UNNECESSARY_CAST,warning:DOWN_CAST_COMPOSITE*/i2i as Object;
|
| + f = /*info:UNNECESSARY_CAST,warning:DOWN_CAST_COMPOSITE*/n2n as Function;
|
| + }
|
| + {
|
| + N2N f;
|
| + f = /*error:INVALID_ASSIGNMENT*/new A();
|
| + f = new B();
|
| + f = /*error:INVALID_ASSIGNMENT*/i2i;
|
| + f = n2n;
|
| + f = /*info:UNNECESSARY_CAST,warning:DOWN_CAST_COMPOSITE*/i2i as Object;
|
| + f = /*info:UNNECESSARY_CAST,warning:DOWN_CAST_COMPOSITE*/n2n as Function;
|
| + }
|
| + {
|
| + A f;
|
| + f = new A();
|
| + f = /*error:INVALID_ASSIGNMENT*/new B();
|
| + f = /*error:INVALID_ASSIGNMENT*/i2i;
|
| + f = /*error:INVALID_ASSIGNMENT*/n2n;
|
| + f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/i2i as Object;
|
| + f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/n2n as Function;
|
| + }
|
| + {
|
| + B f;
|
| + f = /*error:INVALID_ASSIGNMENT*/new A();
|
| + f = new B();
|
| + f = /*error:INVALID_ASSIGNMENT*/i2i;
|
| + f = /*error:INVALID_ASSIGNMENT*/n2n;
|
| + f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/i2i as Object;
|
| + f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/n2n as Function;
|
| + }
|
| + {
|
| + Function f;
|
| + f = new A();
|
| + f = new B();
|
| + f = i2i;
|
| + f = n2n;
|
| + f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/i2i as Object;
|
| + f = /*info:UNNECESSARY_CAST*/n2n as Function;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_staticMethodVariance() {
|
| + checkFile('''
|
| +class A {}
|
| +class B extends A {}
|
| +
|
| +class C {
|
| + static A top(B x) => x;
|
| + static B left(B x) => x;
|
| + static A right(A x) => x;
|
| + static B bot(A x) => x as B;
|
| +}
|
| +
|
| +typedef T Function2<S, T>(S z);
|
| +
|
| +void main() {
|
| + {
|
| + Function2<B, A> f;
|
| + f = C.top;
|
| + f = C.left;
|
| + f = C.right;
|
| + f = C.bot;
|
| + }
|
| + {
|
| + Function2<B, B> f;
|
| + f = /*error:STATIC_TYPE_ERROR*/C.top;
|
| + f = C.left;
|
| + f = /*error:INVALID_ASSIGNMENT*/C.right;
|
| + f = C.bot;
|
| + }
|
| + {
|
| + Function2<A, A> f;
|
| + f = /*error:STATIC_TYPE_ERROR*/C.top;
|
| + f = /*error:INVALID_ASSIGNMENT*/C.left;
|
| + f = C.right;
|
| + f = C.bot;
|
| + }
|
| + {
|
| + Function2<A, B> f;
|
| + f = /*error:STATIC_TYPE_ERROR*/C.top;
|
| + f = /*error:STATIC_TYPE_ERROR*/C.left;
|
| + f = /*error:STATIC_TYPE_ERROR*/C.right;
|
| + f = C.bot;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_subtypeOfUniversalType() {
|
| + checkFile('''
|
| +void main() {
|
| + nonGenericFn(x) => null;
|
| + {
|
| + /*=R*/ f/*<P, R>*/(/*=P*/ p) => null;
|
| + /*=T*/ g/*<S, T>*/(/*=S*/ s) => null;
|
| +
|
| + var local = f;
|
| + local = g; // valid
|
| +
|
| + // Non-generic function cannot subtype a generic one.
|
| + local = /*error:INVALID_ASSIGNMENT*/(x) => null;
|
| + local = /*error:INVALID_ASSIGNMENT*/nonGenericFn;
|
| + }
|
| + {
|
| + Iterable/*<R>*/ f/*<P, R>*/(List/*<P>*/ p) => null;
|
| + List/*<T>*/ g/*<S, T>*/(Iterable/*<S>*/ s) => null;
|
| +
|
| + var local = f;
|
| + local = g; // valid
|
| +
|
| + var local2 = g;
|
| + local = local2;
|
| + local2 = /*error:STATIC_TYPE_ERROR*/f;
|
| + local2 = /*warning:DOWN_CAST_COMPOSITE*/local;
|
| +
|
| + // Non-generic function cannot subtype a generic one.
|
| + local = /*error:INVALID_ASSIGNMENT*/(x) => null;
|
| + local = /*error:INVALID_ASSIGNMENT*/nonGenericFn;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_uninferredClosure() {
|
| + checkFile('''
|
| +typedef num Num2Num(num x);
|
| +void main() {
|
| + Num2Num g = /*info:INFERRED_TYPE_CLOSURE,error:INVALID_ASSIGNMENT*/(int x) { return x; };
|
| + print(g(42));
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_functionTypingAndSubtyping_void() {
|
| + checkFile('''
|
| +class A {
|
| + void bar() => null;
|
| + void foo() => bar(); // allowed
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_genericClassMethodOverride() {
|
| + checkFile('''
|
| +class A {}
|
| +class B extends A {}
|
| +
|
| +class Base<T extends B> {
|
| + T foo() => null;
|
| +}
|
| +
|
| +class Derived<S extends A> extends Base<B> {
|
| + /*error:INVALID_METHOD_OVERRIDE*/S foo() => null;
|
| +}
|
| +
|
| +class Derived2<S extends B> extends Base<B> {
|
| + S foo() => null;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_genericFunctionWrongNumberOfArguments() {
|
| + checkFile(r'''
|
| +/*=T*/ foo/*<T>*/(/*=T*/ x, /*=T*/ y) => x;
|
| +/*=T*/ bar/*<T>*/({/*=T*/ x, /*=T*/ y}) => x;
|
| +
|
| +main() {
|
| + String x;
|
| + // resolving these shouldn't crash.
|
| + foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/(1, 2, 3);
|
| + x = foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/('1', '2', '3');
|
| + foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(1);
|
| + x = foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/('1');
|
| + x = /*error:COULD_NOT_INFER*/foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/1, /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/2, 3);
|
| + x = /*error:COULD_NOT_INFER*/foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/1);
|
| +
|
| + // named arguments
|
| + bar(y: 1, x: 2, /*error:UNDEFINED_NAMED_PARAMETER*/z: 3);
|
| + x = bar(/*error:UNDEFINED_NAMED_PARAMETER*/z: '1', x: '2', y: '3');
|
| + bar(y: 1);
|
| + x = bar(x: '1', /*error:UNDEFINED_NAMED_PARAMETER*/z: 42);
|
| + x = /*error:COULD_NOT_INFER*/bar(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/y: 1, /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/x: 2, /*error:UNDEFINED_NAMED_PARAMETER*/z: 3);
|
| + x = /*error:COULD_NOT_INFER*/bar(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/x: 1);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_genericMethodOverride() {
|
| + checkFile('''
|
| +class Future<T> {
|
| + /*=S*/ then/*<S>*/(/*=S*/ onValue(T t)) => null;
|
| +}
|
| +
|
| +class DerivedFuture<T> extends Future<T> {
|
| + /*=S*/ then/*<S>*/(/*=S*/ onValue(T t)) => null;
|
| +}
|
| +
|
| +class DerivedFuture2<A> extends Future<A> {
|
| + /*=B*/ then/*<B>*/(/*=B*/ onValue(A a)) => null;
|
| +}
|
| +
|
| +class DerivedFuture3<T> extends Future<T> {
|
| + /*=S*/ then/*<S>*/(Object onValue(T t)) => null;
|
| +}
|
| +
|
| +class DerivedFuture4<A> extends Future<A> {
|
| + /*=B*/ then/*<B>*/(Object onValue(A a)) => null;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_getterGetterOverride() {
|
| + checkFile('''
|
| +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 {
|
| + /*error:INVALID_METHOD_OVERRIDE*/A get f1 => null;
|
| + C get f2 => null;
|
| + get f3 => null;
|
| + /*error:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_getterOverride_fuzzyArrows() {
|
| + checkFile('''
|
| +typedef void ToVoid<T>(T x);
|
| +
|
| +class F {
|
| + ToVoid<dynamic> get f => null;
|
| + ToVoid<int> get g => null;
|
| +}
|
| +
|
| +class G extends F {
|
| + ToVoid<int> get f => null;
|
| + /*error:INVALID_METHOD_OVERRIDE*/ToVoid<dynamic> get g => null;
|
| +}
|
| +
|
| +class H implements F {
|
| + ToVoid<int> get f => null;
|
| + /*error:INVALID_METHOD_OVERRIDE*/ToVoid<dynamic> get g => null;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_ifForDoWhileStatementsUseBooleanConversion() {
|
| + checkFile('''
|
| +main() {
|
| + dynamic dyn = 42;
|
| + Object obj = 42;
|
| + int i = 42;
|
| + bool b = false;
|
| +
|
| + if (b) {}
|
| + if (/*info:DYNAMIC_CAST*/dyn) {}
|
| + if (/*info:DOWN_CAST_IMPLICIT*/obj) {}
|
| + if (/*error:NON_BOOL_CONDITION*/i) {}
|
| +
|
| + while (b) {}
|
| + while (/*info:DYNAMIC_CAST*/dyn) {}
|
| + while (/*info:DOWN_CAST_IMPLICIT*/obj) {}
|
| + while (/*error:NON_BOOL_CONDITION*/i) {}
|
| +
|
| + do {} while (b);
|
| + do {} while (/*info:DYNAMIC_CAST*/dyn);
|
| + do {} while (/*info:DOWN_CAST_IMPLICIT*/obj);
|
| + do {} while (/*error:NON_BOOL_CONDITION*/i);
|
| +
|
| + for (;b;) {}
|
| + for (;/*info:DYNAMIC_CAST*/dyn;) {}
|
| + for (;/*info:DOWN_CAST_IMPLICIT*/obj;) {}
|
| + for (;/*error:NON_BOOL_CONDITION*/i;) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_implicitCasts() {
|
| + addFile('num n; int i = /*info:ASSIGNMENT_CAST*/n;');
|
| + check();
|
| + // TODO(jmesserly): should not be emitting the hint as well as the error.
|
| + // It is a "strong mode hint" however, so it will not be user visible.
|
| + addFile(
|
| + 'num n; int i = /*info:ASSIGNMENT_CAST,error:INVALID_ASSIGNMENT*/n;');
|
| + check(implicitCasts: false);
|
| + }
|
| +
|
| + void test_implicitCasts_genericMethods() {
|
| + addFile('var x = <String>[].map((x) => "");');
|
| + check(implicitCasts: false);
|
| + }
|
| +
|
| + void test_implicitCasts_numericOps() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/26912
|
| + addFile(r'''
|
| +void f() {
|
| + int x = 0;
|
| + int y = 0;
|
| + x += y;
|
| +}
|
| + ''');
|
| + check(implicitCasts: false);
|
| + }
|
| +
|
| + void test_implicitDynamic_field() {
|
| + addFile(r'''
|
| +class C {
|
| + var /*error:IMPLICIT_DYNAMIC_FIELD*/x0;
|
| + var /*error:IMPLICIT_DYNAMIC_FIELD*/x1 = (<dynamic>[])[0];
|
| + var /*error:IMPLICIT_DYNAMIC_FIELD*/x2,
|
| + x3 = 42,
|
| + /*error:IMPLICIT_DYNAMIC_FIELD*/x4;
|
| + dynamic y0;
|
| + dynamic y1 = (<dynamic>[])[0];
|
| +}
|
| + ''');
|
| + check(implicitDynamic: false);
|
| + }
|
| +
|
| + void test_implicitDynamic_function() {
|
| + addFile(r'''
|
| +/*=T*/ a/*<T>*/(/*=T*/ t) => t;
|
| +/*=T*/ b/*<T>*/() => null;
|
| +
|
| +void main/*<S>*/() {
|
| + dynamic d;
|
| + int i;
|
| + /*error:IMPLICIT_DYNAMIC_FUNCTION*/a(d);
|
| + a(42);
|
| + /*error:IMPLICIT_DYNAMIC_FUNCTION*/b();
|
| + d = /*error:IMPLICIT_DYNAMIC_FUNCTION*/b();
|
| + i = b();
|
| +
|
| + void f/*<T>*/(/*=T*/ t) {};
|
| + /*=T*/ g/*<T>*/() => null;
|
| +
|
| + /*error:IMPLICIT_DYNAMIC_FUNCTION*/f(d);
|
| + f(42);
|
| + /*error:IMPLICIT_DYNAMIC_FUNCTION*/g();
|
| + d = /*error:IMPLICIT_DYNAMIC_FUNCTION*/g();
|
| + i = g();
|
| +
|
| + /*error:IMPLICIT_DYNAMIC_INVOKE*/(/*<T>*/(/*=T*/ t) => t)(d);
|
| + (/*<T>*/(/*=T*/ t) => t)(42);
|
| + (/*<T>*/() => /*info:UNNECESSARY_CAST*/null as dynamic/*=T*/)/*<int>*/();
|
| +}
|
| + ''');
|
| + check(implicitDynamic: false);
|
| + }
|
| +
|
| + void test_implicitDynamic_listLiteral() {
|
| + addFile(r'''
|
| +
|
| +var l0 = /*error:IMPLICIT_DYNAMIC_LIST_LITERAL*/[];
|
| +List l1 = /*error:IMPLICIT_DYNAMIC_LIST_LITERAL*/[];
|
| +List<dynamic> l2 = /*error:IMPLICIT_DYNAMIC_LIST_LITERAL*/[];
|
| +dynamic d = 42;
|
| +var l3 = /*error:IMPLICIT_DYNAMIC_LIST_LITERAL*/[d, d];
|
| +
|
| +var l4 = <dynamic>[];
|
| +var l5 = <int>[];
|
| +List<int> l6 = /*info:INFERRED_TYPE_LITERAL*/[];
|
| +var l7 = /*info:INFERRED_TYPE_LITERAL*/[42];
|
| + ''');
|
| + check(implicitDynamic: false);
|
| + }
|
| +
|
| + void test_implicitDynamic_mapLiteral() {
|
| + addFile(r'''
|
| +var m0 = /*error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{};
|
| +Map m1 = /*error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{};
|
| +Map<dynamic, dynamic> m2 = /*error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{};
|
| +dynamic d = 42;
|
| +var m3 = /*error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{d: d};
|
| +var m4 = /*info:INFERRED_TYPE_LITERAL,error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{'x': d, 'y': d};
|
| +var m5 = /*info:INFERRED_TYPE_LITERAL,error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{d: 'x'};
|
| +
|
| +var m6 = <dynamic, dynamic>{};
|
| +var m7 = <String, String>{};
|
| +Map<String, String> m8 = /*info:INFERRED_TYPE_LITERAL*/{};
|
| +var m9 = /*info:INFERRED_TYPE_LITERAL*/{'hi': 'there'};
|
| + ''');
|
| + check(implicitDynamic: false);
|
| + }
|
| +
|
| + void test_implicitDynamic_method() {
|
| + addFile(r'''
|
| +class C {
|
| + /*=T*/ m/*<T>*/(/*=T*/ s) => s;
|
| + /*=T*/ n/*<T>*/() => null;
|
| +}
|
| +class D<E> {
|
| + /*=T*/ m/*<T>*/(/*=T*/ s) => s;
|
| + /*=T*/ n/*<T>*/() => null;
|
| +}
|
| +void f() {
|
| + dynamic d;
|
| + int i;
|
| + new C()./*error:IMPLICIT_DYNAMIC_METHOD*/m(d);
|
| + new C().m(42);
|
| + new C()./*error:IMPLICIT_DYNAMIC_METHOD*/n();
|
| + d = new C()./*error:IMPLICIT_DYNAMIC_METHOD*/n();
|
| + i = new C().n();
|
| +
|
| + new D<int>()./*error:IMPLICIT_DYNAMIC_METHOD*/m(d);
|
| + new D<int>().m(42);
|
| + new D<int>()./*error:IMPLICIT_DYNAMIC_METHOD*/n();
|
| + d = new D<int>()./*error:IMPLICIT_DYNAMIC_METHOD*/n();
|
| + i = new D<int>().n();
|
| +}
|
| + ''');
|
| + check(implicitDynamic: false);
|
| + }
|
| +
|
| + void test_implicitDynamic_parameter() {
|
| + addFile(r'''
|
| +const dynamic DYNAMIC_VALUE = 42;
|
| +
|
| +// simple formal
|
| +void f0(/*error:IMPLICIT_DYNAMIC_PARAMETER*/x) {}
|
| +void f1(dynamic x) {}
|
| +
|
| +// default formal
|
| +void df0([/*error:IMPLICIT_DYNAMIC_PARAMETER*/x = DYNAMIC_VALUE]) {}
|
| +void df1([dynamic x = DYNAMIC_VALUE]) {}
|
| +
|
| +// https://github.com/dart-lang/sdk/issues/25794
|
| +void df2([/*error:IMPLICIT_DYNAMIC_PARAMETER*/x = 42]) {}
|
| +
|
| +// default formal (named)
|
| +void nf0({/*error:IMPLICIT_DYNAMIC_PARAMETER*/x: DYNAMIC_VALUE}) {}
|
| +void nf1({dynamic x: DYNAMIC_VALUE}) {}
|
| +
|
| +// https://github.com/dart-lang/sdk/issues/25794
|
| +void nf2({/*error:IMPLICIT_DYNAMIC_PARAMETER*/x: 42}) {}
|
| +
|
| +// field formal
|
| +class C {
|
| + var /*error:IMPLICIT_DYNAMIC_FIELD*/x;
|
| + C(this.x);
|
| +}
|
| +
|
| +// function typed formal
|
| +void ftf0(void x(/*error:IMPLICIT_DYNAMIC_PARAMETER*/y)) {}
|
| +void ftf1(void x(int y)) {}
|
| + ''');
|
| + check(implicitDynamic: false);
|
| + }
|
| +
|
| + void test_implicitDynamic_return() {
|
| + addFile(r'''
|
| +// function
|
| +/*error:IMPLICIT_DYNAMIC_RETURN*/f0() {}
|
| +dynamic f1() { return 42; }
|
| +
|
| +// nested function
|
| +void main() {
|
| + /*error:IMPLICIT_DYNAMIC_RETURN*/g0() {}
|
| + dynamic g1() { return 42; }
|
| +}
|
| +
|
| +// methods
|
| +class B {
|
| + int m1() => 42;
|
| +}
|
| +class C extends B {
|
| + /*error:IMPLICIT_DYNAMIC_RETURN*/m0() => 123;
|
| + m1() => 123;
|
| + dynamic m2() => 'hi';
|
| +}
|
| +
|
| +// accessors
|
| +set x(int value) {}
|
| +/*error:IMPLICIT_DYNAMIC_RETURN*/get y0 => 42;
|
| +dynamic get y1 => 42;
|
| +
|
| +// function typed formals
|
| +void ftf0(/*error:IMPLICIT_DYNAMIC_RETURN*/f(int x)) {}
|
| +void ftf1(dynamic f(int x)) {}
|
| +
|
| +// function expressions
|
| +var fe0 = (int x) => x as dynamic;
|
| +var fe1 = (int x) => x;
|
| + ''');
|
| + check(implicitDynamic: false);
|
| + }
|
| +
|
| + void test_implicitDynamic_type() {
|
| + addFile(r'''
|
| +class C<T> {}
|
| +class M1<T extends /*error:IMPLICIT_DYNAMIC_TYPE*/List> {}
|
| +class M2<T> {}
|
| +class I<T> {}
|
| +class D<T, S> extends /*error:IMPLICIT_DYNAMIC_TYPE*/C
|
| + with M1, /*error:IMPLICIT_DYNAMIC_TYPE*/M2
|
| + implements /*error:IMPLICIT_DYNAMIC_TYPE*/I {}
|
| +
|
| +C f(D d) {
|
| + D x = new /*error:IMPLICIT_DYNAMIC_TYPE*/D();
|
| + D<int, dynamic> y = /*info:INFERRED_TYPE_ALLOCATION*/new /*error:IMPLICIT_DYNAMIC_TYPE*/D();
|
| + D<dynamic, int> z = /*info:INFERRED_TYPE_ALLOCATION*/new /*error:IMPLICIT_DYNAMIC_TYPE*/D();
|
| + return new /*error:IMPLICIT_DYNAMIC_TYPE*/C();
|
| +}
|
| +
|
| +class A<T extends num> {}
|
| +class N1<T extends List<int>> {}
|
| +class N2<T extends Object> {}
|
| +class J<T extends Object> {}
|
| +class B<T extends Object> extends A with N1, N2 implements J {}
|
| +A g(B b) {
|
| + B y = /*info:INFERRED_TYPE_ALLOCATION*/new B();
|
| + return /*info:INFERRED_TYPE_ALLOCATION*/new A();
|
| +}
|
| + ''');
|
| + check(implicitDynamic: false);
|
| + }
|
| +
|
| + void test_implicitDynamic_variable() {
|
| + addFile(r'''
|
| +var /*error:IMPLICIT_DYNAMIC_VARIABLE*/x0;
|
| +var /*error:IMPLICIT_DYNAMIC_VARIABLE*/x1 = (<dynamic>[])[0];
|
| +var /*error:IMPLICIT_DYNAMIC_VARIABLE*/x2,
|
| + x3 = 42,
|
| + /*error:IMPLICIT_DYNAMIC_VARIABLE*/x4;
|
| +dynamic y0;
|
| +dynamic y1 = (<dynamic>[])[0];
|
| + ''');
|
| + check(implicitDynamic: false);
|
| + }
|
| +
|
| + void test_invalidOverrides_baseClassOverrideToChildInterface() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I {
|
| + m(A a);
|
| +}
|
| +
|
| +class Base {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base implements I {}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidOverrides_childOverride() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +class Base {
|
| + A f;
|
| +}
|
| +
|
| +class T1 extends Base {
|
| + /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B get f => null;
|
| +}
|
| +
|
| +class T2 extends Base {
|
| + /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/set f(
|
| + B b) => null;
|
| +}
|
| +
|
| +class T3 extends Base {
|
| + /*error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/final B
|
| + /*warning:FINAL_NOT_INITIALIZED*/f;
|
| +}
|
| +class T4 extends Base {
|
| + // two: one for the getter one for the setter.
|
| + /*error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B f;
|
| +}
|
| +
|
| +class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T5 implements Base {
|
| + /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_METHOD_OVERRIDE*/B get f => null;
|
| +}
|
| +
|
| +class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T6 implements Base {
|
| + /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_METHOD_OVERRIDE*/set f(B b) => null;
|
| +}
|
| +
|
| +class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T7 implements Base {
|
| + /*error:INVALID_METHOD_OVERRIDE*/final B f = null;
|
| +}
|
| +class T8 implements Base {
|
| + // two: one for the getter one for the setter.
|
| + /*error:INVALID_METHOD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B f;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidOverrides_childOverride2() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +class Base {
|
| + m(A a) {}
|
| +}
|
| +
|
| +class Test extends Base {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidOverrides_classOverrideOfInterface() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I {
|
| + m(A a);
|
| +}
|
| +
|
| +class T1 implements I {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidOverrides_doubleOverride() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +class Grandparent {
|
| + m(A a) {}
|
| +}
|
| +class Parent extends Grandparent {
|
| + m(A a) {}
|
| +}
|
| +
|
| +class Test extends Parent {
|
| + // Reported only once
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidOverrides_doubleOverride2() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +class Grandparent {
|
| + m(A a) {}
|
| +}
|
| +class Parent extends Grandparent {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +
|
| +class Test extends Parent {
|
| + m(B a) {}
|
| +}
|
| +''');
|
| + }
|
|
|
| + void test_invalidOverrides_grandChildOverride() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +class Grandparent {
|
| + m(A a) {}
|
| + int x;
|
| +}
|
| +class Parent extends Grandparent {
|
| +}
|
| +
|
| +class Test extends Parent {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| + /*error:INVALID_FIELD_OVERRIDE*/int x;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidOverrides_mixinOverrideOfInterface() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I {
|
| + m(A a);
|
| +}
|
| +
|
| +class M {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M
|
| + implements I {}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidOverrides_mixinOverrideToBase() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +class Base {
|
| + m(A a) {}
|
| + int x;
|
| +}
|
| +
|
| +class M1 {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class M2 {
|
| + int x;
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base
|
| + with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M1 {}
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T2 extends Base
|
| + with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M1, /*error:INVALID_FIELD_OVERRIDE*/M2 {}
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T3 extends Base
|
| + with /*error:INVALID_FIELD_OVERRIDE*/M2, /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M1 {}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidOverrides_mixinOverrideToMixin() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +class Base {
|
| +}
|
| +
|
| +class M1 {
|
| + m(B a) {}
|
| + int x;
|
| +}
|
| +
|
| +class M2 {
|
| + m(A a) {}
|
| + int x;
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base
|
| + with M1,
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN,error:INVALID_FIELD_OVERRIDE*/M2 {}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidOverrides_noDuplicateMixinOverride() {
|
| // 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 {}
|
| - '''
|
| - });
|
| + checkFile('''
|
| +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 /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base
|
| + with M1, /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M2, M3 {}
|
| +''');
|
| + }
|
| +
|
| + void
|
| + test_invalidOverrides_noErrorsIfSubclassCorrectlyOverrideBaseAndInterface() {
|
| // 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()); }
|
| - '''
|
| - });
|
| - });
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +class Base {
|
| + m(A a) {}
|
| +}
|
| +
|
| +class I1 {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base
|
| + implements I1 {}
|
| +
|
| +class T2 extends Base implements I1 {
|
| + m(a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T3
|
| + extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/Base
|
| + implements I1 {}
|
| +
|
| +class T4 extends Object with Base implements I1 {
|
| + m(a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_invalidRuntimeChecks() {
|
| + checkFile('''
|
| +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:NON_GROUND_TYPE_CHECK_INFO*/foo is I2I;
|
| + b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is D2I;
|
| + b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is I2D;
|
| + b = foo is D2D;
|
| +
|
| + b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is II2I;
|
| + b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DI2I;
|
| + b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is ID2I;
|
| + b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is II2D;
|
| + b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DD2I;
|
| + b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DI2D;
|
| + b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is ID2D;
|
| + b = bar is DD2D;
|
| +
|
| + // For as, the validity of checks is deferred to runtime.
|
| + Function f;
|
| + f = /*info:UNNECESSARY_CAST*/foo as I2I;
|
| + f = /*info:UNNECESSARY_CAST*/foo as D2I;
|
| + f = /*info:UNNECESSARY_CAST*/foo as I2D;
|
| + f = /*info:UNNECESSARY_CAST*/foo as D2D;
|
| +
|
| + f = /*info:UNNECESSARY_CAST*/bar as II2I;
|
| + f = /*info:UNNECESSARY_CAST*/bar as DI2I;
|
| + f = /*info:UNNECESSARY_CAST*/bar as ID2I;
|
| + f = /*info:UNNECESSARY_CAST*/bar as II2D;
|
| + f = /*info:UNNECESSARY_CAST*/bar as DD2I;
|
| + f = /*info:UNNECESSARY_CAST*/bar as DI2D;
|
| + f = /*info:UNNECESSARY_CAST*/bar as ID2D;
|
| + f = /*info:UNNECESSARY_CAST*/bar as DD2D;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_leastUpperBounds() {
|
| + checkFile('''
|
| +typedef T Returns<T>();
|
| +
|
| +// regression test for https://github.com/dart-lang/sdk/issues/26094
|
| +class A <S extends Returns<S>, T extends Returns<T>> {
|
| + int test(bool b) {
|
| + S s;
|
| + T t;
|
| + if (b) {
|
| + return /*error:RETURN_OF_INVALID_TYPE*/b ? s : t;
|
| + } else {
|
| + return /*error:RETURN_OF_INVALID_TYPE*/s ?? t;
|
| + }
|
| + }
|
| +}
|
| +
|
| +class B<S, T extends S> {
|
| + T t;
|
| + S s;
|
| + int test(bool b) {
|
| + return /*error:RETURN_OF_INVALID_TYPE*/b ? t : s;
|
| + }
|
| +}
|
| +
|
| +class C {
|
| + // Check that the least upper bound of two types with the same
|
| + // class but different type arguments produces the pointwise
|
| + // least upper bound of the type arguments
|
| + int test1(bool b) {
|
| + List<int> li;
|
| + List<double> ld;
|
| + return /*error:RETURN_OF_INVALID_TYPE*/b ? li : ld;
|
| + }
|
| + // TODO(leafp): This case isn't handled yet. This test checks
|
| + // the case where two related classes are instantiated with related
|
| + // but different types.
|
| + Iterable<num> test2(bool b) {
|
| + List<int> li;
|
| + Iterable<double> id;
|
| + int x =
|
| + /*info:ASSIGNMENT_CAST should be error:INVALID_ASSIGNMENT*/
|
| + b ? li : id;
|
| + return /*warning:DOWN_CAST_COMPOSITE should be pass*/b ? li : id;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_leastUpperBounds_fuzzyArrows() {
|
| + checkFile(r'''
|
| +typedef String TakesA<T>(T item);
|
| +
|
| +void main() {
|
| + TakesA<int> f;
|
| + TakesA<dynamic> g;
|
| + TakesA<String> h;
|
| + g = h;
|
| + f = /*warning:DOWN_CAST_COMPOSITE*/f ?? g;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_loadLibrary() {
|
| + addFile('''library lib1;''', name: '/lib1.dart');
|
| + checkFile(r'''
|
| +import 'lib1.dart' deferred as lib1;
|
| +import 'dart:async' show Future;
|
| +main() {
|
| + Future f = lib1.loadLibrary();
|
| +}''');
|
| + }
|
| +
|
| + void test_methodOverride() {
|
| + checkFile('''
|
| +class A {}
|
| +class B extends A {}
|
| +class C extends B {}
|
| +
|
| +class Base {
|
| + B m1(B a) => null;
|
| + B m2(B a) => null;
|
| + B m3(B a) => null;
|
| + B m4(B a) => null;
|
| + B m5(B a) => null;
|
| + B m6(B a) => null;
|
| +}
|
| +
|
| +class Child extends Base {
|
| + /*error:INVALID_METHOD_OVERRIDE*/A m1(A value) => null;
|
| + /*error:INVALID_METHOD_OVERRIDE*/C m2(C value) => null;
|
| + /*error:INVALID_METHOD_OVERRIDE*/A m3(C value) => null;
|
| + C m4(A value) => null;
|
| + m5(value) => null;
|
| + /*error:INVALID_METHOD_OVERRIDE*/dynamic m6(dynamic value) => null;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_methodOverride_fuzzyArrows() {
|
| + checkFile('''
|
| +abstract class A {
|
| + bool operator ==(Object object);
|
| +}
|
| +
|
| +class B implements A {}
|
| +
|
| +class F {
|
| + void f(x) {}
|
| + void g(int x) {}
|
| +}
|
| +
|
| +class G extends F {
|
| + /*error:INVALID_METHOD_OVERRIDE*/void f(int x) {}
|
| + void g(dynamic x) {}
|
| +}
|
| +
|
| +class H implements F {
|
| + /*error:INVALID_METHOD_OVERRIDE*/void f(int x) {}
|
| + void g(dynamic x) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_methodTearoffStrictArrow() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/26393
|
| + checkFile(r'''
|
| +class A {
|
| + void foo(dynamic x) {}
|
| + void test(void f(int x)) {
|
| + test(foo);
|
| + }
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_mixinOverrideOfGrandInterface_interfaceOfAbstractSuperclass() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +abstract class Base implements I1 {}
|
| +
|
| +class M {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base
|
| + with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M {}
|
| +''');
|
| + }
|
| +
|
| + void test_mixinOverrideOfGrandInterface_interfaceOfConcreteSuperclass() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +
|
| +class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/Base
|
| + implements I1 {}
|
| +
|
| +class M {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base
|
| + with M {}
|
| +''');
|
| + }
|
| +
|
| + void test_mixinOverrideOfGrandInterface_interfaceOfInterfaceOfChild() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 implements I1 {}
|
| +
|
| +class M {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M
|
| + implements I2 {}
|
| +''');
|
| + }
|
| +
|
| + void test_mixinOverrideOfGrandInterface_mixinOfInterfaceOfChild() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class M1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 extends Object with M1 {}
|
| +
|
| +class M {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M
|
| + implements I2 {}
|
| +''');
|
| + }
|
| +
|
| + void test_mixinOverrideOfGrandInterface_superclassOfInterfaceOfChild() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 extends I1 {}
|
| +
|
| +class M {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M
|
| + implements I2 {}
|
| +''');
|
| + }
|
| +
|
| + void
|
| + test_noDuplicateReportsFromOverridingInterfaces_baseTypeAndMixinOverrideSameMethodInInterface() {
|
| + checkFile('''
|
| +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 /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base
|
| + with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M
|
| + implements I1 {}
|
| +''');
|
| + }
|
| +
|
| + void
|
| + test_noDuplicateReportsFromOverridingInterfaces_twoGrandTypesOverrideSameMethodInInterface() {
|
| + checkFile('''
|
| +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 /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Parent1
|
| + implements I1 {}
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T2
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Parent2
|
| + implements I1 {}
|
| +''');
|
| + }
|
| +
|
| + void
|
| + test_noDuplicateReportsFromOverridingInterfaces_twoMixinsOverrideSameMethodInInterface() {
|
| + checkFile('''
|
| +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 /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Object
|
| + with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M1,
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M2
|
| + implements I1 {}
|
| +''');
|
| + }
|
| +
|
| + void
|
| + test_noDuplicateReportsFromOverridingInterfaces_typeAndBaseTypeOverrideSameMethodInInterface() {
|
| + checkFile('''
|
| +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 {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +
|
| +// If there is no error in the class, we do report the error at
|
| +// the base class:
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T2
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base
|
| + implements I1 {}
|
| +''');
|
| + }
|
| +
|
| + void
|
| + test_noDuplicateReportsFromOverridingInterfaces_typeAndMixinOverrideSameMethodInInterface() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +
|
| +class M {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class T1 extends Object with M implements I1 {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T2
|
| + extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M
|
| + implements I1 {}
|
| +''');
|
| + }
|
| +
|
| + void
|
| + test_noDuplicateReportsFromOverridingInterfaces_typeOverridesSomeMethodInMultipleInterfaces() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 implements I1 {
|
| + m(A a);
|
| +}
|
| +
|
| +class Base {}
|
| +
|
| +class T1 implements I2 {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_nullCoalescingOperator() {
|
| + checkFile('''
|
| +class A {}
|
| +class C<T> {}
|
| +main() {
|
| + A a, b;
|
| + a ??= new A();
|
| + b = b ?? new A();
|
| +
|
| + // downwards inference
|
| + C<int> c, d;
|
| + c ??= /*info:INFERRED_TYPE_ALLOCATION*/new C();
|
| + d = d ?? /*info:INFERRED_TYPE_ALLOCATION*/new C();
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_nullCoalescingStrictArrow() {
|
| + checkFile(r'''
|
| +bool _alwaysTrue(x) => true;
|
| +typedef bool TakesA<T>(T t);
|
| +class C<T> {
|
| + TakesA<T> g;
|
| + C(TakesA<T> f)
|
| + : g = f ?? _alwaysTrue;
|
| + C.a() : g = _alwaysTrue;
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_optionalParams() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/26155
|
| + checkFile(r'''
|
| +void takesF(void f(int x)) {
|
| + takesF(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/([x]) { bool z = x.isEven; });
|
| + takesF(/*info:INFERRED_TYPE_CLOSURE*/(y) { bool z = y.isEven; });
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_overrideNarrowsType() {
|
| + addFile(r'''
|
| +class A {}
|
| +class B extends A {}
|
| +
|
| +abstract class C {
|
| + m(A a);
|
| + n(B b);
|
| +}
|
| +abstract class D extends C {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B b);
|
| + n(A a);
|
| +}
|
| + ''');
|
| + check(implicitCasts: false);
|
| + }
|
| +
|
| + void test_overrideNarrowsType_noDuplicateError() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/25232
|
| + _addMetaLibrary();
|
| + checkFile(r'''
|
| +import 'meta.dart';
|
| +abstract class A { void test(A arg) { } }
|
| +abstract class B extends A {
|
| + /*error:INVALID_METHOD_OVERRIDE*/void test(B arg) { }
|
| +}
|
| +abstract class X implements A { }
|
| +class C extends B with X { }
|
| +
|
| +// We treat "implements A" as asking for another check.
|
| +// This feels inconsistent to me.
|
| +class D /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends B implements A { }
|
| + ''');
|
| + }
|
| +
|
| + void test_overrideNarrowsType_legalWithChecked() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/25232
|
| + _addMetaLibrary();
|
| + checkFile(r'''
|
| +import 'meta.dart';
|
| +abstract class A { void test(A arg) { } }
|
| +abstract class B extends A { void test(@checked B arg) { } }
|
| +abstract class X implements A { }
|
| +class C extends B with X { }
|
| +class D extends B implements A { }
|
| + ''');
|
| + }
|
| +
|
| + void test_privateOverride() {
|
| + addFile(
|
| + '''
|
| +import 'main.dart' as main;
|
| +
|
| +class Base {
|
| + var f1;
|
| + var _f2;
|
| + var _f3;
|
| + get _f4 => null;
|
| +
|
| + int _m1() => null;
|
| +}
|
| +
|
| +class GrandChild extends main.Child {
|
| + /*error:INVALID_FIELD_OVERRIDE*/var _f2;
|
| + /*error:INVALID_FIELD_OVERRIDE*/var _f3;
|
| + var _f4;
|
| +
|
| + /*error:INVALID_METHOD_OVERRIDE*/String _m1() => null;
|
| +}
|
| +''',
|
| + name: '/helper.dart');
|
| + checkFile('''
|
| +import 'helper.dart' as helper;
|
| +
|
| +class Child extends helper.Base {
|
| + /*error:INVALID_FIELD_OVERRIDE*/var f1;
|
| + var _f2;
|
| + var _f4;
|
| +
|
| + String _m1() => null;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_proxy() {
|
| + checkFile(r'''
|
| +@proxy class C {}
|
| +@proxy class D {
|
| + var f;
|
| + m() => null;
|
| + operator -() => null;
|
| + operator +(int other) => null;
|
| + operator [](int index) => null;
|
| + call() => null;
|
| +}
|
| +@proxy class F implements Function { noSuchMethod(i) => 42; }
|
| +
|
| +
|
| +m() {
|
| + D d = new D();
|
| + d.m();
|
| + d.m;
|
| + d.f;
|
| + -d;
|
| + d + 7;
|
| + d[7];
|
| + d();
|
| +
|
| + C c = new C();
|
| + /*info:DYNAMIC_INVOKE*/c.m();
|
| + /*info:DYNAMIC_INVOKE*/c.m;
|
| + /*info:DYNAMIC_INVOKE*/-c;
|
| + /*info:DYNAMIC_INVOKE*/c + 7;
|
| + /*info:DYNAMIC_INVOKE*/c[7];
|
| + /*error:INVOCATION_OF_NON_FUNCTION,info:DYNAMIC_INVOKE*/c();
|
| +
|
| + F f = new F();
|
| + /*info:DYNAMIC_INVOKE*/f();
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_redirectingConstructor() {
|
| + checkFile('''
|
| +class A {
|
| + A(A x) {}
|
| + A.two() : this(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/3);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_relaxedCasts() {
|
| + checkFile('''
|
| +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;
|
| + lOfDs = new L(); // Reset type propagation.
|
| + }
|
| + {
|
| + lOfOs = mOfDs;
|
| + lOfOs = mOfOs;
|
| + lOfOs = mOfAs;
|
| + lOfOs = lOfDs;
|
| + lOfOs = lOfOs;
|
| + lOfOs = lOfAs;
|
| + lOfOs = new L<Object>(); // Reset type propagation.
|
| + }
|
| + {
|
| + lOfAs = /*error:INVALID_ASSIGNMENT*/mOfDs;
|
| + lOfAs = /*error:INVALID_ASSIGNMENT*/mOfOs;
|
| + lOfAs = mOfAs;
|
| + lOfAs = /*warning:DOWN_CAST_COMPOSITE*/lOfDs;
|
| + lOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
|
| + lOfAs = lOfAs;
|
| + lOfAs = new L<A>(); // Reset type propagation.
|
| + }
|
| + {
|
| + mOfDs = mOfDs;
|
| + mOfDs = mOfOs;
|
| + mOfDs = mOfAs;
|
| + mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfDs;
|
| + mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
|
| + mOfDs = /*error:INVALID_ASSIGNMENT*/lOfAs;
|
| + mOfDs = new M(); // Reset type propagation.
|
| + }
|
| + {
|
| + mOfOs = mOfDs;
|
| + mOfOs = mOfOs;
|
| + mOfOs = mOfAs;
|
| + mOfOs = /*info:DOWN_CAST_IMPLICIT*/lOfDs;
|
| + mOfOs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
|
| + mOfOs = /*error:INVALID_ASSIGNMENT*/lOfAs;
|
| + mOfOs = new M<Object>(); // Reset type propagation.
|
| + }
|
| + {
|
| + mOfAs = /*warning:DOWN_CAST_COMPOSITE*/mOfDs;
|
| + mOfAs = /*info:DOWN_CAST_IMPLICIT*/mOfOs;
|
| + mOfAs = mOfAs;
|
| + mOfAs = /*warning:DOWN_CAST_COMPOSITE*/lOfDs;
|
| + mOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
|
| + mOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfAs;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_setterOverride_fuzzyArrows() {
|
| + checkFile('''
|
| +typedef void ToVoid<T>(T x);
|
| +class F {
|
| + void set f(ToVoid<dynamic> x) {}
|
| + void set g(ToVoid<int> x) {}
|
| + void set h(dynamic x) {}
|
| + void set i(int x) {}
|
| +}
|
| +
|
| +class G extends F {
|
| + /*error:INVALID_METHOD_OVERRIDE*/void set f(ToVoid<int> x) {}
|
| + void set g(ToVoid<dynamic> x) {}
|
| + /*error:INVALID_METHOD_OVERRIDE*/void set h(int x) {}
|
| + void set i(dynamic x) {}
|
| +}
|
| +
|
| +class H implements F {
|
| + /*error:INVALID_METHOD_OVERRIDE*/void set f(ToVoid<int> x) {}
|
| + void set g(ToVoid<dynamic> x) {}
|
| + /*error:INVALID_METHOD_OVERRIDE*/void set h(int x) {}
|
| + void set i(dynamic x) {}
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_setterReturnTypes() {
|
| + checkFile('''
|
| +void voidFn() => null;
|
| +class A {
|
| + set a(y) => 4;
|
| + set b(y) => voidFn();
|
| + void set c(y) => /*error:RETURN_OF_INVALID_TYPE*/4;
|
| + void set d(y) => voidFn();
|
| + /*warning:NON_VOID_RETURN_FOR_SETTER*/int set e(y) => 4;
|
| + /*warning:NON_VOID_RETURN_FOR_SETTER*/int set f(y) =>
|
| + /*error:RETURN_OF_INVALID_TYPE*/voidFn();
|
| + set g(y) {return /*error:RETURN_OF_INVALID_TYPE*/4;}
|
| + void set h(y) {return /*error:RETURN_OF_INVALID_TYPE*/4;}
|
| + /*warning:NON_VOID_RETURN_FOR_SETTER*/int set i(y) {return 4;}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_setterSetterOverride() {
|
| + checkFile('''
|
| +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) {}
|
| + /*error:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
|
| + void set f3(value) {}
|
| + void set f4(dynamic value) {}
|
| + set f5(B value) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_superCallPlacement() {
|
| + checkFile('''
|
| +class Base {
|
| + var x;
|
| + Base() : x = print('Base.1') { print('Base.2'); }
|
| +}
|
| +
|
| +class Derived extends Base {
|
| + var y, z;
|
| + Derived()
|
| + : y = print('Derived.1'),
|
| + /*error:INVALID_SUPER_INVOCATION*/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();
|
| +''');
|
| + }
|
| +
|
| + void test_superclassOverrideOfGrandInterface_interfaceOfAbstractSuperclass() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +
|
| +abstract class Base implements I1 {
|
| + /*error:INVALID_METHOD_OVERRIDE*/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.
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_superclassOverrideOfGrandInterface_interfaceOfConcreteSuperclass() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +
|
| +class Base implements I1 {
|
| + /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
|
| +}
|
| +
|
| +class T1 extends Base {
|
| + m(B a) {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_superclassOverrideOfGrandInterface_interfaceOfInterfaceOfChild() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 implements I1 {}
|
| +
|
| +class Base {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base implements I2 {}
|
| +''');
|
| + }
|
| +
|
| + void test_superclassOverrideOfGrandInterface_mixinOfInterfaceOfChild() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class M1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 extends Object with M1 {}
|
| +
|
| +class Base {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base
|
| + implements I2 {}
|
| +''');
|
| + }
|
| +
|
| + void test_superclassOverrideOfGrandInterface_superclassOfInterfaceOfChild() {
|
| + checkFile('''
|
| +class A {}
|
| +class B {}
|
| +
|
| +abstract class I1 {
|
| + m(A a);
|
| +}
|
| +abstract class I2 extends I1 {}
|
| +
|
| +class Base {
|
| + m(B a) {}
|
| +}
|
| +
|
| +class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1
|
| + /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base
|
| + implements I2 {}
|
| +''');
|
| + }
|
| +
|
| + void test_superConstructor() {
|
| + checkFile('''
|
| +class A { A(A x) {} }
|
| +class B extends A {
|
| + B() : super(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/3);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_ternaryOperator() {
|
| + checkFile('''
|
| +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;
|
| +
|
| + // The warning on assigning to _comparator is legitimate. Since K has
|
| + // no bound, all we know is that it's object. _comparator's function
|
| + // type is effectively: (Object, Object) -> int
|
| + // We are assigning it a fn of type: (Comparable, Comparable) -> int
|
| + // There's no telling if that will work. For example, consider:
|
| + //
|
| + // new SplayTreeMap<Uri>();
|
| + //
|
| + // This would end up calling .compareTo() on a Uri, which doesn't
|
| + // define that since it doesn't implement Comparable.
|
| + SplayTreeMap([int compare(K key1, K key2),
|
| + bool isValidKey(potentialKey)])
|
| + : _comparator = /*warning:DOWN_CAST_COMPOSITE*/(compare == null) ? Comparable.compare : compare,
|
| + _validKey = (isValidKey != null) ? isValidKey : ((v) => true) {
|
| +
|
| + // NOTE: this is a down cast because isValidKey has fuzzy arrow type.
|
| + _Predicate<Object> v = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
|
| + ? isValidKey : (/*info:INFERRED_TYPE_CLOSURE*/(_) => true);
|
| +
|
| + v = (isValidKey != null)
|
| + ? v : (/*info:INFERRED_TYPE_CLOSURE*/(_) => true);
|
| + }
|
| +}
|
| +void main() {
|
| + Object obj = 42;
|
| + dynamic dyn = 42;
|
| + int i = 42;
|
| +
|
| + // Check the boolean conversion of the condition.
|
| + print(/*error:NON_BOOL_CONDITION*/i ? false : true);
|
| + print((/*info:DOWN_CAST_IMPLICIT*/obj) ? false : true);
|
| + print((/*info:DYNAMIC_CAST*/dyn) ? false : true);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_typeCheckingLiterals() {
|
| + checkFile('''
|
| +test() {
|
| + num n = 3;
|
| + int i = 3;
|
| + String s = "hello";
|
| + {
|
| + List<int> l = <int>[i];
|
| + l = <int>[/*error:LIST_ELEMENT_TYPE_NOT_ASSIGNABLE*/s];
|
| + l = <int>[/*info:DOWN_CAST_IMPLICIT*/n];
|
| + l = <int>[i, /*info:DOWN_CAST_IMPLICIT*/n, /*error:LIST_ELEMENT_TYPE_NOT_ASSIGNABLE*/s];
|
| + }
|
| + {
|
| + List l = /*info:INFERRED_TYPE_LITERAL*/[i];
|
| + l = /*info:INFERRED_TYPE_LITERAL*/[s];
|
| + l = /*info:INFERRED_TYPE_LITERAL*/[n];
|
| + l = /*info:INFERRED_TYPE_LITERAL*/[i, n, s];
|
| + }
|
| + {
|
| + Map<String, int> m = <String, int>{s: i};
|
| + m = <String, int>{s: /*error:MAP_VALUE_TYPE_NOT_ASSIGNABLE*/s};
|
| + m = <String, int>{s: /*info:DOWN_CAST_IMPLICIT*/n};
|
| + m = <String, int>{s: i,
|
| + s: /*info:DOWN_CAST_IMPLICIT*/n,
|
| + s: /*error:MAP_VALUE_TYPE_NOT_ASSIGNABLE*/s};
|
| + }
|
| + // TODO(leafp): We can't currently test for key errors since the
|
| + // error marker binds to the entire entry.
|
| + {
|
| + Map m = /*info:INFERRED_TYPE_LITERAL*/{s: i};
|
| + m = /*info:INFERRED_TYPE_LITERAL*/{s: s};
|
| + m = /*info:INFERRED_TYPE_LITERAL*/{s: n};
|
| + m = /*info:INFERRED_TYPE_LITERAL*/
|
| + {s: i,
|
| + s: n,
|
| + s: s};
|
| + m = /*info:INFERRED_TYPE_LITERAL*/
|
| + {i: s,
|
| + n: s,
|
| + s: s};
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_typePromotionFromDynamic() {
|
| + checkFile(r'''
|
| +f() {
|
| + dynamic x;
|
| + if (x is int) {
|
| + int y = x;
|
| + String z = /*error:INVALID_ASSIGNMENT*/x;
|
| + }
|
| +}
|
| +g() {
|
| + Object x;
|
| + if (x is int) {
|
| + int y = x;
|
| + String z = /*error:INVALID_ASSIGNMENT*/x;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_typePromotionFromTypeParameter() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/26965
|
| + checkFile(r'''
|
| +void f/*<T>*/(/*=T*/ object) {
|
| + if (object is String) print(object.substring(1));
|
| +}
|
| +void g/*<T extends num>*/(/*=T*/ object) {
|
| + if (object is int) print(object.isEven);
|
| + if (object is String) print(/*info:DYNAMIC_INVOKE*/object.substring(1));
|
| +}
|
| +class Clonable<T> {}
|
| +class SubClonable<T> extends Clonable<T> {
|
| + T m(T t) => t;
|
| +}
|
| +void h/*<T extends Clonable<T>>*/(/*=T*/ object) {
|
| + if (/*info:NON_GROUND_TYPE_CHECK_INFO*/object is SubClonable/*<T>*/) {
|
| + // Note we need to cast back to T, because promotion lost that type info.
|
| + print(object.m(object as dynamic/*=T*/));
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_typeSubtyping_assigningClass() {
|
| + checkFile('''
|
| +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 = /*error:INVALID_ASSIGNMENT*/a;
|
| + d = /*error:INVALID_ASSIGNMENT*/a;
|
| + n = /*error:INVALID_ASSIGNMENT*/a;
|
| + a = a;
|
| + b = /*info:DOWN_CAST_IMPLICIT*/a;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_typeSubtyping_assigningSubclass() {
|
| + checkFile('''
|
| +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 = /*error:INVALID_ASSIGNMENT*/b;
|
| + d = /*error:INVALID_ASSIGNMENT*/b;
|
| + n = /*error:INVALID_ASSIGNMENT*/b;
|
| + a = b;
|
| + b = b;
|
| + c = /*error:INVALID_ASSIGNMENT*/b;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_typeSubtyping_dynamicDowncasts() {
|
| + checkFile('''
|
| +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:DYNAMIC_CAST*/y;
|
| + d = /*info:DYNAMIC_CAST*/y;
|
| + n = /*info:DYNAMIC_CAST*/y;
|
| + a = /*info:DYNAMIC_CAST*/y;
|
| + b = /*info:DYNAMIC_CAST*/y;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_typeSubtyping_dynamicIsTop() {
|
| + checkFile('''
|
| +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;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_typeSubtyping_interfaces() {
|
| + checkFile('''
|
| +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:DOWN_CAST_IMPLICIT*/top;
|
| + left = left;
|
| + left = /*error:INVALID_ASSIGNMENT*/right;
|
| + left = bot;
|
| + }
|
| + {
|
| + right = /*info:DOWN_CAST_IMPLICIT*/top;
|
| + right = /*error:INVALID_ASSIGNMENT*/left;
|
| + right = right;
|
| + right = bot;
|
| + }
|
| + {
|
| + bot = /*info:DOWN_CAST_IMPLICIT*/top;
|
| + bot = /*info:DOWN_CAST_IMPLICIT*/left;
|
| + bot = /*info:DOWN_CAST_IMPLICIT*/right;
|
| + bot = bot;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_unaryOperators() {
|
| + checkFile('''
|
| +class A {
|
| + A operator ~() => null;
|
| + A operator +(int x) => null;
|
| + A operator -(int x) => null;
|
| + A operator -() => null;
|
| +}
|
| +class B extends A {}
|
| +class C extends B {}
|
| +
|
| +foo() => new A();
|
| +
|
| +test() {
|
| + A a = new A();
|
| + B b = new B();
|
| + var c = foo();
|
| + dynamic d;
|
| +
|
| + ~a;
|
| + (/*info:DYNAMIC_INVOKE*/~d);
|
| +
|
| + !/*error:NON_BOOL_NEGATION_EXPRESSION*/a;
|
| + !/*info:DYNAMIC_CAST*/d;
|
| +
|
| + -a;
|
| + (/*info:DYNAMIC_INVOKE*/-d);
|
| +
|
| + ++a;
|
| + --a;
|
| + (/*info:DYNAMIC_INVOKE*/++d);
|
| + (/*info:DYNAMIC_INVOKE*/--d);
|
| +
|
| + a++;
|
| + a--;
|
| + (/*info:DYNAMIC_INVOKE*/d++);
|
| + (/*info:DYNAMIC_INVOKE*/d--);
|
| +
|
| + ++/*info:DOWN_CAST_IMPLICIT_ASSIGN*/b;
|
| + --/*info:DOWN_CAST_IMPLICIT_ASSIGN*/b;
|
| + /*info:DOWN_CAST_IMPLICIT_ASSIGN*/b++;
|
| + /*info:DOWN_CAST_IMPLICIT_ASSIGN*/b--;
|
| +
|
| + takesC(C c) => null;
|
| + takesC(/*info:DOWN_CAST_IMPLICIT*/++/*info:DOWN_CAST_IMPLICIT_ASSIGN*/b);
|
| + takesC(/*info:DOWN_CAST_IMPLICIT*/--/*info:DOWN_CAST_IMPLICIT_ASSIGN*/b);
|
| + takesC(/*info:DOWN_CAST_IMPLICIT,info:DOWN_CAST_IMPLICIT_ASSIGN*/b++);
|
| + takesC(/*info:DOWN_CAST_IMPLICIT,info:DOWN_CAST_IMPLICIT_ASSIGN*/b--);
|
| +}''');
|
| + }
|
| +
|
| + void test_unboundRedirectingConstructor() {
|
| + // This is a regression test for https://github.com/dart-lang/sdk/issues/25071
|
| + checkFile('''
|
| +class Foo {
|
| + Foo() : /*error:REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR*/this.init();
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_unboundTypeName() {
|
| + checkFile('''
|
| +void main() {
|
| + /*error:UNDEFINED_CLASS*/AToB y;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_unboundVariable() {
|
| + checkFile('''
|
| +void main() {
|
| + dynamic y = /*error:UNDEFINED_IDENTIFIER*/unboundVariable;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_voidSubtyping() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/25069
|
| + checkFile('''
|
| +typedef int Foo();
|
| +void foo() {}
|
| +void main () {
|
| + Foo x = /*error:INVALID_ASSIGNMENT,info:USE_OF_VOID_RESULT*/foo();
|
| +}
|
| +''');
|
| + }
|
| +}
|
| +
|
| +void _addMetaLibrary() {
|
| + addFile(r'''
|
| +library meta;
|
| +class _Checked { const _Checked(); }
|
| +const Object checked = const _Checked();
|
| +
|
| +class _Virtual { const _Virtual(); }
|
| +const Object virtual = const _Virtual();
|
| + ''', name: '/meta.dart');
|
| }
|
|
|