Index: test/checker/inferred_type_test.dart |
diff --git a/test/checker/inferred_type_test.dart b/test/checker/inferred_type_test.dart |
deleted file mode 100644 |
index d10fb67b54ddc1c40df2d2baba70d7c562572cc6..0000000000000000000000000000000000000000 |
--- a/test/checker/inferred_type_test.dart |
+++ /dev/null |
@@ -1,1291 +0,0 @@ |
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-/// Tests for type inference. |
-library dev_compiler.test.inferred_type_test; |
- |
-import 'package:test/test.dart'; |
- |
-import '../testing.dart'; |
- |
-void main() { |
- // Error also expected when declared type is `int`. |
- testChecker('infer type on var', { |
- '/main.dart': ''' |
- test1() { |
- int x = 3; |
- x = /*severe:StaticTypeError*/"hi"; |
- } |
- ''' |
- }); |
- |
- // If inferred type is `int`, error is also reported |
- testChecker('infer type on var 2', { |
- '/main.dart': ''' |
- test2() { |
- var x = 3; |
- x = /*severe:StaticTypeError*/"hi"; |
- } |
- ''' |
- }); |
- |
- testChecker('No error when declared type is `num` and assigned null.', { |
- '/main.dart': ''' |
- test1() { |
- num x = 3; |
- x = null; |
- } |
- ''' |
- }); |
- |
- testChecker('do not infer type on dynamic', { |
- '/main.dart': ''' |
- test() { |
- dynamic x = 3; |
- x = "hi"; |
- } |
- ''' |
- }); |
- |
- testChecker('do not infer type when initializer is null', { |
- '/main.dart': ''' |
- test() { |
- var x = null; |
- x = "hi"; |
- x = 3; |
- } |
- ''' |
- }); |
- |
- testChecker('infer type on var from field', { |
- '/main.dart': ''' |
- class A { |
- int x = 0; |
- |
- test1() { |
- var a = x; |
- a = /*severe:StaticTypeError*/"hi"; |
- a = 3; |
- var b = y; |
- b = /*severe:StaticTypeError*/"hi"; |
- b = 4; |
- var c = z; |
- c = /*severe:StaticTypeError*/"hi"; |
- c = 4; |
- } |
- |
- int y; // field def after use |
- final z = 42; // should infer `int` |
- } |
- ''' |
- }); |
- |
- testChecker('infer type on var from top-level', { |
- '/main.dart': ''' |
- int x = 0; |
- |
- test1() { |
- var a = x; |
- a = /*severe:StaticTypeError*/"hi"; |
- a = 3; |
- var b = y; |
- b = /*severe:StaticTypeError*/"hi"; |
- b = 4; |
- var c = z; |
- c = /*severe:StaticTypeError*/"hi"; |
- c = 4; |
- } |
- |
- int y = 0; // field def after use |
- final z = 42; // should infer `int` |
- ''' |
- }); |
- |
- testChecker('do not infer field type when initializer is null', { |
- '/main.dart': ''' |
- var x = null; |
- var y = 3; |
- class A { |
- static var x = null; |
- static var y = 3; |
- |
- var x2 = null; |
- var y2 = 3; |
- } |
- |
- test() { |
- x = "hi"; |
- y = /*severe:StaticTypeError*/"hi"; |
- A.x = "hi"; |
- A.y = /*severe:StaticTypeError*/"hi"; |
- new A().x2 = "hi"; |
- new A().y2 = /*severe:StaticTypeError*/"hi"; |
- } |
- ''' |
- }); |
- |
- testChecker('infer from variables in non-cycle imports with flag', { |
- '/a.dart': ''' |
- var x = 2; |
- ''', |
- '/main.dart': ''' |
- import 'a.dart'; |
- var y = x; |
- |
- test1() { |
- x = /*severe:StaticTypeError*/"hi"; |
- y = /*severe:StaticTypeError*/"hi"; |
- } |
- ''' |
- }); |
- |
- testChecker('infer from variables in non-cycle imports with flag 2', { |
- '/a.dart': ''' |
- class A { static var x = 2; } |
- ''', |
- '/main.dart': ''' |
- import 'a.dart'; |
- class B { static var y = A.x; } |
- |
- test1() { |
- A.x = /*severe:StaticTypeError*/"hi"; |
- B.y = /*severe:StaticTypeError*/"hi"; |
- } |
- ''' |
- }); |
- |
- testChecker('infer from variables in cycle libs when flag is on', { |
- '/a.dart': ''' |
- import 'main.dart'; |
- var x = 2; // ok to infer |
- ''', |
- '/main.dart': ''' |
- import 'a.dart'; |
- var y = x; // now ok :) |
- |
- test1() { |
- int t = 3; |
- t = x; |
- t = y; |
- } |
- ''' |
- }); |
- |
- testChecker('infer from variables in cycle libs when flag is on 2', { |
- '/a.dart': ''' |
- import 'main.dart'; |
- class A { static var x = 2; } |
- ''', |
- '/main.dart': ''' |
- import 'a.dart'; |
- class B { static var y = A.x; } |
- |
- test1() { |
- int t = 3; |
- t = A.x; |
- t = B.y; |
- } |
- ''' |
- }); |
- |
- testChecker('can infer also from static and instance fields (flag on)', { |
- '/a.dart': ''' |
- import 'b.dart'; |
- class A { |
- static final a1 = B.b1; |
- final a2 = new B().b2; |
- } |
- ''', |
- '/b.dart': ''' |
- class B { |
- static final b1 = 1; |
- final b2 = 1; |
- } |
- ''', |
- '/main.dart': ''' |
- import "a.dart"; |
- |
- test1() { |
- int x = 0; |
- // inference in A now works. |
- x = A.a1; |
- x = new A().a2; |
- } |
- ''' |
- }); |
- |
- testChecker('inference in cycles is deterministic', { |
- '/a.dart': ''' |
- import 'b.dart'; |
- class A { |
- static final a1 = B.b1; |
- final a2 = new B().b2; |
- } |
- ''', |
- '/b.dart': ''' |
- class B { |
- static final b1 = 1; |
- final b2 = 1; |
- } |
- ''', |
- '/c.dart': ''' |
- import "main.dart"; // creates a cycle |
- |
- class C { |
- static final c1 = 1; |
- final c2 = 1; |
- } |
- ''', |
- '/e.dart': ''' |
- import 'a.dart'; |
- part 'e2.dart'; |
- |
- class E { |
- static final e1 = 1; |
- static final e2 = F.f1; |
- static final e3 = A.a1; |
- final e4 = 1; |
- final e5 = new F().f2; |
- final e6 = new A().a2; |
- } |
- ''', |
- '/f.dart': ''' |
- part 'f2.dart'; |
- ''', |
- '/e2.dart': ''' |
- class F { |
- static final f1 = 1; |
- final f2 = 1; |
- } |
- ''', |
- '/main.dart': ''' |
- import "a.dart"; |
- import "c.dart"; |
- import "e.dart"; |
- |
- class D { |
- static final d1 = A.a1 + 1; |
- static final d2 = C.c1 + 1; |
- final d3 = new A().a2; |
- final d4 = new C().c2; |
- } |
- |
- test1() { |
- int x = 0; |
- // inference in A works, it's not in a cycle |
- x = A.a1; |
- x = new A().a2; |
- |
- // Within a cycle we allow inference when the RHS is well known, but |
- // not when it depends on other fields within the cycle |
- x = C.c1; |
- x = D.d1; |
- x = D.d2; |
- x = new C().c2; |
- x = new D().d3; |
- x = /*info:DynamicCast*/new D().d4; |
- |
- |
- // Similarly if the library contains parts. |
- x = E.e1; |
- x = E.e2; |
- x = E.e3; |
- x = new E().e4; |
- x = /*info:DynamicCast*/new E().e5; |
- x = new E().e6; |
- x = F.f1; |
- x = new F().f2; |
- } |
- ''' |
- }); |
- |
- testChecker( |
- 'infer from complex expressions if the outer-most value is precise', { |
- '/main.dart': ''' |
- class A { int x; B operator+(other) {} } |
- class B extends A { B(ignore); } |
- var a = new A(); |
- // Note: it doesn't matter that some of these refer to 'x'. |
- var b = new B(x); // allocations |
- var c1 = [x]; // list literals |
- var c2 = const []; |
- var d = {'a': 'b'}; // map literals |
- var e = new A()..x = 3; // cascades |
- var f = 2 + 3; // binary expressions are OK if the left operand |
- // is from a library in a different strongest |
- // conected component. |
- var g = -3; |
- var h = new A() + 3; |
- var i = - new A(); |
- var j = null as B; |
- |
- test1() { |
- a = /*severe:StaticTypeError*/"hi"; |
- a = new B(3); |
- b = /*severe:StaticTypeError*/"hi"; |
- b = new B(3); |
- c1 = []; |
- c1 = /*severe:StaticTypeError*/{}; |
- c2 = []; |
- c2 = /*severe:StaticTypeError*/{}; |
- d = {}; |
- d = /*severe:StaticTypeError*/3; |
- e = new A(); |
- e = /*severe:StaticTypeError*/{}; |
- f = 3; |
- f = /*severe:StaticTypeError*/false; |
- g = 1; |
- g = /*severe:StaticTypeError*/false; |
- h = /*severe:StaticTypeError*/false; |
- h = new B(); |
- i = false; |
- j = new B(); |
- j = /*severe:StaticTypeError*/false; |
- j = /*severe:StaticTypeError*/[]; |
- } |
- ''' |
- }); |
- |
- // but flags can enable this behavior. |
- testChecker('infer if complex expressions read possibly inferred field', { |
- '/a.dart': ''' |
- class A { |
- var x = 3; |
- } |
- ''', |
- '/main.dart': ''' |
- import 'a.dart'; |
- class B { |
- var y = 3; |
- } |
- final t1 = new A(); |
- final t2 = new A().x; |
- final t3 = new B(); |
- final t4 = new B().y; |
- |
- test1() { |
- int i = 0; |
- A a; |
- B b; |
- a = t1; |
- i = t2; |
- b = t3; |
- i = /*info:DynamicCast*/t4; |
- i = new B().y; // B.y was inferred though |
- } |
- ''' |
- }); |
- |
- group('infer types on loop indices', () { |
- testChecker('foreach loop', { |
- '/main.dart': ''' |
- class Foo { |
- int bar = 42; |
- } |
- |
- test() { |
- var list = <Foo>[]; |
- for (var x in list) { |
- String y = /*severe:StaticTypeError*/x; |
- } |
- |
- for (dynamic x in list) { |
- String y = /*info:DynamicCast*/x; |
- } |
- |
- for (String x in /*severe:StaticTypeError*/list) { |
- String y = x; |
- } |
- |
- var z; |
- for(z in list) { |
- String y = /*info:DynamicCast*/z; |
- } |
- |
- Iterable iter = list; |
- for (Foo x in /*warning:DownCastComposite*/iter) { |
- var y = x; |
- } |
- |
- dynamic iter2 = list; |
- for (Foo x in /*warning:DownCastComposite*/iter2) { |
- var y = x; |
- } |
- |
- var map = <String, Foo>{}; |
- // Error: map must be an Iterable. |
- for (var x in /*severe:StaticTypeError*/map) { |
- String y = /*info:DynamicCast*/x; |
- } |
- |
- // We're not properly inferring that map.keys is an Iterable<String> |
- // and that x is a String. |
- for (var x in map.keys) { |
- String y = x; |
- } |
- } |
- ''' |
- }); |
- |
- testChecker('for loop, with inference', { |
- '/main.dart': ''' |
- test() { |
- for (var i = 0; i < 10; i++) { |
- int j = i + 1; |
- } |
- } |
- ''' |
- }); |
- }); |
- |
- testChecker('propagate inference to field in class', { |
- '/main.dart': ''' |
- class A { |
- int x = 2; |
- } |
- |
- test() { |
- var a = new A(); |
- A b = a; // doesn't require down cast |
- print(a.x); // doesn't require dynamic invoke |
- print(a.x + 2); // ok to use in bigger expression |
- } |
- ''' |
- }); |
- |
- testChecker('propagate inference to field in class dynamic warnings', { |
- '/main.dart': ''' |
- class A { |
- int x = 2; |
- } |
- |
- test() { |
- dynamic a = new A(); |
- A b = /*info:DynamicCast*/a; |
- print(/*info:DynamicInvoke*/a.x); |
- print(/*info:DynamicInvoke*/(/*info:DynamicInvoke*/a.x) + 2); |
- } |
- ''' |
- }); |
- |
- testChecker('propagate inference transitively', { |
- '/main.dart': ''' |
- class A { |
- int x = 2; |
- } |
- |
- test5() { |
- var a1 = new A(); |
- a1.x = /*severe:StaticTypeError*/"hi"; |
- |
- A a2 = new A(); |
- a2.x = /*severe:StaticTypeError*/"hi"; |
- } |
- ''' |
- }); |
- |
- testChecker('propagate inference transitively 2', { |
- '/main.dart': ''' |
- class A { |
- int x = 42; |
- } |
- |
- class B { |
- A a = new A(); |
- } |
- |
- class C { |
- B b = new B(); |
- } |
- |
- class D { |
- C c = new C(); |
- } |
- |
- void main() { |
- var d1 = new D(); |
- print(d1.c.b.a.x); |
- |
- D d2 = new D(); |
- print(d2.c.b.a.x); |
- } |
- ''' |
- }); |
- |
- group('infer type on overridden fields', () { |
- testChecker('2', { |
- '/main.dart': ''' |
- class A { |
- int x = 2; |
- } |
- |
- class B extends A { |
- get x => 3; |
- } |
- |
- foo() { |
- String y = /*severe:StaticTypeError*/new B().x; |
- int z = new B().x; |
- } |
- ''' |
- }); |
- |
- testChecker('4', { |
- '/main.dart': ''' |
- class A { |
- int x = 2; |
- } |
- |
- class B implements A { |
- get x => 3; |
- } |
- |
- foo() { |
- String y = /*severe:StaticTypeError*/new B().x; |
- int z = new B().x; |
- } |
- ''' |
- }); |
- }); |
- |
- group('infer types on generic instantiations', () { |
- testChecker('infer', { |
- '/main.dart': ''' |
- class A<T> { |
- T x; |
- } |
- |
- class B implements A<int> { |
- /*severe:InvalidMethodOverride*/dynamic get x => 3; |
- } |
- |
- foo() { |
- String y = /*info:DynamicCast*/new B().x; |
- int z = /*info:DynamicCast*/new B().x; |
- } |
- ''' |
- }); |
- |
- testChecker('3', { |
- '/main.dart': ''' |
- class A<T> { |
- T x; |
- T w; |
- } |
- |
- class B implements A<int> { |
- get x => 3; |
- get w => /*severe:StaticTypeError*/"hello"; |
- } |
- |
- foo() { |
- String y = /*severe:StaticTypeError*/new B().x; |
- int z = new B().x; |
- } |
- ''' |
- }); |
- |
- testChecker('4', { |
- '/main.dart': ''' |
- class A<T> { |
- T x; |
- } |
- |
- class B<E> extends A<E> { |
- E y; |
- get x => y; |
- } |
- |
- foo() { |
- int y = /*severe:StaticTypeError*/new B<String>().x; |
- String z = new B<String>().x; |
- } |
- ''' |
- }); |
- |
- testChecker('5', { |
- '/main.dart': ''' |
- abstract class I<E> { |
- String m(a, String f(v, T e)); |
- } |
- |
- abstract class A<E> implements I<E> { |
- const A(); |
- String m(a, String f(v, T e)); |
- } |
- |
- abstract class M { |
- int y; |
- } |
- |
- class B<E> extends A<E> implements M { |
- const B(); |
- int get y => 0; |
- |
- m(a, f(v, T e)) {} |
- } |
- |
- foo () { |
- int y = /*severe:StaticTypeError*/new B().m(null, null); |
- String z = new B().m(null, null); |
- } |
- ''' |
- }); |
- }); |
- |
- testChecker('infer type regardless of declaration order or cycles', { |
- '/b.dart': ''' |
- import 'main.dart'; |
- |
- class B extends A { } |
- ''', |
- '/main.dart': ''' |
- import 'b.dart'; |
- class C extends B { |
- get x; |
- } |
- class A { |
- int get x; |
- } |
- foo () { |
- int y = new C().x; |
- String y = /*severe:StaticTypeError*/new C().x; |
- } |
- ''' |
- }); |
- |
- // Note: this is a regression test for a non-deterministic behavior we used to |
- // have with inference in library cycles. If you see this test flake out, |
- // change `test` to `skip_test` and reopen bug #48. |
- testChecker('infer types on generic instantiations in library cycle', { |
- '/a.dart': ''' |
- import 'main.dart'; |
- abstract class I<E> { |
- A<E> m(a, String f(v, int e)); |
- } |
- ''', |
- '/main.dart': ''' |
- import 'a.dart'; |
- |
- abstract class A<E> implements I<E> { |
- const A(); |
- |
- E value; |
- } |
- |
- abstract class M { |
- int y; |
- } |
- |
- class B<E> extends A<E> implements M { |
- const B(); |
- int get y => 0; |
- |
- m(a, f(v, int e)) {} |
- } |
- |
- foo () { |
- int y = /*severe:StaticTypeError*/new B<String>().m(null, null).value; |
- String z = new B<String>().m(null, null).value; |
- } |
- ''' |
- }); |
- |
- group('do not infer overridden fields that explicitly say dynamic', () { |
- testChecker('infer', { |
- '/main.dart': ''' |
- class A { |
- int x = 2; |
- } |
- |
- class B implements A { |
- /*severe:InvalidMethodOverride*/dynamic get x => 3; |
- } |
- |
- foo() { |
- String y = /*info:DynamicCast*/new B().x; |
- int z = /*info:DynamicCast*/new B().x; |
- } |
- ''' |
- }); |
- }); |
- |
- testChecker('conflicts can happen', { |
- '/main.dart': ''' |
- class I1 { |
- int x; |
- } |
- class I2 extends I1 { |
- int y; |
- } |
- |
- class A { |
- final I1 a; |
- } |
- |
- class B { |
- final I2 a; |
- } |
- |
- class C1 extends A implements B { |
- /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a => null; |
- } |
- |
- // Still ambiguous |
- class C2 extends B implements A { |
- /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a => null; |
- } |
- ''' |
- }); |
- |
- testChecker('conflicts can happen 2', { |
- '/main.dart': ''' |
- class I1 { |
- int x; |
- } |
- class I2 { |
- int y; |
- } |
- |
- class I3 implements I1, I2 { |
- int x; |
- int y; |
- } |
- |
- class A { |
- final I1 a; |
- } |
- |
- class B { |
- final I2 a; |
- } |
- |
- class C1 extends A implements B { |
- I3 get a => null; |
- } |
- |
- class C2 extends A implements B { |
- /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a => null; |
- } |
- ''' |
- }); |
- |
- testChecker( |
- 'infer from RHS only if it wont conflict with overridden fields', { |
- '/main.dart': ''' |
- class A { |
- var x; |
- } |
- |
- class B extends A { |
- var x = 2; |
- } |
- |
- foo() { |
- String y = /*info:DynamicCast*/new B().x; |
- int z = /*info:DynamicCast*/new B().x; |
- } |
- ''' |
- }); |
- |
- testChecker( |
- 'infer from RHS only if it wont conflict with overridden fields 2', { |
- '/main.dart': ''' |
- class A { |
- final x; |
- } |
- |
- class B extends A { |
- final x = 2; |
- } |
- |
- foo() { |
- String y = /*severe:StaticTypeError*/new B().x; |
- int z = new B().x; |
- } |
- ''' |
- }); |
- |
- testChecker('infer correctly on multiple variables declared together', { |
- '/main.dart': ''' |
- class A { |
- var x, y = 2, z = "hi"; |
- } |
- |
- class B extends A { |
- var x = 2, y = 3, z, w = 2; |
- } |
- |
- foo() { |
- String s; |
- int i; |
- |
- s = /*info:DynamicCast*/new B().x; |
- s = /*severe:StaticTypeError*/new B().y; |
- s = new B().z; |
- s = /*severe:StaticTypeError*/new B().w; |
- |
- i = /*info:DynamicCast*/new B().x; |
- i = new B().y; |
- i = /*severe:StaticTypeError*/new B().z; |
- i = new B().w; |
- } |
- ''' |
- }); |
- |
- testChecker('infer consts transitively', { |
- '/b.dart': ''' |
- const b1 = 2; |
- ''', |
- '/a.dart': ''' |
- import 'main.dart'; |
- import 'b.dart'; |
- const a1 = m2; |
- const a2 = b1; |
- ''', |
- '/main.dart': ''' |
- import 'a.dart'; |
- const m1 = a1; |
- const m2 = a2; |
- |
- foo() { |
- int i; |
- i = m1; |
- } |
- ''' |
- }); |
- |
- testChecker('infer statics transitively', { |
- '/b.dart': ''' |
- final b1 = 2; |
- ''', |
- '/a.dart': ''' |
- import 'main.dart'; |
- import 'b.dart'; |
- final a1 = m2; |
- class A { |
- static final a2 = b1; |
- } |
- ''', |
- '/main.dart': ''' |
- import 'a.dart'; |
- final m1 = a1; |
- final m2 = A.a2; |
- |
- foo() { |
- int i; |
- i = m1; |
- } |
- ''' |
- }); |
- |
- testChecker('infer statics transitively 2', { |
- '/main.dart': ''' |
- const x1 = 1; |
- final x2 = 1; |
- final y1 = x1; |
- final y2 = x2; |
- |
- foo() { |
- int i; |
- i = y1; |
- i = y2; |
- } |
- ''' |
- }); |
- |
- testChecker('infer statics transitively 3', { |
- '/a.dart': ''' |
- const a1 = 3; |
- const a2 = 4; |
- class A { |
- a3; |
- } |
- ''', |
- '/main.dart': ''' |
- import 'a.dart' show a1, A; |
- import 'a.dart' as p show a2, A; |
- const t1 = 1; |
- const t2 = t1; |
- const t3 = a1; |
- const t4 = p.a2; |
- const t5 = A.a3; |
- const t6 = p.A.a3; |
- |
- foo() { |
- int i; |
- i = t1; |
- i = t2; |
- i = t3; |
- i = t4; |
- } |
- ''' |
- }); |
- |
- testChecker('infer statics with method invocations', { |
- '/a.dart': ''' |
- m3(String a, String b, [a1,a2]) {} |
- ''', |
- '/main.dart': ''' |
- import 'a.dart'; |
- class T { |
- static final T foo = m1(m2(m3('', ''))); |
- static T m1(String m) { return null; } |
- static String m2(e) { return ''; } |
- } |
- |
- |
- ''' |
- }); |
- |
- testChecker('downwards inference: miscellaneous', { |
- '/main.dart': ''' |
- typedef (T x); |
- class A<T> { |
- Function2<T> x; |
- A(this.x); |
- } |
- void main() { |
- { // Variables, nested literals |
- var x = "hello"; |
- var y = 3; |
- void f(List<Map<int, String>> l) {}; |
- f(/*info:InferredTypeLiteral*/[{y: x}]); |
- } |
- { |
- int f(int x) {}; |
- A<int> a = /*info:InferredTypeAllocation*/new A(f); |
- } |
- } |
- ''' |
- }); |
- |
- group('downwards inference on instance creations', () { |
- String info = 'info:InferredTypeAllocation'; |
- String code = ''' |
- class A<S, T> { |
- S x; |
- T y; |
- A(this.x, this.y); |
- A.named(this.x, this.y); |
- } |
- |
- class B<S, T> extends A<T, S> { |
- B(S y, T x) : super(x, y); |
- B.named(S y, T x) : super.named(x, y); |
- } |
- |
- class C<S> extends B<S, S> { |
- C(S a) : super(a, a); |
- C.named(S a) : super.named(a, a); |
- } |
- |
- class D<S, T> extends B<T, int> { |
- D(T a) : super(a, 3); |
- D.named(T a) : super.named(a, 3); |
- } |
- |
- class E<S, T> extends A<C<S>, T> { |
- E(T a) : super(null, a); |
- } |
- |
- class F<S, T> extends A<S, T> { |
- F(S x, T y, {List<S> a, List<T> b}) : super(x, y); |
- F.named(S x, T y, [S a, T b]) : super(a, b); |
- } |
- |
- void main() { |
- { |
- A<int, String> a0 = /*$info*/new A(3, "hello"); |
- A<int, String> a1 = /*$info*/new A.named(3, "hello"); |
- A<int, String> a2 = new A<int, String>(3, "hello"); |
- A<int, String> a3 = new A<int, String>.named(3, "hello"); |
- A<int, String> a4 = /*severe:StaticTypeError*/new A<int, dynamic>(3, "hello"); |
- A<int, String> a5 = /*severe:StaticTypeError*/new A<dynamic, dynamic>.named(3, "hello"); |
- } |
- { |
- A<int, String> a0 = /*severe:StaticTypeError*/new A("hello", 3); |
- A<int, String> a1 = /*severe:StaticTypeError*/new A.named("hello", 3); |
- } |
- { |
- A<int, String> a0 = /*$info*/new B("hello", 3); |
- A<int, String> a1 = /*$info*/new B.named("hello", 3); |
- A<int, String> a2 = new B<String, int>("hello", 3); |
- A<int, String> a3 = new B<String, int>.named("hello", 3); |
- A<int, String> a4 = /*severe:StaticTypeError*/new B<String, dynamic>("hello", 3); |
- A<int, String> a5 = /*severe:StaticTypeError*/new B<dynamic, dynamic>.named("hello", 3); |
- } |
- { |
- A<int, String> a0 = /*severe:StaticTypeError*/new B(3, "hello"); |
- A<int, String> a1 = /*severe:StaticTypeError*/new B.named(3, "hello"); |
- } |
- { |
- A<int, int> a0 = /*$info*/new C(3); |
- A<int, int> a1 = /*$info*/new C.named(3); |
- A<int, int> a2 = new C<int>(3); |
- A<int, int> a3 = new C<int>.named(3); |
- A<int, int> a4 = /*severe:StaticTypeError*/new C<dynamic>(3); |
- A<int, int> a5 = /*severe:StaticTypeError*/new C<dynamic>.named(3); |
- } |
- { |
- A<int, int> a0 = /*severe:StaticTypeError*/new C("hello"); |
- A<int, int> a1 = /*severe:StaticTypeError*/new C.named("hello"); |
- } |
- { |
- A<int, String> a0 = /*$info*/new D("hello"); |
- A<int, String> a1 = /*$info*/new D.named("hello"); |
- A<int, String> a2 = new D<int, String>("hello"); |
- A<int, String> a3 = new D<String, String>.named("hello"); |
- A<int, String> a4 = /*severe:StaticTypeError*/new D<num, dynamic>("hello"); |
- A<int, String> a5 = /*severe:StaticTypeError*/new D<dynamic, dynamic>.named("hello"); |
- } |
- { |
- A<int, String> a0 = /*severe:StaticTypeError*/new D(3); |
- A<int, String> a1 = /*severe:StaticTypeError*/new D.named(3); |
- } |
- { // Currently we only allow variable constraints. Test that we reject. |
- A<C<int>, String> a0 = /*severe:StaticTypeError*/new E("hello"); |
- } |
- { // Check named and optional arguments |
- A<int, String> a0 = /*$info*/new F(3, "hello", a: [3], b: ["hello"]); |
- A<int, String> a1 = /*severe:StaticTypeError*/new F(3, "hello", a: ["hello"], b:[3]); |
- A<int, String> a2 = /*$info*/new F.named(3, "hello", 3, "hello"); |
- A<int, String> a3 = /*$info*/new F.named(3, "hello"); |
- A<int, String> a4 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello", 3); |
- A<int, String> a5 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello"); |
- } |
- } |
- '''; |
- testChecker('infer downwards', {'/main.dart': code}); |
- }); |
- |
- group('downwards inference on list literals', () { |
- String info = "info:InferredTypeLiteral"; |
- String code = ''' |
- void foo([List<String> list1 = /*$info*/const [], |
- List<String> list2 = /*severe:StaticTypeError*/const [42]]) { |
- } |
- |
- void main() { |
- { |
- List<int> l0 = /*$info*/[]; |
- List<int> l1 = /*$info*/[3]; |
- List<int> l2 = /*severe:StaticTypeError*/["hello"]; |
- List<int> l3 = /*severe:StaticTypeError*/["hello", 3]; |
- } |
- { |
- List<dynamic> l0 = []; |
- List<dynamic> l1 = [3]; |
- List<dynamic> l2 = ["hello"]; |
- List<dynamic> l3 = ["hello", 3]; |
- } |
- { |
- List<int> l0 = /*severe:StaticTypeError*/<num>[]; |
- List<int> l1 = /*severe:StaticTypeError*/<num>[3]; |
- List<int> l2 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeError*/"hello"]; |
- List<int> l3 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeError*/"hello", 3]; |
- } |
- { |
- Iterable<int> i0 = /*$info*/[]; |
- Iterable<int> i1 = /*$info*/[3]; |
- Iterable<int> i2 = /*severe:StaticTypeError*/["hello"]; |
- Iterable<int> i3 = /*severe:StaticTypeError*/["hello", 3]; |
- } |
- { |
- const List<int> c0 = /*$info*/const []; |
- const List<int> c1 = /*$info*/const [3]; |
- const List<int> c2 = /*severe:StaticTypeError*/const ["hello"]; |
- const List<int> c3 = /*severe:StaticTypeError*/const ["hello", 3]; |
- } |
- } |
- '''; |
- testChecker('infer downwards', {'/main.dart': code}); |
- }); |
- |
- group('downwards inference on function arguments', () { |
- String info = "info:InferredTypeLiteral"; |
- String code = ''' |
- void f0(List<int> a) {}; |
- void f1({List<int> a}) {}; |
- void f2(Iterable<int> a) {}; |
- void f3(Iterable<Iterable<int>> a) {}; |
- void f4({Iterable<Iterable<int>> a}) {}; |
- void main() { |
- f0(/*$info*/[]); |
- f0(/*$info*/[3]); |
- f0(/*severe:StaticTypeError*/["hello"]); |
- f0(/*severe:StaticTypeError*/["hello", 3]); |
- |
- f1(a: /*$info*/[]); |
- f1(a: /*$info*/[3]); |
- f1(a: /*severe:StaticTypeError*/["hello"]); |
- f1(a: /*severe:StaticTypeError*/["hello", 3]); |
- |
- f2(/*$info*/[]); |
- f2(/*$info*/[3]); |
- f2(/*severe:StaticTypeError*/["hello"]); |
- f2(/*severe:StaticTypeError*/["hello", 3]); |
- |
- f3(/*$info*/[]); |
- f3(/*$info*/[[3]]); |
- f3(/*severe:StaticTypeError*/[["hello"]]); |
- f3(/*severe:StaticTypeError*/[["hello"], [3]]); |
- |
- f4(a: /*$info*/[]); |
- f4(a: /*$info*/[[3]]); |
- f4(a: /*severe:StaticTypeError*/[["hello"]]); |
- f4(a: /*severe:StaticTypeError*/[["hello"], [3]]); |
- } |
- '''; |
- testChecker('infer downwards', {'/main.dart': code}); |
- }); |
- |
- group('downwards inference on map literals', () { |
- String info = "info:InferredTypeLiteral"; |
- String code = ''' |
- void foo([Map<int, String> m1 = /*$info*/const {1: "hello"}, |
- Map<int, String> m1 = /*severe:StaticTypeError*/const {"hello": "world"}]) { |
- } |
- void main() { |
- { |
- Map<int, String> l0 = /*$info*/{}; |
- Map<int, String> l1 = /*$info*/{3: "hello"}; |
- Map<int, String> l2 = /*severe:StaticTypeError*/{"hello": "hello"}; |
- Map<int, String> l3 = /*severe:StaticTypeError*/{3: 3}; |
- Map<int, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3}; |
- } |
- { |
- Map<dynamic, dynamic> l0 = {}; |
- Map<dynamic, dynamic> l1 = {3: "hello"}; |
- Map<dynamic, dynamic> l2 = {"hello": "hello"}; |
- Map<dynamic, dynamic> l3 = {3: 3}; |
- Map<dynamic, dynamic> l4 = {3:"hello", "hello": 3}; |
- } |
- { |
- Map<dynamic, String> l0 = /*$info*/{}; |
- Map<dynamic, String> l1 = /*$info*/{3: "hello"}; |
- Map<dynamic, String> l2 = /*$info*/{"hello": "hello"}; |
- Map<dynamic, String> l3 = /*severe:StaticTypeError*/{3: 3}; |
- Map<dynamic, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3}; |
- } |
- { |
- Map<int, dynamic> l0 = /*$info*/{}; |
- Map<int, dynamic> l1 = /*$info*/{3: "hello"}; |
- Map<int, dynamic> l2 = /*severe:StaticTypeError*/{"hello": "hello"}; |
- Map<int, dynamic> l3 = /*$info*/{3: 3}; |
- Map<int, dynamic> l3 = /*severe:StaticTypeError*/{3:"hello", "hello": 3}; |
- } |
- { |
- Map<int, String> l0 = /*severe:StaticTypeError*/<num, dynamic>{}; |
- Map<int, String> l1 = /*severe:StaticTypeError*/<num, dynamic>{3: "hello"}; |
- Map<int, String> l3 = /*severe:StaticTypeError*/<num, dynamic>{3: 3}; |
- } |
- { |
- const Map<int, String> l0 = /*$info*/const {}; |
- const Map<int, String> l1 = /*$info*/const {3: "hello"}; |
- const Map<int, String> l2 = /*severe:StaticTypeError*/const {"hello": "hello"}; |
- const Map<int, String> l3 = /*severe:StaticTypeError*/const {3: 3}; |
- const Map<int, String> l4 = /*severe:StaticTypeError*/const {3:"hello", "hello": 3}; |
- } |
- } |
- '''; |
- testChecker('infer downwards', {'/main.dart': code}); |
- }); |
- |
- testChecker('downwards inference on function expressions', { |
- '/main.dart': ''' |
- typedef T Function2<S, T>(S x); |
- |
- void main () { |
- { |
- Function2<int, String> l0 = (int x) => null; |
- Function2<int, String> l1 = (int x) => "hello"; |
- Function2<int, String> l2 = /*severe:StaticTypeError*/(String x) => "hello"; |
- Function2<int, String> l3 = /*severe:StaticTypeError*/(int x) => 3; |
- Function2<int, String> l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return 3}; |
- } |
- { |
- Function2<int, String> l0 = /*info:InferredTypeClosure*/(x) => null; |
- Function2<int, String> l1 = /*info:InferredTypeClosure*/(x) => "hello"; |
- Function2<int, String> l2 = /*severe:StaticTypeError*/(x) => 3; |
- Function2<int, String> l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(x) {return 3}; |
- } |
- { |
- Function2<int, List<String>> l0 = (int x) => null; |
- Function2<int, List<String>> l1 = /*info:InferredTypeClosure*/(int x) => ["hello"]; |
- Function2<int, List<String>> l2 = /*severe:StaticTypeError*/(String x) => ["hello"]; |
- Function2<int, List<String>> l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) => [3]; |
- Function2<int, List<String>> l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return [3]}; |
- } |
- { |
- Function2<int, int> l0 = /*info:InferredTypeClosure*/(x) => x; |
- Function2<int, int> l1 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x+1; |
- Function2<int, String> l2 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => x; |
- Function2<int, String> l3 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3); |
- Function2<String, String> l4 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3); |
- } |
- } |
- ''' |
- }); |
- |
- testChecker('inferred initializing formal checks default value', { |
- '/main.dart': ''' |
- class Foo { |
- var x = 1; |
- Foo([this.x = /*severe:StaticTypeError*/"1"]); |
- }''' |
- }); |
- |
- group('quasi-generics', () { |
- testChecker('dart:math min/max', { |
- '/main.dart': ''' |
- import 'dart:math'; |
- |
- void printInt(int x) => print(x); |
- void printDouble(double x) => print(x); |
- |
- num myMax(num x, num y) => max(x, y); |
- |
- main() { |
- // Okay if static types match. |
- printInt(max(1, 2)); |
- printInt(min(1, 2)); |
- printDouble(max(1.0, 2.0)); |
- printDouble(min(1.0, 2.0)); |
- |
- // No help for user-defined functions from num->num->num. |
- printInt(/*info:DownCastImplicit*/myMax(1, 2)); |
- printInt(myMax(1, 2) as int); |
- |
- // Mixing int and double means return type is num. |
- printInt(/*info:DownCastImplicit*/max(1, 2.0)); |
- printInt(/*info:DownCastImplicit*/min(1, 2.0)); |
- printDouble(/*info:DownCastImplicit*/max(1, 2.0)); |
- printDouble(/*info:DownCastImplicit*/min(1, 2.0)); |
- |
- // Types other than int and double are not accepted. |
- printInt( |
- /*info:DownCastImplicit*/min( |
- /*severe:StaticTypeError*/"hi", |
- /*severe:StaticTypeError*/"there")); |
- } |
- ''' |
- }); |
- |
- testChecker('Iterable and Future', { |
- '/main.dart': ''' |
- import 'dart:async'; |
- |
- Future<int> make(int x) => (/*info:InferredTypeAllocation*/new Future(() => x)); |
- |
- main() { |
- Iterable<Future<int>> list = <int>[1, 2, 3].map(make); |
- Future<List<int>> results = Future.wait(list); |
- Future<String> results2 = results.then((List<int> list) |
- => list.fold('', (String x, int y) => x + y.toString())); |
- } |
- ''' |
- }); |
- }); |
-} |