| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(jmesserly): this file needs to be refactored, it's a port from | 5 library analyzer.test.src.task.strong.checker_test; |
| 6 // package:dev_compiler's tests | 6 |
| 7 /// General type checking tests | 7 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| 8 library test.src.task.strong.checker_test; | |
| 9 | |
| 10 import 'package:unittest/unittest.dart'; | |
| 11 | 8 |
| 12 import 'strong_test_helper.dart'; | 9 import 'strong_test_helper.dart'; |
| 13 | 10 |
| 14 void main() { | 11 void main() { |
| 15 testChecker('ternary operator', { | 12 initStrongModeTests(); |
| 16 '/main.dart': ''' | 13 defineReflectiveTests(CheckerTest); |
| 17 abstract class Comparable<T> { | 14 } |
| 18 int compareTo(T other); | 15 |
| 19 static int compare(Comparable a, Comparable b) => a.compareTo(b); | 16 @reflectiveTest |
| 20 } | 17 class CheckerTest { |
| 21 typedef int Comparator<T>(T a, T b); | 18 void test_awaitForInCastsStreamElementToVariable() { |
| 22 | 19 checkFile(''' |
| 23 typedef bool _Predicate<T>(T value); | 20 import 'dart:async'; |
| 24 | 21 main() async { |
| 25 class SplayTreeMap<K, V> { | 22 // Don't choke if sequence is not stream. |
| 26 Comparator<K> _comparator; | 23 await for (var i in /*error:FOR_IN_OF_INVALID_TYPE*/1234) {} |
| 27 _Predicate _validKey; | 24 |
| 28 | 25 // Dynamic cast. |
| 29 // Initializing _comparator needs a cast, since K may not always be | 26 await for (String /*info:DYNAMIC_CAST*/s in new Stream<dynamic>()) {} |
| 30 // Comparable. | 27 |
| 31 // Initializing _validKey shouldn't need a cast. Currently | 28 // Identity cast. |
| 32 // it requires inference to work because of dartbug.com/23381 | 29 await for (String s in new Stream<String>()) {} |
| 33 SplayTreeMap([int compare(K key1, K key2), | 30 |
| 34 bool isValidKey(potentialKey)]) { | 31 // Untyped. |
| 35 : _comparator = /*warning:DownCastComposite*/(compare == null) ? Com
parable.compare : compare, | 32 await for (var s in new Stream<String>()) {} |
| 36 _validKey = /*info:InferredType should be pass*/(isValidKey != nul
l) ? isValidKey : ((v) => true); | 33 |
| 37 _Predicate<Object> _v = /*warning:DownCastComposite*/(isValidKey !
= null) ? isValidKey : ((v) => true); | 34 // Downcast. |
| 38 _v = /*info:InferredType should be pass*/(isValidKey != null) ? _v
: ((v) => true); | 35 await for (int /*info:DOWN_CAST_IMPLICIT*/i in new Stream<num>()) {} |
| 39 } | 36 } |
| 40 } | 37 '''); |
| 41 void main() { | 38 } |
| 42 Object obj = 42; | 39 |
| 43 dynamic dyn = 42; | 40 void test_awaitForInCastsSupertypeSequenceToStream() { |
| 44 int i = 42; | 41 checkFile(''' |
| 45 | 42 main() async { |
| 46 // Check the boolean conversion of the condition. | 43 dynamic d; |
| 47 print((/*severe:StaticTypeError*/i) ? false : true); | 44 await for (var i in /*info:DYNAMIC_CAST*/d) {} |
| 48 print((/*info:DownCastImplicit*/obj) ? false : true); | 45 |
| 49 print((/*info:DynamicCast*/dyn) ? false : true); | 46 Object o; |
| 50 } | 47 await for (var i in /*info:DOWN_CAST_IMPLICIT*/o) {} |
| 51 ''' | 48 } |
| 52 }); | 49 '''); |
| 53 | 50 } |
| 54 testChecker('if/for/do/while statements use boolean conversion', { | 51 |
| 55 '/main.dart': ''' | 52 void test_binaryAndIndexOperators() { |
| 56 main() { | 53 checkFile(''' |
| 57 dynamic d = 42; | 54 class A { |
| 58 Object obj = 42; | 55 A operator *(B b) => null; |
| 59 int i = 42; | 56 A operator /(B b) => null; |
| 60 bool b = false; | 57 A operator ~/(B b) => null; |
| 61 | 58 A operator %(B b) => null; |
| 62 if (b) {} | 59 A operator +(B b) => null; |
| 63 if (/*info:DynamicCast*/dyn) {} | 60 A operator -(B b) => null; |
| 64 if (/*info:DownCastImplicit*/obj) {} | 61 A operator <<(B b) => null; |
| 65 if (/*severe:StaticTypeError*/i) {} | 62 A operator >>(B b) => null; |
| 66 | 63 A operator &(B b) => null; |
| 67 while (b) {} | 64 A operator ^(B b) => null; |
| 68 while (/*info:DynamicCast*/dyn) {} | 65 A operator |(B b) => null; |
| 69 while (/*info:DownCastImplicit*/obj) {} | 66 A operator[](B b) => null; |
| 70 while (/*severe:StaticTypeError*/i) {} | 67 } |
| 71 | 68 |
| 72 do {} while (b); | 69 class B { |
| 73 do {} while (/*info:DynamicCast*/dyn); | 70 A operator -(B b) => null; |
| 74 do {} while (/*info:DownCastImplicit*/obj); | 71 } |
| 75 do {} while (/*severe:StaticTypeError*/i); | 72 |
| 76 | 73 foo() => new A(); |
| 77 for (;b;) {} | 74 |
| 78 for (;/*info:DynamicCast*/dyn;) {} | 75 test() { |
| 79 for (;/*info:DownCastImplicit*/obj;) {} | 76 A a = new A(); |
| 80 for (;/*severe:StaticTypeError*/i;) {} | 77 B b = new B(); |
| 81 } | 78 var c = foo(); |
| 82 ''' | 79 a = a * b; |
| 83 }); | 80 a = a * /*info:DYNAMIC_CAST*/c; |
| 84 | 81 a = a / b; |
| 85 testChecker('dynamic invocation', { | 82 a = a ~/ b; |
| 86 '/main.dart': ''' | 83 a = a % b; |
| 87 | 84 a = a + b; |
| 88 class A { | 85 a = a + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/a; |
| 89 dynamic call(dynamic x) => x; | 86 a = a - b; |
| 90 } | 87 b = /*error:INVALID_ASSIGNMENT*/b - b; |
| 91 class B extends A { | 88 a = a << b; |
| 92 int call(int x) => x; | 89 a = a >> b; |
| 93 double col(double x) => x; | 90 a = a & b; |
| 94 } | 91 a = a ^ b; |
| 95 void main() { | 92 a = a | b; |
| 96 { | 93 c = (/*info:DYNAMIC_INVOKE*/c + b); |
| 97 B f = new B(); | 94 |
| 98 int x; | 95 String x = 'hello'; |
| 99 double y; | 96 int y = 42; |
| 100 // The analyzer has what I believe is a bug (dartbug.com/23252) which | 97 x = x + x; |
| 101 // causes the return type of calls to f to be treated as dynamic. | 98 x = x + /*info:DYNAMIC_CAST*/c; |
| 102 x = /*info:DynamicCast should be pass*/f(3); | 99 x = x + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/y; |
| 103 x = /*severe:StaticTypeError*/f.col(3.0); | 100 |
| 104 y = /*info:DynamicCast should be severe:StaticTypeError*/f(3); | 101 bool p = true; |
| 105 y = f.col(3.0); | 102 p = p && p; |
| 106 f(/*severe:StaticTypeError*/3.0); | 103 p = p && /*info:DYNAMIC_CAST*/c; |
| 107 f.col(/*severe:StaticTypeError*/3); | 104 p = (/*info:DYNAMIC_CAST*/c) && p; |
| 108 } | 105 p = (/*info:DYNAMIC_CAST*/c) && /*info:DYNAMIC_CAST*/c; |
| 109 { | 106 p = /*error:NON_BOOL_OPERAND*/y && p; |
| 110 Function f = new B(); | 107 p = c == y; |
| 111 int x; | 108 |
| 112 double y; | 109 a = a[b]; |
| 113 x = /*info:DynamicCast, info:DynamicInvoke*/f(3); | 110 a = a[/*info:DYNAMIC_CAST*/c]; |
| 114 x = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0); | 111 c = (/*info:DYNAMIC_INVOKE*/c[b]); |
| 115 y = /*info:DynamicCast, info:DynamicInvoke*/f(3); | 112 a[/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/y]; |
| 116 y = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0); | 113 } |
| 117 (/*info:DynamicInvoke*/f(3.0)); | 114 '''); |
| 118 (/*info:DynamicInvoke*/f.col(3)); | 115 } |
| 119 } | 116 |
| 120 { | 117 void test_callMethodOnFunctions() { |
| 121 A f = new B(); | 118 checkFile(r''' |
| 122 int x; | 119 void f(int x) => print(x); |
| 123 double y; | 120 main() { |
| 124 x = /*info:DynamicCast, info:DynamicInvoke*/f(3); | 121 f.call(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi'); |
| 125 y = /*info:DynamicCast, info:DynamicInvoke*/f(3); | 122 } |
| 126 (/*info:DynamicInvoke*/f(3.0)); | 123 '''); |
| 127 } | 124 } |
| 128 } | 125 |
| 129 ''' | 126 void test_castsInConditions() { |
| 130 }); | 127 checkFile(''' |
| 131 | 128 main() { |
| 132 testChecker('conversion and dynamic invoke', { | 129 bool b = true; |
| 133 '/helper.dart': ''' | 130 num x = b ? 1 : 2.3; |
| 134 dynamic toString = (int x) => x + 42; | 131 int y = /*info:ASSIGNMENT_CAST*/b ? 1 : 2.3; |
| 135 dynamic hashCode = "hello"; | 132 String z = !b ? "hello" : null; |
| 136 ''', | 133 z = b ? null : "hello"; |
| 137 '/main.dart': ''' | 134 } |
| 138 import 'helper.dart' as helper; | 135 '''); |
| 139 | 136 } |
| 140 class A { | 137 |
| 141 String x = "hello world"; | 138 void test_castsInConstantContexts() { |
| 142 | 139 checkFile(''' |
| 143 void baz1(y) => x + /*info:DynamicCast*/y; | 140 class A { |
| 144 static baz2(y) => /*info:DynamicInvoke*/y + y; | 141 static const num n = 3.0; |
| 145 } | 142 // The severe error is from constant evaluation where we know the |
| 146 | 143 // concrete type. |
| 147 void foo(String str) { | 144 static const int /*error:VARIABLE_TYPE_MISMATCH*/i = /*info:ASSIGNMENT_CAST*/n
; |
| 148 print(str); | 145 final int fi; |
| 149 } | 146 const A(num a) : this.fi = /*info:DOWN_CAST_IMPLICIT*/a; |
| 150 | 147 } |
| 151 class B { | 148 class B extends A { |
| 152 String toString([int arg]) => arg.toString(); | 149 const B(Object a) : super(/*info:DOWN_CAST_IMPLICIT*/a); |
| 153 } | 150 } |
| 154 | 151 void foo(Object o) { |
| 155 void bar(a) { | 152 var a = const A(/*info:DOWN_CAST_IMPLICIT, error:CONST_WITH_NON_CONSTANT_ARGUM
ENT, error:INVALID_CONSTANT*/o); |
| 156 foo(/*info:DynamicCast,info:DynamicInvoke*/a.x); | 153 } |
| 157 } | 154 '''); |
| 158 | 155 } |
| 159 baz() => new B(); | 156 |
| 160 | 157 void test_classOverrideOfGrandInterface_interfaceOfAbstractSuperclass() { |
| 161 typedef DynFun(x); | 158 checkFile(''' |
| 162 typedef StrFun(String x); | 159 class A {} |
| 163 | 160 class B {} |
| 164 var bar1 = bar; | 161 |
| 165 | 162 abstract class I1 { |
| 166 void main() { | 163 m(A a); |
| 167 var a = new A(); | 164 } |
| 168 bar(a); | 165 abstract class Base implements I1 {} |
| 169 (/*info:DynamicInvoke*/bar1(a)); | 166 |
| 170 var b = bar; | 167 class T1 extends Base { |
| 171 (/*info:DynamicInvoke*/b(a)); | 168 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 172 var f1 = foo; | 169 } |
| 173 f1("hello"); | 170 '''); |
| 174 dynamic f2 = foo; | 171 } |
| 175 (/*info:DynamicInvoke*/f2("hello")); | 172 |
| 176 DynFun f3 = foo; | 173 void test_classOverrideOfGrandInterface_interfaceOfConcreteSuperclass() { |
| 177 (/*info:DynamicInvoke*/f3("hello")); | 174 checkFile(''' |
| 178 (/*info:DynamicInvoke*/f3(42)); | 175 class A {} |
| 179 StrFun f4 = foo; | 176 class B {} |
| 180 f4("hello"); | 177 |
| 181 a.baz1("hello"); | 178 abstract class I1 { |
| 182 var b1 = a.baz1; | 179 m(A a); |
| 183 (/*info:DynamicInvoke*/b1("hello")); | 180 } |
| 184 A.baz2("hello"); | 181 |
| 185 var b2 = A.baz2; | 182 class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/Base |
| 186 (/*info:DynamicInvoke*/b2("hello")); | 183 implements I1 {} |
| 187 | 184 |
| 188 dynamic a1 = new B(); | 185 class T1 extends Base { |
| 189 (/*info:DynamicInvoke*/a1.x); | 186 // not reported technically because if the class is concrete, |
| 190 a1.toString(); | 187 // it should implement all its interfaces and hence it is |
| 191 (/*info:DynamicInvoke*/a1.toString(42)); | 188 // sufficient to check overrides against it. |
| 192 var toStringClosure = a1.toString; | 189 m(B a) {} |
| 193 (/*info:DynamicInvoke*/a1.toStringClosure()); | 190 } |
| 194 (/*info:DynamicInvoke*/a1.toStringClosure(42)); | 191 '''); |
| 195 (/*info:DynamicInvoke*/a1.toStringClosure("hello")); | 192 } |
| 196 a1.hashCode; | 193 |
| 197 | 194 void test_classOverrideOfGrandInterface_interfaceOfInterfaceOfChild() { |
| 198 dynamic toString = () => null; | 195 checkFile(''' |
| 199 (/*info:DynamicInvoke*/toString()); | 196 class A {} |
| 200 | 197 class B {} |
| 201 (/*info:DynamicInvoke*/helper.toString()); | 198 |
| 202 var toStringClosure2 = helper.toString; | 199 abstract class I1 { |
| 203 (/*info:DynamicInvoke*/toStringClosure2()); | 200 m(A a); |
| 204 int hashCode = /*info:DynamicCast*/helper.hashCode; | 201 } |
| 205 | 202 abstract class I2 implements I1 {} |
| 206 baz().toString(); | 203 |
| 207 baz().hashCode; | 204 class T1 implements I2 { |
| 208 } | 205 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 209 ''' | 206 } |
| 210 }); | 207 '''); |
| 211 | 208 } |
| 212 testChecker('Constructors', { | 209 |
| 213 '/main.dart': ''' | 210 void test_classOverrideOfGrandInterface_mixinOfInterfaceOfChild() { |
| 214 const num z = 25; | 211 checkFile(''' |
| 215 Object obj = "world"; | 212 class A {} |
| 216 | 213 class B {} |
| 217 class A { | 214 |
| 218 int x; | 215 abstract class M1 { |
| 219 String y; | 216 m(A a); |
| 220 | 217 } |
| 221 A(this.x) : this.y = /*severe:StaticTypeError*/42; | 218 abstract class I2 extends Object with M1 {} |
| 222 | 219 |
| 223 A.c1(p): this.x = /*info:DownCastImplicit*/z, this.y = /*info:DynamicCas
t*/p; | 220 class T1 implements I2 { |
| 224 | 221 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 225 A.c2(this.x, this.y); | 222 } |
| 226 | 223 '''); |
| 227 A.c3(/*severe:InvalidParameterDeclaration*/num this.x, String this.y); | 224 } |
| 228 } | 225 |
| 229 | 226 void test_classOverrideOfGrandInterface_superclassOfInterfaceOfChild() { |
| 230 class B extends A { | 227 checkFile(''' |
| 231 B() : super(/*severe:StaticTypeError*/"hello"); | 228 class A {} |
| 232 | 229 class B {} |
| 233 B.c2(int x, String y) : super.c2(/*severe:StaticTypeError*/y, | 230 |
| 234 /*severe:StaticTypeError*/x); | 231 abstract class I1 { |
| 235 | 232 m(A a); |
| 236 B.c3(num x, Object y) : super.c3(x, /*info:DownCastImplicit*/y); | 233 } |
| 237 } | 234 abstract class I2 extends I1 {} |
| 238 | 235 |
| 239 void main() { | 236 class T1 implements I2 { |
| 240 A a = new A.c2(/*info:DownCastImplicit*/z, /*severe:StaticTypeError*/z)
; | 237 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 241 var b = new B.c2(/*severe:StaticTypeError*/"hello", /*info:DownCastImpl
icit*/obj); | 238 } |
| 242 } | 239 '''); |
| 243 ''' | 240 } |
| 244 }); | 241 |
| 245 | 242 void test_compoundAssignments() { |
| 246 testChecker('Unbound variable', { | 243 checkFile(''' |
| 247 '/main.dart': ''' | 244 class A { |
| 248 void main() { | 245 A operator *(B b) => null; |
| 249 dynamic y = /*pass should be severe:StaticTypeError*/unboundVariable; | 246 A operator /(B b) => null; |
| 250 } | 247 A operator ~/(B b) => null; |
| 251 ''' | 248 A operator %(B b) => null; |
| 252 }); | 249 A operator +(B b) => null; |
| 253 | 250 A operator -(B b) => null; |
| 254 testChecker('Unbound type name', { | 251 A operator <<(B b) => null; |
| 255 '/main.dart': ''' | 252 A operator >>(B b) => null; |
| 256 void main() { | 253 A operator &(B b) => null; |
| 257 /*pass should be severe:StaticTypeError*/AToB y; | 254 A operator ^(B b) => null; |
| 258 } | 255 A operator |(B b) => null; |
| 259 ''' | 256 D operator [](B index) => null; |
| 260 }); | 257 void operator []=(B index, D value) => null; |
| 261 | 258 } |
| 262 testChecker('Ground type subtyping: dynamic is top', { | 259 |
| 263 '/main.dart': ''' | 260 class B { |
| 264 | 261 A operator -(B b) => null; |
| 265 class A {} | 262 } |
| 266 class B extends A {} | 263 |
| 267 | 264 class D { |
| 268 void main() { | 265 D operator +(D d) => null; |
| 269 dynamic y; | 266 } |
| 270 Object o; | 267 |
| 271 int i = 0; | 268 class SubA extends A {} |
| 272 double d = 0.0; | 269 class SubSubA extends SubA {} |
| 273 num n; | 270 |
| 274 A a; | 271 foo() => new A(); |
| 275 B b; | 272 |
| 276 y = o; | 273 test() { |
| 277 y = i; | 274 int x = 0; |
| 278 y = d; | 275 x += 5; |
| 279 y = n; | 276 x += /*error:INVALID_ASSIGNMENT*/3.14; |
| 280 y = a; | 277 |
| 281 y = b; | 278 double y = 0.0; |
| 282 } | 279 y += 5; |
| 283 ''' | 280 y += 3.14; |
| 284 }); | 281 |
| 285 | 282 num z = 0; |
| 286 testChecker('Ground type subtyping: dynamic downcasts', { | 283 z += 5; |
| 287 '/main.dart': ''' | 284 z += 3.14; |
| 288 | 285 |
| 289 class A {} | 286 x = /*info:DOWN_CAST_IMPLICIT*/x + z; |
| 290 class B extends A {} | 287 /*info:DOWN_CAST_IMPLICIT_ASSIGN*/x += z; |
| 291 | 288 y = y + z; |
| 292 void main() { | 289 y += z; |
| 293 dynamic y; | 290 |
| 294 Object o; | 291 dynamic w = 42; |
| 295 int i = 0; | 292 /*info:DOWN_CAST_IMPLICIT_ASSIGN*/x += /*info:DYNAMIC_CAST*/w; |
| 296 double d = 0.0; | 293 y += /*info:DYNAMIC_CAST*/w; |
| 297 num n; | 294 z += /*info:DYNAMIC_CAST*/w; |
| 298 A a; | 295 |
| 299 B b; | 296 A a = new A(); |
| 300 o = y; | 297 B b = new B(); |
| 301 i = /*info:DynamicCast*/y; | 298 var c = foo(); |
| 302 d = /*info:DynamicCast*/y; | 299 a = a * b; |
| 303 n = /*info:DynamicCast*/y; | 300 a *= b; |
| 304 a = /*info:DynamicCast*/y; | 301 a *= /*info:DYNAMIC_CAST*/c; |
| 305 b = /*info:DynamicCast*/y; | 302 a /= b; |
| 306 } | 303 a ~/= b; |
| 307 ''' | 304 a %= b; |
| 308 }); | 305 a += b; |
| 309 | 306 a += /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/a; |
| 310 testChecker('Ground type subtyping: assigning a class', { | 307 a -= b; |
| 311 '/main.dart': ''' | 308 b -= /*error:INVALID_ASSIGNMENT*/b; |
| 312 | 309 a <<= b; |
| 313 class A {} | 310 a >>= b; |
| 314 class B extends A {} | 311 a &= b; |
| 315 | 312 a ^= b; |
| 316 void main() { | 313 a |= b; |
| 317 dynamic y; | 314 /*info:DYNAMIC_INVOKE*/c += b; |
| 318 Object o; | 315 |
| 319 int i = 0; | 316 SubA sa; |
| 320 double d = 0.0; | 317 /*info:DOWN_CAST_IMPLICIT_ASSIGN*/sa += b; |
| 321 num n; | 318 SubSubA ssa = /*info:ASSIGNMENT_CAST,info:DOWN_CAST_IMPLICIT_ASSIGN*/sa += b; |
| 322 A a; | 319 |
| 323 B b; | 320 var d = new D(); |
| 324 y = a; | 321 a[b] += d; |
| 325 o = a; | 322 a[/*info:DYNAMIC_CAST*/c] += d; |
| 326 i = /*severe:StaticTypeError*/a; | 323 a[/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/z] += d; |
| 327 d = /*severe:StaticTypeError*/a; | 324 a[b] += /*info:DYNAMIC_CAST*/c; |
| 328 n = /*severe:StaticTypeError*/a; | 325 a[b] += /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/z; |
| 329 a = a; | 326 /*info:DYNAMIC_INVOKE,info:DYNAMIC_INVOKE*/c[b] += d; |
| 330 b = /*info:DownCastImplicit*/a; | 327 } |
| 331 } | 328 '''); |
| 332 ''' | 329 } |
| 333 }); | 330 |
| 334 | 331 void test_constantGenericTypeArg_explict() { |
| 335 testChecker('Ground type subtyping: assigning a subclass', { | 332 // Regression test for https://github.com/dart-lang/sdk/issues/26141 |
| 336 '/main.dart': ''' | 333 checkFile(''' |
| 337 | 334 abstract class Equality<R> {} |
| 338 class A {} | 335 abstract class EqualityBase<R> implements Equality<R> { |
| 339 class B extends A {} | 336 final C<R> c = const C<R>(); |
| 340 class C extends A {} | 337 const EqualityBase(); |
| 341 | 338 } |
| 342 void main() { | 339 class DefaultEquality<S> extends EqualityBase<S> { |
| 343 dynamic y; | 340 const DefaultEquality(); |
| 344 Object o; | 341 } |
| 345 int i = 0; | 342 class SetEquality<T> implements Equality<T> { |
| 346 double d = 0.0; | 343 final Equality<T> field = const DefaultEquality<T>(); |
| 347 num n; | 344 const SetEquality([Equality<T> inner = const DefaultEquality<T>()]); |
| 348 A a; | 345 } |
| 349 B b; | 346 class C<Q> { |
| 350 C c; | 347 final List<Q> list = const <Q>[]; |
| 351 y = b; | 348 final Map<Q, Iterable<Q>> m = const <Q, Iterable<Q>>{}; |
| 352 o = b; | 349 const C(); |
| 353 i = /*severe:StaticTypeError*/b; | 350 } |
| 354 d = /*severe:StaticTypeError*/b; | 351 main() { |
| 355 n = /*severe:StaticTypeError*/b; | 352 const SetEquality<String>(); |
| 356 a = b; | 353 } |
| 357 b = b; | 354 '''); |
| 358 c = /*severe:StaticTypeError*/b; | 355 } |
| 359 } | 356 |
| 360 ''' | 357 void test_constantGenericTypeArg_infer() { |
| 361 }); | 358 // Regression test for https://github.com/dart-lang/sdk/issues/26141 |
| 362 | 359 checkFile(''' |
| 363 testChecker('Ground type subtyping: interfaces', { | 360 abstract class Equality<Q> {} |
| 364 '/main.dart': ''' | 361 abstract class EqualityBase<R> implements Equality<R> { |
| 365 | 362 final C<R> c = /*info:INFERRED_TYPE_ALLOCATION*/const C(); |
| 366 class A {} | 363 const EqualityBase(); |
| 367 class B extends A {} | 364 } |
| 368 class C extends A {} | 365 class DefaultEquality<S> extends EqualityBase<S> { |
| 369 class D extends B implements C {} | 366 const DefaultEquality(); |
| 370 | 367 } |
| 371 void main() { | 368 class SetEquality<T> implements Equality<T> { |
| 372 A top; | 369 final Equality<T> field = const DefaultEquality(); |
| 373 B left; | 370 const SetEquality([Equality<T> inner = const DefaultEquality()]); |
| 374 C right; | 371 } |
| 375 D bot; | 372 class C<Q> { |
| 376 { | 373 final List<Q> list = /*info:INFERRED_TYPE_LITERAL*/const []; |
| 377 top = top; | 374 final Map<Q, Iterable<Q>> m = /*info:INFERRED_TYPE_LITERAL*/const {}; |
| 378 top = left; | 375 const C(); |
| 379 top = right; | 376 } |
| 380 top = bot; | 377 main() { |
| 381 } | 378 const SetEquality<String>(); |
| 382 { | 379 } |
| 383 left = /*info:DownCastImplicit*/top; | 380 '''); |
| 384 left = left; | 381 } |
| 385 left = /*severe:StaticTypeError*/right; | 382 |
| 386 left = bot; | 383 void test_compoundAssignment_returnsDynamic() { |
| 387 } | 384 checkFile(r''' |
| 388 { | 385 class Foo { |
| 389 right = /*info:DownCastImplicit*/top; | 386 operator +(other) => null; |
| 390 right = /*severe:StaticTypeError*/left; | 387 } |
| 391 right = right; | 388 |
| 392 right = bot; | 389 main() { |
| 393 } | 390 var foo = new Foo(); |
| 394 { | 391 foo = /*info:DYNAMIC_CAST*/foo + 1; |
| 395 bot = /*info:DownCastImplicit*/top; | 392 /*info:DYNAMIC_CAST*/foo += 1; |
| 396 bot = /*info:DownCastImplicit*/left; | 393 } |
| 397 bot = /*info:DownCastImplicit*/right; | 394 '''); |
| 398 bot = bot; | 395 } |
| 399 } | 396 |
| 400 } | 397 void test_constructorInvalid() { |
| 401 ''' | 398 // Regression test for https://github.com/dart-lang/sdk/issues/26695 |
| 402 }); | 399 checkFile(''' |
| 403 | 400 class A { |
| 404 testChecker('Function typing and subtyping: int and object', { | 401 B({ /*error:FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR*/this.test: 1.0 }) {} |
| 405 '/main.dart': ''' | 402 final double test = 0.0; |
| 406 | 403 } |
| 407 typedef Object Top(int x); // Top of the lattice | 404 '''); |
| 408 typedef int Left(int x); // Left branch | 405 } |
| 409 typedef int Left2(int x); // Left branch | 406 |
| 410 typedef Object Right(Object x); // Right branch | 407 void test_constructors() { |
| 411 typedef int Bot(Object x); // Bottom of the lattice | 408 checkFile(''' |
| 412 | 409 const num z = 25; |
| 413 Object top(int x) => x; | 410 Object obj = "world"; |
| 414 int left(int x) => x; | 411 |
| 415 Object right(Object x) => x; | 412 class A { |
| 416 int _bot(Object x) => /*info:DownCastImplicit*/x; | 413 int x; |
| 417 int bot(Object x) => x as int; | 414 String y; |
| 418 | 415 |
| 419 void main() { | 416 A(this.x) : this.y = /*error:FIELD_INITIALIZER_NOT_ASSIGNABLE*/42; |
| 420 { // Check typedef equality | 417 |
| 421 Left f = left; | 418 A.c1(p): this.x = /*info:DOWN_CAST_IMPLICIT*/z, this.y = /*info:DYNAMIC_CAST*/
p; |
| 422 Left2 g = f; | 419 |
| 423 } | 420 A.c2(this.x, this.y); |
| 424 { | 421 |
| 425 Top f; | 422 A.c3(/*error:INVALID_PARAMETER_DECLARATION*/num this.x, String this.y); |
| 426 f = top; | 423 } |
| 427 f = left; | 424 |
| 428 f = right; | 425 class B extends A { |
| 429 f = bot; | 426 B() : super(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/"hello"); |
| 430 } | 427 |
| 431 { | 428 B.c2(int x, String y) : super.c2(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/y, |
| 432 Left f; | 429 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/x); |
| 433 f = /*warning:DownCastComposite*/top; | 430 |
| 434 f = left; | 431 B.c3(num x, Object y) : super.c3(x, /*info:DOWN_CAST_IMPLICIT*/y); |
| 435 f = /*warning:DownCastComposite*/right; // Should we reject this? | 432 } |
| 436 f = bot; | 433 |
| 437 } | 434 void main() { |
| 438 { | 435 A a = new A.c2(/*info:DOWN_CAST_IMPLICIT*/z, /*error:ARGUMENT_TYPE_NOT_ASSIGN
ABLE*/z); |
| 439 Right f; | 436 var b = new B.c2(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/"hello", /*info:DOWN_C
AST_IMPLICIT*/obj); |
| 440 f = /*warning:DownCastComposite*/top; | 437 } |
| 441 f = /*warning:DownCastComposite*/left; // Should we reject this? | 438 '''); |
| 442 f = right; | 439 } |
| 443 f = bot; | 440 |
| 444 } | 441 void test_conversionAndDynamicInvoke() { |
| 445 { | 442 addFile( |
| 446 Bot f; | 443 ''' |
| 447 f = /*warning:DownCastComposite*/top; | 444 dynamic toString = (int x) => x + 42; |
| 448 f = /*warning:DownCastComposite*/left; | 445 dynamic hashCode = "hello"; |
| 449 f = /*warning:DownCastComposite*/right; | 446 ''', |
| 450 f = bot; | 447 name: '/helper.dart'); |
| 451 } | 448 checkFile(''' |
| 452 } | 449 import 'helper.dart' as helper; |
| 453 ''' | 450 |
| 454 }); | 451 class A { |
| 455 | 452 String x = "hello world"; |
| 456 testChecker('Function typing and subtyping: classes', { | 453 |
| 457 '/main.dart': ''' | 454 void baz1(y) { x + /*info:DYNAMIC_CAST*/y; } |
| 458 | 455 static baz2(y) => /*info:DYNAMIC_INVOKE*/y + y; |
| 459 class A {} | 456 } |
| 460 class B extends A {} | 457 |
| 461 | 458 void foo(String str) { |
| 462 typedef A Top(B x); // Top of the lattice | 459 print(str); |
| 463 typedef B Left(B x); // Left branch | 460 } |
| 464 typedef B Left2(B x); // Left branch | 461 |
| 465 typedef A Right(A x); // Right branch | 462 class B { |
| 466 typedef B Bot(A x); // Bottom of the lattice | 463 String toString([int arg]) => arg.toString(); |
| 467 | 464 } |
| 468 B left(B x) => x; | 465 |
| 469 B _bot(A x) => /*info:DownCastImplicit*/x; | 466 void bar(a) { |
| 470 B bot(A x) => x as B; | 467 foo(/*info:DYNAMIC_CAST,info:DYNAMIC_INVOKE*/a.x); |
| 471 A top(B x) => x; | 468 } |
| 472 A right(A x) => x; | 469 |
| 473 | 470 baz() => new B(); |
| 474 void main() { | 471 |
| 475 { // Check typedef equality | 472 typedef DynFun(x); |
| 476 Left f = left; | 473 typedef StrFun(String x); |
| 477 Left2 g = f; | 474 |
| 478 } | 475 var bar1 = bar; |
| 479 { | 476 |
| 480 Top f; | 477 void main() { |
| 481 f = top; | 478 var a = new A(); |
| 482 f = left; | 479 bar(a); |
| 483 f = right; | 480 (/*info:DYNAMIC_INVOKE*/bar1(a)); |
| 484 f = bot; | 481 var b = bar; |
| 485 } | 482 (/*info:DYNAMIC_INVOKE*/b(a)); |
| 486 { | 483 var f1 = foo; |
| 487 Left f; | 484 f1("hello"); |
| 488 f = /*warning:DownCastComposite*/top; | 485 dynamic f2 = foo; |
| 489 f = left; | 486 (/*info:DYNAMIC_INVOKE*/f2("hello")); |
| 490 f = /*warning:DownCastComposite*/right; // Should we reject this? | 487 DynFun f3 = foo; |
| 491 f = bot; | 488 (/*info:DYNAMIC_INVOKE*/f3("hello")); |
| 492 } | 489 (/*info:DYNAMIC_INVOKE*/f3(42)); |
| 493 { | 490 StrFun f4 = foo; |
| 494 Right f; | 491 f4("hello"); |
| 495 f = /*warning:DownCastComposite*/top; | 492 a.baz1("hello"); |
| 496 f = /*warning:DownCastComposite*/left; // Should we reject this? | 493 var b1 = a.baz1; |
| 497 f = right; | 494 (/*info:DYNAMIC_INVOKE*/b1("hello")); |
| 498 f = bot; | 495 A.baz2("hello"); |
| 499 } | 496 var b2 = A.baz2; |
| 500 { | 497 (/*info:DYNAMIC_INVOKE*/b2("hello")); |
| 501 Bot f; | 498 |
| 502 f = /*warning:DownCastComposite*/top; | 499 dynamic a1 = new B(); |
| 503 f = /*warning:DownCastComposite*/left; | 500 (/*info:DYNAMIC_INVOKE*/a1.x); |
| 504 f = /*warning:DownCastComposite*/right; | 501 a1.toString(); |
| 505 f = bot; | 502 (/*info:DYNAMIC_INVOKE*/a1.toString(42)); |
| 506 } | 503 var toStringClosure = a1.toString; |
| 507 } | 504 (/*info:DYNAMIC_INVOKE*/a1.toStringClosure()); |
| 508 ''' | 505 (/*info:DYNAMIC_INVOKE*/a1.toStringClosure(42)); |
| 509 }); | 506 (/*info:DYNAMIC_INVOKE*/a1.toStringClosure("hello")); |
| 510 | 507 a1.hashCode; |
| 511 testChecker('Function typing and subtyping: dynamic', { | 508 |
| 512 '/main.dart': ''' | 509 dynamic toString = () => null; |
| 513 | 510 (/*info:DYNAMIC_INVOKE*/toString()); |
| 514 class A {} | 511 |
| 515 | 512 (/*info:DYNAMIC_INVOKE*/helper.toString()); |
| 516 typedef dynamic Top(dynamic x); // Top of the lattice | 513 var toStringClosure2 = helper.toString; |
| 517 typedef dynamic Left(A x); // Left branch | 514 (/*info:DYNAMIC_INVOKE*/toStringClosure2()); |
| 518 typedef A Right(dynamic x); // Right branch | 515 int hashCode = /*info:DYNAMIC_CAST*/helper.hashCode; |
| 519 typedef A Bottom(A x); // Bottom of the lattice | 516 |
| 520 | 517 baz().toString(); |
| 521 dynamic left(A x) => x; | 518 baz().hashCode; |
| 522 A bot(A x) => x; | 519 } |
| 523 dynamic top(dynamic x) => x; | 520 '''); |
| 524 A right(dynamic x) => /*info:DynamicCast*/x; | 521 } |
| 525 | 522 |
| 526 void main() { | 523 void test_covariantOverride() { |
| 527 { | 524 _addMetaLibrary(); |
| 528 Top f; | 525 checkFile(r''' |
| 529 f = top; | 526 import 'meta.dart'; |
| 530 f = left; | 527 class C { |
| 531 f = right; | 528 num f(num x) => x; |
| 532 f = bot; | 529 } |
| 533 } | 530 class D extends C { |
| 534 { | 531 int f(@checked int x) => x; |
| 535 Left f; | 532 } |
| 536 f = /*warning:DownCastComposite*/top; | 533 class E extends D { |
| 537 f = left; | 534 int f(Object x) => /*info:DOWN_CAST_IMPLICIT*/x; |
| 538 f = /*warning:DownCastComposite*/right; | 535 } |
| 539 f = bot; | 536 class F extends E { |
| 540 } | 537 int f(@checked int x) => x; |
| 541 { | 538 } |
| 542 Right f; | 539 class G extends E implements D {} |
| 543 f = /*warning:DownCastComposite*/top; | 540 |
| 544 f = /*warning:DownCastComposite*/left; | 541 class D_error extends C { |
| 545 f = right; | 542 /*error:INVALID_METHOD_OVERRIDE*/int f(int x) => x; |
| 546 f = bot; | 543 } |
| 547 } | 544 class E_error extends D { |
| 548 { | 545 /*error:INVALID_METHOD_OVERRIDE*/int f(@checked double x) => 0; |
| 549 Bottom f; | 546 } |
| 550 f = /*warning:DownCastComposite*/top; | 547 class F_error extends E { |
| 551 f = /*warning:DownCastComposite*/left; | 548 /*error:INVALID_METHOD_OVERRIDE*/int f(@checked double x) => 0; |
| 552 f = /*warning:DownCastComposite*/right; | 549 } |
| 553 f = bot; | 550 class G_error extends E implements D { |
| 554 } | 551 /*error:INVALID_METHOD_OVERRIDE*/int f(@checked double x) => 0; |
| 555 } | 552 } |
| 556 ''' | 553 '''); |
| 557 }); | 554 } |
| 558 | 555 |
| 559 testChecker('Function typing and subtyping: function literal variance', { | 556 void test_covariantOverride_fields() { |
| 560 '/main.dart': ''' | 557 _addMetaLibrary(); |
| 561 | 558 checkFile(r''' |
| 562 class A {} | 559 import 'meta.dart'; |
| 563 class B extends A {} | 560 class A { |
| 564 | 561 get foo => ''; |
| 565 typedef T Function2<S, T>(S z); | 562 set foo(_) {} |
| 566 | 563 } |
| 567 A top(B x) => x; | 564 |
| 568 B left(B x) => x; | 565 class B extends A { |
| 569 A right(A x) => x; | 566 @checked num foo; |
| 570 B bot(A x) => x as B; | 567 } |
| 571 | 568 class C extends A { |
| 572 void main() { | 569 @checked @virtual num foo; |
| 573 { | 570 } |
| 574 Function2<B, A> f; | 571 class D extends C { |
| 575 f = top; | 572 @virtual int foo; |
| 576 f = left; | 573 } |
| 577 f = right; | 574 class E extends D { |
| 578 f = bot; | 575 @virtual /*error:INVALID_METHOD_OVERRIDE*/num foo; |
| 579 } | 576 } |
| 580 { | 577 '''); |
| 581 Function2<B, B> f; | 578 } |
| 582 f = /*warning:DownCastComposite*/top; | 579 |
| 583 f = left; | 580 void test_covariantOverride_leastUpperBound() { |
| 584 f = /*warning:DownCastComposite*/right; // Should we reject this? | 581 _addMetaLibrary(); |
| 585 f = bot; | 582 checkFile(r''' |
| 586 } | 583 import "meta.dart"; |
| 587 { | 584 abstract class Top {} |
| 588 Function2<A, A> f; | 585 abstract class Left implements Top {} |
| 589 f = /*warning:DownCastComposite*/top; | 586 abstract class Right implements Top {} |
| 590 f = /*warning:DownCastComposite*/left; // Should we reject this? | 587 abstract class Bottom implements Left, Right {} |
| 591 f = right; | 588 |
| 592 f = bot; | 589 abstract class TakesLeft { |
| 593 } | 590 m(Left x); |
| 594 { | 591 } |
| 595 Function2<A, B> f; | 592 abstract class TakesRight { |
| 596 f = /*warning:DownCastComposite*/top; | 593 m(Right x); |
| 597 f = /*warning:DownCastComposite*/left; | 594 } |
| 598 f = /*warning:DownCastComposite*/right; | 595 abstract class TakesTop implements TakesLeft, TakesRight { |
| 599 f = bot; | 596 m(Top x); // works today |
| 600 } | 597 } |
| 601 } | 598 abstract class TakesBottom implements TakesLeft, TakesRight { |
| 602 ''' | 599 // LUB(Left, Right) == Top, so this is an implicit cast from Top to Bottom. |
| 603 }); | 600 m(@checked Bottom x); |
| 604 | 601 } |
| 605 testChecker('Function typing and subtyping: function variable variance', { | 602 '''); |
| 606 '/main.dart': ''' | 603 } |
| 607 | 604 |
| 608 class A {} | 605 void test_covariantOverride_markerIsInherited() { |
| 609 class B extends A {} | 606 _addMetaLibrary(); |
| 610 | 607 checkFile(r''' |
| 611 typedef T Function2<S, T>(S z); | 608 import 'meta.dart'; |
| 612 | 609 class C { |
| 613 void main() { | 610 num f(@checked num x) => x; |
| 614 { | 611 } |
| 615 Function2<B, A> top; | 612 class D extends C { |
| 616 Function2<B, B> left; | 613 int f(int x) => x; |
| 617 Function2<A, A> right; | 614 } |
| 618 Function2<A, B> bot; | 615 class E extends D { |
| 619 | 616 int f(Object x) => /*info:DOWN_CAST_IMPLICIT*/x; |
| 620 top = right; | 617 } |
| 621 top = bot; | 618 class F extends E { |
| 622 top = top; | 619 int f(int x) => x; |
| 623 top = left; | 620 } |
| 624 | 621 class G extends E implements D {} |
| 625 left = /*warning:DownCastComposite*/top; | 622 |
| 626 left = left; | 623 class D_error extends C { |
| 627 left = /*warning:DownCastComposite*/right; // Should we reject this? | 624 /*error:INVALID_METHOD_OVERRIDE*/int f(String x) => 0; |
| 628 left = bot; | 625 } |
| 629 | 626 class E_error extends D { |
| 630 right = /*warning:DownCastComposite*/top; | 627 /*error:INVALID_METHOD_OVERRIDE*/int f(double x) => 0; |
| 631 right = /*warning:DownCastComposite*/left; // Should we reject this? | 628 } |
| 632 right = right; | 629 class F_error extends E { |
| 633 right = bot; | 630 /*error:INVALID_METHOD_OVERRIDE*/int f(double x) => 0; |
| 634 | 631 } |
| 635 bot = /*warning:DownCastComposite*/top; | 632 class G_error extends E implements D { |
| 636 bot = /*warning:DownCastComposite*/left; | 633 /*error:INVALID_METHOD_OVERRIDE*/int f(double x) => 0; |
| 637 bot = /*warning:DownCastComposite*/right; | 634 } |
| 638 bot = bot; | 635 '''); |
| 639 } | 636 } |
| 640 } | 637 |
| 641 ''' | 638 void test_dynamicInvocation() { |
| 642 }); | 639 checkFile(''' |
| 643 | 640 typedef dynamic A(dynamic x); |
| 644 testChecker('Function typing and subtyping: higher order function literals', { | 641 class B { |
| 645 '/main.dart': ''' | 642 int call(int x) => x; |
| 646 | 643 double col(double x) => x; |
| 647 class A {} | 644 } |
| 648 class B extends A {} | 645 void main() { |
| 649 | 646 { |
| 650 typedef T Function2<S, T>(S z); | 647 B f = new B(); |
| 651 | 648 int x; |
| 652 typedef A BToA(B x); // Top of the base lattice | 649 double y; |
| 653 typedef B AToB(A x); // Bot of the base lattice | 650 x = f(3); |
| 654 | 651 x = /*error:INVALID_ASSIGNMENT*/f.col(3.0); |
| 655 BToA top(AToB f) => f; | 652 y = /*error:INVALID_ASSIGNMENT*/f(3); |
| 656 AToB left(AToB f) => f; | 653 y = f.col(3.0); |
| 657 BToA right(BToA f) => f; | 654 f(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/3.0); |
| 658 AToB _bot(BToA f) => /*warning:DownCastComposite*/f; | 655 f.col(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/3); |
| 659 AToB bot(BToA f) => f as AToB; | 656 } |
| 660 | 657 { |
| 661 Function2<B, A> top(AToB f) => f; | 658 Function f = new B(); |
| 662 Function2<A, B> left(AToB f) => f; | 659 int x; |
| 663 Function2<B, A> right(BToA f) => f; | 660 double y; |
| 664 Function2<A, B> _bot(BToA f) => /*warning:DownCastComposite*/f; | 661 x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3); |
| 665 Function2<A, B> bot(BToA f) => f as Function2<A, B>; | 662 x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f.col(3.0); |
| 666 | 663 y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3); |
| 667 | 664 y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f.col(3.0); |
| 668 BToA top(Function2<A, B> f) => f; | 665 /*info:DYNAMIC_INVOKE*/f(3.0); |
| 669 AToB left(Function2<A, B> f) => f; | 666 // Through type propagation, we know f is actually a B, hence the |
| 670 BToA right(Function2<B, A> f) => f; | 667 // hint. |
| 671 AToB _bot(Function2<B, A> f) => /*warning:DownCastComposite*/f; | 668 /*info:DYNAMIC_INVOKE*/f.col(3); |
| 672 AToB bot(Function2<B, A> f) => f as AToB; | 669 } |
| 673 | 670 { |
| 674 void main() { | 671 A f = new B(); |
| 675 { | 672 int x; |
| 676 Function2<AToB, BToA> f; // Top | 673 double y; |
| 677 f = top; | 674 x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3); |
| 678 f = left; | 675 y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3); |
| 679 f = right; | 676 /*info:DYNAMIC_INVOKE*/f(3.0); |
| 680 f = bot; | 677 } |
| 681 } | 678 { |
| 682 { | 679 dynamic g = new B(); |
| 683 Function2<AToB, AToB> f; // Left | 680 /*info:DYNAMIC_INVOKE*/g.call(32.0); |
| 684 f = /*warning:DownCastComposite*/top; | 681 /*info:DYNAMIC_INVOKE*/g.col(42.0); |
| 685 f = left; | 682 /*info:DYNAMIC_INVOKE*/g.foo(42.0); |
| 686 f = /*warning:DownCastComposite*/right; // Should we reject this? | 683 /*info:DYNAMIC_INVOKE*/g.x; |
| 687 f = bot; | 684 A f = new B(); |
| 688 } | 685 /*info:DYNAMIC_INVOKE*/f.col(42.0); |
| 689 { | 686 /*info:DYNAMIC_INVOKE*/f.foo(42.0); |
| 690 Function2<BToA, BToA> f; // Right | 687 /*info:DYNAMIC_INVOKE*/f./*error:UNDEFINED_GETTER*/x; |
| 691 f = /*warning:DownCastComposite*/top; | 688 } |
| 692 f = /*warning:DownCastComposite*/left; // Should we reject this? | 689 } |
| 693 f = right; | 690 '''); |
| 694 f = bot; | 691 } |
| 695 } | 692 |
| 696 { | 693 void test_factoryConstructorDowncast() { |
| 697 Function2<BToA, AToB> f; // Bot | 694 checkFile(r''' |
| 698 f = bot; | 695 class Animal { |
| 699 f = /*warning:DownCastComposite*/left; | 696 Animal(); |
| 700 f = /*warning:DownCastComposite*/top; | 697 factory Animal.cat() => new Cat(); |
| 701 f = /*warning:DownCastComposite*/left; | 698 } |
| 702 } | 699 |
| 703 } | 700 class Cat extends Animal {} |
| 704 ''' | 701 |
| 705 }); | 702 void main() { |
| 706 | 703 Cat c = /*info:ASSIGNMENT_CAST*/new Animal.cat(); |
| 707 testChecker( | 704 c = /*error:STATIC_TYPE_ERROR*/new Animal(); |
| 708 'Function typing and subtyping: higher order function variables', { | 705 }'''); |
| 709 '/main.dart': ''' | 706 } |
| 710 | 707 |
| 711 class A {} | 708 void test_fieldFieldOverride() { |
| 712 class B extends A {} | 709 checkFile(''' |
| 713 | 710 class A {} |
| 714 typedef T Function2<S, T>(S z); | 711 class B extends A {} |
| 715 | 712 class C extends B {} |
| 716 void main() { | 713 |
| 717 { | 714 class Base { |
| 718 Function2<Function2<A, B>, Function2<B, A>> top; | 715 B f1; |
| 719 Function2<Function2<B, A>, Function2<B, A>> right; | 716 B f2; |
| 720 Function2<Function2<A, B>, Function2<A, B>> left; | 717 B f3; |
| 721 Function2<Function2<B, A>, Function2<A, B>> bot; | 718 B f4; |
| 722 | 719 } |
| 723 top = right; | 720 |
| 724 top = bot; | 721 class Child extends Base { |
| 725 top = top; | 722 /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/A f1; // invalid
for getter |
| 726 top = left; | 723 /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/C f2; // invalid
for setter |
| 727 | 724 /*error:INVALID_FIELD_OVERRIDE*/var f3; |
| 728 left = /*warning:DownCastComposite*/top; | 725 /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/dynamic f4; |
| 729 left = left; | 726 } |
| 730 left = | 727 |
| 731 /*warning:DownCastComposite should be severe:StaticTypeError*/right; | 728 class Child2 implements Base { |
| 732 left = bot; | 729 /*error:INVALID_METHOD_OVERRIDE*/A f1; // invalid for getter |
| 733 | 730 /*error:INVALID_METHOD_OVERRIDE*/C f2; // invalid for setter |
| 734 right = /*warning:DownCastComposite*/top; | 731 var f3; |
| 735 right = | 732 /*error:INVALID_METHOD_OVERRIDE*/dynamic f4; |
| 736 /*warning:DownCastComposite should be severe:StaticTypeError*/left; | 733 } |
| 737 right = right; | 734 '''); |
| 738 right = bot; | 735 } |
| 739 | 736 |
| 740 bot = /*warning:DownCastComposite*/top; | 737 void test_fieldGetterOverride() { |
| 741 bot = /*warning:DownCastComposite*/left; | 738 checkFile(''' |
| 742 bot = /*warning:DownCastComposite*/right; | 739 class A {} |
| 743 bot = bot; | 740 class B extends A {} |
| 744 } | 741 class C extends B {} |
| 742 |
| 743 abstract class Base { |
| 744 B f1; |
| 745 B f2; |
| 746 B f3; |
| 747 B f4; |
| 748 } |
| 749 |
| 750 class Child extends Base { |
| 751 /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/A get f1 => null
; |
| 752 /*error:INVALID_FIELD_OVERRIDE*/C get f2 => null; |
| 753 /*error:INVALID_FIELD_OVERRIDE*/get f3 => null; |
| 754 /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/dynamic get f4 =
> null; |
| 755 } |
| 756 |
| 757 class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR*/Child2 implement
s Base { |
| 758 /*error:INVALID_METHOD_OVERRIDE*/A get f1 => null; |
| 759 C get f2 => null; |
| 760 get f3 => null; |
| 761 /*error:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null; |
| 762 } |
| 763 '''); |
| 764 } |
| 765 |
| 766 void test_fieldOverride_fuzzyArrows() { |
| 767 checkFile(''' |
| 768 typedef void ToVoid<T>(T x); |
| 769 class F { |
| 770 final ToVoid<dynamic> f = null; |
| 771 final ToVoid<int> g = null; |
| 772 } |
| 773 |
| 774 class G extends F { |
| 775 /*error:INVALID_FIELD_OVERRIDE*/final ToVoid<int> f = null; |
| 776 /*error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/final ToVoid<dy
namic> g = null; |
| 777 } |
| 778 |
| 779 class H implements F { |
| 780 final ToVoid<int> f = null; |
| 781 /*error:INVALID_METHOD_OVERRIDE*/final ToVoid<dynamic> g = null; |
| 782 } |
| 783 '''); |
| 784 } |
| 785 |
| 786 void test_fieldOverride_virtual() { |
| 787 _addMetaLibrary(); |
| 788 checkFile(r''' |
| 789 import 'meta.dart'; |
| 790 class C { |
| 791 @virtual int x; |
| 792 } |
| 793 class OverrideGetter extends C { |
| 794 int get x => 42; |
| 795 } |
| 796 class OverrideSetter extends C { |
| 797 set x(int v) {} |
| 798 } |
| 799 class OverrideBoth extends C { |
| 800 int get x => 42; |
| 801 set x(int v) {} |
| 802 } |
| 803 class OverrideWithField extends C { |
| 804 int x; |
| 805 |
| 806 // expose the hidden storage slot |
| 807 int get superX => super.x; |
| 808 set superX(int v) { super.x = v; } |
| 809 } |
| 810 class VirtualNotInherited extends OverrideWithField { |
| 811 /*error:INVALID_FIELD_OVERRIDE*/int x; |
| 812 } |
| 813 '''); |
| 814 } |
| 815 |
| 816 void test_fieldSetterOverride() { |
| 817 checkFile(''' |
| 818 class A {} |
| 819 class B extends A {} |
| 820 class C extends B {} |
| 821 |
| 822 class Base { |
| 823 B f1; |
| 824 B f2; |
| 825 B f3; |
| 826 B f4; |
| 827 B f5; |
| 828 } |
| 829 |
| 830 class Child extends Base { |
| 831 /*error:INVALID_FIELD_OVERRIDE*/B get f1 => null; |
| 832 /*error:INVALID_FIELD_OVERRIDE*/B get f2 => null; |
| 833 /*error:INVALID_FIELD_OVERRIDE*/B get f3 => null; |
| 834 /*error:INVALID_FIELD_OVERRIDE*/B get f4 => null; |
| 835 /*error:INVALID_FIELD_OVERRIDE*/B get f5 => null; |
| 836 |
| 837 /*error:INVALID_FIELD_OVERRIDE*/void set f1(A value) {} |
| 838 /*error:INVALID_FIELD_OVERRIDE,error:INVALID_METHOD_OVERRIDE*/void set f2(C va
lue) {} |
| 839 /*error:INVALID_FIELD_OVERRIDE*/void set f3(value) {} |
| 840 /*error:INVALID_FIELD_OVERRIDE*/void set f4(dynamic value) {} |
| 841 /*error:INVALID_FIELD_OVERRIDE*/set f5(B value) {} |
| 842 } |
| 843 |
| 844 class Child2 implements Base { |
| 845 B get f1 => null; |
| 846 B get f2 => null; |
| 847 B get f3 => null; |
| 848 B get f4 => null; |
| 849 B get f5 => null; |
| 850 |
| 851 void set f1(A value) {} |
| 852 /*error:INVALID_METHOD_OVERRIDE*/void set f2(C value) {} |
| 853 void set f3(value) {} |
| 854 void set f4(dynamic value) {} |
| 855 set f5(B value) {} |
| 856 } |
| 857 '''); |
| 858 } |
| 859 |
| 860 void test_forInCastsIterateElementToVariable() { |
| 861 checkFile(''' |
| 862 main() { |
| 863 // Don't choke if sequence is not iterable. |
| 864 for (var i in /*error:FOR_IN_OF_INVALID_TYPE*/1234) {} |
| 865 |
| 866 // Dynamic cast. |
| 867 for (String /*info:DYNAMIC_CAST*/s in <dynamic>[]) {} |
| 868 |
| 869 // Identity cast. |
| 870 for (String s in <String>[]) {} |
| 871 |
| 872 // Untyped. |
| 873 for (var s in <String>[]) {} |
| 874 |
| 875 // Downcast. |
| 876 for (int /*info:DOWN_CAST_IMPLICIT*/i in <num>[]) {} |
| 877 } |
| 878 '''); |
| 879 } |
| 880 |
| 881 void test_forInCastsSupertypeSequenceToIterate() { |
| 882 checkFile(''' |
| 883 main() { |
| 884 dynamic d; |
| 885 for (var i in /*info:DYNAMIC_CAST*/d) {} |
| 886 |
| 887 Object o; |
| 888 for (var i in /*info:DOWN_CAST_IMPLICIT*/o) {} |
| 889 } |
| 890 '''); |
| 891 } |
| 892 |
| 893 void test_forLoopVariable() { |
| 894 checkFile(''' |
| 895 foo() { |
| 896 for (int i = 0; i < 10; i++) { |
| 897 i = /*error:INVALID_ASSIGNMENT*/"hi"; |
| 898 } |
| 899 } |
| 900 bar() { |
| 901 for (var i = 0; i < 10; i++) { |
| 902 int j = i + 1; |
| 903 } |
| 904 } |
| 905 '''); |
| 906 } |
| 907 |
| 908 void test_functionModifiers_async() { |
| 909 checkFile(''' |
| 910 import 'dart:async'; |
| 911 import 'dart:math' show Random; |
| 912 |
| 913 dynamic x; |
| 914 |
| 915 foo1() async => x; |
| 916 Future foo2() async => x; |
| 917 Future<int> foo3() async => x; |
| 918 Future<int> foo4() async => new Future<int>.value(/*info:DYNAMIC_CAST*/x); |
| 919 Future<int> foo5() async => |
| 920 /*error:RETURN_OF_INVALID_TYPE*/new Future<String>.value(/*info:DYNAMIC_CAST
*/x); |
| 921 |
| 922 bar1() async { return x; } |
| 923 Future bar2() async { return x; } |
| 924 Future<int> bar3() async { return x; } |
| 925 Future<int> bar4() async { return new Future<int>.value(/*info:DYNAMIC_CAST*/x);
} |
| 926 Future<int> bar5() async { |
| 927 return /*error:RETURN_OF_INVALID_TYPE*/new Future<String>.value(/*info:DYNAMIC
_CAST*/x); |
| 928 } |
| 929 |
| 930 int y; |
| 931 Future<int> z; |
| 932 |
| 933 baz() async { |
| 934 int a = /*info:DYNAMIC_CAST*/await x; |
| 935 int b = await y; |
| 936 int c = await z; |
| 937 String d = /*error:INVALID_ASSIGNMENT*/await z; |
| 938 } |
| 939 |
| 940 Future<bool> get issue_ddc_264 async { |
| 941 await 42; |
| 942 if (new Random().nextBool()) { |
| 943 return true; |
| 944 } else { |
| 945 return new Future<bool>.value(false); |
| 946 } |
| 947 } |
| 948 |
| 949 |
| 950 Future<String> issue_sdk_26404() async { |
| 951 return (1 > 0) ? new Future<String>.value('hello') : "world"; |
| 952 } |
| 953 '''); |
| 954 } |
| 955 |
| 956 void test_functionModifiers_asyncStar() { |
| 957 checkFile(''' |
| 958 import 'dart:async'; |
| 959 |
| 960 dynamic x; |
| 961 |
| 962 bar1() async* { yield x; } |
| 963 Stream bar2() async* { yield x; } |
| 964 Stream<int> bar3() async* { yield /*info:DYNAMIC_CAST*/x; } |
| 965 Stream<int> bar4() async* { yield /*error:YIELD_OF_INVALID_TYPE*/new Stream<int>
(); } |
| 966 |
| 967 baz1() async* { yield* /*info:DYNAMIC_CAST*/x; } |
| 968 Stream baz2() async* { yield* /*info:DYNAMIC_CAST*/x; } |
| 969 Stream<int> baz3() async* { yield* /*warning:DOWN_CAST_COMPOSITE*/x; } |
| 970 Stream<int> baz4() async* { yield* new Stream<int>(); } |
| 971 Stream<int> baz5() async* { yield* /*info:INFERRED_TYPE_ALLOCATION*/new Stream()
; } |
| 972 '''); |
| 973 } |
| 974 |
| 975 void test_functionModifiers_syncStar() { |
| 976 checkFile(''' |
| 977 dynamic x; |
| 978 |
| 979 bar1() sync* { yield x; } |
| 980 Iterable bar2() sync* { yield x; } |
| 981 Iterable<int> bar3() sync* { yield /*info:DYNAMIC_CAST*/x; } |
| 982 Iterable<int> bar4() sync* { yield /*error:YIELD_OF_INVALID_TYPE*/bar3(); } |
| 983 |
| 984 baz1() sync* { yield* /*info:DYNAMIC_CAST*/x; } |
| 985 Iterable baz2() sync* { yield* /*info:DYNAMIC_CAST*/x; } |
| 986 Iterable<int> baz3() sync* { yield* /*warning:DOWN_CAST_COMPOSITE*/x; } |
| 987 Iterable<int> baz4() sync* { yield* bar3(); } |
| 988 Iterable<int> baz5() sync* { yield* /*info:INFERRED_TYPE_ALLOCATION*/new List();
} |
| 989 '''); |
| 990 } |
| 991 |
| 992 void test_functionTypingAndSubtyping_classes() { |
| 993 checkFile(''' |
| 994 class A {} |
| 995 class B extends A {} |
| 996 |
| 997 typedef A Top(B x); // Top of the lattice |
| 998 typedef B Left(B x); // Left branch |
| 999 typedef B Left2(B x); // Left branch |
| 1000 typedef A Right(A x); // Right branch |
| 1001 typedef B Bot(A x); // Bottom of the lattice |
| 1002 |
| 1003 B left(B x) => x; |
| 1004 B bot_(A x) => /*info:DOWN_CAST_IMPLICIT*/x; |
| 1005 B bot(A x) => x as B; |
| 1006 A top(B x) => x; |
| 1007 A right(A x) => x; |
| 1008 |
| 1009 void main() { |
| 1010 { // Check typedef equality |
| 1011 Left f = left; |
| 1012 Left2 g = f; |
| 1013 } |
| 1014 { |
| 1015 Top f; |
| 1016 f = top; |
| 1017 f = left; |
| 1018 f = right; |
| 1019 f = bot; |
| 1020 } |
| 1021 { |
| 1022 Left f; |
| 1023 f = /*error:STATIC_TYPE_ERROR*/top; |
| 1024 f = left; |
| 1025 f = /*error:INVALID_ASSIGNMENT*/right; |
| 1026 f = bot; |
| 1027 } |
| 1028 { |
| 1029 Right f; |
| 1030 f = /*error:STATIC_TYPE_ERROR*/top; |
| 1031 f = /*error:INVALID_ASSIGNMENT*/left; |
| 1032 f = right; |
| 1033 f = bot; |
| 1034 } |
| 1035 { |
| 1036 Bot f; |
| 1037 f = /*error:STATIC_TYPE_ERROR*/top; |
| 1038 f = /*error:STATIC_TYPE_ERROR*/left; |
| 1039 f = /*error:STATIC_TYPE_ERROR*/right; |
| 1040 f = bot; |
| 1041 } |
| 1042 } |
| 1043 '''); |
| 1044 } |
| 1045 |
| 1046 void test_functionTypingAndSubtyping_dynamic() { |
| 1047 checkFile(''' |
| 1048 class A {} |
| 1049 |
| 1050 typedef dynamic Top(dynamic x); // Top of the lattice |
| 1051 typedef dynamic Left(A x); // Left branch |
| 1052 typedef A Right(dynamic x); // Right branch |
| 1053 typedef A Bottom(A x); // Bottom of the lattice |
| 1054 |
| 1055 void main() { |
| 1056 Top top; |
| 1057 Left left; |
| 1058 Right right; |
| 1059 Bottom bot; |
| 1060 { |
| 1061 Top f; |
| 1062 f = top; |
| 1063 f = left; |
| 1064 f = right; |
| 1065 f = bot; |
| 1066 } |
| 1067 { |
| 1068 Left f; |
| 1069 f = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 1070 f = left; |
| 1071 f = /*error:INVALID_ASSIGNMENT*/right; |
| 1072 f = bot; |
| 1073 } |
| 1074 { |
| 1075 Right f; |
| 1076 f = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 1077 f = /*error:INVALID_ASSIGNMENT*/left; |
| 1078 f = right; |
| 1079 f = bot; |
| 1080 } |
| 1081 { |
| 1082 Bottom f; |
| 1083 f = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 1084 f = /*warning:DOWN_CAST_COMPOSITE*/left; |
| 1085 f = /*warning:DOWN_CAST_COMPOSITE*/right; |
| 1086 f = bot; |
| 1087 } |
| 1088 } |
| 1089 '''); |
| 1090 } |
| 1091 |
| 1092 void test_functionTypingAndSubtyping_dynamic_knownFunctions() { |
| 1093 // Our lattice should look like this: |
| 1094 // |
| 1095 // |
| 1096 // Bot -> Top |
| 1097 // / \ |
| 1098 // A -> Top Bot -> A |
| 1099 // / \ / |
| 1100 // Top -> Top A -> A |
| 1101 // \ / |
| 1102 // Top -> A |
| 1103 // |
| 1104 // Note that downcasts of known functions are promoted to |
| 1105 // static type errors, since they cannot succeed. |
| 1106 // This makes some of what look like downcasts turn into |
| 1107 // type errors below. |
| 1108 checkFile(''' |
| 1109 class A {} |
| 1110 |
| 1111 typedef dynamic BotTop(dynamic x); |
| 1112 typedef dynamic ATop(A x); |
| 1113 typedef A BotA(dynamic x); |
| 1114 typedef A AA(A x); |
| 1115 typedef A TopA(Object x); |
| 1116 typedef dynamic TopTop(Object x); |
| 1117 |
| 1118 dynamic aTop(A x) => x; |
| 1119 A aa(A x) => x; |
| 1120 dynamic topTop(dynamic x) => x; |
| 1121 A topA(dynamic x) => /*info:DYNAMIC_CAST*/x; |
| 1122 void apply/*<T>*/(/*=T*/ f0, /*=T*/ f1, /*=T*/ f2, |
| 1123 /*=T*/ f3, /*=T*/ f4, /*=T*/ f5) {} |
| 1124 void main() { |
| 1125 BotTop botTop; |
| 1126 BotA botA; |
| 1127 { |
| 1128 BotTop f; |
| 1129 f = topA; |
| 1130 f = topTop; |
| 1131 f = aa; |
| 1132 f = aTop; |
| 1133 f = botA; |
| 1134 f = botTop; |
| 1135 apply/*<BotTop>*/( |
| 1136 topA, |
| 1137 topTop, |
| 1138 aa, |
| 1139 aTop, |
| 1140 botA, |
| 1141 botTop |
| 1142 ); |
| 1143 apply/*<BotTop>*/( |
| 1144 (dynamic x) => new A(), |
| 1145 (dynamic x) => (x as Object), |
| 1146 (A x) => x, |
| 1147 (A x) => null, |
| 1148 botA, |
| 1149 botTop |
| 1150 ); |
| 1151 } |
| 1152 { |
| 1153 ATop f; |
| 1154 f = topA; |
| 1155 f = topTop; |
| 1156 f = aa; |
| 1157 f = aTop; |
| 1158 f = /*error:INVALID_ASSIGNMENT*/botA; |
| 1159 f = /*warning:DOWN_CAST_COMPOSITE*/botTop; |
| 1160 apply/*<ATop>*/( |
| 1161 topA, |
| 1162 topTop, |
| 1163 aa, |
| 1164 aTop, |
| 1165 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA, |
| 1166 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1167 ); |
| 1168 apply/*<ATop>*/( |
| 1169 (dynamic x) => new A(), |
| 1170 (dynamic x) => (x as Object), |
| 1171 (A x) => x, |
| 1172 (A x) => null, |
| 1173 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA, |
| 1174 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1175 ); |
| 1176 } |
| 1177 { |
| 1178 BotA f; |
| 1179 f = topA; |
| 1180 f = /*error:INVALID_ASSIGNMENT*/topTop; |
| 1181 f = aa; |
| 1182 f = /*error:INVALID_ASSIGNMENT*/aTop; |
| 1183 f = botA; |
| 1184 f = /*warning:DOWN_CAST_COMPOSITE*/botTop; |
| 1185 apply/*<BotA>*/( |
| 1186 topA, |
| 1187 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/topTop, |
| 1188 aa, |
| 1189 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/aTop, |
| 1190 botA, |
| 1191 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1192 ); |
| 1193 apply/*<BotA>*/( |
| 1194 (dynamic x) => new A(), |
| 1195 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(dynamic x) => (x as Object), |
| 1196 (A x) => x, |
| 1197 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(A x) => (/*info:UNNECESSARY_CAST*
/x as Object), |
| 1198 botA, |
| 1199 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1200 ); |
| 1201 } |
| 1202 { |
| 1203 AA f; |
| 1204 f = topA; |
| 1205 f = /*error:INVALID_ASSIGNMENT*/topTop; |
| 1206 f = aa; |
| 1207 f = /*error:STATIC_TYPE_ERROR*/aTop; // known function |
| 1208 f = /*warning:DOWN_CAST_COMPOSITE*/botA; |
| 1209 f = /*warning:DOWN_CAST_COMPOSITE*/botTop; |
| 1210 apply/*<AA>*/( |
| 1211 topA, |
| 1212 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/topTop, |
| 1213 aa, |
| 1214 /*error:STATIC_TYPE_ERROR*/aTop, // known function |
| 1215 /*warning:DOWN_CAST_COMPOSITE*/botA, |
| 1216 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1217 ); |
| 1218 apply/*<AA>*/( |
| 1219 (dynamic x) => new A(), |
| 1220 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(dynamic x) => (x as Object), |
| 1221 (A x) => x, |
| 1222 /*error:STATIC_TYPE_ERROR*/(A x) => (/*info:UNNECESSARY_CAST*/x as Objec
t), // known function |
| 1223 /*warning:DOWN_CAST_COMPOSITE*/botA, |
| 1224 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1225 ); |
| 1226 } |
| 1227 { |
| 1228 TopTop f; |
| 1229 f = topA; |
| 1230 f = topTop; |
| 1231 f = /*error:INVALID_ASSIGNMENT*/aa; |
| 1232 f = /*error:STATIC_TYPE_ERROR*/aTop; // known function |
| 1233 f = /*error:INVALID_ASSIGNMENT*/botA; |
| 1234 f = /*warning:DOWN_CAST_COMPOSITE*/botTop; |
| 1235 apply/*<TopTop>*/( |
| 1236 topA, |
| 1237 topTop, |
| 1238 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/aa, |
| 1239 /*error:STATIC_TYPE_ERROR*/aTop, // known function |
| 1240 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA, |
| 1241 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1242 ); |
| 1243 apply/*<TopTop>*/( |
| 1244 (dynamic x) => new A(), |
| 1245 (dynamic x) => (x as Object), |
| 1246 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/(A x) => x, |
| 1247 /*error:STATIC_TYPE_ERROR*/(A x) => (/*info:UNNECESSARY_CAST*/x as Objec
t), // known function |
| 1248 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/botA, |
| 1249 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1250 ); |
| 1251 } |
| 1252 { |
| 1253 TopA f; |
| 1254 f = topA; |
| 1255 f = /*error:STATIC_TYPE_ERROR*/topTop; // known function |
| 1256 f = /*error:STATIC_TYPE_ERROR*/aa; // known function |
| 1257 f = /*error:STATIC_TYPE_ERROR*/aTop; // known function |
| 1258 f = /*warning:DOWN_CAST_COMPOSITE*/botA; |
| 1259 f = /*warning:DOWN_CAST_COMPOSITE*/botTop; |
| 1260 apply/*<TopA>*/( |
| 1261 topA, |
| 1262 /*error:STATIC_TYPE_ERROR*/topTop, // known function |
| 1263 /*error:STATIC_TYPE_ERROR*/aa, // known function |
| 1264 /*error:STATIC_TYPE_ERROR*/aTop, // known function |
| 1265 /*warning:DOWN_CAST_COMPOSITE*/botA, |
| 1266 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1267 ); |
| 1268 apply/*<TopA>*/( |
| 1269 (dynamic x) => new A(), |
| 1270 /*error:STATIC_TYPE_ERROR*/(dynamic x) => (x as Object), // known functi
on |
| 1271 /*error:STATIC_TYPE_ERROR*/(A x) => x, // known function |
| 1272 /*error:STATIC_TYPE_ERROR*/(A x) => (/*info:UNNECESSARY_CAST*/x as Objec
t), // known function |
| 1273 /*warning:DOWN_CAST_COMPOSITE*/botA, |
| 1274 /*warning:DOWN_CAST_COMPOSITE*/botTop |
| 1275 ); |
| 1276 } |
| 1277 } |
| 1278 '''); |
| 1279 } |
| 1280 |
| 1281 void test_functionTypingAndSubtyping_dynamicFunctions_clasuresAreNotFuzzy() { |
| 1282 // Regression test for |
| 1283 // https://github.com/dart-lang/sdk/issues/26118 |
| 1284 // https://github.com/dart-lang/sdk/issues/26156 |
| 1285 checkFile(''' |
| 1286 void takesF(void f(int x)) {} |
| 1287 |
| 1288 typedef void TakesInt(int x); |
| 1289 |
| 1290 void update(_) {} |
| 1291 void updateOpt([_]) {} |
| 1292 void updateOptNum([num x]) {} |
| 1293 |
| 1294 class A { |
| 1295 TakesInt f; |
| 1296 A(TakesInt g) { |
| 1297 f = update; |
| 1298 f = updateOpt; |
| 1299 f = updateOptNum; |
| 1300 } |
| 1301 TakesInt g(bool a, bool b) { |
| 1302 if (a) { |
| 1303 return update; |
| 1304 } else if (b) { |
| 1305 return updateOpt; |
| 1306 } else { |
| 1307 return updateOptNum; |
| 745 } | 1308 } |
| 746 ''' | 1309 } |
| 747 }); | 1310 } |
| 748 | 1311 |
| 749 testChecker('Function typing and subtyping: named and optional parameters', { | 1312 void test0() { |
| 750 '/main.dart': ''' | 1313 takesF(update); |
| 751 | 1314 takesF(updateOpt); |
| 752 class A {} | 1315 takesF(updateOptNum); |
| 753 | 1316 TakesInt f; |
| 754 typedef A FR(A x); | 1317 f = update; |
| 755 typedef A FO([A x]); | 1318 f = updateOpt; |
| 756 typedef A FN({A x}); | 1319 f = updateOptNum; |
| 757 typedef A FRR(A x, A y); | 1320 new A(update); |
| 758 typedef A FRO(A x, [A y]); | 1321 new A(updateOpt); |
| 759 typedef A FRN(A x, {A n}); | 1322 new A(updateOptNum); |
| 760 typedef A FOO([A x, A y]); | 1323 } |
| 761 typedef A FNN({A x, A y}); | 1324 |
| 762 typedef A FNNN({A z, A y, A x}); | 1325 void test1() { |
| 763 | 1326 void takesF(f(int x)) => null; |
| 764 void main() { | 1327 takesF((dynamic y) => 3); |
| 765 FR r; | 1328 } |
| 766 FO o; | 1329 |
| 767 FN n; | 1330 void test2() { |
| 768 FRR rr; | 1331 int x; |
| 769 FRO ro; | 1332 int f/*<T>*/(/*=T*/ t, callback(/*=T*/ x)) { return 3; } |
| 770 FRN rn; | 1333 f(x, (y) => 3); |
| 771 FOO oo; | 1334 } |
| 772 FNN nn; | 1335 '''); |
| 773 FNNN nnn; | 1336 } |
| 774 | 1337 |
| 775 r = r; | 1338 void test_functionTypingAndSubtyping_functionLiteralVariance() { |
| 776 r = o; | 1339 checkFile(''' |
| 777 r = /*severe:StaticTypeError*/n; | 1340 class A {} |
| 778 r = /*severe:StaticTypeError*/rr; | 1341 class B extends A {} |
| 779 r = ro; | 1342 |
| 780 r = rn; | 1343 typedef T Function2<S, T>(S z); |
| 781 r = oo; | 1344 |
| 782 r = /*severe:StaticTypeError*/nn; | 1345 A top(B x) => x; |
| 783 r = /*severe:StaticTypeError*/nnn; | 1346 B left(B x) => x; |
| 784 | 1347 A right(A x) => x; |
| 785 o = /*warning:DownCastComposite*/r; | 1348 B bot(A x) => x as B; |
| 786 o = o; | 1349 |
| 787 o = /*severe:StaticTypeError*/n; | 1350 void main() { |
| 788 o = /*severe:StaticTypeError*/rr; | 1351 { |
| 789 o = /*severe:StaticTypeError*/ro; | 1352 Function2<B, A> f; |
| 790 o = /*severe:StaticTypeError*/rn; | 1353 f = top; |
| 791 o = oo; | 1354 f = left; |
| 792 o = /*severe:StaticTypeError*/nn | 1355 f = right; |
| 793 o = /*severe:StaticTypeError*/nnn; | 1356 f = bot; |
| 794 | 1357 } |
| 795 n = /*severe:StaticTypeError*/r; | 1358 { |
| 796 n = /*severe:StaticTypeError*/o; | 1359 Function2<B, B> f; // left |
| 797 n = n; | 1360 f = /*error:STATIC_TYPE_ERROR*/top; |
| 798 n = /*severe:StaticTypeError*/rr; | 1361 f = left; |
| 799 n = /*severe:StaticTypeError*/ro; | 1362 f = /*error:INVALID_ASSIGNMENT*/right; |
| 800 n = /*severe:StaticTypeError*/rn; | 1363 f = bot; |
| 801 n = /*severe:StaticTypeError*/oo; | 1364 } |
| 802 n = nn; | 1365 { |
| 803 n = nnn; | 1366 Function2<A, A> f; // right |
| 804 | 1367 f = /*error:STATIC_TYPE_ERROR*/top; |
| 805 rr = /*severe:StaticTypeError*/r; | 1368 f = /*error:INVALID_ASSIGNMENT*/left; |
| 806 rr = /*severe:StaticTypeError*/o; | 1369 f = right; |
| 807 rr = /*severe:StaticTypeError*/n; | 1370 f = bot; |
| 808 rr = rr; | 1371 } |
| 809 rr = ro; | 1372 { |
| 810 rr = /*severe:StaticTypeError*/rn; | 1373 Function2<A, B> f; |
| 811 rr = oo; | 1374 f = /*error:STATIC_TYPE_ERROR*/top; |
| 812 rr = /*severe:StaticTypeError*/nn; | 1375 f = /*error:STATIC_TYPE_ERROR*/left; |
| 813 rr = /*severe:StaticTypeError*/nnn; | 1376 f = /*error:STATIC_TYPE_ERROR*/right; |
| 814 | 1377 f = bot; |
| 815 ro = /*warning:DownCastComposite*/r; | 1378 } |
| 816 ro = /*severe:StaticTypeError*/o; | 1379 } |
| 817 ro = /*severe:StaticTypeError*/n; | 1380 '''); |
| 818 ro = /*warning:DownCastComposite*/rr; | 1381 } |
| 819 ro = ro; | 1382 |
| 820 ro = /*severe:StaticTypeError*/rn; | 1383 void test_functionTypingAndSubtyping_functionVariableVariance() { |
| 821 ro = oo; | 1384 checkFile(''' |
| 822 ro = /*severe:StaticTypeError*/nn; | 1385 class A {} |
| 823 ro = /*severe:StaticTypeError*/nnn; | 1386 class B extends A {} |
| 824 | 1387 |
| 825 rn = /*warning:DownCastComposite*/r; | 1388 typedef T Function2<S, T>(S z); |
| 826 rn = /*severe:StaticTypeError*/o; | 1389 |
| 827 rn = /*severe:StaticTypeError*/n; | 1390 void main() { |
| 828 rn = /*severe:StaticTypeError*/rr; | 1391 { |
| 829 rn = /*severe:StaticTypeError*/ro; | 1392 Function2<B, A> top; |
| 830 rn = rn; | 1393 Function2<B, B> left; |
| 831 rn = /*severe:StaticTypeError*/oo; | 1394 Function2<A, A> right; |
| 832 rn = /*severe:StaticTypeError*/nn; | 1395 Function2<A, B> bot; |
| 833 rn = /*severe:StaticTypeError*/nnn; | 1396 |
| 834 | 1397 top = right; |
| 835 oo = /*warning:DownCastComposite*/r; | 1398 top = bot; |
| 836 oo = /*warning:DownCastComposite*/o; | 1399 top = top; |
| 837 oo = /*severe:StaticTypeError*/n; | 1400 top = left; |
| 838 oo = /*warning:DownCastComposite*/rr; | 1401 |
| 839 oo = /*warning:DownCastComposite*/ro; | 1402 left = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 840 oo = /*severe:StaticTypeError*/rn; | 1403 left = left; |
| 841 oo = oo; | 1404 left = /*error:INVALID_ASSIGNMENT*/right; |
| 842 oo = /*severe:StaticTypeError*/nn; | 1405 left = bot; |
| 843 oo = /*severe:StaticTypeError*/nnn; | 1406 |
| 844 | 1407 right = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 845 nn = /*severe:StaticTypeError*/r; | 1408 right = /*error:INVALID_ASSIGNMENT*/left; |
| 846 nn = /*severe:StaticTypeError*/o; | 1409 right = right; |
| 847 nn = /*warning:DownCastComposite*/n; | 1410 right = bot; |
| 848 nn = /*severe:StaticTypeError*/rr; | 1411 |
| 849 nn = /*severe:StaticTypeError*/ro; | 1412 bot = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 850 nn = /*severe:StaticTypeError*/rn; | 1413 bot = /*warning:DOWN_CAST_COMPOSITE*/left; |
| 851 nn = /*severe:StaticTypeError*/oo; | 1414 bot = /*warning:DOWN_CAST_COMPOSITE*/right; |
| 852 nn = nn; | 1415 bot = bot; |
| 853 nn = nnn; | 1416 } |
| 854 | 1417 } |
| 855 nnn = /*severe:StaticTypeError*/r; | 1418 '''); |
| 856 nnn = /*severe:StaticTypeError*/o; | 1419 } |
| 857 nnn = /*warning:DownCastComposite*/n; | 1420 |
| 858 nnn = /*severe:StaticTypeError*/rr; | 1421 void test_functionTypingAndSubtyping_higherOrderFunctionLiteral1() { |
| 859 nnn = /*severe:StaticTypeError*/ro; | 1422 checkFile(''' |
| 860 nnn = /*severe:StaticTypeError*/rn; | 1423 class A {} |
| 861 nnn = /*severe:StaticTypeError*/oo; | 1424 class B extends A {} |
| 862 nnn = /*warning:DownCastComposite*/nn; | 1425 |
| 863 nnn = nnn; | 1426 typedef T Function2<S, T>(S z); |
| 864 } | 1427 |
| 865 ''' | 1428 typedef A BToA(B x); // Top of the base lattice |
| 866 }); | 1429 typedef B AToB(A x); // Bot of the base lattice |
| 867 | 1430 |
| 868 testChecker('Function subtyping: objects with call methods', { | 1431 BToA top(AToB f) => f; |
| 869 '/main.dart': ''' | 1432 AToB left(AToB f) => f; |
| 870 | 1433 BToA right(BToA f) => f; |
| 871 typedef int I2I(int x); | 1434 AToB bot_(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f; |
| 872 typedef num N2N(num x); | 1435 AToB bot(BToA f) => f as AToB; |
| 873 class A { | 1436 |
| 874 int call(int x) => x; | 1437 void main() { |
| 875 } | 1438 { |
| 876 class B { | 1439 Function2<AToB, BToA> f; // Top |
| 877 num call(num x) => x; | 1440 f = top; |
| 878 } | 1441 f = left; |
| 879 int i2i(int x) => x; | 1442 f = right; |
| 880 num n2n(num x) => x; | 1443 f = bot; |
| 881 void main() { | 1444 } |
| 882 { | 1445 { |
| 883 I2I f; | 1446 Function2<AToB, AToB> f; // Left |
| 884 f = new A(); | 1447 f = /*error:STATIC_TYPE_ERROR*/top; |
| 885 f = /*severe:StaticTypeError*/new B(); | 1448 f = left; |
| 886 f = i2i; | 1449 f = /*error:INVALID_ASSIGNMENT*/right; |
| 887 f = /*warning:DownCastComposite*/n2n; | 1450 f = bot; |
| 888 f = /*warning:DownCastComposite*/i2i as Object; | 1451 } |
| 889 f = /*warning:DownCastComposite*/n2n as Function; | 1452 { |
| 890 } | 1453 Function2<BToA, BToA> f; // Right |
| 891 { | 1454 f = /*error:STATIC_TYPE_ERROR*/top; |
| 892 N2N f; | 1455 f = /*error:INVALID_ASSIGNMENT*/left; |
| 893 f = /*severe:StaticTypeError*/new A(); | 1456 f = right; |
| 894 f = new B(); | 1457 f = bot; |
| 895 f = /*warning:DownCastComposite*/i2i; | 1458 } |
| 896 f = n2n; | 1459 { |
| 897 f = /*warning:DownCastComposite*/i2i as Object; | 1460 Function2<BToA, AToB> f; // Bot |
| 898 f = /*warning:DownCastComposite*/n2n as Function; | 1461 f = bot; |
| 899 } | 1462 f = /*error:STATIC_TYPE_ERROR*/left; |
| 900 { | 1463 f = /*error:STATIC_TYPE_ERROR*/top; |
| 901 A f; | 1464 f = /*error:STATIC_TYPE_ERROR*/right; |
| 902 f = new A(); | 1465 } |
| 903 f = /*severe:StaticTypeError*/new B(); | 1466 } |
| 904 f = /*severe:StaticTypeError*/i2i; | 1467 '''); |
| 905 f = /*severe:StaticTypeError*/n2n; | 1468 } |
| 906 f = /*info:DownCastImplicit*/i2i as Object; | 1469 |
| 907 f = /*info:DownCastImplicit*/n2n as Function; | 1470 void test_functionTypingAndSubtyping_higherOrderFunctionLiteral2() { |
| 908 } | 1471 checkFile(''' |
| 909 { | 1472 class A {} |
| 910 B f; | 1473 class B extends A {} |
| 911 f = /*severe:StaticTypeError*/new A(); | 1474 |
| 912 f = new B(); | 1475 typedef T Function2<S, T>(S z); |
| 913 f = /*severe:StaticTypeError*/i2i; | 1476 |
| 914 f = /*severe:StaticTypeError*/n2n; | 1477 typedef A BToA(B x); // Top of the base lattice |
| 915 f = /*info:DownCastImplicit*/i2i as Object; | 1478 typedef B AToB(A x); // Bot of the base lattice |
| 916 f = /*info:DownCastImplicit*/n2n as Function; | 1479 |
| 917 } | 1480 Function2<B, A> top(AToB f) => f; |
| 918 { | 1481 Function2<A, B> left(AToB f) => f; |
| 919 Function f; | 1482 Function2<B, A> right(BToA f) => f; |
| 920 f = new A(); | 1483 Function2<A, B> bot_(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f; |
| 921 f = new B(); | 1484 Function2<A, B> bot(BToA f) => f as Function2<A, B>; |
| 922 f = i2i; | 1485 |
| 923 f = n2n; | 1486 void main() { |
| 924 f = /*info:DownCastImplicit*/i2i as Object; | 1487 { |
| 925 f = (n2n as Function); | 1488 Function2<AToB, BToA> f; // Top |
| 926 } | 1489 f = top; |
| 927 } | 1490 f = left; |
| 928 ''' | 1491 f = right; |
| 929 }); | 1492 f = bot; |
| 930 | 1493 } |
| 931 testChecker('Function typing and subtyping: void', { | 1494 { |
| 932 '/main.dart': ''' | 1495 Function2<AToB, AToB> f; // Left |
| 933 | 1496 f = /*error:STATIC_TYPE_ERROR*/top; |
| 934 class A { | 1497 f = left; |
| 935 void bar() => null; | 1498 f = /*error:INVALID_ASSIGNMENT*/right; |
| 936 void foo() => bar; // allowed | 1499 f = bot; |
| 937 } | 1500 } |
| 938 ''' | 1501 { |
| 939 }); | 1502 Function2<BToA, BToA> f; // Right |
| 940 | 1503 f = /*error:STATIC_TYPE_ERROR*/top; |
| 941 testChecker('Relaxed casts', { | 1504 f = /*error:INVALID_ASSIGNMENT*/left; |
| 942 '/main.dart': ''' | 1505 f = right; |
| 943 | 1506 f = bot; |
| 944 class A {} | 1507 } |
| 945 | 1508 { |
| 946 class L<T> {} | 1509 Function2<BToA, AToB> f; // Bot |
| 947 class M<T> extends L<T> {} | 1510 f = bot; |
| 948 // L<dynamic|Object> | 1511 f = /*error:STATIC_TYPE_ERROR*/left; |
| 949 // / \ | 1512 f = /*error:STATIC_TYPE_ERROR*/top; |
| 950 // M<dynamic|Object> L<A> | 1513 f = /*error:STATIC_TYPE_ERROR*/right; |
| 951 // \ / | 1514 } |
| 952 // M<A> | 1515 } |
| 953 // In normal Dart, there are additional edges | 1516 '''); |
| 954 // from M<A> to M<dynamic> | 1517 } |
| 955 // from L<A> to M<dynamic> | 1518 |
| 956 // from L<A> to L<dynamic> | 1519 void test_functionTypingAndSubtyping_higherOrderFunctionLiteral3() { |
| 957 void main() { | 1520 checkFile(''' |
| 958 L lOfDs; | 1521 class A {} |
| 959 L<Object> lOfOs; | 1522 class B extends A {} |
| 960 L<A> lOfAs; | 1523 |
| 961 | 1524 typedef T Function2<S, T>(S z); |
| 962 M mOfDs; | 1525 |
| 963 M<Object> mOfOs; | 1526 typedef A BToA(B x); // Top of the base lattice |
| 964 M<A> mOfAs; | 1527 typedef B AToB(A x); // Bot of the base lattice |
| 965 | 1528 |
| 966 { | 1529 BToA top(Function2<A, B> f) => f; |
| 967 lOfDs = mOfDs; | 1530 AToB left(Function2<A, B> f) => f; |
| 968 lOfDs = mOfOs; | 1531 BToA right(Function2<B, A> f) => f; |
| 969 lOfDs = mOfAs; | 1532 AToB bot_(Function2<B, A> f) => /*warning:DOWN_CAST_COMPOSITE*/f; |
| 970 lOfDs = lOfDs; | 1533 AToB bot(Function2<B, A> f) => f as AToB; |
| 971 lOfDs = lOfOs; | 1534 |
| 972 lOfDs = lOfAs; | 1535 void main() { |
| 973 } | 1536 { |
| 974 { | 1537 Function2<AToB, BToA> f; // Top |
| 975 lOfOs = mOfDs; | 1538 f = top; |
| 976 lOfOs = mOfOs; | 1539 f = left; |
| 977 lOfOs = mOfAs; | 1540 f = right; |
| 978 lOfOs = lOfDs; | 1541 f = bot; |
| 979 lOfOs = lOfOs; | 1542 } |
| 980 lOfOs = lOfAs; | 1543 { |
| 981 } | 1544 Function2<AToB, AToB> f; // Left |
| 982 { | 1545 f = /*error:STATIC_TYPE_ERROR*/top; |
| 983 lOfAs = /*warning:DownCastComposite*/mOfDs; | 1546 f = left; |
| 984 lOfAs = /*severe:StaticTypeError*/mOfOs; | 1547 f = /*error:INVALID_ASSIGNMENT*/right; |
| 985 lOfAs = mOfAs; | 1548 f = bot; |
| 986 lOfAs = /*warning:DownCastComposite*/lOfDs; | 1549 } |
| 987 lOfAs = /*warning:DownCastComposite*/lOfOs; | 1550 { |
| 988 lOfAs = lOfAs; | 1551 Function2<BToA, BToA> f; // Right |
| 989 } | 1552 f = /*error:STATIC_TYPE_ERROR*/top; |
| 990 { | 1553 f = /*error:INVALID_ASSIGNMENT*/left; |
| 991 mOfDs = mOfDs; | 1554 f = right; |
| 992 mOfDs = mOfOs; | 1555 f = bot; |
| 993 mOfDs = mOfAs; | 1556 } |
| 994 mOfDs = /*info:DownCastImplicit*/lOfDs; | 1557 { |
| 995 mOfDs = /*info:DownCastImplicit*/lOfOs; | 1558 Function2<BToA, AToB> f; // Bot |
| 996 mOfDs = /*info:DownCastImplicit*/lOfAs; | 1559 f = bot; |
| 997 } | 1560 f = /*error:STATIC_TYPE_ERROR*/left; |
| 998 { | 1561 f = /*error:STATIC_TYPE_ERROR*/top; |
| 999 mOfOs = mOfDs; | 1562 f = /*error:STATIC_TYPE_ERROR*/right; |
| 1000 mOfOs = mOfOs; | 1563 } |
| 1001 mOfOs = mOfAs; | 1564 } |
| 1002 mOfOs = /*info:DownCastImplicit*/lOfDs; | 1565 '''); |
| 1003 mOfOs = /*info:DownCastImplicit*/lOfOs; | 1566 } |
| 1004 mOfOs = /*severe:StaticTypeError*/lOfAs; | 1567 |
| 1005 } | 1568 void test_functionTypingAndSubtyping_higherOrderFunctionVariables() { |
| 1006 { | 1569 checkFile(''' |
| 1007 mOfAs = /*warning:DownCastComposite*/mOfDs; | 1570 class A {} |
| 1008 mOfAs = /*warning:DownCastComposite*/mOfOs; | 1571 class B extends A {} |
| 1009 mOfAs = mOfAs; | 1572 |
| 1010 mOfAs = /*warning:DownCastComposite*/lOfDs; | 1573 typedef T Function2<S, T>(S z); |
| 1011 mOfAs = /*warning:DownCastComposite*/lOfOs; | 1574 |
| 1012 mOfAs = /*warning:DownCastComposite*/lOfAs; | 1575 void main() { |
| 1013 } | 1576 { |
| 1014 | 1577 Function2<Function2<A, B>, Function2<B, A>> top; |
| 1015 } | 1578 Function2<Function2<B, A>, Function2<B, A>> right; |
| 1016 ''' | 1579 Function2<Function2<A, B>, Function2<A, B>> left; |
| 1017 }); | 1580 Function2<Function2<B, A>, Function2<A, B>> bot; |
| 1018 | 1581 |
| 1019 testChecker('Type checking literals', { | 1582 top = right; |
| 1020 '/main.dart': ''' | 1583 top = bot; |
| 1021 test() { | 1584 top = top; |
| 1022 num n = 3; | 1585 top = left; |
| 1023 int i = 3; | 1586 |
| 1024 String s = "hello"; | 1587 left = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 1025 { | 1588 left = left; |
| 1026 List<int> l = <int>[i]; | 1589 left = |
| 1027 l = <int>[/*severe:StaticTypeError*/s]; | 1590 /*error:INVALID_ASSIGNMENT*/right; |
| 1028 l = <int>[/*info:DownCastImplicit*/n]; | 1591 left = bot; |
| 1029 l = <int>[i, /*info:DownCastImplicit*/n, /*severe:StaticTypeError
*/s]; | 1592 |
| 1030 } | 1593 right = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 1031 { | 1594 right = |
| 1032 List l = [i]; | 1595 /*error:INVALID_ASSIGNMENT*/left; |
| 1033 l = [s]; | 1596 right = right; |
| 1034 l = [n]; | 1597 right = bot; |
| 1035 l = [i, n, s]; | 1598 |
| 1036 } | 1599 bot = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 1037 { | 1600 bot = /*warning:DOWN_CAST_COMPOSITE*/left; |
| 1038 Map<String, int> m = <String, int>{s: i}; | 1601 bot = /*warning:DOWN_CAST_COMPOSITE*/right; |
| 1039 m = <String, int>{s: /*severe:StaticTypeError*/s}; | 1602 bot = bot; |
| 1040 m = <String, int>{s: /*info:DownCastImplicit*/n}; | 1603 } |
| 1041 m = <String, int>{s: i, | 1604 } |
| 1042 s: /*info:DownCastImplicit*/n, | 1605 '''); |
| 1043 s: /*severe:StaticTypeError*/s}; | 1606 } |
| 1044 } | 1607 |
| 1045 // TODO(leafp): We can't currently test for key errors since the | 1608 void test_functionTypingAndSubtyping_instanceMethodVariance() { |
| 1046 // error marker binds to the entire entry. | 1609 checkFile(''' |
| 1047 { | 1610 class A {} |
| 1048 Map m = {s: i}; | 1611 class B extends A {} |
| 1049 m = {s: s}; | 1612 |
| 1050 m = {s: n}; | 1613 class C { |
| 1051 m = {s: i, | 1614 A top(B x) => x; |
| 1052 s: n, | 1615 B left(B x) => x; |
| 1053 s: s}; | 1616 A right(A x) => x; |
| 1054 m = {i: s, | 1617 B bot(A x) => x as B; |
| 1055 n: s, | 1618 } |
| 1056 s: s}; | 1619 |
| 1057 } | 1620 typedef T Function2<S, T>(S z); |
| 1058 } | 1621 |
| 1059 ''' | 1622 void main() { |
| 1060 }); | 1623 C c = new C(); |
| 1061 | 1624 { |
| 1062 testChecker('casts in constant contexts', { | 1625 Function2<B, A> f; |
| 1063 '/main.dart': ''' | 1626 f = c.top; |
| 1064 class A { | 1627 f = c.left; |
| 1065 static const num n = 3.0; | 1628 f = c.right; |
| 1066 static const int i = /*info:AssignmentCast*/n; | 1629 f = c.bot; |
| 1067 final int fi; | 1630 } |
| 1068 const A(num a) : this.fi = /*info:DownCastImplicit*/a; | 1631 { |
| 1069 } | 1632 Function2<B, B> f; |
| 1070 class B extends A { | 1633 f = /*warning:DOWN_CAST_COMPOSITE*/c.top; |
| 1071 const B(Object a) : super(/*info:DownCastImplicit*/a); | 1634 f = c.left; |
| 1072 } | 1635 f = /*error:INVALID_ASSIGNMENT*/c.right; |
| 1073 void foo(Object o) { | 1636 f = c.bot; |
| 1074 var a = const A(/*info:DownCastImplicit*/o); | 1637 } |
| 1075 } | 1638 { |
| 1076 ''' | 1639 Function2<A, A> f; |
| 1077 }); | 1640 f = /*warning:DOWN_CAST_COMPOSITE*/c.top; |
| 1078 | 1641 f = /*error:INVALID_ASSIGNMENT*/c.left; |
| 1079 testChecker('casts in conditionals', { | 1642 f = c.right; |
| 1080 '/main.dart': ''' | 1643 f = c.bot; |
| 1081 main() { | 1644 } |
| 1082 bool b = true; | 1645 { |
| 1083 num x = b ? 1 : 2.3; | 1646 Function2<A, B> f; |
| 1084 int y = /*info:AssignmentCast*/b ? 1 : 2.3; | 1647 f = /*warning:DOWN_CAST_COMPOSITE*/c.top; |
| 1085 String z = !b ? "hello" : null; | 1648 f = /*warning:DOWN_CAST_COMPOSITE*/c.left; |
| 1086 z = b ? null : "hello"; | 1649 f = /*warning:DOWN_CAST_COMPOSITE*/c.right; |
| 1087 } | 1650 f = c.bot; |
| 1088 ''' | 1651 } |
| 1089 }); | 1652 } |
| 1090 | 1653 '''); |
| 1091 testChecker('redirecting constructor', { | 1654 } |
| 1092 '/main.dart': ''' | 1655 |
| 1093 class A { | 1656 void test_functionTypingAndSubtyping_intAndObject() { |
| 1094 A(A x) {} | 1657 checkFile(''' |
| 1095 A.two() : this(/*severe:StaticTypeError*/3); | 1658 typedef Object Top(int x); // Top of the lattice |
| 1096 } | 1659 typedef int Left(int x); // Left branch |
| 1097 ''' | 1660 typedef int Left2(int x); // Left branch |
| 1098 }); | 1661 typedef Object Right(Object x); // Right branch |
| 1099 | 1662 typedef int Bot(Object x); // Bottom of the lattice |
| 1100 testChecker('super constructor', { | 1663 |
| 1101 '/main.dart': ''' | 1664 Object globalTop(int x) => x; |
| 1102 class A { A(A x) {} } | 1665 int globalLeft(int x) => x; |
| 1103 class B extends A { | 1666 Object globalRight(Object x) => x; |
| 1104 B() : super(/*severe:StaticTypeError*/3); | 1667 int bot_(Object x) => /*info:DOWN_CAST_IMPLICIT*/x; |
| 1105 } | 1668 int globalBot(Object x) => x as int; |
| 1106 ''' | 1669 |
| 1107 }); | 1670 void main() { |
| 1108 | 1671 // Note: use locals so we only know the type, not that it's a specific |
| 1109 testChecker('field/field override', { | 1672 // function declaration. (we can issue better errors in that case.) |
| 1110 '/main.dart': ''' | 1673 var top = globalTop; |
| 1111 class A {} | 1674 var left = globalLeft; |
| 1112 class B extends A {} | 1675 var right = globalRight; |
| 1113 class C extends B {} | 1676 var bot = globalBot; |
| 1114 | 1677 |
| 1115 class Base { | 1678 { // Check typedef equality |
| 1116 B f1; | 1679 Left f = left; |
| 1117 B f2; | 1680 Left2 g = f; |
| 1118 B f3; | 1681 } |
| 1119 B f4; | 1682 { |
| 1120 } | 1683 Top f; |
| 1121 | 1684 f = top; |
| 1122 class Child extends Base { | 1685 f = left; |
| 1123 /*severe:InvalidMethodOverride*/A f1; // invalid for getter | 1686 f = right; |
| 1124 /*severe:InvalidMethodOverride*/C f2; // invalid for setter | 1687 f = bot; |
| 1125 var f3; | 1688 } |
| 1126 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/dynamic
f4; | 1689 { |
| 1127 } | 1690 Left f; |
| 1128 ''' | 1691 f = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 1129 }); | 1692 f = left; |
| 1130 | 1693 f = /*error:INVALID_ASSIGNMENT*/right; |
| 1131 testChecker('getter/getter override', { | 1694 f = bot; |
| 1132 '/main.dart': ''' | 1695 } |
| 1133 class A {} | 1696 { |
| 1134 class B extends A {} | 1697 Right f; |
| 1135 class C extends B {} | 1698 f = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 1136 | 1699 f = /*error:INVALID_ASSIGNMENT*/left; |
| 1137 abstract class Base { | 1700 f = right; |
| 1138 B get f1; | 1701 f = bot; |
| 1139 B get f2; | 1702 } |
| 1140 B get f3; | 1703 { |
| 1141 B get f4; | 1704 Bot f; |
| 1142 } | 1705 f = /*warning:DOWN_CAST_COMPOSITE*/top; |
| 1143 | 1706 f = /*warning:DOWN_CAST_COMPOSITE*/left; |
| 1144 class Child extends Base { | 1707 f = /*warning:DOWN_CAST_COMPOSITE*/right; |
| 1145 /*severe:InvalidMethodOverride*/A get f1 => null; | 1708 f = bot; |
| 1146 C get f2 => null; | 1709 } |
| 1147 get f3 => null; | 1710 } |
| 1148 /*severe:InvalidMethodOverride*/dynamic get f4 => null; | 1711 '''); |
| 1149 } | 1712 } |
| 1150 ''' | 1713 |
| 1151 }); | 1714 void test_functionTypingAndSubtyping_namedAndOptionalParameters() { |
| 1152 | 1715 checkFile(''' |
| 1153 testChecker('field/getter override', { | 1716 class A {} |
| 1154 '/main.dart': ''' | 1717 |
| 1155 class A {} | 1718 typedef A FR(A x); |
| 1156 class B extends A {} | 1719 typedef A FO([A x]); |
| 1157 class C extends B {} | 1720 typedef A FN({A x}); |
| 1158 | 1721 typedef A FRR(A x, A y); |
| 1159 abstract class Base { | 1722 typedef A FRO(A x, [A y]); |
| 1160 B f1; | 1723 typedef A FRN(A x, {A n}); |
| 1161 B f2; | 1724 typedef A FOO([A x, A y]); |
| 1162 B f3; | 1725 typedef A FNN({A x, A y}); |
| 1163 B f4; | 1726 typedef A FNNN({A z, A y, A x}); |
| 1164 } | 1727 |
| 1165 | 1728 void main() { |
| 1166 class Child extends Base { | 1729 FR r; |
| 1167 /*severe:InvalidMethodOverride*/A get f1 => null; | 1730 FO o; |
| 1168 C get f2 => null; | 1731 FN n; |
| 1169 get f3 => null; | 1732 FRR rr; |
| 1170 /*severe:InvalidMethodOverride*/dynamic get f4 => null; | 1733 FRO ro; |
| 1171 } | 1734 FRN rn; |
| 1172 ''' | 1735 FOO oo; |
| 1173 }); | 1736 FNN nn; |
| 1174 | 1737 FNNN nnn; |
| 1175 testChecker('setter/setter override', { | 1738 |
| 1176 '/main.dart': ''' | 1739 r = r; |
| 1177 class A {} | 1740 r = o; |
| 1178 class B extends A {} | 1741 r = /*error:INVALID_ASSIGNMENT*/n; |
| 1179 class C extends B {} | 1742 r = /*error:INVALID_ASSIGNMENT*/rr; |
| 1180 | 1743 r = ro; |
| 1181 abstract class Base { | 1744 r = rn; |
| 1182 void set f1(B value); | 1745 r = oo; |
| 1183 void set f2(B value); | 1746 r = /*error:INVALID_ASSIGNMENT*/nn; |
| 1184 void set f3(B value); | 1747 r = /*error:INVALID_ASSIGNMENT*/nnn; |
| 1185 void set f4(B value); | 1748 |
| 1186 void set f5(B value); | 1749 o = /*warning:DOWN_CAST_COMPOSITE*/r; |
| 1187 } | 1750 o = o; |
| 1188 | 1751 o = /*error:INVALID_ASSIGNMENT*/n; |
| 1189 class Child extends Base { | 1752 o = /*error:INVALID_ASSIGNMENT*/rr; |
| 1190 void set f1(A value) {} | 1753 o = /*error:INVALID_ASSIGNMENT*/ro; |
| 1191 /*severe:InvalidMethodOverride*/void set f2(C value) {} | 1754 o = /*error:INVALID_ASSIGNMENT*/rn; |
| 1192 void set f3(value) {} | 1755 o = oo; |
| 1193 /*severe:InvalidMethodOverride*/void set f4(dynamic value) {} | 1756 o = /*error:INVALID_ASSIGNMENT*/nn; |
| 1194 set f5(B value) {} | 1757 o = /*error:INVALID_ASSIGNMENT*/nnn; |
| 1195 } | 1758 |
| 1196 ''' | 1759 n = /*error:INVALID_ASSIGNMENT*/r; |
| 1197 }); | 1760 n = /*error:INVALID_ASSIGNMENT*/o; |
| 1198 | 1761 n = n; |
| 1199 testChecker('field/setter override', { | 1762 n = /*error:INVALID_ASSIGNMENT*/rr; |
| 1200 '/main.dart': ''' | 1763 n = /*error:INVALID_ASSIGNMENT*/ro; |
| 1201 class A {} | 1764 n = /*error:INVALID_ASSIGNMENT*/rn; |
| 1202 class B extends A {} | 1765 n = /*error:INVALID_ASSIGNMENT*/oo; |
| 1203 class C extends B {} | 1766 n = nn; |
| 1204 | 1767 n = nnn; |
| 1205 class Base { | 1768 |
| 1206 B f1; | 1769 rr = /*error:INVALID_ASSIGNMENT*/r; |
| 1207 B f2; | 1770 rr = /*error:INVALID_ASSIGNMENT*/o; |
| 1208 B f3; | 1771 rr = /*error:INVALID_ASSIGNMENT*/n; |
| 1209 B f4; | 1772 rr = rr; |
| 1210 B f5; | 1773 rr = ro; |
| 1211 } | 1774 rr = /*error:INVALID_ASSIGNMENT*/rn; |
| 1212 | 1775 rr = oo; |
| 1213 class Child extends Base { | 1776 rr = /*error:INVALID_ASSIGNMENT*/nn; |
| 1214 B get f1 => null; | 1777 rr = /*error:INVALID_ASSIGNMENT*/nnn; |
| 1215 B get f2 => null; | 1778 |
| 1216 B get f3 => null; | 1779 ro = /*warning:DOWN_CAST_COMPOSITE*/r; |
| 1217 B get f4 => null; | 1780 ro = /*error:INVALID_ASSIGNMENT*/o; |
| 1218 B get f5 => null; | 1781 ro = /*error:INVALID_ASSIGNMENT*/n; |
| 1219 | 1782 ro = /*warning:DOWN_CAST_COMPOSITE*/rr; |
| 1220 void set f1(A value) {} | 1783 ro = ro; |
| 1221 /*severe:InvalidMethodOverride*/void set f2(C value) {} | 1784 ro = /*error:INVALID_ASSIGNMENT*/rn; |
| 1222 void set f3(value) {} | 1785 ro = oo; |
| 1223 /*severe:InvalidMethodOverride*/void set f4(dynamic value) {} | 1786 ro = /*error:INVALID_ASSIGNMENT*/nn; |
| 1224 set f5(B value) {} | 1787 ro = /*error:INVALID_ASSIGNMENT*/nnn; |
| 1225 } | 1788 |
| 1226 ''' | 1789 rn = /*warning:DOWN_CAST_COMPOSITE*/r; |
| 1227 }); | 1790 rn = /*error:INVALID_ASSIGNMENT*/o; |
| 1228 | 1791 rn = /*error:INVALID_ASSIGNMENT*/n; |
| 1229 testChecker('method override', { | 1792 rn = /*error:INVALID_ASSIGNMENT*/rr; |
| 1230 '/main.dart': ''' | 1793 rn = /*error:INVALID_ASSIGNMENT*/ro; |
| 1231 class A {} | 1794 rn = rn; |
| 1232 class B extends A {} | 1795 rn = /*error:INVALID_ASSIGNMENT*/oo; |
| 1233 class C extends B {} | 1796 rn = /*error:INVALID_ASSIGNMENT*/nn; |
| 1234 | 1797 rn = /*error:INVALID_ASSIGNMENT*/nnn; |
| 1235 class Base { | 1798 |
| 1236 B m1(B a); | 1799 oo = /*warning:DOWN_CAST_COMPOSITE*/r; |
| 1237 B m2(B a); | 1800 oo = /*warning:DOWN_CAST_COMPOSITE*/o; |
| 1238 B m3(B a); | 1801 oo = /*error:INVALID_ASSIGNMENT*/n; |
| 1239 B m4(B a); | 1802 oo = /*warning:DOWN_CAST_COMPOSITE*/rr; |
| 1240 B m5(B a); | 1803 oo = /*warning:DOWN_CAST_COMPOSITE*/ro; |
| 1241 B m6(B a); | 1804 oo = /*error:INVALID_ASSIGNMENT*/rn; |
| 1242 } | 1805 oo = oo; |
| 1243 | 1806 oo = /*error:INVALID_ASSIGNMENT*/nn; |
| 1244 class Child extends Base { | 1807 oo = /*error:INVALID_ASSIGNMENT*/nnn; |
| 1245 /*severe:InvalidMethodOverride*/A m1(A value) {} | 1808 |
| 1246 /*severe:InvalidMethodOverride*/C m2(C value) {} | 1809 nn = /*error:INVALID_ASSIGNMENT*/r; |
| 1247 /*severe:InvalidMethodOverride*/A m3(C value) {} | 1810 nn = /*error:INVALID_ASSIGNMENT*/o; |
| 1248 C m4(A value) {} | 1811 nn = /*warning:DOWN_CAST_COMPOSITE*/n; |
| 1249 m5(value) {} | 1812 nn = /*error:INVALID_ASSIGNMENT*/rr; |
| 1250 /*severe:InvalidMethodOverride*/dynamic m6(dynamic value) {} | 1813 nn = /*error:INVALID_ASSIGNMENT*/ro; |
| 1251 } | 1814 nn = /*error:INVALID_ASSIGNMENT*/rn; |
| 1252 ''' | 1815 nn = /*error:INVALID_ASSIGNMENT*/oo; |
| 1253 }); | 1816 nn = nn; |
| 1254 | 1817 nn = nnn; |
| 1255 testChecker('unary operators', { | 1818 |
| 1256 '/main.dart': ''' | 1819 nnn = /*error:INVALID_ASSIGNMENT*/r; |
| 1257 class A { | 1820 nnn = /*error:INVALID_ASSIGNMENT*/o; |
| 1258 A operator ~() {} | 1821 nnn = /*warning:DOWN_CAST_COMPOSITE*/n; |
| 1259 A operator +(int x) {} | 1822 nnn = /*error:INVALID_ASSIGNMENT*/rr; |
| 1260 A operator -(int x) {} | 1823 nnn = /*error:INVALID_ASSIGNMENT*/ro; |
| 1261 A operator -() {} | 1824 nnn = /*error:INVALID_ASSIGNMENT*/rn; |
| 1262 } | 1825 nnn = /*error:INVALID_ASSIGNMENT*/oo; |
| 1263 | 1826 nnn = /*warning:DOWN_CAST_COMPOSITE*/nn; |
| 1264 foo() => new A(); | 1827 nnn = nnn; |
| 1265 | 1828 } |
| 1266 test() { | 1829 '''); |
| 1267 A a = new A(); | 1830 } |
| 1268 var c = foo(); | 1831 |
| 1269 | 1832 void test_functionTypingAndSubtyping_objectsWithCallMethods() { |
| 1270 ~a; | 1833 checkFile(''' |
| 1271 (/*info:DynamicInvoke*/~d); | 1834 typedef int I2I(int x); |
| 1272 | 1835 typedef num N2N(num x); |
| 1273 !/*severe:StaticTypeError*/a; | 1836 class A { |
| 1274 !/*info:DynamicCast*/d; | 1837 int call(int x) => x; |
| 1275 | 1838 } |
| 1276 -a; | 1839 class B { |
| 1277 (/*info:DynamicInvoke*/-d); | 1840 num call(num x) => x; |
| 1278 | 1841 } |
| 1279 ++a; | 1842 int i2i(int x) => x; |
| 1280 --a; | 1843 num n2n(num x) => x; |
| 1281 (/*info:DynamicInvoke*/++d); | 1844 void main() { |
| 1282 (/*info:DynamicInvoke*/--d); | 1845 { |
| 1283 | 1846 I2I f; |
| 1284 a++; | 1847 f = new A(); |
| 1285 a--; | 1848 f = /*error:INVALID_ASSIGNMENT*/new B(); |
| 1286 (/*info:DynamicInvoke*/d++); | 1849 f = i2i; |
| 1287 (/*info:DynamicInvoke*/d--); | 1850 f = /*error:INVALID_ASSIGNMENT*/n2n; |
| 1288 }''' | 1851 f = /*info:UNNECESSARY_CAST,warning:DOWN_CAST_COMPOSITE*/i2i as Object; |
| 1289 }); | 1852 f = /*info:UNNECESSARY_CAST,warning:DOWN_CAST_COMPOSITE*/n2n as Function; |
| 1290 | 1853 } |
| 1291 testChecker('binary and index operators', { | 1854 { |
| 1292 '/main.dart': ''' | 1855 N2N f; |
| 1293 class A { | 1856 f = /*error:INVALID_ASSIGNMENT*/new A(); |
| 1294 A operator *(B b) {} | 1857 f = new B(); |
| 1295 A operator /(B b) {} | 1858 f = /*error:INVALID_ASSIGNMENT*/i2i; |
| 1296 A operator ~/(B b) {} | 1859 f = n2n; |
| 1297 A operator %(B b) {} | 1860 f = /*info:UNNECESSARY_CAST,warning:DOWN_CAST_COMPOSITE*/i2i as Object; |
| 1298 A operator +(B b) {} | 1861 f = /*info:UNNECESSARY_CAST,warning:DOWN_CAST_COMPOSITE*/n2n as Function; |
| 1299 A operator -(B b) {} | 1862 } |
| 1300 A operator <<(B b) {} | 1863 { |
| 1301 A operator >>(B b) {} | 1864 A f; |
| 1302 A operator &(B b) {} | 1865 f = new A(); |
| 1303 A operator ^(B b) {} | 1866 f = /*error:INVALID_ASSIGNMENT*/new B(); |
| 1304 A operator |(B b) {} | 1867 f = /*error:INVALID_ASSIGNMENT*/i2i; |
| 1305 A operator[](B b) {} | 1868 f = /*error:INVALID_ASSIGNMENT*/n2n; |
| 1306 } | 1869 f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/i2i as Object; |
| 1307 | 1870 f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/n2n as Function; |
| 1308 class B { | 1871 } |
| 1309 A operator -(B b) {} | 1872 { |
| 1310 } | 1873 B f; |
| 1311 | 1874 f = /*error:INVALID_ASSIGNMENT*/new A(); |
| 1312 foo() => new A(); | 1875 f = new B(); |
| 1313 | 1876 f = /*error:INVALID_ASSIGNMENT*/i2i; |
| 1314 test() { | 1877 f = /*error:INVALID_ASSIGNMENT*/n2n; |
| 1315 A a = new A(); | 1878 f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/i2i as Object; |
| 1316 B b = new B(); | 1879 f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/n2n as Function; |
| 1317 var c = foo(); | 1880 } |
| 1318 a = a * b; | 1881 { |
| 1319 a = a * /*info:DynamicCast*/c; | 1882 Function f; |
| 1320 a = a / b; | 1883 f = new A(); |
| 1321 a = a ~/ b; | 1884 f = new B(); |
| 1322 a = a % b; | 1885 f = i2i; |
| 1323 a = a + b; | 1886 f = n2n; |
| 1324 a = a + /*severe:StaticTypeError*/a; | 1887 f = /*info:UNNECESSARY_CAST,info:DOWN_CAST_IMPLICIT*/i2i as Object; |
| 1325 a = a - b; | 1888 f = /*info:UNNECESSARY_CAST*/n2n as Function; |
| 1326 b = /*severe:StaticTypeError*/b - b; | 1889 } |
| 1327 a = a << b; | 1890 } |
| 1328 a = a >> b; | 1891 '''); |
| 1329 a = a & b; | 1892 } |
| 1330 a = a ^ b; | 1893 |
| 1331 a = a | b; | 1894 void test_functionTypingAndSubtyping_staticMethodVariance() { |
| 1332 c = (/*info:DynamicInvoke*/c + b); | 1895 checkFile(''' |
| 1333 | 1896 class A {} |
| 1334 String x = 'hello'; | 1897 class B extends A {} |
| 1335 int y = 42; | 1898 |
| 1336 x = x + x; | 1899 class C { |
| 1337 x = x + /*info:DynamicCast*/c; | 1900 static A top(B x) => x; |
| 1338 x = x + /*severe:StaticTypeError*/y; | 1901 static B left(B x) => x; |
| 1339 | 1902 static A right(A x) => x; |
| 1340 bool p = true; | 1903 static B bot(A x) => x as B; |
| 1341 p = p && p; | 1904 } |
| 1342 p = p && /*info:DynamicCast*/c; | 1905 |
| 1343 p = (/*info:DynamicCast*/c) && p; | 1906 typedef T Function2<S, T>(S z); |
| 1344 p = (/*info:DynamicCast*/c) && /*info:DynamicCast*/c; | 1907 |
| 1345 p = (/*severe:StaticTypeError*/y) && p; | 1908 void main() { |
| 1346 p = c == y; | 1909 { |
| 1347 | 1910 Function2<B, A> f; |
| 1348 a = a[b]; | 1911 f = C.top; |
| 1349 a = a[/*info:DynamicCast*/c]; | 1912 f = C.left; |
| 1350 c = (/*info:DynamicInvoke*/c[b]); | 1913 f = C.right; |
| 1351 a[/*severe:StaticTypeError*/y]; | 1914 f = C.bot; |
| 1352 } | 1915 } |
| 1353 ''' | 1916 { |
| 1354 }); | 1917 Function2<B, B> f; |
| 1355 | 1918 f = /*error:STATIC_TYPE_ERROR*/C.top; |
| 1356 testChecker('compound assignments', { | 1919 f = C.left; |
| 1357 '/main.dart': ''' | 1920 f = /*error:INVALID_ASSIGNMENT*/C.right; |
| 1358 class A { | 1921 f = C.bot; |
| 1359 A operator *(B b) {} | 1922 } |
| 1360 A operator /(B b) {} | 1923 { |
| 1361 A operator ~/(B b) {} | 1924 Function2<A, A> f; |
| 1362 A operator %(B b) {} | 1925 f = /*error:STATIC_TYPE_ERROR*/C.top; |
| 1363 A operator +(B b) {} | 1926 f = /*error:INVALID_ASSIGNMENT*/C.left; |
| 1364 A operator -(B b) {} | 1927 f = C.right; |
| 1365 A operator <<(B b) {} | 1928 f = C.bot; |
| 1366 A operator >>(B b) {} | 1929 } |
| 1367 A operator &(B b) {} | 1930 { |
| 1368 A operator ^(B b) {} | 1931 Function2<A, B> f; |
| 1369 A operator |(B b) {} | 1932 f = /*error:STATIC_TYPE_ERROR*/C.top; |
| 1370 D operator [](B index) {} | 1933 f = /*error:STATIC_TYPE_ERROR*/C.left; |
| 1371 void operator []=(B index, D value) {} | 1934 f = /*error:STATIC_TYPE_ERROR*/C.right; |
| 1372 } | 1935 f = C.bot; |
| 1373 | 1936 } |
| 1374 class B { | 1937 } |
| 1375 A operator -(B b) {} | 1938 '''); |
| 1376 } | 1939 } |
| 1377 | 1940 |
| 1378 class D { | 1941 void test_functionTypingAndSubtyping_subtypeOfUniversalType() { |
| 1379 D operator +(D d) {} | 1942 checkFile(''' |
| 1380 } | 1943 void main() { |
| 1381 | 1944 nonGenericFn(x) => null; |
| 1382 foo() => new A(); | 1945 { |
| 1383 | 1946 /*=R*/ f/*<P, R>*/(/*=P*/ p) => null; |
| 1384 test() { | 1947 /*=T*/ g/*<S, T>*/(/*=S*/ s) => null; |
| 1385 int x = 0; | 1948 |
| 1386 x += 5; | 1949 var local = f; |
| 1387 (/*severe:StaticTypeError*/x += 3.14); | 1950 local = g; // valid |
| 1388 | 1951 |
| 1389 double y = 0.0; | 1952 // Non-generic function cannot subtype a generic one. |
| 1390 y += 5; | 1953 local = /*error:INVALID_ASSIGNMENT*/(x) => null; |
| 1391 y += 3.14; | 1954 local = /*error:INVALID_ASSIGNMENT*/nonGenericFn; |
| 1392 | 1955 } |
| 1393 num z = 0; | 1956 { |
| 1394 z += 5; | 1957 Iterable/*<R>*/ f/*<P, R>*/(List/*<P>*/ p) => null; |
| 1395 z += 3.14; | 1958 List/*<T>*/ g/*<S, T>*/(Iterable/*<S>*/ s) => null; |
| 1396 | 1959 |
| 1397 x = /*info:DownCastImplicit*/x + z; | 1960 var local = f; |
| 1398 x += /*info:DownCastImplicit*/z; | 1961 local = g; // valid |
| 1399 y = /*info:DownCastImplicit*/y + z; | 1962 |
| 1400 y += /*info:DownCastImplicit*/z; | 1963 var local2 = g; |
| 1401 | 1964 local = local2; |
| 1402 dynamic w = 42; | 1965 local2 = /*error:STATIC_TYPE_ERROR*/f; |
| 1403 x += /*info:DynamicCast*/w; | 1966 local2 = /*warning:DOWN_CAST_COMPOSITE*/local; |
| 1404 y += /*info:DynamicCast*/w; | 1967 |
| 1405 z += /*info:DynamicCast*/w; | 1968 // Non-generic function cannot subtype a generic one. |
| 1406 | 1969 local = /*error:INVALID_ASSIGNMENT*/(x) => null; |
| 1407 A a = new A(); | 1970 local = /*error:INVALID_ASSIGNMENT*/nonGenericFn; |
| 1408 B b = new B(); | 1971 } |
| 1409 var c = foo(); | 1972 } |
| 1410 a = a * b; | 1973 '''); |
| 1411 a *= b; | 1974 } |
| 1412 a *= /*info:DynamicCast*/c; | 1975 |
| 1413 a /= b; | 1976 void test_functionTypingAndSubtyping_uninferredClosure() { |
| 1414 a ~/= b; | 1977 checkFile(''' |
| 1415 a %= b; | 1978 typedef num Num2Num(num x); |
| 1416 a += b; | 1979 void main() { |
| 1417 a += /*severe:StaticTypeError*/a; | 1980 Num2Num g = /*info:INFERRED_TYPE_CLOSURE,error:INVALID_ASSIGNMENT*/(int x) { r
eturn x; }; |
| 1418 a -= b; | 1981 print(g(42)); |
| 1419 (/*severe:StaticTypeError*/b -= b); | 1982 } |
| 1420 a <<= b; | 1983 '''); |
| 1421 a >>= b; | 1984 } |
| 1422 a &= b; | 1985 |
| 1423 a ^= b; | 1986 void test_functionTypingAndSubtyping_void() { |
| 1424 a |= b; | 1987 checkFile(''' |
| 1425 (/*info:DynamicInvoke*/c += b); | 1988 class A { |
| 1426 | 1989 void bar() => null; |
| 1427 var d = new D(); | 1990 void foo() => bar(); // allowed |
| 1428 a[b] += d; | 1991 } |
| 1429 a[/*info:DynamicCast*/c] += d; | 1992 '''); |
| 1430 a[/*severe:StaticTypeError*/z] += d; | 1993 } |
| 1431 a[b] += /*info:DynamicCast*/c; | 1994 |
| 1432 a[b] += /*severe:StaticTypeError*/z; | 1995 void test_genericClassMethodOverride() { |
| 1433 (/*info:DynamicInvoke*/(/*info:DynamicInvoke*/c[b]) += d); | 1996 checkFile(''' |
| 1434 } | 1997 class A {} |
| 1435 ''' | 1998 class B extends A {} |
| 1436 }); | 1999 |
| 1437 | 2000 class Base<T extends B> { |
| 1438 testChecker('super call placement', { | 2001 T foo() => null; |
| 1439 '/main.dart': ''' | 2002 } |
| 1440 class Base { | 2003 |
| 1441 var x; | 2004 class Derived<S extends A> extends Base<B> { |
| 1442 Base() : x = print('Base.1') { print('Base.2'); } | 2005 /*error:INVALID_METHOD_OVERRIDE*/S foo() => null; |
| 1443 } | 2006 } |
| 1444 | 2007 |
| 1445 class Derived extends Base { | 2008 class Derived2<S extends B> extends Base<B> { |
| 1446 var y, z; | 2009 S foo() => null; |
| 1447 Derived() | 2010 } |
| 1448 : y = print('Derived.1'), | 2011 '''); |
| 1449 /*severe:InvalidSuperInvocation*/super(), | 2012 } |
| 1450 z = print('Derived.2') { | 2013 |
| 1451 print('Derived.3'); | 2014 void test_genericFunctionWrongNumberOfArguments() { |
| 1452 } | 2015 checkFile(r''' |
| 1453 } | 2016 /*=T*/ foo/*<T>*/(/*=T*/ x, /*=T*/ y) => x; |
| 1454 | 2017 /*=T*/ bar/*<T>*/({/*=T*/ x, /*=T*/ y}) => x; |
| 1455 class Valid extends Base { | 2018 |
| 1456 var y, z; | 2019 main() { |
| 1457 Valid() | 2020 String x; |
| 1458 : y = print('Valid.1'), | 2021 // resolving these shouldn't crash. |
| 1459 z = print('Valid.2'), | 2022 foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/(1, 2, 3); |
| 1460 super() { | 2023 x = foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/('1', '2', '3'); |
| 1461 print('Valid.3'); | 2024 foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(1); |
| 1462 } | 2025 x = foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/('1'); |
| 1463 } | 2026 x = /*error:COULD_NOT_INFER*/foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/(/*error:A
RGUMENT_TYPE_NOT_ASSIGNABLE*/1, /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/2, 3); |
| 1464 | 2027 x = /*error:COULD_NOT_INFER*/foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(/*erro
r:ARGUMENT_TYPE_NOT_ASSIGNABLE*/1); |
| 1465 class AlsoValid extends Base { | 2028 |
| 1466 AlsoValid() : super(); | 2029 // named arguments |
| 1467 } | 2030 bar(y: 1, x: 2, /*error:UNDEFINED_NAMED_PARAMETER*/z: 3); |
| 1468 | 2031 x = bar(/*error:UNDEFINED_NAMED_PARAMETER*/z: '1', x: '2', y: '3'); |
| 1469 main() => new Derived(); | 2032 bar(y: 1); |
| 1470 ''' | 2033 x = bar(x: '1', /*error:UNDEFINED_NAMED_PARAMETER*/z: 42); |
| 1471 }); | 2034 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); |
| 1472 | 2035 x = /*error:COULD_NOT_INFER*/bar(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/x: 1); |
| 1473 testChecker('for loop variable', { | 2036 } |
| 1474 '/main.dart': ''' | 2037 '''); |
| 1475 foo() { | 2038 } |
| 1476 for (int i = 0; i < 10; i++) { | 2039 |
| 1477 i = /*severe:StaticTypeError*/"hi"; | 2040 void test_genericMethodOverride() { |
| 1478 } | 2041 checkFile(''' |
| 1479 } | 2042 class Future<T> { |
| 1480 bar() { | 2043 /*=S*/ then/*<S>*/(/*=S*/ onValue(T t)) => null; |
| 1481 for (var i = 0; i < 10; i++) { | 2044 } |
| 1482 int j = i + 1; | 2045 |
| 1483 } | 2046 class DerivedFuture<T> extends Future<T> { |
| 1484 } | 2047 /*=S*/ then/*<S>*/(/*=S*/ onValue(T t)) => null; |
| 1485 ''' | 2048 } |
| 1486 }); | 2049 |
| 1487 | 2050 class DerivedFuture2<A> extends Future<A> { |
| 1488 group('invalid overrides', () { | 2051 /*=B*/ then/*<B>*/(/*=B*/ onValue(A a)) => null; |
| 1489 testChecker('child override', { | 2052 } |
| 1490 '/main.dart': ''' | 2053 |
| 1491 class A {} | 2054 class DerivedFuture3<T> extends Future<T> { |
| 1492 class B {} | 2055 /*=S*/ then/*<S>*/(Object onValue(T t)) => null; |
| 1493 | 2056 } |
| 1494 class Base { | 2057 |
| 1495 A f; | 2058 class DerivedFuture4<A> extends Future<A> { |
| 1496 } | 2059 /*=B*/ then/*<B>*/(Object onValue(A a)) => null; |
| 1497 | 2060 } |
| 1498 class T1 extends Base { | 2061 '''); |
| 1499 /*severe:InvalidMethodOverride*/B get f => null; | 2062 } |
| 1500 } | 2063 |
| 1501 | 2064 void test_getterGetterOverride() { |
| 1502 class T2 extends Base { | 2065 checkFile(''' |
| 1503 /*severe:InvalidMethodOverride*/set f(B b) => null; | 2066 class A {} |
| 1504 } | 2067 class B extends A {} |
| 1505 | 2068 class C extends B {} |
| 1506 class T3 extends Base { | 2069 |
| 1507 /*severe:InvalidMethodOverride*/final B f; | 2070 abstract class Base { |
| 1508 } | 2071 B get f1; |
| 1509 class T4 extends Base { | 2072 B get f2; |
| 1510 // two: one for the getter one for the setter. | 2073 B get f3; |
| 1511 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/B f; | 2074 B get f4; |
| 1512 } | 2075 } |
| 1513 ''' | 2076 |
| 1514 }); | 2077 class Child extends Base { |
| 1515 | 2078 /*error:INVALID_METHOD_OVERRIDE*/A get f1 => null; |
| 1516 testChecker('child override 2', { | 2079 C get f2 => null; |
| 1517 '/main.dart': ''' | 2080 get f3 => null; |
| 1518 class A {} | 2081 /*error:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null; |
| 1519 class B {} | 2082 } |
| 1520 | 2083 '''); |
| 1521 class Base { | 2084 } |
| 1522 m(A a) {} | 2085 |
| 1523 } | 2086 void test_getterOverride_fuzzyArrows() { |
| 1524 | 2087 checkFile(''' |
| 1525 class Test extends Base { | 2088 typedef void ToVoid<T>(T x); |
| 1526 /*severe:InvalidMethodOverride*/m(B a) {} | 2089 |
| 1527 } | 2090 class F { |
| 1528 ''' | 2091 ToVoid<dynamic> get f => null; |
| 1529 }); | 2092 ToVoid<int> get g => null; |
| 1530 testChecker('grandchild override', { | 2093 } |
| 1531 '/main.dart': ''' | 2094 |
| 1532 class A {} | 2095 class G extends F { |
| 1533 class B {} | 2096 ToVoid<int> get f => null; |
| 1534 | 2097 /*error:INVALID_METHOD_OVERRIDE*/ToVoid<dynamic> get g => null; |
| 1535 class Grandparent { | 2098 } |
| 1536 m(A a) {} | 2099 |
| 1537 } | 2100 class H implements F { |
| 1538 class Parent extends Grandparent { | 2101 ToVoid<int> get f => null; |
| 1539 } | 2102 /*error:INVALID_METHOD_OVERRIDE*/ToVoid<dynamic> get g => null; |
| 1540 | 2103 } |
| 1541 class Test extends Parent { | 2104 '''); |
| 1542 /*severe:InvalidMethodOverride*/m(B a) {} | 2105 } |
| 1543 } | 2106 |
| 1544 ''' | 2107 void test_ifForDoWhileStatementsUseBooleanConversion() { |
| 1545 }); | 2108 checkFile(''' |
| 1546 | 2109 main() { |
| 1547 testChecker('double override', { | 2110 dynamic dyn = 42; |
| 1548 '/main.dart': ''' | 2111 Object obj = 42; |
| 1549 class A {} | 2112 int i = 42; |
| 1550 class B {} | 2113 bool b = false; |
| 1551 | 2114 |
| 1552 class Grandparent { | 2115 if (b) {} |
| 1553 m(A a) {} | 2116 if (/*info:DYNAMIC_CAST*/dyn) {} |
| 1554 } | 2117 if (/*info:DOWN_CAST_IMPLICIT*/obj) {} |
| 1555 class Parent extends Grandparent { | 2118 if (/*error:NON_BOOL_CONDITION*/i) {} |
| 1556 m(A a) {} | 2119 |
| 1557 } | 2120 while (b) {} |
| 1558 | 2121 while (/*info:DYNAMIC_CAST*/dyn) {} |
| 1559 class Test extends Parent { | 2122 while (/*info:DOWN_CAST_IMPLICIT*/obj) {} |
| 1560 // Reported only once | 2123 while (/*error:NON_BOOL_CONDITION*/i) {} |
| 1561 /*severe:InvalidMethodOverride*/m(B a) {} | 2124 |
| 1562 } | 2125 do {} while (b); |
| 1563 ''' | 2126 do {} while (/*info:DYNAMIC_CAST*/dyn); |
| 1564 }); | 2127 do {} while (/*info:DOWN_CAST_IMPLICIT*/obj); |
| 1565 | 2128 do {} while (/*error:NON_BOOL_CONDITION*/i); |
| 1566 testChecker('double override 2', { | 2129 |
| 1567 '/main.dart': ''' | 2130 for (;b;) {} |
| 1568 class A {} | 2131 for (;/*info:DYNAMIC_CAST*/dyn;) {} |
| 1569 class B {} | 2132 for (;/*info:DOWN_CAST_IMPLICIT*/obj;) {} |
| 1570 | 2133 for (;/*error:NON_BOOL_CONDITION*/i;) {} |
| 1571 class Grandparent { | 2134 } |
| 1572 m(A a) {} | 2135 '''); |
| 1573 } | 2136 } |
| 1574 class Parent extends Grandparent { | 2137 |
| 1575 /*severe:InvalidMethodOverride*/m(B a) {} | 2138 void test_implicitCasts() { |
| 1576 } | 2139 addFile('num n; int i = /*info:ASSIGNMENT_CAST*/n;'); |
| 1577 | 2140 check(); |
| 1578 class Test extends Parent { | 2141 // TODO(jmesserly): should not be emitting the hint as well as the error. |
| 1579 m(B a) {} | 2142 // It is a "strong mode hint" however, so it will not be user visible. |
| 1580 } | 2143 addFile( |
| 1581 ''' | 2144 'num n; int i = /*info:ASSIGNMENT_CAST,error:INVALID_ASSIGNMENT*/n;'); |
| 1582 }); | 2145 check(implicitCasts: false); |
| 1583 | 2146 } |
| 1584 testChecker('mixin override to base', { | 2147 |
| 1585 '/main.dart': ''' | 2148 void test_implicitCasts_genericMethods() { |
| 1586 class A {} | 2149 addFile('var x = <String>[].map((x) => "");'); |
| 1587 class B {} | 2150 check(implicitCasts: false); |
| 1588 | 2151 } |
| 1589 class Base { | 2152 |
| 1590 m(A a) {} | 2153 void test_implicitCasts_numericOps() { |
| 1591 } | 2154 // Regression test for https://github.com/dart-lang/sdk/issues/26912 |
| 1592 | 2155 addFile(r''' |
| 1593 class M1 { | 2156 void f() { |
| 1594 m(B a) {} | 2157 int x = 0; |
| 1595 } | 2158 int y = 0; |
| 1596 | 2159 x += y; |
| 1597 class M2 {} | 2160 } |
| 1598 | 2161 '''); |
| 1599 class T1 extends Base with /*severe:InvalidMethodOverride*/M1 {} | 2162 check(implicitCasts: false); |
| 1600 class T2 extends Base with /*severe:InvalidMethodOverride*/M1, M2 {} | 2163 } |
| 1601 class T3 extends Base with M2, /*severe:InvalidMethodOverride*/M1 {} | 2164 |
| 1602 ''' | 2165 void test_implicitDynamic_field() { |
| 1603 }); | 2166 addFile(r''' |
| 1604 | 2167 class C { |
| 1605 testChecker('mixin override to mixin', { | 2168 var /*error:IMPLICIT_DYNAMIC_FIELD*/x0; |
| 1606 '/main.dart': ''' | 2169 var /*error:IMPLICIT_DYNAMIC_FIELD*/x1 = (<dynamic>[])[0]; |
| 1607 class A {} | 2170 var /*error:IMPLICIT_DYNAMIC_FIELD*/x2, |
| 1608 class B {} | 2171 x3 = 42, |
| 1609 | 2172 /*error:IMPLICIT_DYNAMIC_FIELD*/x4; |
| 1610 class Base { | 2173 dynamic y0; |
| 1611 } | 2174 dynamic y1 = (<dynamic>[])[0]; |
| 1612 | 2175 } |
| 1613 class M1 { | 2176 '''); |
| 1614 m(B a) {} | 2177 check(implicitDynamic: false); |
| 1615 } | 2178 } |
| 1616 | 2179 |
| 1617 class M2 { | 2180 void test_implicitDynamic_function() { |
| 1618 m(A a) {} | 2181 addFile(r''' |
| 1619 } | 2182 /*=T*/ a/*<T>*/(/*=T*/ t) => t; |
| 1620 | 2183 /*=T*/ b/*<T>*/() => null; |
| 1621 class T1 extends Base with M1, /*severe:InvalidMethodOverride*/M2 {} | 2184 |
| 1622 ''' | 2185 void main/*<S>*/() { |
| 1623 }); | 2186 dynamic d; |
| 1624 | 2187 int i; |
| 2188 /*error:IMPLICIT_DYNAMIC_FUNCTION*/a(d); |
| 2189 a(42); |
| 2190 /*error:IMPLICIT_DYNAMIC_FUNCTION*/b(); |
| 2191 d = /*error:IMPLICIT_DYNAMIC_FUNCTION*/b(); |
| 2192 i = b(); |
| 2193 |
| 2194 void f/*<T>*/(/*=T*/ t) {}; |
| 2195 /*=T*/ g/*<T>*/() => null; |
| 2196 |
| 2197 /*error:IMPLICIT_DYNAMIC_FUNCTION*/f(d); |
| 2198 f(42); |
| 2199 /*error:IMPLICIT_DYNAMIC_FUNCTION*/g(); |
| 2200 d = /*error:IMPLICIT_DYNAMIC_FUNCTION*/g(); |
| 2201 i = g(); |
| 2202 |
| 2203 /*error:IMPLICIT_DYNAMIC_INVOKE*/(/*<T>*/(/*=T*/ t) => t)(d); |
| 2204 (/*<T>*/(/*=T*/ t) => t)(42); |
| 2205 (/*<T>*/() => /*info:UNNECESSARY_CAST*/null as dynamic/*=T*/)/*<int>*/(); |
| 2206 } |
| 2207 '''); |
| 2208 check(implicitDynamic: false); |
| 2209 } |
| 2210 |
| 2211 void test_implicitDynamic_listLiteral() { |
| 2212 addFile(r''' |
| 2213 |
| 2214 var l0 = /*error:IMPLICIT_DYNAMIC_LIST_LITERAL*/[]; |
| 2215 List l1 = /*error:IMPLICIT_DYNAMIC_LIST_LITERAL*/[]; |
| 2216 List<dynamic> l2 = /*error:IMPLICIT_DYNAMIC_LIST_LITERAL*/[]; |
| 2217 dynamic d = 42; |
| 2218 var l3 = /*error:IMPLICIT_DYNAMIC_LIST_LITERAL*/[d, d]; |
| 2219 |
| 2220 var l4 = <dynamic>[]; |
| 2221 var l5 = <int>[]; |
| 2222 List<int> l6 = /*info:INFERRED_TYPE_LITERAL*/[]; |
| 2223 var l7 = /*info:INFERRED_TYPE_LITERAL*/[42]; |
| 2224 '''); |
| 2225 check(implicitDynamic: false); |
| 2226 } |
| 2227 |
| 2228 void test_implicitDynamic_mapLiteral() { |
| 2229 addFile(r''' |
| 2230 var m0 = /*error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{}; |
| 2231 Map m1 = /*error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{}; |
| 2232 Map<dynamic, dynamic> m2 = /*error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{}; |
| 2233 dynamic d = 42; |
| 2234 var m3 = /*error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{d: d}; |
| 2235 var m4 = /*info:INFERRED_TYPE_LITERAL,error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{'x':
d, 'y': d}; |
| 2236 var m5 = /*info:INFERRED_TYPE_LITERAL,error:IMPLICIT_DYNAMIC_MAP_LITERAL*/{d: 'x
'}; |
| 2237 |
| 2238 var m6 = <dynamic, dynamic>{}; |
| 2239 var m7 = <String, String>{}; |
| 2240 Map<String, String> m8 = /*info:INFERRED_TYPE_LITERAL*/{}; |
| 2241 var m9 = /*info:INFERRED_TYPE_LITERAL*/{'hi': 'there'}; |
| 2242 '''); |
| 2243 check(implicitDynamic: false); |
| 2244 } |
| 2245 |
| 2246 void test_implicitDynamic_method() { |
| 2247 addFile(r''' |
| 2248 class C { |
| 2249 /*=T*/ m/*<T>*/(/*=T*/ s) => s; |
| 2250 /*=T*/ n/*<T>*/() => null; |
| 2251 } |
| 2252 class D<E> { |
| 2253 /*=T*/ m/*<T>*/(/*=T*/ s) => s; |
| 2254 /*=T*/ n/*<T>*/() => null; |
| 2255 } |
| 2256 void f() { |
| 2257 dynamic d; |
| 2258 int i; |
| 2259 new C()./*error:IMPLICIT_DYNAMIC_METHOD*/m(d); |
| 2260 new C().m(42); |
| 2261 new C()./*error:IMPLICIT_DYNAMIC_METHOD*/n(); |
| 2262 d = new C()./*error:IMPLICIT_DYNAMIC_METHOD*/n(); |
| 2263 i = new C().n(); |
| 2264 |
| 2265 new D<int>()./*error:IMPLICIT_DYNAMIC_METHOD*/m(d); |
| 2266 new D<int>().m(42); |
| 2267 new D<int>()./*error:IMPLICIT_DYNAMIC_METHOD*/n(); |
| 2268 d = new D<int>()./*error:IMPLICIT_DYNAMIC_METHOD*/n(); |
| 2269 i = new D<int>().n(); |
| 2270 } |
| 2271 '''); |
| 2272 check(implicitDynamic: false); |
| 2273 } |
| 2274 |
| 2275 void test_implicitDynamic_parameter() { |
| 2276 addFile(r''' |
| 2277 const dynamic DYNAMIC_VALUE = 42; |
| 2278 |
| 2279 // simple formal |
| 2280 void f0(/*error:IMPLICIT_DYNAMIC_PARAMETER*/x) {} |
| 2281 void f1(dynamic x) {} |
| 2282 |
| 2283 // default formal |
| 2284 void df0([/*error:IMPLICIT_DYNAMIC_PARAMETER*/x = DYNAMIC_VALUE]) {} |
| 2285 void df1([dynamic x = DYNAMIC_VALUE]) {} |
| 2286 |
| 2287 // https://github.com/dart-lang/sdk/issues/25794 |
| 2288 void df2([/*error:IMPLICIT_DYNAMIC_PARAMETER*/x = 42]) {} |
| 2289 |
| 2290 // default formal (named) |
| 2291 void nf0({/*error:IMPLICIT_DYNAMIC_PARAMETER*/x: DYNAMIC_VALUE}) {} |
| 2292 void nf1({dynamic x: DYNAMIC_VALUE}) {} |
| 2293 |
| 2294 // https://github.com/dart-lang/sdk/issues/25794 |
| 2295 void nf2({/*error:IMPLICIT_DYNAMIC_PARAMETER*/x: 42}) {} |
| 2296 |
| 2297 // field formal |
| 2298 class C { |
| 2299 var /*error:IMPLICIT_DYNAMIC_FIELD*/x; |
| 2300 C(this.x); |
| 2301 } |
| 2302 |
| 2303 // function typed formal |
| 2304 void ftf0(void x(/*error:IMPLICIT_DYNAMIC_PARAMETER*/y)) {} |
| 2305 void ftf1(void x(int y)) {} |
| 2306 '''); |
| 2307 check(implicitDynamic: false); |
| 2308 } |
| 2309 |
| 2310 void test_implicitDynamic_return() { |
| 2311 addFile(r''' |
| 2312 // function |
| 2313 /*error:IMPLICIT_DYNAMIC_RETURN*/f0() {} |
| 2314 dynamic f1() { return 42; } |
| 2315 |
| 2316 // nested function |
| 2317 void main() { |
| 2318 /*error:IMPLICIT_DYNAMIC_RETURN*/g0() {} |
| 2319 dynamic g1() { return 42; } |
| 2320 } |
| 2321 |
| 2322 // methods |
| 2323 class B { |
| 2324 int m1() => 42; |
| 2325 } |
| 2326 class C extends B { |
| 2327 /*error:IMPLICIT_DYNAMIC_RETURN*/m0() => 123; |
| 2328 m1() => 123; |
| 2329 dynamic m2() => 'hi'; |
| 2330 } |
| 2331 |
| 2332 // accessors |
| 2333 set x(int value) {} |
| 2334 /*error:IMPLICIT_DYNAMIC_RETURN*/get y0 => 42; |
| 2335 dynamic get y1 => 42; |
| 2336 |
| 2337 // function typed formals |
| 2338 void ftf0(/*error:IMPLICIT_DYNAMIC_RETURN*/f(int x)) {} |
| 2339 void ftf1(dynamic f(int x)) {} |
| 2340 |
| 2341 // function expressions |
| 2342 var fe0 = (int x) => x as dynamic; |
| 2343 var fe1 = (int x) => x; |
| 2344 '''); |
| 2345 check(implicitDynamic: false); |
| 2346 } |
| 2347 |
| 2348 void test_implicitDynamic_type() { |
| 2349 addFile(r''' |
| 2350 class C<T> {} |
| 2351 class M1<T extends /*error:IMPLICIT_DYNAMIC_TYPE*/List> {} |
| 2352 class M2<T> {} |
| 2353 class I<T> {} |
| 2354 class D<T, S> extends /*error:IMPLICIT_DYNAMIC_TYPE*/C |
| 2355 with M1, /*error:IMPLICIT_DYNAMIC_TYPE*/M2 |
| 2356 implements /*error:IMPLICIT_DYNAMIC_TYPE*/I {} |
| 2357 |
| 2358 C f(D d) { |
| 2359 D x = new /*error:IMPLICIT_DYNAMIC_TYPE*/D(); |
| 2360 D<int, dynamic> y = /*info:INFERRED_TYPE_ALLOCATION*/new /*error:IMPLICIT_DYNA
MIC_TYPE*/D(); |
| 2361 D<dynamic, int> z = /*info:INFERRED_TYPE_ALLOCATION*/new /*error:IMPLICIT_DYNA
MIC_TYPE*/D(); |
| 2362 return new /*error:IMPLICIT_DYNAMIC_TYPE*/C(); |
| 2363 } |
| 2364 |
| 2365 class A<T extends num> {} |
| 2366 class N1<T extends List<int>> {} |
| 2367 class N2<T extends Object> {} |
| 2368 class J<T extends Object> {} |
| 2369 class B<T extends Object> extends A with N1, N2 implements J {} |
| 2370 A g(B b) { |
| 2371 B y = /*info:INFERRED_TYPE_ALLOCATION*/new B(); |
| 2372 return /*info:INFERRED_TYPE_ALLOCATION*/new A(); |
| 2373 } |
| 2374 '''); |
| 2375 check(implicitDynamic: false); |
| 2376 } |
| 2377 |
| 2378 void test_implicitDynamic_variable() { |
| 2379 addFile(r''' |
| 2380 var /*error:IMPLICIT_DYNAMIC_VARIABLE*/x0; |
| 2381 var /*error:IMPLICIT_DYNAMIC_VARIABLE*/x1 = (<dynamic>[])[0]; |
| 2382 var /*error:IMPLICIT_DYNAMIC_VARIABLE*/x2, |
| 2383 x3 = 42, |
| 2384 /*error:IMPLICIT_DYNAMIC_VARIABLE*/x4; |
| 2385 dynamic y0; |
| 2386 dynamic y1 = (<dynamic>[])[0]; |
| 2387 '''); |
| 2388 check(implicitDynamic: false); |
| 2389 } |
| 2390 |
| 2391 void test_invalidOverrides_baseClassOverrideToChildInterface() { |
| 2392 checkFile(''' |
| 2393 class A {} |
| 2394 class B {} |
| 2395 |
| 2396 abstract class I { |
| 2397 m(A a); |
| 2398 } |
| 2399 |
| 2400 class Base { |
| 2401 m(B a) {} |
| 2402 } |
| 2403 |
| 2404 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 2405 /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base implements I {} |
| 2406 '''); |
| 2407 } |
| 2408 |
| 2409 void test_invalidOverrides_childOverride() { |
| 2410 checkFile(''' |
| 2411 class A {} |
| 2412 class B {} |
| 2413 |
| 2414 class Base { |
| 2415 A f; |
| 2416 } |
| 2417 |
| 2418 class T1 extends Base { |
| 2419 /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_FIE
LD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B get f => null; |
| 2420 } |
| 2421 |
| 2422 class T2 extends Base { |
| 2423 /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_FIE
LD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/set f( |
| 2424 B b) => null; |
| 2425 } |
| 2426 |
| 2427 class T3 extends Base { |
| 2428 /*error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/final B |
| 2429 /*warning:FINAL_NOT_INITIALIZED*/f; |
| 2430 } |
| 2431 class T4 extends Base { |
| 2432 // two: one for the getter one for the setter. |
| 2433 /*error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE, error:INVALID_M
ETHOD_OVERRIDE*/B f; |
| 2434 } |
| 2435 |
| 2436 class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T5 implements Bas
e { |
| 2437 /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_MET
HOD_OVERRIDE*/B get f => null; |
| 2438 } |
| 2439 |
| 2440 class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T6 implements Bas
e { |
| 2441 /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_MET
HOD_OVERRIDE*/set f(B b) => null; |
| 2442 } |
| 2443 |
| 2444 class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T7 implements Bas
e { |
| 2445 /*error:INVALID_METHOD_OVERRIDE*/final B f = null; |
| 2446 } |
| 2447 class T8 implements Base { |
| 2448 // two: one for the getter one for the setter. |
| 2449 /*error:INVALID_METHOD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B f; |
| 2450 } |
| 2451 '''); |
| 2452 } |
| 2453 |
| 2454 void test_invalidOverrides_childOverride2() { |
| 2455 checkFile(''' |
| 2456 class A {} |
| 2457 class B {} |
| 2458 |
| 2459 class Base { |
| 2460 m(A a) {} |
| 2461 } |
| 2462 |
| 2463 class Test extends Base { |
| 2464 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 2465 } |
| 2466 '''); |
| 2467 } |
| 2468 |
| 2469 void test_invalidOverrides_classOverrideOfInterface() { |
| 2470 checkFile(''' |
| 2471 class A {} |
| 2472 class B {} |
| 2473 |
| 2474 abstract class I { |
| 2475 m(A a); |
| 2476 } |
| 2477 |
| 2478 class T1 implements I { |
| 2479 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 2480 } |
| 2481 '''); |
| 2482 } |
| 2483 |
| 2484 void test_invalidOverrides_doubleOverride() { |
| 2485 checkFile(''' |
| 2486 class A {} |
| 2487 class B {} |
| 2488 |
| 2489 class Grandparent { |
| 2490 m(A a) {} |
| 2491 } |
| 2492 class Parent extends Grandparent { |
| 2493 m(A a) {} |
| 2494 } |
| 2495 |
| 2496 class Test extends Parent { |
| 2497 // Reported only once |
| 2498 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 2499 } |
| 2500 '''); |
| 2501 } |
| 2502 |
| 2503 void test_invalidOverrides_doubleOverride2() { |
| 2504 checkFile(''' |
| 2505 class A {} |
| 2506 class B {} |
| 2507 |
| 2508 class Grandparent { |
| 2509 m(A a) {} |
| 2510 } |
| 2511 class Parent extends Grandparent { |
| 2512 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 2513 } |
| 2514 |
| 2515 class Test extends Parent { |
| 2516 m(B a) {} |
| 2517 } |
| 2518 '''); |
| 2519 } |
| 2520 |
| 2521 void test_invalidOverrides_grandChildOverride() { |
| 2522 checkFile(''' |
| 2523 class A {} |
| 2524 class B {} |
| 2525 |
| 2526 class Grandparent { |
| 2527 m(A a) {} |
| 2528 int x; |
| 2529 } |
| 2530 class Parent extends Grandparent { |
| 2531 } |
| 2532 |
| 2533 class Test extends Parent { |
| 2534 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 2535 /*error:INVALID_FIELD_OVERRIDE*/int x; |
| 2536 } |
| 2537 '''); |
| 2538 } |
| 2539 |
| 2540 void test_invalidOverrides_mixinOverrideOfInterface() { |
| 2541 checkFile(''' |
| 2542 class A {} |
| 2543 class B {} |
| 2544 |
| 2545 abstract class I { |
| 2546 m(A a); |
| 2547 } |
| 2548 |
| 2549 class M { |
| 2550 m(B a) {} |
| 2551 } |
| 2552 |
| 2553 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 2554 extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M |
| 2555 implements I {} |
| 2556 '''); |
| 2557 } |
| 2558 |
| 2559 void test_invalidOverrides_mixinOverrideToBase() { |
| 2560 checkFile(''' |
| 2561 class A {} |
| 2562 class B {} |
| 2563 |
| 2564 class Base { |
| 2565 m(A a) {} |
| 2566 int x; |
| 2567 } |
| 2568 |
| 2569 class M1 { |
| 2570 m(B a) {} |
| 2571 } |
| 2572 |
| 2573 class M2 { |
| 2574 int x; |
| 2575 } |
| 2576 |
| 2577 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base |
| 2578 with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M1 {} |
| 2579 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T2 extends Base |
| 2580 with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M1, /*error:INVALID_FIELD_O
VERRIDE*/M2 {} |
| 2581 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T3 extends Base |
| 2582 with /*error:INVALID_FIELD_OVERRIDE*/M2, /*error:INVALID_METHOD_OVERRIDE_FRO
M_MIXIN*/M1 {} |
| 2583 '''); |
| 2584 } |
| 2585 |
| 2586 void test_invalidOverrides_mixinOverrideToMixin() { |
| 2587 checkFile(''' |
| 2588 class A {} |
| 2589 class B {} |
| 2590 |
| 2591 class Base { |
| 2592 } |
| 2593 |
| 2594 class M1 { |
| 2595 m(B a) {} |
| 2596 int x; |
| 2597 } |
| 2598 |
| 2599 class M2 { |
| 2600 m(A a) {} |
| 2601 int x; |
| 2602 } |
| 2603 |
| 2604 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base |
| 2605 with M1, |
| 2606 /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN,error:INVALID_FIELD_OVERRIDE*/M2
{} |
| 2607 '''); |
| 2608 } |
| 2609 |
| 2610 void test_invalidOverrides_noDuplicateMixinOverride() { |
| 1625 // This is a regression test for a bug in an earlier implementation were | 2611 // This is a regression test for a bug in an earlier implementation were |
| 1626 // names were hiding errors if the first mixin override looked correct, | 2612 // names were hiding errors if the first mixin override looked correct, |
| 1627 // but subsequent ones did not. | 2613 // but subsequent ones did not. |
| 1628 testChecker('no duplicate mixin override', { | 2614 checkFile(''' |
| 1629 '/main.dart': ''' | 2615 class A {} |
| 1630 class A {} | 2616 class B {} |
| 1631 class B {} | 2617 |
| 1632 | 2618 class Base { |
| 1633 class Base { | 2619 m(A a) {} |
| 1634 m(A a) {} | 2620 } |
| 1635 } | 2621 |
| 1636 | 2622 class M1 { |
| 1637 class M1 { | 2623 m(A a) {} |
| 1638 m(A a) {} | 2624 } |
| 1639 } | 2625 |
| 1640 | 2626 class M2 { |
| 1641 class M2 { | 2627 m(B a) {} |
| 1642 m(B a) {} | 2628 } |
| 1643 } | 2629 |
| 1644 | 2630 class M3 { |
| 1645 class M3 { | 2631 m(B a) {} |
| 1646 m(B a) {} | 2632 } |
| 1647 } | 2633 |
| 1648 | 2634 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base |
| 1649 class T1 extends Base | 2635 with M1, /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M2, M3 {} |
| 1650 with M1, /*severe:InvalidMethodOverride*/M2, M3 {} | 2636 '''); |
| 1651 ''' | 2637 } |
| 1652 }); | 2638 |
| 1653 | 2639 void |
| 1654 testChecker('class override of interface', { | 2640 test_invalidOverrides_noErrorsIfSubclassCorrectlyOverrideBaseAndInterface(
) { |
| 1655 '/main.dart': ''' | |
| 1656 class A {} | |
| 1657 class B {} | |
| 1658 | |
| 1659 abstract class I { | |
| 1660 m(A a); | |
| 1661 } | |
| 1662 | |
| 1663 class T1 implements I { | |
| 1664 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1665 } | |
| 1666 ''' | |
| 1667 }); | |
| 1668 | |
| 1669 testChecker('base class override to child interface', { | |
| 1670 '/main.dart': ''' | |
| 1671 class A {} | |
| 1672 class B {} | |
| 1673 | |
| 1674 abstract class I { | |
| 1675 m(A a); | |
| 1676 } | |
| 1677 | |
| 1678 class Base { | |
| 1679 m(B a) {} | |
| 1680 } | |
| 1681 | |
| 1682 | |
| 1683 class T1 /*severe:InvalidMethodOverride*/extends Base implements I { | |
| 1684 } | |
| 1685 ''' | |
| 1686 }); | |
| 1687 | |
| 1688 testChecker('mixin override of interface', { | |
| 1689 '/main.dart': ''' | |
| 1690 class A {} | |
| 1691 class B {} | |
| 1692 | |
| 1693 abstract class I { | |
| 1694 m(A a); | |
| 1695 } | |
| 1696 | |
| 1697 class M { | |
| 1698 m(B a) {} | |
| 1699 } | |
| 1700 | |
| 1701 class T1 extends Object with /*severe:InvalidMethodOverride*/M | |
| 1702 implements I {} | |
| 1703 ''' | |
| 1704 }); | |
| 1705 | |
| 1706 // This is a case were it is incorrect to say that the base class | 2641 // This is a case were it is incorrect to say that the base class |
| 1707 // incorrectly overrides the interface. | 2642 // incorrectly overrides the interface. |
| 1708 testChecker( | 2643 checkFile(''' |
| 1709 'no errors if subclass correctly overrides base and interface', { | 2644 class A {} |
| 1710 '/main.dart': ''' | 2645 class B {} |
| 1711 class A {} | 2646 |
| 1712 class B {} | 2647 class Base { |
| 1713 | 2648 m(A a) {} |
| 1714 class Base { | 2649 } |
| 1715 m(A a) {} | 2650 |
| 1716 } | 2651 class I1 { |
| 1717 | 2652 m(B a) {} |
| 1718 class I1 { | 2653 } |
| 1719 m(B a) {} | 2654 |
| 1720 } | 2655 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 1721 | 2656 /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base |
| 1722 class T1 /*severe:InvalidMethodOverride*/extends Base | 2657 implements I1 {} |
| 1723 implements I1 {} | 2658 |
| 1724 | 2659 class T2 extends Base implements I1 { |
| 1725 class T2 extends Base implements I1 { | 2660 m(a) {} |
| 1726 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a
) {} | 2661 } |
| 1727 } | 2662 |
| 1728 | 2663 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T3 |
| 1729 class T3 extends Object with /*severe:InvalidMethodOverride*/Base | 2664 extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/Base |
| 1730 implements I1 {} | 2665 implements I1 {} |
| 1731 | 2666 |
| 1732 class T4 extends Object with Base implements I1 { | 2667 class T4 extends Object with Base implements I1 { |
| 1733 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a
) {} | 2668 m(a) {} |
| 1734 } | 2669 } |
| 1735 ''' | 2670 '''); |
| 1736 }); | 2671 } |
| 1737 }); | 2672 |
| 1738 | 2673 void test_invalidRuntimeChecks() { |
| 1739 group('class override of grand interface', () { | 2674 checkFile(''' |
| 1740 testChecker('interface of interface of child', { | 2675 typedef int I2I(int x); |
| 1741 '/main.dart': ''' | 2676 typedef int D2I(x); |
| 1742 class A {} | 2677 typedef int II2I(int x, int y); |
| 1743 class B {} | 2678 typedef int DI2I(x, int y); |
| 1744 | 2679 typedef int ID2I(int x, y); |
| 1745 abstract class I1 { | 2680 typedef int DD2I(x, y); |
| 1746 m(A a); | 2681 |
| 1747 } | 2682 typedef I2D(int x); |
| 1748 abstract class I2 implements I1 {} | 2683 typedef D2D(x); |
| 1749 | 2684 typedef II2D(int x, int y); |
| 1750 class T1 implements I2 { | 2685 typedef DI2D(x, int y); |
| 1751 /*severe:InvalidMethodOverride*/m(B a) {} | 2686 typedef ID2D(int x, y); |
| 1752 } | 2687 typedef DD2D(x, y); |
| 1753 ''' | 2688 |
| 1754 }); | 2689 int foo(int x) => x; |
| 1755 testChecker('superclass of interface of child', { | 2690 int bar(int x, int y) => x + y; |
| 1756 '/main.dart': ''' | 2691 |
| 1757 class A {} | 2692 void main() { |
| 1758 class B {} | 2693 bool b; |
| 1759 | 2694 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is I2I; |
| 1760 abstract class I1 { | 2695 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is D2I; |
| 1761 m(A a); | 2696 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is I2D; |
| 1762 } | 2697 b = foo is D2D; |
| 1763 abstract class I2 extends I1 {} | 2698 |
| 1764 | 2699 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is II2I; |
| 1765 class T1 implements I2 { | 2700 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DI2I; |
| 1766 /*severe:InvalidMethodOverride*/m(B a) {} | 2701 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is ID2I; |
| 1767 } | 2702 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is II2D; |
| 1768 ''' | 2703 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DD2I; |
| 1769 }); | 2704 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DI2D; |
| 1770 testChecker('mixin of interface of child', { | 2705 b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is ID2D; |
| 1771 '/main.dart': ''' | 2706 b = bar is DD2D; |
| 1772 class A {} | 2707 |
| 1773 class B {} | 2708 // For as, the validity of checks is deferred to runtime. |
| 1774 | 2709 Function f; |
| 1775 abstract class M1 { | 2710 f = /*info:UNNECESSARY_CAST*/foo as I2I; |
| 1776 m(A a); | 2711 f = /*info:UNNECESSARY_CAST*/foo as D2I; |
| 1777 } | 2712 f = /*info:UNNECESSARY_CAST*/foo as I2D; |
| 1778 abstract class I2 extends Object with M1 {} | 2713 f = /*info:UNNECESSARY_CAST*/foo as D2D; |
| 1779 | 2714 |
| 1780 class T1 implements I2 { | 2715 f = /*info:UNNECESSARY_CAST*/bar as II2I; |
| 1781 /*severe:InvalidMethodOverride*/m(B a) {} | 2716 f = /*info:UNNECESSARY_CAST*/bar as DI2I; |
| 1782 } | 2717 f = /*info:UNNECESSARY_CAST*/bar as ID2I; |
| 1783 ''' | 2718 f = /*info:UNNECESSARY_CAST*/bar as II2D; |
| 1784 }); | 2719 f = /*info:UNNECESSARY_CAST*/bar as DD2I; |
| 1785 testChecker('interface of abstract superclass', { | 2720 f = /*info:UNNECESSARY_CAST*/bar as DI2D; |
| 1786 '/main.dart': ''' | 2721 f = /*info:UNNECESSARY_CAST*/bar as ID2D; |
| 1787 class A {} | 2722 f = /*info:UNNECESSARY_CAST*/bar as DD2D; |
| 1788 class B {} | 2723 } |
| 1789 | 2724 '''); |
| 1790 abstract class I1 { | 2725 } |
| 1791 m(A a); | 2726 |
| 1792 } | 2727 void test_leastUpperBounds() { |
| 1793 abstract class Base implements I1 {} | 2728 checkFile(''' |
| 1794 | 2729 typedef T Returns<T>(); |
| 1795 class T1 extends Base { | 2730 |
| 1796 /*severe:InvalidMethodOverride*/m(B a) {} | 2731 // regression test for https://github.com/dart-lang/sdk/issues/26094 |
| 1797 } | 2732 class A <S extends Returns<S>, T extends Returns<T>> { |
| 1798 ''' | 2733 int test(bool b) { |
| 1799 }); | 2734 S s; |
| 1800 testChecker('interface of concrete superclass', { | 2735 T t; |
| 1801 '/main.dart': ''' | 2736 if (b) { |
| 1802 class A {} | 2737 return /*error:RETURN_OF_INVALID_TYPE*/b ? s : t; |
| 1803 class B {} | 2738 } else { |
| 1804 | 2739 return /*error:RETURN_OF_INVALID_TYPE*/s ?? t; |
| 1805 abstract class I1 { | 2740 } |
| 1806 m(A a); | 2741 } |
| 1807 } | 2742 } |
| 1808 | 2743 |
| 1809 // See issue #25 | 2744 class B<S, T extends S> { |
| 1810 /*pass should be warning:AnalyzerError*/class Base implements I1 { | 2745 T t; |
| 1811 } | 2746 S s; |
| 1812 | 2747 int test(bool b) { |
| 1813 class T1 extends Base { | 2748 return /*error:RETURN_OF_INVALID_TYPE*/b ? t : s; |
| 1814 // not reported technically because if the class is concrete, | 2749 } |
| 1815 // it should implement all its interfaces and hence it is | 2750 } |
| 1816 // sufficient to check overrides against it. | 2751 |
| 1817 m(B a) {} | 2752 class C { |
| 1818 } | 2753 // Check that the least upper bound of two types with the same |
| 1819 ''' | 2754 // class but different type arguments produces the pointwise |
| 1820 }); | 2755 // least upper bound of the type arguments |
| 1821 }); | 2756 int test1(bool b) { |
| 1822 | 2757 List<int> li; |
| 1823 group('mixin override of grand interface', () { | 2758 List<double> ld; |
| 1824 testChecker('interface of interface of child', { | 2759 return /*error:RETURN_OF_INVALID_TYPE*/b ? li : ld; |
| 1825 '/main.dart': ''' | 2760 } |
| 1826 class A {} | 2761 // TODO(leafp): This case isn't handled yet. This test checks |
| 1827 class B {} | 2762 // the case where two related classes are instantiated with related |
| 1828 | 2763 // but different types. |
| 1829 abstract class I1 { | 2764 Iterable<num> test2(bool b) { |
| 1830 m(A a); | 2765 List<int> li; |
| 1831 } | 2766 Iterable<double> id; |
| 1832 abstract class I2 implements I1 {} | 2767 int x = |
| 1833 | 2768 /*info:ASSIGNMENT_CAST should be error:INVALID_ASSIGNMENT*/ |
| 1834 class M { | 2769 b ? li : id; |
| 1835 m(B a) {} | 2770 return /*warning:DOWN_CAST_COMPOSITE should be pass*/b ? li : id; |
| 1836 } | 2771 } |
| 1837 | 2772 } |
| 1838 class T1 extends Object with /*severe:InvalidMethodOverride*/M | 2773 '''); |
| 1839 implements I2 { | 2774 } |
| 1840 } | 2775 |
| 1841 ''' | 2776 void test_leastUpperBounds_fuzzyArrows() { |
| 1842 }); | 2777 checkFile(r''' |
| 1843 testChecker('superclass of interface of child', { | 2778 typedef String TakesA<T>(T item); |
| 1844 '/main.dart': ''' | 2779 |
| 1845 class A {} | 2780 void main() { |
| 1846 class B {} | 2781 TakesA<int> f; |
| 1847 | 2782 TakesA<dynamic> g; |
| 1848 abstract class I1 { | 2783 TakesA<String> h; |
| 1849 m(A a); | 2784 g = h; |
| 1850 } | 2785 f = /*warning:DOWN_CAST_COMPOSITE*/f ?? g; |
| 1851 abstract class I2 extends I1 {} | 2786 } |
| 1852 | 2787 '''); |
| 1853 class M { | 2788 } |
| 1854 m(B a) {} | 2789 |
| 1855 } | 2790 void test_loadLibrary() { |
| 1856 | 2791 addFile('''library lib1;''', name: '/lib1.dart'); |
| 1857 class T1 extends Object with /*severe:InvalidMethodOverride*/M | 2792 checkFile(r''' |
| 1858 implements I2 { | 2793 import 'lib1.dart' deferred as lib1; |
| 1859 } | 2794 import 'dart:async' show Future; |
| 1860 ''' | 2795 main() { |
| 1861 }); | 2796 Future f = lib1.loadLibrary(); |
| 1862 testChecker('mixin of interface of child', { | 2797 }'''); |
| 1863 '/main.dart': ''' | 2798 } |
| 1864 class A {} | 2799 |
| 1865 class B {} | 2800 void test_methodOverride() { |
| 1866 | 2801 checkFile(''' |
| 1867 abstract class M1 { | 2802 class A {} |
| 1868 m(A a); | 2803 class B extends A {} |
| 1869 } | 2804 class C extends B {} |
| 1870 abstract class I2 extends Object with M1 {} | 2805 |
| 1871 | 2806 class Base { |
| 1872 class M { | 2807 B m1(B a) => null; |
| 1873 m(B a) {} | 2808 B m2(B a) => null; |
| 1874 } | 2809 B m3(B a) => null; |
| 1875 | 2810 B m4(B a) => null; |
| 1876 class T1 extends Object with /*severe:InvalidMethodOverride*/M | 2811 B m5(B a) => null; |
| 1877 implements I2 { | 2812 B m6(B a) => null; |
| 1878 } | 2813 } |
| 1879 ''' | 2814 |
| 1880 }); | 2815 class Child extends Base { |
| 1881 testChecker('interface of abstract superclass', { | 2816 /*error:INVALID_METHOD_OVERRIDE*/A m1(A value) => null; |
| 1882 '/main.dart': ''' | 2817 /*error:INVALID_METHOD_OVERRIDE*/C m2(C value) => null; |
| 1883 class A {} | 2818 /*error:INVALID_METHOD_OVERRIDE*/A m3(C value) => null; |
| 1884 class B {} | 2819 C m4(A value) => null; |
| 1885 | 2820 m5(value) => null; |
| 1886 abstract class I1 { | 2821 /*error:INVALID_METHOD_OVERRIDE*/dynamic m6(dynamic value) => null; |
| 1887 m(A a); | 2822 } |
| 1888 } | 2823 '''); |
| 1889 abstract class Base implements I1 {} | 2824 } |
| 1890 | 2825 |
| 1891 class M { | 2826 void test_methodOverride_fuzzyArrows() { |
| 1892 m(B a) {} | 2827 checkFile(''' |
| 1893 } | 2828 abstract class A { |
| 1894 | 2829 bool operator ==(Object object); |
| 1895 class T1 extends Base with /*severe:InvalidMethodOverride*/M { | 2830 } |
| 1896 } | 2831 |
| 1897 ''' | 2832 class B implements A {} |
| 1898 }); | 2833 |
| 1899 testChecker('interface of concrete superclass', { | 2834 class F { |
| 1900 '/main.dart': ''' | 2835 void f(x) {} |
| 1901 class A {} | 2836 void g(int x) {} |
| 1902 class B {} | 2837 } |
| 1903 | 2838 |
| 1904 abstract class I1 { | 2839 class G extends F { |
| 1905 m(A a); | 2840 /*error:INVALID_METHOD_OVERRIDE*/void f(int x) {} |
| 1906 } | 2841 void g(dynamic x) {} |
| 1907 | 2842 } |
| 1908 // See issue #25 | 2843 |
| 1909 /*pass should be warning:AnalyzerError*/class Base implements I1 { | 2844 class H implements F { |
| 1910 } | 2845 /*error:INVALID_METHOD_OVERRIDE*/void f(int x) {} |
| 1911 | 2846 void g(dynamic x) {} |
| 1912 class M { | 2847 } |
| 1913 m(B a) {} | 2848 '''); |
| 1914 } | 2849 } |
| 1915 | 2850 |
| 1916 class T1 extends Base with M { | 2851 void test_methodTearoffStrictArrow() { |
| 1917 } | 2852 // Regression test for https://github.com/dart-lang/sdk/issues/26393 |
| 1918 ''' | 2853 checkFile(r''' |
| 1919 }); | 2854 class A { |
| 1920 }); | 2855 void foo(dynamic x) {} |
| 1921 | 2856 void test(void f(int x)) { |
| 1922 group('superclass override of grand interface', () { | 2857 test(foo); |
| 1923 testChecker('interface of interface of child', { | 2858 } |
| 1924 '/main.dart': ''' | 2859 } |
| 1925 class A {} | 2860 '''); |
| 1926 class B {} | 2861 } |
| 1927 | 2862 |
| 1928 abstract class I1 { | 2863 void test_mixinOverrideOfGrandInterface_interfaceOfAbstractSuperclass() { |
| 1929 m(A a); | 2864 checkFile(''' |
| 1930 } | 2865 class A {} |
| 1931 abstract class I2 implements I1 {} | 2866 class B {} |
| 1932 | 2867 |
| 1933 class Base { | 2868 abstract class I1 { |
| 1934 m(B a) {} | 2869 m(A a); |
| 1935 } | 2870 } |
| 1936 | 2871 abstract class Base implements I1 {} |
| 1937 class T1 /*severe:InvalidMethodOverride*/extends Base | 2872 |
| 1938 implements I2 { | 2873 class M { |
| 1939 } | 2874 m(B a) {} |
| 1940 ''' | 2875 } |
| 1941 }); | 2876 |
| 1942 testChecker('superclass of interface of child', { | 2877 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base |
| 1943 '/main.dart': ''' | 2878 with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M {} |
| 1944 class A {} | 2879 '''); |
| 1945 class B {} | 2880 } |
| 1946 | 2881 |
| 1947 abstract class I1 { | 2882 void test_mixinOverrideOfGrandInterface_interfaceOfConcreteSuperclass() { |
| 1948 m(A a); | 2883 checkFile(''' |
| 1949 } | 2884 class A {} |
| 1950 abstract class I2 extends I1 {} | 2885 class B {} |
| 1951 | 2886 |
| 1952 class Base { | 2887 abstract class I1 { |
| 1953 m(B a) {} | 2888 m(A a); |
| 1954 } | 2889 } |
| 1955 | 2890 |
| 1956 class T1 /*severe:InvalidMethodOverride*/extends Base | 2891 class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/Base |
| 1957 implements I2 { | 2892 implements I1 {} |
| 1958 } | 2893 |
| 1959 ''' | 2894 class M { |
| 1960 }); | 2895 m(B a) {} |
| 1961 testChecker('mixin of interface of child', { | 2896 } |
| 1962 '/main.dart': ''' | 2897 |
| 1963 class A {} | 2898 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Base |
| 1964 class B {} | 2899 with M {} |
| 1965 | 2900 '''); |
| 1966 abstract class M1 { | 2901 } |
| 1967 m(A a); | 2902 |
| 1968 } | 2903 void test_mixinOverrideOfGrandInterface_interfaceOfInterfaceOfChild() { |
| 1969 abstract class I2 extends Object with M1 {} | 2904 checkFile(''' |
| 1970 | 2905 class A {} |
| 1971 class Base { | 2906 class B {} |
| 1972 m(B a) {} | 2907 |
| 1973 } | 2908 abstract class I1 { |
| 1974 | 2909 m(A a); |
| 1975 class T1 /*severe:InvalidMethodOverride*/extends Base | 2910 } |
| 1976 implements I2 { | 2911 abstract class I2 implements I1 {} |
| 1977 } | 2912 |
| 1978 ''' | 2913 class M { |
| 1979 }); | 2914 m(B a) {} |
| 1980 testChecker('interface of abstract superclass', { | 2915 } |
| 1981 '/main.dart': ''' | 2916 |
| 1982 class A {} | 2917 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 1983 class B {} | 2918 extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M |
| 1984 | 2919 implements I2 {} |
| 1985 abstract class I1 { | 2920 '''); |
| 1986 m(A a); | 2921 } |
| 1987 } | 2922 |
| 1988 | 2923 void test_mixinOverrideOfGrandInterface_mixinOfInterfaceOfChild() { |
| 1989 abstract class Base implements I1 { | 2924 checkFile(''' |
| 1990 /*severe:InvalidMethodOverride*/m(B a) {} | 2925 class A {} |
| 1991 } | 2926 class B {} |
| 1992 | 2927 |
| 1993 class T1 extends Base { | 2928 abstract class M1 { |
| 1994 // we consider the base class incomplete because it is | 2929 m(A a); |
| 1995 // abstract, so we report the error here too. | 2930 } |
| 1996 // TODO(sigmund): consider tracking overrides in a fine-grain | 2931 abstract class I2 extends Object with M1 {} |
| 1997 // manner, then this and the double-overrides would not be | 2932 |
| 1998 // reported. | 2933 class M { |
| 1999 /*severe:InvalidMethodOverride*/m(B a) {} | 2934 m(B a) {} |
| 2000 } | 2935 } |
| 2001 ''' | 2936 |
| 2002 }); | 2937 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 2003 testChecker('interface of concrete superclass', { | 2938 extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M |
| 2004 '/main.dart': ''' | 2939 implements I2 {} |
| 2005 class A {} | 2940 '''); |
| 2006 class B {} | 2941 } |
| 2007 | 2942 |
| 2008 abstract class I1 { | 2943 void test_mixinOverrideOfGrandInterface_superclassOfInterfaceOfChild() { |
| 2009 m(A a); | 2944 checkFile(''' |
| 2010 } | 2945 class A {} |
| 2011 | 2946 class B {} |
| 2012 class Base implements I1 { | 2947 |
| 2013 /*severe:InvalidMethodOverride*/m(B a) {} | 2948 abstract class I1 { |
| 2014 } | 2949 m(A a); |
| 2015 | 2950 } |
| 2016 class T1 extends Base { | 2951 abstract class I2 extends I1 {} |
| 2017 m(B a) {} | 2952 |
| 2018 } | 2953 class M { |
| 2019 ''' | 2954 m(B a) {} |
| 2020 }); | 2955 } |
| 2021 }); | 2956 |
| 2022 | 2957 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 2023 group('no duplicate reports from overriding interfaces', () { | 2958 extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M |
| 2024 testChecker('type overrides same method in multiple interfaces', { | 2959 implements I2 {} |
| 2025 '/main.dart': ''' | 2960 '''); |
| 2026 class A {} | 2961 } |
| 2027 class B {} | 2962 |
| 2028 | 2963 void |
| 2029 abstract class I1 { | 2964 test_noDuplicateReportsFromOverridingInterfaces_baseTypeAndMixinOverrideSa
meMethodInInterface() { |
| 2030 m(A a); | 2965 checkFile(''' |
| 2031 } | 2966 class A {} |
| 2032 abstract class I2 implements I1 { | 2967 class B {} |
| 2033 m(A a); | 2968 |
| 2034 } | 2969 abstract class I1 { |
| 2035 | 2970 m(A a); |
| 2036 class Base { | 2971 } |
| 2037 } | 2972 |
| 2038 | 2973 class Base { |
| 2039 class T1 implements I2 { | 2974 m(B a) {} |
| 2040 /*severe:InvalidMethodOverride*/m(B a) {} | 2975 } |
| 2041 } | 2976 |
| 2042 ''' | 2977 class M { |
| 2043 }); | 2978 m(B a) {} |
| 2044 | 2979 } |
| 2045 testChecker('type and base type override same method in interface', { | 2980 |
| 2046 '/main.dart': ''' | 2981 // Here we want to report both, because the error location is |
| 2047 class A {} | 2982 // different. |
| 2048 class B {} | 2983 // TODO(sigmund): should we merge these as well? |
| 2049 | 2984 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 2050 abstract class I1 { | 2985 /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base |
| 2051 m(A a); | 2986 with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M |
| 2052 } | 2987 implements I1 {} |
| 2053 | 2988 '''); |
| 2054 class Base { | 2989 } |
| 2055 m(B a); | 2990 |
| 2056 } | 2991 void |
| 2057 | 2992 test_noDuplicateReportsFromOverridingInterfaces_twoGrandTypesOverrideSameM
ethodInInterface() { |
| 2058 // Note: no error reported in `extends Base` to avoid duplicating | 2993 checkFile(''' |
| 2059 // the error in T1. | 2994 class A {} |
| 2060 class T1 extends Base implements I1 { | 2995 class B {} |
| 2061 /*severe:InvalidMethodOverride*/m(B a) {} | 2996 |
| 2062 } | 2997 abstract class I1 { |
| 2063 | 2998 m(A a); |
| 2064 // If there is no error in the class, we do report the error at | 2999 } |
| 2065 // the base class: | 3000 |
| 2066 class T2 /*severe:InvalidMethodOverride*/extends Base | 3001 class Grandparent { |
| 2067 implements I1 { | 3002 m(B a) {} |
| 2068 } | 3003 } |
| 2069 ''' | 3004 |
| 2070 }); | 3005 class Parent1 extends Grandparent { |
| 2071 | 3006 m(B a) {} |
| 2072 testChecker('type and mixin override same method in interface', { | 3007 } |
| 2073 '/main.dart': ''' | 3008 class Parent2 extends Grandparent {} |
| 2074 class A {} | 3009 |
| 2075 class B {} | 3010 // Note: otherwise both errors would be reported on this line |
| 2076 | 3011 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 2077 abstract class I1 { | 3012 /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Parent1 |
| 2078 m(A a); | 3013 implements I1 {} |
| 2079 } | 3014 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T2 |
| 2080 | 3015 /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Parent2 |
| 2081 class M { | 3016 implements I1 {} |
| 2082 m(B a); | 3017 '''); |
| 2083 } | 3018 } |
| 2084 | 3019 |
| 2085 class T1 extends Object with M implements I1 { | 3020 void |
| 2086 /*severe:InvalidMethodOverride*/m(B a) {} | 3021 test_noDuplicateReportsFromOverridingInterfaces_twoMixinsOverrideSameMetho
dInInterface() { |
| 2087 } | 3022 checkFile(''' |
| 2088 | 3023 class A {} |
| 2089 class T2 extends Object with /*severe:InvalidMethodOverride*/M | 3024 class B {} |
| 2090 implements I1 { | 3025 |
| 2091 } | 3026 abstract class I1 { |
| 2092 ''' | 3027 m(A a); |
| 2093 }); | 3028 } |
| 2094 | 3029 |
| 2095 testChecker('two grand types override same method in interface', { | 3030 class M1 { |
| 2096 '/main.dart': ''' | 3031 m(B a) {} |
| 2097 class A {} | 3032 } |
| 2098 class B {} | 3033 |
| 2099 | 3034 class M2 { |
| 2100 abstract class I1 { | 3035 m(B a) {} |
| 2101 m(A a); | 3036 } |
| 2102 } | 3037 |
| 2103 | 3038 // Here we want to report both, because the error location is |
| 2104 class Grandparent { | 3039 // different. |
| 2105 m(B a) {} | 3040 // TODO(sigmund): should we merge these as well? |
| 2106 } | 3041 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 extends Object |
| 2107 | 3042 with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M1, |
| 2108 class Parent1 extends Grandparent { | 3043 /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M2 |
| 2109 m(B a) {} | 3044 implements I1 {} |
| 2110 } | 3045 '''); |
| 2111 class Parent2 extends Grandparent { | 3046 } |
| 2112 } | 3047 |
| 2113 | 3048 void |
| 2114 // Note: otherwise both errors would be reported on this line | 3049 test_noDuplicateReportsFromOverridingInterfaces_typeAndBaseTypeOverrideSam
eMethodInInterface() { |
| 2115 class T1 /*severe:InvalidMethodOverride*/extends Parent1 | 3050 checkFile(''' |
| 2116 implements I1 { | 3051 class A {} |
| 2117 } | 3052 class B {} |
| 2118 class T2 /*severe:InvalidMethodOverride*/extends Parent2 | 3053 |
| 2119 implements I1 { | 3054 abstract class I1 { |
| 2120 } | 3055 m(A a); |
| 2121 ''' | 3056 } |
| 2122 }); | 3057 |
| 2123 | 3058 class Base { |
| 2124 testChecker('two mixins override same method in interface', { | 3059 m(B a) {} |
| 2125 '/main.dart': ''' | 3060 } |
| 2126 class A {} | 3061 |
| 2127 class B {} | 3062 // Note: no error reported in `extends Base` to avoid duplicating |
| 2128 | 3063 // the error in T1. |
| 2129 abstract class I1 { | 3064 class T1 extends Base implements I1 { |
| 2130 m(A a); | 3065 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 2131 } | 3066 } |
| 2132 | 3067 |
| 2133 class M1 { | 3068 // If there is no error in the class, we do report the error at |
| 2134 m(B a) {} | 3069 // the base class: |
| 2135 } | 3070 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T2 |
| 2136 | 3071 /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base |
| 2137 class M2 { | 3072 implements I1 {} |
| 2138 m(B a) {} | 3073 '''); |
| 2139 } | 3074 } |
| 2140 | 3075 |
| 2141 // Here we want to report both, because the error location is | 3076 void |
| 2142 // different. | 3077 test_noDuplicateReportsFromOverridingInterfaces_typeAndMixinOverrideSameMe
thodInInterface() { |
| 2143 // TODO(sigmund): should we merge these as well? | 3078 checkFile(''' |
| 2144 class T1 extends Object | 3079 class A {} |
| 2145 with /*severe:InvalidMethodOverride*/M1 | 3080 class B {} |
| 2146 with /*severe:InvalidMethodOverride*/M2 | 3081 |
| 2147 implements I1 { | 3082 abstract class I1 { |
| 2148 } | 3083 m(A a); |
| 2149 ''' | 3084 } |
| 2150 }); | 3085 |
| 2151 | 3086 class M { |
| 2152 testChecker('base type and mixin override same method in interface', { | 3087 m(B a) {} |
| 2153 '/main.dart': ''' | 3088 } |
| 2154 class A {} | 3089 |
| 2155 class B {} | 3090 class T1 extends Object with M implements I1 { |
| 2156 | 3091 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 2157 abstract class I1 { | 3092 } |
| 2158 m(A a); | 3093 |
| 2159 } | 3094 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T2 |
| 2160 | 3095 extends Object with /*error:INVALID_METHOD_OVERRIDE_FROM_MIXIN*/M |
| 2161 class Base { | 3096 implements I1 {} |
| 2162 m(B a) {} | 3097 '''); |
| 2163 } | 3098 } |
| 2164 | 3099 |
| 2165 class M { | 3100 void |
| 2166 m(B a) {} | 3101 test_noDuplicateReportsFromOverridingInterfaces_typeOverridesSomeMethodInM
ultipleInterfaces() { |
| 2167 } | 3102 checkFile(''' |
| 2168 | 3103 class A {} |
| 2169 // Here we want to report both, because the error location is | 3104 class B {} |
| 2170 // different. | 3105 |
| 2171 // TODO(sigmund): should we merge these as well? | 3106 abstract class I1 { |
| 2172 class T1 /*severe:InvalidMethodOverride*/extends Base | 3107 m(A a); |
| 2173 with /*severe:InvalidMethodOverride*/M | 3108 } |
| 2174 implements I1 { | 3109 abstract class I2 implements I1 { |
| 2175 } | 3110 m(A a); |
| 2176 ''' | 3111 } |
| 2177 }); | 3112 |
| 2178 }); | 3113 class Base {} |
| 2179 | 3114 |
| 2180 testChecker('invalid runtime checks', { | 3115 class T1 implements I2 { |
| 2181 '/main.dart': ''' | 3116 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 2182 typedef int I2I(int x); | 3117 } |
| 2183 typedef int D2I(x); | 3118 '''); |
| 2184 typedef int II2I(int x, int y); | 3119 } |
| 2185 typedef int DI2I(x, int y); | 3120 |
| 2186 typedef int ID2I(int x, y); | 3121 void test_nullCoalescingOperator() { |
| 2187 typedef int DD2I(x, y); | 3122 checkFile(''' |
| 2188 | 3123 class A {} |
| 2189 typedef I2D(int x); | 3124 class C<T> {} |
| 2190 typedef D2D(x); | 3125 main() { |
| 2191 typedef II2D(int x, int y); | 3126 A a, b; |
| 2192 typedef DI2D(x, int y); | 3127 a ??= new A(); |
| 2193 typedef ID2D(int x, y); | 3128 b = b ?? new A(); |
| 2194 typedef DD2D(x, y); | 3129 |
| 2195 | 3130 // downwards inference |
| 2196 int foo(int x) => x; | 3131 C<int> c, d; |
| 2197 int bar(int x, int y) => x + y; | 3132 c ??= /*info:INFERRED_TYPE_ALLOCATION*/new C(); |
| 2198 | 3133 d = d ?? /*info:INFERRED_TYPE_ALLOCATION*/new C(); |
| 2199 void main() { | 3134 } |
| 2200 bool b; | 3135 '''); |
| 2201 b = /*info:NonGroundTypeCheckInfo*/foo is I2I; | 3136 } |
| 2202 b = /*info:NonGroundTypeCheckInfo*/foo is D2I; | 3137 |
| 2203 b = /*info:NonGroundTypeCheckInfo*/foo is I2D; | 3138 void test_nullCoalescingStrictArrow() { |
| 2204 b = foo is D2D; | 3139 checkFile(r''' |
| 2205 | 3140 bool _alwaysTrue(x) => true; |
| 2206 b = /*info:NonGroundTypeCheckInfo*/bar is II2I; | 3141 typedef bool TakesA<T>(T t); |
| 2207 b = /*info:NonGroundTypeCheckInfo*/bar is DI2I; | 3142 class C<T> { |
| 2208 b = /*info:NonGroundTypeCheckInfo*/bar is ID2I; | 3143 TakesA<T> g; |
| 2209 b = /*info:NonGroundTypeCheckInfo*/bar is II2D; | 3144 C(TakesA<T> f) |
| 2210 b = /*info:NonGroundTypeCheckInfo*/bar is DD2I; | 3145 : g = f ?? _alwaysTrue; |
| 2211 b = /*info:NonGroundTypeCheckInfo*/bar is DI2D; | 3146 C.a() : g = _alwaysTrue; |
| 2212 b = /*info:NonGroundTypeCheckInfo*/bar is ID2D; | 3147 } |
| 2213 b = bar is DD2D; | 3148 '''); |
| 2214 | 3149 } |
| 2215 // For as, the validity of checks is deferred to runtime. | 3150 |
| 2216 Function f; | 3151 void test_optionalParams() { |
| 2217 f = foo as I2I; | 3152 // Regression test for https://github.com/dart-lang/sdk/issues/26155 |
| 2218 f = foo as D2I; | 3153 checkFile(r''' |
| 2219 f = foo as I2D; | 3154 void takesF(void f(int x)) { |
| 2220 f = foo as D2D; | 3155 takesF(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/([x]) { bool z
= x.isEven; }); |
| 2221 | 3156 takesF(/*info:INFERRED_TYPE_CLOSURE*/(y) { bool z = y.isEven; }); |
| 2222 f = bar as II2I; | 3157 } |
| 2223 f = bar as DI2I; | 3158 '''); |
| 2224 f = bar as ID2I; | 3159 } |
| 2225 f = bar as II2D; | 3160 |
| 2226 f = bar as DD2I; | 3161 void test_overrideNarrowsType() { |
| 2227 f = bar as DI2D; | 3162 addFile(r''' |
| 2228 f = bar as ID2D; | 3163 class A {} |
| 2229 f = bar as DD2D; | 3164 class B extends A {} |
| 2230 } | 3165 |
| 2231 ''' | 3166 abstract class C { |
| 2232 }); | 3167 m(A a); |
| 2233 | 3168 n(B b); |
| 2234 group('function modifiers', () { | 3169 } |
| 2235 testChecker('async', { | 3170 abstract class D extends C { |
| 2236 '/main.dart': ''' | 3171 /*error:INVALID_METHOD_OVERRIDE*/m(B b); |
| 2237 import 'dart:async'; | 3172 n(A a); |
| 2238 import 'dart:math' show Random; | 3173 } |
| 2239 | 3174 '''); |
| 2240 dynamic x; | 3175 check(implicitCasts: false); |
| 2241 | 3176 } |
| 2242 foo1() async => x; | 3177 |
| 2243 Future foo2() async => x; | 3178 void test_overrideNarrowsType_noDuplicateError() { |
| 2244 Future<int> foo3() async => (/*info:DynamicCast*/x); | 3179 // Regression test for https://github.com/dart-lang/sdk/issues/25232 |
| 2245 Future<int> foo4() async => (/*severe:StaticTypeError*/new Future<int>.v
alue(/*info:DynamicCast*/x)); | 3180 _addMetaLibrary(); |
| 2246 | 3181 checkFile(r''' |
| 2247 bar1() async { return x; } | 3182 import 'meta.dart'; |
| 2248 Future bar2() async { return x; } | 3183 abstract class A { void test(A arg) { } } |
| 2249 Future<int> bar3() async { return (/*info:DynamicCast*/x); } | 3184 abstract class B extends A { |
| 2250 Future<int> bar4() async { return (/*severe:StaticTypeError*/new Future<
int>.value(/*info:DynamicCast*/x)); } | 3185 /*error:INVALID_METHOD_OVERRIDE*/void test(B arg) { } |
| 2251 | 3186 } |
| 2252 int y; | 3187 abstract class X implements A { } |
| 2253 Future<int> z; | 3188 class C extends B with X { } |
| 2254 | 3189 |
| 2255 void baz() async { | 3190 // We treat "implements A" as asking for another check. |
| 2256 int a = /*info:DynamicCast*/await x; | 3191 // This feels inconsistent to me. |
| 2257 int b = await y; | 3192 class D /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends B implements A { } |
| 2258 int c = await z; | 3193 '''); |
| 2259 String d = /*severe:StaticTypeError*/await z; | 3194 } |
| 2260 } | 3195 |
| 2261 | 3196 void test_overrideNarrowsType_legalWithChecked() { |
| 2262 Future<bool> get issue_264 async { | 3197 // Regression test for https://github.com/dart-lang/sdk/issues/25232 |
| 2263 await 42; | 3198 _addMetaLibrary(); |
| 2264 if (new Random().nextBool()) { | 3199 checkFile(r''' |
| 2265 return true; | 3200 import 'meta.dart'; |
| 2266 } else { | 3201 abstract class A { void test(A arg) { } } |
| 2267 return /*severe:StaticTypeError*/new Future<bool>.value(false); | 3202 abstract class B extends A { void test(@checked B arg) { } } |
| 2268 } | 3203 abstract class X implements A { } |
| 2269 } | 3204 class C extends B with X { } |
| 2270 ''' | 3205 class D extends B implements A { } |
| 2271 }); | 3206 '''); |
| 2272 | 3207 } |
| 2273 testChecker('async*', { | 3208 |
| 2274 '/main.dart': ''' | 3209 void test_privateOverride() { |
| 2275 import 'dart:async'; | 3210 addFile( |
| 2276 | 3211 ''' |
| 2277 dynamic x; | 3212 import 'main.dart' as main; |
| 2278 | 3213 |
| 2279 bar1() async* { yield x; } | 3214 class Base { |
| 2280 Stream bar2() async* { yield x; } | 3215 var f1; |
| 2281 Stream<int> bar3() async* { yield (/*info:DynamicCast*/x); } | 3216 var _f2; |
| 2282 Stream<int> bar4() async* { yield (/*severe:StaticTypeError*/new Stream<
int>()); } | 3217 var _f3; |
| 2283 | 3218 get _f4 => null; |
| 2284 baz1() async* { yield* (/*info:DynamicCast*/x); } | 3219 |
| 2285 Stream baz2() async* { yield* (/*info:DynamicCast*/x); } | 3220 int _m1() => null; |
| 2286 Stream<int> baz3() async* { yield* (/*warning:DownCastComposite*/x); } | 3221 } |
| 2287 Stream<int> baz4() async* { yield* new Stream<int>(); } | 3222 |
| 2288 Stream<int> baz5() async* { yield* (/*info:InferredTypeAllocation*/new S
tream()); } | 3223 class GrandChild extends main.Child { |
| 2289 ''' | 3224 /*error:INVALID_FIELD_OVERRIDE*/var _f2; |
| 2290 }); | 3225 /*error:INVALID_FIELD_OVERRIDE*/var _f3; |
| 2291 | 3226 var _f4; |
| 2292 testChecker('sync*', { | 3227 |
| 2293 '/main.dart': ''' | 3228 /*error:INVALID_METHOD_OVERRIDE*/String _m1() => null; |
| 2294 import 'dart:async'; | 3229 } |
| 2295 | 3230 ''', |
| 2296 dynamic x; | 3231 name: '/helper.dart'); |
| 2297 | 3232 checkFile(''' |
| 2298 bar1() sync* { yield x; } | 3233 import 'helper.dart' as helper; |
| 2299 Iterable bar2() sync* { yield x; } | 3234 |
| 2300 Iterable<int> bar3() sync* { yield (/*info:DynamicCast*/x); } | 3235 class Child extends helper.Base { |
| 2301 Iterable<int> bar4() sync* { yield (/*severe:StaticTypeError*/new Iterab
le<int>()); } | 3236 /*error:INVALID_FIELD_OVERRIDE*/var f1; |
| 2302 | 3237 var _f2; |
| 2303 baz1() sync* { yield* (/*info:DynamicCast*/x); } | 3238 var _f4; |
| 2304 Iterable baz2() sync* { yield* (/*info:DynamicCast*/x); } | 3239 |
| 2305 Iterable<int> baz3() sync* { yield* (/*warning:DownCastComposite*/x); } | 3240 String _m1() => null; |
| 2306 Iterable<int> baz4() sync* { yield* new Iterable<int>(); } | 3241 } |
| 2307 Iterable<int> baz5() sync* { yield* (/*info:InferredTypeAllocation*/new
Iterable()); } | 3242 '''); |
| 2308 ''' | 3243 } |
| 2309 }); | 3244 |
| 2310 }); | 3245 void test_proxy() { |
| 2311 } | 3246 checkFile(r''' |
| 3247 @proxy class C {} |
| 3248 @proxy class D { |
| 3249 var f; |
| 3250 m() => null; |
| 3251 operator -() => null; |
| 3252 operator +(int other) => null; |
| 3253 operator [](int index) => null; |
| 3254 call() => null; |
| 3255 } |
| 3256 @proxy class F implements Function { noSuchMethod(i) => 42; } |
| 3257 |
| 3258 |
| 3259 m() { |
| 3260 D d = new D(); |
| 3261 d.m(); |
| 3262 d.m; |
| 3263 d.f; |
| 3264 -d; |
| 3265 d + 7; |
| 3266 d[7]; |
| 3267 d(); |
| 3268 |
| 3269 C c = new C(); |
| 3270 /*info:DYNAMIC_INVOKE*/c.m(); |
| 3271 /*info:DYNAMIC_INVOKE*/c.m; |
| 3272 /*info:DYNAMIC_INVOKE*/-c; |
| 3273 /*info:DYNAMIC_INVOKE*/c + 7; |
| 3274 /*info:DYNAMIC_INVOKE*/c[7]; |
| 3275 /*error:INVOCATION_OF_NON_FUNCTION,info:DYNAMIC_INVOKE*/c(); |
| 3276 |
| 3277 F f = new F(); |
| 3278 /*info:DYNAMIC_INVOKE*/f(); |
| 3279 } |
| 3280 '''); |
| 3281 } |
| 3282 |
| 3283 void test_redirectingConstructor() { |
| 3284 checkFile(''' |
| 3285 class A { |
| 3286 A(A x) {} |
| 3287 A.two() : this(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/3); |
| 3288 } |
| 3289 '''); |
| 3290 } |
| 3291 |
| 3292 void test_relaxedCasts() { |
| 3293 checkFile(''' |
| 3294 class A {} |
| 3295 |
| 3296 class L<T> {} |
| 3297 class M<T> extends L<T> {} |
| 3298 // L<dynamic|Object> |
| 3299 // / \ |
| 3300 // M<dynamic|Object> L<A> |
| 3301 // \ / |
| 3302 // M<A> |
| 3303 // In normal Dart, there are additional edges |
| 3304 // from M<A> to M<dynamic> |
| 3305 // from L<A> to M<dynamic> |
| 3306 // from L<A> to L<dynamic> |
| 3307 void main() { |
| 3308 L lOfDs; |
| 3309 L<Object> lOfOs; |
| 3310 L<A> lOfAs; |
| 3311 |
| 3312 M mOfDs; |
| 3313 M<Object> mOfOs; |
| 3314 M<A> mOfAs; |
| 3315 |
| 3316 { |
| 3317 lOfDs = mOfDs; |
| 3318 lOfDs = mOfOs; |
| 3319 lOfDs = mOfAs; |
| 3320 lOfDs = lOfDs; |
| 3321 lOfDs = lOfOs; |
| 3322 lOfDs = lOfAs; |
| 3323 lOfDs = new L(); // Reset type propagation. |
| 3324 } |
| 3325 { |
| 3326 lOfOs = mOfDs; |
| 3327 lOfOs = mOfOs; |
| 3328 lOfOs = mOfAs; |
| 3329 lOfOs = lOfDs; |
| 3330 lOfOs = lOfOs; |
| 3331 lOfOs = lOfAs; |
| 3332 lOfOs = new L<Object>(); // Reset type propagation. |
| 3333 } |
| 3334 { |
| 3335 lOfAs = /*error:INVALID_ASSIGNMENT*/mOfDs; |
| 3336 lOfAs = /*error:INVALID_ASSIGNMENT*/mOfOs; |
| 3337 lOfAs = mOfAs; |
| 3338 lOfAs = /*warning:DOWN_CAST_COMPOSITE*/lOfDs; |
| 3339 lOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfOs; |
| 3340 lOfAs = lOfAs; |
| 3341 lOfAs = new L<A>(); // Reset type propagation. |
| 3342 } |
| 3343 { |
| 3344 mOfDs = mOfDs; |
| 3345 mOfDs = mOfOs; |
| 3346 mOfDs = mOfAs; |
| 3347 mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfDs; |
| 3348 mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfOs; |
| 3349 mOfDs = /*error:INVALID_ASSIGNMENT*/lOfAs; |
| 3350 mOfDs = new M(); // Reset type propagation. |
| 3351 } |
| 3352 { |
| 3353 mOfOs = mOfDs; |
| 3354 mOfOs = mOfOs; |
| 3355 mOfOs = mOfAs; |
| 3356 mOfOs = /*info:DOWN_CAST_IMPLICIT*/lOfDs; |
| 3357 mOfOs = /*info:DOWN_CAST_IMPLICIT*/lOfOs; |
| 3358 mOfOs = /*error:INVALID_ASSIGNMENT*/lOfAs; |
| 3359 mOfOs = new M<Object>(); // Reset type propagation. |
| 3360 } |
| 3361 { |
| 3362 mOfAs = /*warning:DOWN_CAST_COMPOSITE*/mOfDs; |
| 3363 mOfAs = /*info:DOWN_CAST_IMPLICIT*/mOfOs; |
| 3364 mOfAs = mOfAs; |
| 3365 mOfAs = /*warning:DOWN_CAST_COMPOSITE*/lOfDs; |
| 3366 mOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfOs; |
| 3367 mOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfAs; |
| 3368 } |
| 3369 } |
| 3370 '''); |
| 3371 } |
| 3372 |
| 3373 void test_setterOverride_fuzzyArrows() { |
| 3374 checkFile(''' |
| 3375 typedef void ToVoid<T>(T x); |
| 3376 class F { |
| 3377 void set f(ToVoid<dynamic> x) {} |
| 3378 void set g(ToVoid<int> x) {} |
| 3379 void set h(dynamic x) {} |
| 3380 void set i(int x) {} |
| 3381 } |
| 3382 |
| 3383 class G extends F { |
| 3384 /*error:INVALID_METHOD_OVERRIDE*/void set f(ToVoid<int> x) {} |
| 3385 void set g(ToVoid<dynamic> x) {} |
| 3386 /*error:INVALID_METHOD_OVERRIDE*/void set h(int x) {} |
| 3387 void set i(dynamic x) {} |
| 3388 } |
| 3389 |
| 3390 class H implements F { |
| 3391 /*error:INVALID_METHOD_OVERRIDE*/void set f(ToVoid<int> x) {} |
| 3392 void set g(ToVoid<dynamic> x) {} |
| 3393 /*error:INVALID_METHOD_OVERRIDE*/void set h(int x) {} |
| 3394 void set i(dynamic x) {} |
| 3395 } |
| 3396 '''); |
| 3397 } |
| 3398 |
| 3399 void test_setterReturnTypes() { |
| 3400 checkFile(''' |
| 3401 void voidFn() => null; |
| 3402 class A { |
| 3403 set a(y) => 4; |
| 3404 set b(y) => voidFn(); |
| 3405 void set c(y) => /*error:RETURN_OF_INVALID_TYPE*/4; |
| 3406 void set d(y) => voidFn(); |
| 3407 /*warning:NON_VOID_RETURN_FOR_SETTER*/int set e(y) => 4; |
| 3408 /*warning:NON_VOID_RETURN_FOR_SETTER*/int set f(y) => |
| 3409 /*error:RETURN_OF_INVALID_TYPE*/voidFn(); |
| 3410 set g(y) {return /*error:RETURN_OF_INVALID_TYPE*/4;} |
| 3411 void set h(y) {return /*error:RETURN_OF_INVALID_TYPE*/4;} |
| 3412 /*warning:NON_VOID_RETURN_FOR_SETTER*/int set i(y) {return 4;} |
| 3413 } |
| 3414 '''); |
| 3415 } |
| 3416 |
| 3417 void test_setterSetterOverride() { |
| 3418 checkFile(''' |
| 3419 class A {} |
| 3420 class B extends A {} |
| 3421 class C extends B {} |
| 3422 |
| 3423 abstract class Base { |
| 3424 void set f1(B value); |
| 3425 void set f2(B value); |
| 3426 void set f3(B value); |
| 3427 void set f4(B value); |
| 3428 void set f5(B value); |
| 3429 } |
| 3430 |
| 3431 class Child extends Base { |
| 3432 void set f1(A value) {} |
| 3433 /*error:INVALID_METHOD_OVERRIDE*/void set f2(C value) {} |
| 3434 void set f3(value) {} |
| 3435 void set f4(dynamic value) {} |
| 3436 set f5(B value) {} |
| 3437 } |
| 3438 '''); |
| 3439 } |
| 3440 |
| 3441 void test_superCallPlacement() { |
| 3442 checkFile(''' |
| 3443 class Base { |
| 3444 var x; |
| 3445 Base() : x = print('Base.1') { print('Base.2'); } |
| 3446 } |
| 3447 |
| 3448 class Derived extends Base { |
| 3449 var y, z; |
| 3450 Derived() |
| 3451 : y = print('Derived.1'), |
| 3452 /*error:INVALID_SUPER_INVOCATION*/super(), |
| 3453 z = print('Derived.2') { |
| 3454 print('Derived.3'); |
| 3455 } |
| 3456 } |
| 3457 |
| 3458 class Valid extends Base { |
| 3459 var y, z; |
| 3460 Valid() |
| 3461 : y = print('Valid.1'), |
| 3462 z = print('Valid.2'), |
| 3463 super() { |
| 3464 print('Valid.3'); |
| 3465 } |
| 3466 } |
| 3467 |
| 3468 class AlsoValid extends Base { |
| 3469 AlsoValid() : super(); |
| 3470 } |
| 3471 |
| 3472 main() => new Derived(); |
| 3473 '''); |
| 3474 } |
| 3475 |
| 3476 void test_superclassOverrideOfGrandInterface_interfaceOfAbstractSuperclass() { |
| 3477 checkFile(''' |
| 3478 class A {} |
| 3479 class B {} |
| 3480 |
| 3481 abstract class I1 { |
| 3482 m(A a); |
| 3483 } |
| 3484 |
| 3485 abstract class Base implements I1 { |
| 3486 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 3487 } |
| 3488 |
| 3489 class T1 extends Base { |
| 3490 // we consider the base class incomplete because it is |
| 3491 // abstract, so we report the error here too. |
| 3492 // TODO(sigmund): consider tracking overrides in a fine-grain |
| 3493 // manner, then this and the double-overrides would not be |
| 3494 // reported. |
| 3495 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 3496 } |
| 3497 '''); |
| 3498 } |
| 3499 |
| 3500 void test_superclassOverrideOfGrandInterface_interfaceOfConcreteSuperclass() { |
| 3501 checkFile(''' |
| 3502 class A {} |
| 3503 class B {} |
| 3504 |
| 3505 abstract class I1 { |
| 3506 m(A a); |
| 3507 } |
| 3508 |
| 3509 class Base implements I1 { |
| 3510 /*error:INVALID_METHOD_OVERRIDE*/m(B a) {} |
| 3511 } |
| 3512 |
| 3513 class T1 extends Base { |
| 3514 m(B a) {} |
| 3515 } |
| 3516 '''); |
| 3517 } |
| 3518 |
| 3519 void test_superclassOverrideOfGrandInterface_interfaceOfInterfaceOfChild() { |
| 3520 checkFile(''' |
| 3521 class A {} |
| 3522 class B {} |
| 3523 |
| 3524 abstract class I1 { |
| 3525 m(A a); |
| 3526 } |
| 3527 abstract class I2 implements I1 {} |
| 3528 |
| 3529 class Base { |
| 3530 m(B a) {} |
| 3531 } |
| 3532 |
| 3533 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 3534 /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base implements I2 {} |
| 3535 '''); |
| 3536 } |
| 3537 |
| 3538 void test_superclassOverrideOfGrandInterface_mixinOfInterfaceOfChild() { |
| 3539 checkFile(''' |
| 3540 class A {} |
| 3541 class B {} |
| 3542 |
| 3543 abstract class M1 { |
| 3544 m(A a); |
| 3545 } |
| 3546 abstract class I2 extends Object with M1 {} |
| 3547 |
| 3548 class Base { |
| 3549 m(B a) {} |
| 3550 } |
| 3551 |
| 3552 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 3553 /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base |
| 3554 implements I2 {} |
| 3555 '''); |
| 3556 } |
| 3557 |
| 3558 void test_superclassOverrideOfGrandInterface_superclassOfInterfaceOfChild() { |
| 3559 checkFile(''' |
| 3560 class A {} |
| 3561 class B {} |
| 3562 |
| 3563 abstract class I1 { |
| 3564 m(A a); |
| 3565 } |
| 3566 abstract class I2 extends I1 {} |
| 3567 |
| 3568 class Base { |
| 3569 m(B a) {} |
| 3570 } |
| 3571 |
| 3572 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T1 |
| 3573 /*error:INVALID_METHOD_OVERRIDE_FROM_BASE*/extends Base |
| 3574 implements I2 {} |
| 3575 '''); |
| 3576 } |
| 3577 |
| 3578 void test_superConstructor() { |
| 3579 checkFile(''' |
| 3580 class A { A(A x) {} } |
| 3581 class B extends A { |
| 3582 B() : super(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/3); |
| 3583 } |
| 3584 '''); |
| 3585 } |
| 3586 |
| 3587 void test_ternaryOperator() { |
| 3588 checkFile(''' |
| 3589 abstract class Comparable<T> { |
| 3590 int compareTo(T other); |
| 3591 static int compare(Comparable a, Comparable b) => a.compareTo(b); |
| 3592 } |
| 3593 typedef int Comparator<T>(T a, T b); |
| 3594 |
| 3595 typedef bool _Predicate<T>(T value); |
| 3596 |
| 3597 class SplayTreeMap<K, V> { |
| 3598 Comparator<K> _comparator; |
| 3599 _Predicate _validKey; |
| 3600 |
| 3601 // The warning on assigning to _comparator is legitimate. Since K has |
| 3602 // no bound, all we know is that it's object. _comparator's function |
| 3603 // type is effectively: (Object, Object) -> int |
| 3604 // We are assigning it a fn of type: (Comparable, Comparable) -> int |
| 3605 // There's no telling if that will work. For example, consider: |
| 3606 // |
| 3607 // new SplayTreeMap<Uri>(); |
| 3608 // |
| 3609 // This would end up calling .compareTo() on a Uri, which doesn't |
| 3610 // define that since it doesn't implement Comparable. |
| 3611 SplayTreeMap([int compare(K key1, K key2), |
| 3612 bool isValidKey(potentialKey)]) |
| 3613 : _comparator = /*warning:DOWN_CAST_COMPOSITE*/(compare == null) ? Comparabl
e.compare : compare, |
| 3614 _validKey = (isValidKey != null) ? isValidKey : ((v) => true) { |
| 3615 |
| 3616 // NOTE: this is a down cast because isValidKey has fuzzy arrow type. |
| 3617 _Predicate<Object> v = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null) |
| 3618 ? isValidKey : (/*info:INFERRED_TYPE_CLOSURE*/(_) => true); |
| 3619 |
| 3620 v = (isValidKey != null) |
| 3621 ? v : (/*info:INFERRED_TYPE_CLOSURE*/(_) => true); |
| 3622 } |
| 3623 } |
| 3624 void main() { |
| 3625 Object obj = 42; |
| 3626 dynamic dyn = 42; |
| 3627 int i = 42; |
| 3628 |
| 3629 // Check the boolean conversion of the condition. |
| 3630 print(/*error:NON_BOOL_CONDITION*/i ? false : true); |
| 3631 print((/*info:DOWN_CAST_IMPLICIT*/obj) ? false : true); |
| 3632 print((/*info:DYNAMIC_CAST*/dyn) ? false : true); |
| 3633 } |
| 3634 '''); |
| 3635 } |
| 3636 |
| 3637 void test_typeCheckingLiterals() { |
| 3638 checkFile(''' |
| 3639 test() { |
| 3640 num n = 3; |
| 3641 int i = 3; |
| 3642 String s = "hello"; |
| 3643 { |
| 3644 List<int> l = <int>[i]; |
| 3645 l = <int>[/*error:LIST_ELEMENT_TYPE_NOT_ASSIGNABLE*/s]; |
| 3646 l = <int>[/*info:DOWN_CAST_IMPLICIT*/n]; |
| 3647 l = <int>[i, /*info:DOWN_CAST_IMPLICIT*/n, /*error:LIST_ELEMENT_TYPE_NOT_AS
SIGNABLE*/s]; |
| 3648 } |
| 3649 { |
| 3650 List l = /*info:INFERRED_TYPE_LITERAL*/[i]; |
| 3651 l = /*info:INFERRED_TYPE_LITERAL*/[s]; |
| 3652 l = /*info:INFERRED_TYPE_LITERAL*/[n]; |
| 3653 l = /*info:INFERRED_TYPE_LITERAL*/[i, n, s]; |
| 3654 } |
| 3655 { |
| 3656 Map<String, int> m = <String, int>{s: i}; |
| 3657 m = <String, int>{s: /*error:MAP_VALUE_TYPE_NOT_ASSIGNABLE*/s}; |
| 3658 m = <String, int>{s: /*info:DOWN_CAST_IMPLICIT*/n}; |
| 3659 m = <String, int>{s: i, |
| 3660 s: /*info:DOWN_CAST_IMPLICIT*/n, |
| 3661 s: /*error:MAP_VALUE_TYPE_NOT_ASSIGNABLE*/s}; |
| 3662 } |
| 3663 // TODO(leafp): We can't currently test for key errors since the |
| 3664 // error marker binds to the entire entry. |
| 3665 { |
| 3666 Map m = /*info:INFERRED_TYPE_LITERAL*/{s: i}; |
| 3667 m = /*info:INFERRED_TYPE_LITERAL*/{s: s}; |
| 3668 m = /*info:INFERRED_TYPE_LITERAL*/{s: n}; |
| 3669 m = /*info:INFERRED_TYPE_LITERAL*/ |
| 3670 {s: i, |
| 3671 s: n, |
| 3672 s: s}; |
| 3673 m = /*info:INFERRED_TYPE_LITERAL*/ |
| 3674 {i: s, |
| 3675 n: s, |
| 3676 s: s}; |
| 3677 } |
| 3678 } |
| 3679 '''); |
| 3680 } |
| 3681 |
| 3682 void test_typePromotionFromDynamic() { |
| 3683 checkFile(r''' |
| 3684 f() { |
| 3685 dynamic x; |
| 3686 if (x is int) { |
| 3687 int y = x; |
| 3688 String z = /*error:INVALID_ASSIGNMENT*/x; |
| 3689 } |
| 3690 } |
| 3691 g() { |
| 3692 Object x; |
| 3693 if (x is int) { |
| 3694 int y = x; |
| 3695 String z = /*error:INVALID_ASSIGNMENT*/x; |
| 3696 } |
| 3697 } |
| 3698 '''); |
| 3699 } |
| 3700 |
| 3701 void test_typePromotionFromTypeParameter() { |
| 3702 // Regression test for https://github.com/dart-lang/sdk/issues/26965 |
| 3703 checkFile(r''' |
| 3704 void f/*<T>*/(/*=T*/ object) { |
| 3705 if (object is String) print(object.substring(1)); |
| 3706 } |
| 3707 void g/*<T extends num>*/(/*=T*/ object) { |
| 3708 if (object is int) print(object.isEven); |
| 3709 if (object is String) print(/*info:DYNAMIC_INVOKE*/object.substring(1)); |
| 3710 } |
| 3711 class Clonable<T> {} |
| 3712 class SubClonable<T> extends Clonable<T> { |
| 3713 T m(T t) => t; |
| 3714 } |
| 3715 void h/*<T extends Clonable<T>>*/(/*=T*/ object) { |
| 3716 if (/*info:NON_GROUND_TYPE_CHECK_INFO*/object is SubClonable/*<T>*/) { |
| 3717 // Note we need to cast back to T, because promotion lost that type info. |
| 3718 print(object.m(object as dynamic/*=T*/)); |
| 3719 } |
| 3720 } |
| 3721 '''); |
| 3722 } |
| 3723 |
| 3724 void test_typeSubtyping_assigningClass() { |
| 3725 checkFile(''' |
| 3726 class A {} |
| 3727 class B extends A {} |
| 3728 |
| 3729 void main() { |
| 3730 dynamic y; |
| 3731 Object o; |
| 3732 int i = 0; |
| 3733 double d = 0.0; |
| 3734 num n; |
| 3735 A a; |
| 3736 B b; |
| 3737 y = a; |
| 3738 o = a; |
| 3739 i = /*error:INVALID_ASSIGNMENT*/a; |
| 3740 d = /*error:INVALID_ASSIGNMENT*/a; |
| 3741 n = /*error:INVALID_ASSIGNMENT*/a; |
| 3742 a = a; |
| 3743 b = /*info:DOWN_CAST_IMPLICIT*/a; |
| 3744 } |
| 3745 '''); |
| 3746 } |
| 3747 |
| 3748 void test_typeSubtyping_assigningSubclass() { |
| 3749 checkFile(''' |
| 3750 class A {} |
| 3751 class B extends A {} |
| 3752 class C extends A {} |
| 3753 |
| 3754 void main() { |
| 3755 dynamic y; |
| 3756 Object o; |
| 3757 int i = 0; |
| 3758 double d = 0.0; |
| 3759 num n; |
| 3760 A a; |
| 3761 B b; |
| 3762 C c; |
| 3763 y = b; |
| 3764 o = b; |
| 3765 i = /*error:INVALID_ASSIGNMENT*/b; |
| 3766 d = /*error:INVALID_ASSIGNMENT*/b; |
| 3767 n = /*error:INVALID_ASSIGNMENT*/b; |
| 3768 a = b; |
| 3769 b = b; |
| 3770 c = /*error:INVALID_ASSIGNMENT*/b; |
| 3771 } |
| 3772 '''); |
| 3773 } |
| 3774 |
| 3775 void test_typeSubtyping_dynamicDowncasts() { |
| 3776 checkFile(''' |
| 3777 class A {} |
| 3778 class B extends A {} |
| 3779 |
| 3780 void main() { |
| 3781 dynamic y; |
| 3782 Object o; |
| 3783 int i = 0; |
| 3784 double d = 0.0; |
| 3785 num n; |
| 3786 A a; |
| 3787 B b; |
| 3788 o = y; |
| 3789 i = /*info:DYNAMIC_CAST*/y; |
| 3790 d = /*info:DYNAMIC_CAST*/y; |
| 3791 n = /*info:DYNAMIC_CAST*/y; |
| 3792 a = /*info:DYNAMIC_CAST*/y; |
| 3793 b = /*info:DYNAMIC_CAST*/y; |
| 3794 } |
| 3795 '''); |
| 3796 } |
| 3797 |
| 3798 void test_typeSubtyping_dynamicIsTop() { |
| 3799 checkFile(''' |
| 3800 class A {} |
| 3801 class B extends A {} |
| 3802 |
| 3803 void main() { |
| 3804 dynamic y; |
| 3805 Object o; |
| 3806 int i = 0; |
| 3807 double d = 0.0; |
| 3808 num n; |
| 3809 A a; |
| 3810 B b; |
| 3811 y = o; |
| 3812 y = i; |
| 3813 y = d; |
| 3814 y = n; |
| 3815 y = a; |
| 3816 y = b; |
| 3817 } |
| 3818 '''); |
| 3819 } |
| 3820 |
| 3821 void test_typeSubtyping_interfaces() { |
| 3822 checkFile(''' |
| 3823 class A {} |
| 3824 class B extends A {} |
| 3825 class C extends A {} |
| 3826 class D extends B implements C {} |
| 3827 |
| 3828 void main() { |
| 3829 A top; |
| 3830 B left; |
| 3831 C right; |
| 3832 D bot; |
| 3833 { |
| 3834 top = top; |
| 3835 top = left; |
| 3836 top = right; |
| 3837 top = bot; |
| 3838 } |
| 3839 { |
| 3840 left = /*info:DOWN_CAST_IMPLICIT*/top; |
| 3841 left = left; |
| 3842 left = /*error:INVALID_ASSIGNMENT*/right; |
| 3843 left = bot; |
| 3844 } |
| 3845 { |
| 3846 right = /*info:DOWN_CAST_IMPLICIT*/top; |
| 3847 right = /*error:INVALID_ASSIGNMENT*/left; |
| 3848 right = right; |
| 3849 right = bot; |
| 3850 } |
| 3851 { |
| 3852 bot = /*info:DOWN_CAST_IMPLICIT*/top; |
| 3853 bot = /*info:DOWN_CAST_IMPLICIT*/left; |
| 3854 bot = /*info:DOWN_CAST_IMPLICIT*/right; |
| 3855 bot = bot; |
| 3856 } |
| 3857 } |
| 3858 '''); |
| 3859 } |
| 3860 |
| 3861 void test_unaryOperators() { |
| 3862 checkFile(''' |
| 3863 class A { |
| 3864 A operator ~() => null; |
| 3865 A operator +(int x) => null; |
| 3866 A operator -(int x) => null; |
| 3867 A operator -() => null; |
| 3868 } |
| 3869 class B extends A {} |
| 3870 class C extends B {} |
| 3871 |
| 3872 foo() => new A(); |
| 3873 |
| 3874 test() { |
| 3875 A a = new A(); |
| 3876 B b = new B(); |
| 3877 var c = foo(); |
| 3878 dynamic d; |
| 3879 |
| 3880 ~a; |
| 3881 (/*info:DYNAMIC_INVOKE*/~d); |
| 3882 |
| 3883 !/*error:NON_BOOL_NEGATION_EXPRESSION*/a; |
| 3884 !/*info:DYNAMIC_CAST*/d; |
| 3885 |
| 3886 -a; |
| 3887 (/*info:DYNAMIC_INVOKE*/-d); |
| 3888 |
| 3889 ++a; |
| 3890 --a; |
| 3891 (/*info:DYNAMIC_INVOKE*/++d); |
| 3892 (/*info:DYNAMIC_INVOKE*/--d); |
| 3893 |
| 3894 a++; |
| 3895 a--; |
| 3896 (/*info:DYNAMIC_INVOKE*/d++); |
| 3897 (/*info:DYNAMIC_INVOKE*/d--); |
| 3898 |
| 3899 ++/*info:DOWN_CAST_IMPLICIT_ASSIGN*/b; |
| 3900 --/*info:DOWN_CAST_IMPLICIT_ASSIGN*/b; |
| 3901 /*info:DOWN_CAST_IMPLICIT_ASSIGN*/b++; |
| 3902 /*info:DOWN_CAST_IMPLICIT_ASSIGN*/b--; |
| 3903 |
| 3904 takesC(C c) => null; |
| 3905 takesC(/*info:DOWN_CAST_IMPLICIT*/++/*info:DOWN_CAST_IMPLICIT_ASSIGN*/b); |
| 3906 takesC(/*info:DOWN_CAST_IMPLICIT*/--/*info:DOWN_CAST_IMPLICIT_ASSIGN*/b); |
| 3907 takesC(/*info:DOWN_CAST_IMPLICIT,info:DOWN_CAST_IMPLICIT_ASSIGN*/b++); |
| 3908 takesC(/*info:DOWN_CAST_IMPLICIT,info:DOWN_CAST_IMPLICIT_ASSIGN*/b--); |
| 3909 }'''); |
| 3910 } |
| 3911 |
| 3912 void test_unboundRedirectingConstructor() { |
| 3913 // This is a regression test for https://github.com/dart-lang/sdk/issues/250
71 |
| 3914 checkFile(''' |
| 3915 class Foo { |
| 3916 Foo() : /*error:REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR*/this.init(); |
| 3917 } |
| 3918 '''); |
| 3919 } |
| 3920 |
| 3921 void test_unboundTypeName() { |
| 3922 checkFile(''' |
| 3923 void main() { |
| 3924 /*error:UNDEFINED_CLASS*/AToB y; |
| 3925 } |
| 3926 '''); |
| 3927 } |
| 3928 |
| 3929 void test_unboundVariable() { |
| 3930 checkFile(''' |
| 3931 void main() { |
| 3932 dynamic y = /*error:UNDEFINED_IDENTIFIER*/unboundVariable; |
| 3933 } |
| 3934 '''); |
| 3935 } |
| 3936 |
| 3937 void test_voidSubtyping() { |
| 3938 // Regression test for https://github.com/dart-lang/sdk/issues/25069 |
| 3939 checkFile(''' |
| 3940 typedef int Foo(); |
| 3941 void foo() {} |
| 3942 void main () { |
| 3943 Foo x = /*error:INVALID_ASSIGNMENT,info:USE_OF_VOID_RESULT*/foo(); |
| 3944 } |
| 3945 '''); |
| 3946 } |
| 3947 } |
| 3948 |
| 3949 void _addMetaLibrary() { |
| 3950 addFile(r''' |
| 3951 library meta; |
| 3952 class _Checked { const _Checked(); } |
| 3953 const Object checked = const _Checked(); |
| 3954 |
| 3955 class _Virtual { const _Virtual(); } |
| 3956 const Object virtual = const _Virtual(); |
| 3957 ''', name: '/meta.dart'); |
| 3958 } |
| OLD | NEW |