OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'package:kernel/ast.dart'; | 5 import 'package:kernel/ast.dart'; |
5 import 'package:kernel/text/ast_to_text.dart'; | 6 import 'package:kernel/text/ast_to_text.dart'; |
6 import 'package:kernel/verifier.dart'; | 7 import 'package:kernel/verifier.dart'; |
7 import 'package:test/test.dart'; | 8 import 'package:test/test.dart'; |
8 | 9 |
| 10 const String varRegexp = "#t[0-9]+"; |
| 11 |
| 12 const String tvarRegexp = "#T[0-9]+"; |
| 13 |
9 /// Checks that the verifier correctly find errors in invalid programs. | 14 /// Checks that the verifier correctly find errors in invalid programs. |
10 /// | 15 /// |
11 /// The frontend should never generate invalid programs, so we have to test | 16 /// The frontend should never generate invalid programs, so we have to test |
12 /// these by manually constructing invalid ASTs. | 17 /// these by manually constructing invalid ASTs. |
13 /// | 18 /// |
14 /// We mostly test negative cases here, as we get plenty of positive cases by | 19 /// We mostly test negative cases here, as we get plenty of positive cases by |
15 /// compiling the Dart test suite with the verifier enabled. | 20 /// compiling the Dart test suite with the verifier enabled. |
16 main() { | 21 main() { |
17 positiveTest('Test harness has no errors', (TestHarness test) { | 22 positiveTest('Test harness has no errors', (TestHarness test) { |
18 return new NullLiteral(); | 23 return new NullLiteral(); |
19 }); | 24 }); |
20 negativeTest('VariableGet out of scope', (TestHarness test) { | 25 negativeTest('VariableGet out of scope', |
| 26 matches("Variable '$varRegexp' used out of scope\\."), |
| 27 (TestHarness test) { |
21 return new VariableGet(test.makeVariable()); | 28 return new VariableGet(test.makeVariable()); |
22 }); | 29 }); |
23 negativeTest('VariableSet out of scope', (TestHarness test) { | 30 negativeTest('VariableSet out of scope', |
| 31 matches("Variable '$varRegexp' used out of scope\\."), |
| 32 (TestHarness test) { |
24 return new VariableSet(test.makeVariable(), new NullLiteral()); | 33 return new VariableSet(test.makeVariable(), new NullLiteral()); |
25 }); | 34 }); |
26 negativeTest('Variable block scope', (TestHarness test) { | 35 negativeTest('Variable block scope', |
| 36 matches("Variable '$varRegexp' used out of scope\\."), |
| 37 (TestHarness test) { |
27 VariableDeclaration variable = test.makeVariable(); | 38 VariableDeclaration variable = test.makeVariable(); |
28 return new Block([ | 39 return new Block([ |
29 new Block([variable]), | 40 new Block([variable]), |
30 new ReturnStatement(new VariableGet(variable)) | 41 new ReturnStatement(new VariableGet(variable)) |
31 ]); | 42 ]); |
32 }); | 43 }); |
33 negativeTest('Variable let scope', (TestHarness test) { | 44 negativeTest('Variable let scope', |
| 45 matches("Variable '$varRegexp' used out of scope\\."), |
| 46 (TestHarness test) { |
34 VariableDeclaration variable = test.makeVariable(); | 47 VariableDeclaration variable = test.makeVariable(); |
35 return new LogicalExpression(new Let(variable, new VariableGet(variable)), | 48 return new LogicalExpression(new Let(variable, new VariableGet(variable)), |
36 '&&', new VariableGet(variable)); | 49 '&&', new VariableGet(variable)); |
37 }); | 50 }); |
38 negativeTest('Variable redeclared', (TestHarness test) { | 51 negativeTest('Variable redeclared', |
| 52 matches("Variable '$varRegexp' declared more than once\\."), |
| 53 (TestHarness test) { |
39 VariableDeclaration variable = test.makeVariable(); | 54 VariableDeclaration variable = test.makeVariable(); |
40 return new Block([variable, variable]); | 55 return new Block([variable, variable]); |
41 }); | 56 }); |
42 negativeTest('Member redeclared', (TestHarness test) { | 57 negativeTest('Member redeclared', |
| 58 "Member 'test_lib::Test::field' has been declared more than once.", |
| 59 (TestHarness test) { |
43 Field field = new Field(new Name('field'), initializer: new NullLiteral()); | 60 Field field = new Field(new Name('field'), initializer: new NullLiteral()); |
44 return new Class( | 61 return new Class( |
45 name: 'Test', | 62 name: 'Test', |
46 supertype: test.objectClass.asRawSupertype, | 63 supertype: test.objectClass.asRawSupertype, |
47 fields: [field, field]); | 64 fields: [field, field]); |
48 }); | 65 }); |
49 negativeTest('Class redeclared', (TestHarness test) { | 66 negativeTest('Class redeclared', |
| 67 "Class 'test_lib::OtherClass' declared more than once.", |
| 68 (TestHarness test) { |
50 return test.otherClass; // Test harness also adds otherClass to program. | 69 return test.otherClass; // Test harness also adds otherClass to program. |
51 }); | 70 }); |
52 negativeTest('Class type parameter redeclared', (TestHarness test) { | 71 negativeTest('Class type parameter redeclared', |
| 72 matches("Type parameter 'test_lib::Test::$tvarRegexp' redeclared\\."), |
| 73 (TestHarness test) { |
53 var parameter = test.makeTypeParameter(); | 74 var parameter = test.makeTypeParameter(); |
54 return new Class( | 75 return new Class( |
55 name: 'Test', | 76 name: 'Test', |
56 supertype: test.objectClass.asRawSupertype, | 77 supertype: test.objectClass.asRawSupertype, |
57 typeParameters: [parameter, parameter]); | 78 typeParameters: [parameter, parameter]); |
58 }); | 79 }); |
59 negativeTest('Member type parameter redeclared', (TestHarness test) { | 80 negativeTest('Member type parameter redeclared', |
| 81 matches("Type parameter '$tvarRegexp' redeclared\\."), |
| 82 (TestHarness test) { |
60 var parameter = test.makeTypeParameter(); | 83 var parameter = test.makeTypeParameter(); |
61 return new Procedure( | 84 return new Procedure( |
62 new Name('bar'), | 85 new Name('bar'), |
63 ProcedureKind.Method, | 86 ProcedureKind.Method, |
64 new FunctionNode(new ReturnStatement(new NullLiteral()), | 87 new FunctionNode(new ReturnStatement(new NullLiteral()), |
65 typeParameters: [parameter, parameter])); | 88 typeParameters: [parameter, parameter])); |
66 }); | 89 }); |
67 negativeTest('Type parameter out of scope', (TestHarness test) { | 90 negativeTest( |
| 91 'Type parameter out of scope', |
| 92 matches("Type parameter '$tvarRegexp' referenced out of scope," |
| 93 " parent is: 'null'\\."), (TestHarness test) { |
68 var parameter = test.makeTypeParameter(); | 94 var parameter = test.makeTypeParameter(); |
69 return new ListLiteral([], typeArgument: new TypeParameterType(parameter)); | 95 return new ListLiteral([], typeArgument: new TypeParameterType(parameter)); |
70 }); | 96 }); |
71 negativeTest('Class type parameter from another class', (TestHarness test) { | 97 negativeTest( |
| 98 'Class type parameter from another class', |
| 99 "Type parameter 'test_lib::OtherClass::OtherT' referenced out of scope," |
| 100 " parent is: 'test_lib::OtherClass'.", (TestHarness test) { |
72 return new TypeLiteral( | 101 return new TypeLiteral( |
73 new TypeParameterType(test.otherClass.typeParameters[0])); | 102 new TypeParameterType(test.otherClass.typeParameters[0])); |
74 }); | 103 }); |
75 negativeTest('Class type parameter in static method', (TestHarness test) { | 104 negativeTest( |
| 105 'Class type parameter in static method', |
| 106 "Type parameter 'test_lib::TestClass::T' referenced from static context," |
| 107 " parent is 'test_lib::TestClass'.", (TestHarness test) { |
76 return new Procedure( | 108 return new Procedure( |
77 new Name('bar'), | 109 new Name('bar'), |
78 ProcedureKind.Method, | 110 ProcedureKind.Method, |
79 new FunctionNode(new ReturnStatement( | 111 new FunctionNode(new ReturnStatement( |
80 new TypeLiteral(new TypeParameterType(test.classTypeParameter)))), | 112 new TypeLiteral(new TypeParameterType(test.classTypeParameter)))), |
81 isStatic: true); | 113 isStatic: true); |
82 }); | 114 }); |
83 negativeTest('Class type parameter in static field', (TestHarness test) { | 115 negativeTest( |
| 116 'Class type parameter in static field', |
| 117 "Type parameter 'test_lib::TestClass::T' referenced from static context," |
| 118 " parent is 'test_lib::TestClass'.", (TestHarness test) { |
84 return new Field(new Name('field'), | 119 return new Field(new Name('field'), |
85 initializer: | 120 initializer: |
86 new TypeLiteral(new TypeParameterType(test.classTypeParameter)), | 121 new TypeLiteral(new TypeParameterType(test.classTypeParameter)), |
87 isStatic: true); | 122 isStatic: true); |
88 }); | 123 }); |
89 negativeTest('Method type parameter out of scope', (TestHarness test) { | 124 negativeTest( |
| 125 'Method type parameter out of scope', |
| 126 matches("Type parameter '$tvarRegexp' referenced out of scope," |
| 127 " parent is: '<FunctionNode>'\\."), (TestHarness test) { |
90 var parameter = test.makeTypeParameter(); | 128 var parameter = test.makeTypeParameter(); |
91 return new Class( | 129 return new Class( |
92 name: 'Test', | 130 name: 'Test', |
93 supertype: test.objectClass.asRawSupertype, | 131 supertype: test.objectClass.asRawSupertype, |
94 procedures: [ | 132 procedures: [ |
95 new Procedure( | 133 new Procedure( |
96 new Name('generic'), | 134 new Name('generic'), |
97 ProcedureKind.Method, | 135 ProcedureKind.Method, |
98 new FunctionNode(new EmptyStatement(), | 136 new FunctionNode(new EmptyStatement(), |
99 typeParameters: [parameter])), | 137 typeParameters: [parameter])), |
100 new Procedure( | 138 new Procedure( |
101 new Name('use'), | 139 new Name('use'), |
102 ProcedureKind.Method, | 140 ProcedureKind.Method, |
103 new FunctionNode(new ReturnStatement( | 141 new FunctionNode(new ReturnStatement( |
104 new TypeLiteral(new TypeParameterType(parameter))))) | 142 new TypeLiteral(new TypeParameterType(parameter))))) |
105 ]); | 143 ]); |
106 }); | 144 }); |
107 negativeTest('Interface type arity too low', (TestHarness test) { | 145 negativeTest( |
| 146 'Interface type arity too low', |
| 147 "Type test_lib::OtherClass provides 0 type arguments" |
| 148 " but the class declares 1 parameters.", (TestHarness test) { |
108 return new TypeLiteral(new InterfaceType(test.otherClass, [])); | 149 return new TypeLiteral(new InterfaceType(test.otherClass, [])); |
109 }); | 150 }); |
110 negativeTest('Interface type arity too high', (TestHarness test) { | 151 negativeTest( |
| 152 'Interface type arity too high', |
| 153 "Type test_lib::OtherClass<dynamic, dynamic> provides 2 type arguments" |
| 154 " but the class declares 1 parameters.", (TestHarness test) { |
111 return new TypeLiteral(new InterfaceType( | 155 return new TypeLiteral(new InterfaceType( |
112 test.otherClass, [new DynamicType(), new DynamicType()])); | 156 test.otherClass, [new DynamicType(), new DynamicType()])); |
113 }); | 157 }); |
114 negativeTest('Dangling interface type', (TestHarness test) { | 158 negativeTest( |
| 159 'Dangling interface type', |
| 160 matches("Dangling reference to 'null::#class[0-9]+'," |
| 161 " parent is: 'null'\\."), (TestHarness test) { |
115 var orphan = new Class(); | 162 var orphan = new Class(); |
116 return new TypeLiteral(new InterfaceType(orphan)); | 163 return new TypeLiteral(new InterfaceType(orphan)); |
117 }); | 164 }); |
118 negativeTest('Dangling field get', (TestHarness test) { | 165 negativeTest('Dangling field get', |
| 166 "Dangling reference to 'null::foo', parent is: 'null'.", |
| 167 (TestHarness test) { |
119 var orphan = new Field(new Name('foo')); | 168 var orphan = new Field(new Name('foo')); |
120 return new DirectPropertyGet(new NullLiteral(), orphan); | 169 return new DirectPropertyGet(new NullLiteral(), orphan); |
121 }); | 170 }); |
122 negativeTest('Missing block parent pointer', (TestHarness test) { | 171 negativeTest( |
| 172 'Missing block parent pointer', |
| 173 "Incorrect parent pointer on ReturnStatement:" |
| 174 " expected 'Block', but found: 'Null'.", (TestHarness test) { |
123 var block = new Block([]); | 175 var block = new Block([]); |
124 block.statements.add(new ReturnStatement()); | 176 block.statements.add(new ReturnStatement()); |
125 return block; | 177 return block; |
126 }); | 178 }); |
127 negativeTest('Missing function parent pointer', (TestHarness test) { | 179 negativeTest( |
| 180 'Missing function parent pointer', |
| 181 "Incorrect parent pointer on FunctionNode:" |
| 182 " expected 'Procedure', but found: 'Null'.", (TestHarness test) { |
128 var procedure = new Procedure(new Name('bar'), ProcedureKind.Method, null); | 183 var procedure = new Procedure(new Name('bar'), ProcedureKind.Method, null); |
129 procedure.function = new FunctionNode(new EmptyStatement()); | 184 procedure.function = new FunctionNode(new EmptyStatement()); |
130 return procedure; | 185 return procedure; |
131 }); | 186 }); |
132 negativeTest('StaticGet without target', (TestHarness test) { | 187 negativeTest('StaticGet without target', "StaticGet without target.", |
| 188 (TestHarness test) { |
133 return new StaticGet(null); | 189 return new StaticGet(null); |
134 }); | 190 }); |
135 negativeTest('StaticSet without target', (TestHarness test) { | 191 negativeTest('StaticSet without target', "StaticSet without target.", |
| 192 (TestHarness test) { |
136 return new StaticSet(null, new NullLiteral()); | 193 return new StaticSet(null, new NullLiteral()); |
137 }); | 194 }); |
138 negativeTest('StaticInvocation without target', (TestHarness test) { | 195 negativeTest( |
| 196 'StaticInvocation without target', "StaticInvocation without target.", |
| 197 (TestHarness test) { |
139 return new StaticInvocation(null, new Arguments.empty()); | 198 return new StaticInvocation(null, new Arguments.empty()); |
140 }); | 199 }); |
141 positiveTest('Correct StaticInvocation', (TestHarness test) { | 200 positiveTest('Correct StaticInvocation', (TestHarness test) { |
142 var method = new Procedure( | 201 var method = new Procedure( |
143 new Name('foo'), | 202 new Name('foo'), |
144 ProcedureKind.Method, | 203 ProcedureKind.Method, |
145 new FunctionNode(new EmptyStatement(), | 204 new FunctionNode(new EmptyStatement(), |
146 positionalParameters: [new VariableDeclaration('p')]), | 205 positionalParameters: [new VariableDeclaration('p')]), |
147 isStatic: true); | 206 isStatic: true); |
148 test.enclosingClass.addMember(method); | 207 test.enclosingClass.addMember(method); |
149 return new StaticInvocation(method, new Arguments([new NullLiteral()])); | 208 return new StaticInvocation(method, new Arguments([new NullLiteral()])); |
150 }); | 209 }); |
151 negativeTest('StaticInvocation with too many parameters', (TestHarness test) { | 210 negativeTest( |
| 211 'StaticInvocation with too many parameters', |
| 212 "StaticInvocation with incompatible arguments for" |
| 213 " 'test_lib::TestClass::bar'.", (TestHarness test) { |
152 var method = new Procedure(new Name('bar'), ProcedureKind.Method, | 214 var method = new Procedure(new Name('bar'), ProcedureKind.Method, |
153 new FunctionNode(new EmptyStatement()), | 215 new FunctionNode(new EmptyStatement()), |
154 isStatic: true); | 216 isStatic: true); |
155 test.enclosingClass.addMember(method); | 217 test.enclosingClass.addMember(method); |
156 return new StaticInvocation(method, new Arguments([new NullLiteral()])); | 218 return new StaticInvocation(method, new Arguments([new NullLiteral()])); |
157 }); | 219 }); |
158 negativeTest('StaticInvocation with too few parameters', (TestHarness test) { | 220 negativeTest( |
| 221 'StaticInvocation with too few parameters', |
| 222 "StaticInvocation with incompatible arguments for" |
| 223 " 'test_lib::TestClass::bar'.", (TestHarness test) { |
159 var method = new Procedure( | 224 var method = new Procedure( |
160 new Name('bar'), | 225 new Name('bar'), |
161 ProcedureKind.Method, | 226 ProcedureKind.Method, |
162 new FunctionNode(new EmptyStatement(), | 227 new FunctionNode(new EmptyStatement(), |
163 positionalParameters: [new VariableDeclaration('p')]), | 228 positionalParameters: [new VariableDeclaration('p')]), |
164 isStatic: true); | 229 isStatic: true); |
165 test.enclosingClass.addMember(method); | 230 test.enclosingClass.addMember(method); |
166 return new StaticInvocation(method, new Arguments.empty()); | 231 return new StaticInvocation(method, new Arguments.empty()); |
167 }); | 232 }); |
168 negativeTest('StaticInvocation with unmatched named parameter', | 233 negativeTest( |
169 (TestHarness test) { | 234 'StaticInvocation with unmatched named parameter', |
| 235 "StaticInvocation with incompatible arguments for" |
| 236 " 'test_lib::TestClass::bar'.", (TestHarness test) { |
170 var method = new Procedure(new Name('bar'), ProcedureKind.Method, | 237 var method = new Procedure(new Name('bar'), ProcedureKind.Method, |
171 new FunctionNode(new EmptyStatement()), | 238 new FunctionNode(new EmptyStatement()), |
172 isStatic: true); | 239 isStatic: true); |
173 test.enclosingClass.addMember(method); | 240 test.enclosingClass.addMember(method); |
174 return new StaticInvocation( | 241 return new StaticInvocation( |
175 method, | 242 method, |
176 new Arguments([], | 243 new Arguments([], |
177 named: [new NamedExpression('p', new NullLiteral())])); | 244 named: [new NamedExpression('p', new NullLiteral())])); |
178 }); | 245 }); |
179 negativeTest('StaticInvocation with missing type argument', | 246 negativeTest( |
180 (TestHarness test) { | 247 'StaticInvocation with missing type argument', |
| 248 "StaticInvocation with wrong number of type arguments for" |
| 249 " 'test_lib::TestClass::bar'.", (TestHarness test) { |
181 var method = new Procedure( | 250 var method = new Procedure( |
182 new Name('bar'), | 251 new Name('bar'), |
183 ProcedureKind.Method, | 252 ProcedureKind.Method, |
184 new FunctionNode(new EmptyStatement(), | 253 new FunctionNode(new EmptyStatement(), |
185 typeParameters: [test.makeTypeParameter()]), | 254 typeParameters: [test.makeTypeParameter()]), |
186 isStatic: true); | 255 isStatic: true); |
187 test.enclosingClass.addMember(method); | 256 test.enclosingClass.addMember(method); |
188 return new StaticInvocation(method, new Arguments.empty()); | 257 return new StaticInvocation(method, new Arguments.empty()); |
189 }); | 258 }); |
190 negativeTest('ConstructorInvocation with missing type argument', | 259 negativeTest( |
191 (TestHarness test) { | 260 'ConstructorInvocation with missing type argument', |
| 261 "ConstructorInvocation with wrong number of type arguments for" |
| 262 " 'test_lib::TestClass::foo'.", (TestHarness test) { |
192 var class_ = new Class( | 263 var class_ = new Class( |
193 name: 'Test', | 264 name: 'Test', |
194 typeParameters: [test.makeTypeParameter()], | 265 typeParameters: [test.makeTypeParameter()], |
195 supertype: test.objectClass.asRawSupertype); | 266 supertype: test.objectClass.asRawSupertype); |
196 test.enclosingLibrary.addClass(class_); | 267 test.enclosingLibrary.addClass(class_); |
197 var constructor = new Constructor(new FunctionNode(new EmptyStatement()), | 268 var constructor = new Constructor(new FunctionNode(new EmptyStatement()), |
198 name: new Name('foo')); | 269 name: new Name('foo')); |
199 test.enclosingClass.addMember(constructor); | 270 test.enclosingClass.addMember(constructor); |
200 return new ConstructorInvocation(constructor, new Arguments.empty()); | 271 return new ConstructorInvocation(constructor, new Arguments.empty()); |
201 }); | 272 }); |
(...skipping 19 matching lines...) Expand all Loading... |
221 var foo = new Typedef('Foo', null); | 292 var foo = new Typedef('Foo', null); |
222 var bar = new Typedef('Bar', null); | 293 var bar = new Typedef('Bar', null); |
223 foo.type = new InterfaceType(test.otherClass, [new TypedefType(bar)]); | 294 foo.type = new InterfaceType(test.otherClass, [new TypedefType(bar)]); |
224 bar.type = test.otherClass.rawType; | 295 bar.type = test.otherClass.rawType; |
225 test.enclosingLibrary.addTypedef(foo); | 296 test.enclosingLibrary.addTypedef(foo); |
226 test.enclosingLibrary.addTypedef(bar); | 297 test.enclosingLibrary.addTypedef(bar); |
227 }); | 298 }); |
228 positiveTest('Valid typedef type in field', (TestHarness test) { | 299 positiveTest('Valid typedef type in field', (TestHarness test) { |
229 var typedef_ = new Typedef( | 300 var typedef_ = new Typedef( |
230 'Foo', new FunctionType([test.otherClass.rawType], const VoidType())); | 301 'Foo', new FunctionType([test.otherClass.rawType], const VoidType())); |
231 var field = new Field(new Name('field'), type: new TypedefType(typedef_)); | 302 var field = new Field(new Name('field'), |
| 303 type: new TypedefType(typedef_), isStatic: true); |
232 test.enclosingLibrary.addTypedef(typedef_); | 304 test.enclosingLibrary.addTypedef(typedef_); |
233 test.enclosingLibrary.addMember(field); | 305 test.enclosingLibrary.addMember(field); |
234 }); | 306 }); |
235 negativeTest('Invalid typedef Foo = Foo', (TestHarness test) { | 307 negativeTest( |
| 308 'Invalid typedef Foo = Foo', |
| 309 "The typedef 'typedef Foo = test_lib::Foo;\n'" |
| 310 " refers to itself", (TestHarness test) { |
236 var typedef_ = new Typedef('Foo', null); | 311 var typedef_ = new Typedef('Foo', null); |
237 typedef_.type = new TypedefType(typedef_); | 312 typedef_.type = new TypedefType(typedef_); |
238 test.enclosingLibrary.addTypedef(typedef_); | 313 test.enclosingLibrary.addTypedef(typedef_); |
239 }); | 314 }); |
240 negativeTest('Invalid typedef Foo = `(Foo) => void`', (TestHarness test) { | 315 negativeTest( |
| 316 'Invalid typedef Foo = `(Foo) => void`', |
| 317 "The typedef 'typedef Foo = (test_lib::Foo) → void;\n'" |
| 318 " refers to itself", (TestHarness test) { |
241 var typedef_ = new Typedef('Foo', null); | 319 var typedef_ = new Typedef('Foo', null); |
242 typedef_.type = | 320 typedef_.type = |
243 new FunctionType([new TypedefType(typedef_)], const VoidType()); | 321 new FunctionType([new TypedefType(typedef_)], const VoidType()); |
244 test.enclosingLibrary.addTypedef(typedef_); | 322 test.enclosingLibrary.addTypedef(typedef_); |
245 }); | 323 }); |
246 negativeTest('Invalid typedef Foo = `() => Foo`', (TestHarness test) { | 324 negativeTest( |
| 325 'Invalid typedef Foo = `() => Foo`', |
| 326 "The typedef 'typedef Foo = () → test_lib::Foo;\n'" |
| 327 " refers to itself", (TestHarness test) { |
247 var typedef_ = new Typedef('Foo', null); | 328 var typedef_ = new Typedef('Foo', null); |
248 typedef_.type = new FunctionType([], new TypedefType(typedef_)); | 329 typedef_.type = new FunctionType([], new TypedefType(typedef_)); |
249 test.enclosingLibrary.addTypedef(typedef_); | 330 test.enclosingLibrary.addTypedef(typedef_); |
250 }); | 331 }); |
251 negativeTest('Invalid typedef Foo = C<Foo>', (TestHarness test) { | 332 negativeTest( |
| 333 'Invalid typedef Foo = C<Foo>', |
| 334 "The typedef 'typedef Foo = test_lib::OtherClass<test_lib::Foo>;\n'" |
| 335 " refers to itself", (TestHarness test) { |
252 var typedef_ = new Typedef('Foo', null); | 336 var typedef_ = new Typedef('Foo', null); |
253 typedef_.type = | 337 typedef_.type = |
254 new InterfaceType(test.otherClass, [new TypedefType(typedef_)]); | 338 new InterfaceType(test.otherClass, [new TypedefType(typedef_)]); |
255 test.enclosingLibrary.addTypedef(typedef_); | 339 test.enclosingLibrary.addTypedef(typedef_); |
256 }); | 340 }); |
257 negativeTest('Invalid typedefs Foo = Bar, Bar = Foo', (TestHarness test) { | 341 negativeTest( |
| 342 'Invalid typedefs Foo = Bar, Bar = Foo', |
| 343 "The typedef 'typedef Foo = test_lib::Bar;\n'" |
| 344 " refers to itself", (TestHarness test) { |
258 var foo = new Typedef('Foo', null); | 345 var foo = new Typedef('Foo', null); |
259 var bar = new Typedef('Bar', null); | 346 var bar = new Typedef('Bar', null); |
260 foo.type = new TypedefType(bar); | 347 foo.type = new TypedefType(bar); |
261 bar.type = new TypedefType(foo); | 348 bar.type = new TypedefType(foo); |
262 test.enclosingLibrary.addTypedef(foo); | 349 test.enclosingLibrary.addTypedef(foo); |
263 test.enclosingLibrary.addTypedef(bar); | 350 test.enclosingLibrary.addTypedef(bar); |
264 }); | 351 }); |
265 negativeTest('Invalid typedefs Foo = Bar, Bar = C<Foo>', (TestHarness test) { | 352 negativeTest( |
| 353 'Invalid typedefs Foo = Bar, Bar = C<Foo>', |
| 354 "The typedef 'typedef Foo = test_lib::Bar;\n'" |
| 355 " refers to itself", (TestHarness test) { |
266 var foo = new Typedef('Foo', null); | 356 var foo = new Typedef('Foo', null); |
267 var bar = new Typedef('Bar', null); | 357 var bar = new Typedef('Bar', null); |
268 foo.type = new TypedefType(bar); | 358 foo.type = new TypedefType(bar); |
269 bar.type = new InterfaceType(test.otherClass, [new TypedefType(foo)]); | 359 bar.type = new InterfaceType(test.otherClass, [new TypedefType(foo)]); |
270 test.enclosingLibrary.addTypedef(foo); | 360 test.enclosingLibrary.addTypedef(foo); |
271 test.enclosingLibrary.addTypedef(bar); | 361 test.enclosingLibrary.addTypedef(bar); |
272 }); | 362 }); |
273 negativeTest('Invalid typedefs Foo = C<Bar>, Bar = C<Foo>', | 363 negativeTest( |
274 (TestHarness test) { | 364 'Invalid typedefs Foo = C<Bar>, Bar = C<Foo>', |
| 365 "The typedef 'typedef Foo = test_lib::OtherClass<test_lib::Bar>;\n'" |
| 366 " refers to itself", (TestHarness test) { |
275 var foo = new Typedef('Foo', null); | 367 var foo = new Typedef('Foo', null); |
276 var bar = new Typedef('Bar', null); | 368 var bar = new Typedef('Bar', null); |
277 foo.type = new InterfaceType(test.otherClass, [new TypedefType(bar)]); | 369 foo.type = new InterfaceType(test.otherClass, [new TypedefType(bar)]); |
278 bar.type = new InterfaceType(test.otherClass, [new TypedefType(foo)]); | 370 bar.type = new InterfaceType(test.otherClass, [new TypedefType(foo)]); |
279 test.enclosingLibrary.addTypedef(foo); | 371 test.enclosingLibrary.addTypedef(foo); |
280 test.enclosingLibrary.addTypedef(bar); | 372 test.enclosingLibrary.addTypedef(bar); |
281 }); | 373 }); |
282 positiveTest('Valid long typedefs C20 = C19 = ... = C1 = C0 = dynamic', | 374 positiveTest('Valid long typedefs C20 = C19 = ... = C1 = C0 = dynamic', |
283 (TestHarness test) { | 375 (TestHarness test) { |
284 var typedef_ = new Typedef('C0', const DynamicType()); | 376 var typedef_ = new Typedef('C0', const DynamicType()); |
285 test.enclosingLibrary.addTypedef(typedef_); | 377 test.enclosingLibrary.addTypedef(typedef_); |
286 for (int i = 1; i < 20; ++i) { | 378 for (int i = 1; i < 20; ++i) { |
287 typedef_ = new Typedef('C$i', new TypedefType(typedef_)); | 379 typedef_ = new Typedef('C$i', new TypedefType(typedef_)); |
288 test.enclosingLibrary.addTypedef(typedef_); | 380 test.enclosingLibrary.addTypedef(typedef_); |
289 } | 381 } |
290 }); | 382 }); |
291 negativeTest('Invalid long typedefs C20 = C19 = ... = C1 = C0 = C20', | 383 negativeTest( |
292 (TestHarness test) { | 384 'Invalid long typedefs C20 = C19 = ... = C1 = C0 = C20', |
| 385 "The typedef 'typedef C0 = test_lib::C19;\n'" |
| 386 " refers to itself", (TestHarness test) { |
293 var typedef_ = new Typedef('C0', null); | 387 var typedef_ = new Typedef('C0', null); |
294 test.enclosingLibrary.addTypedef(typedef_); | 388 test.enclosingLibrary.addTypedef(typedef_); |
295 var first = typedef_; | 389 var first = typedef_; |
296 for (int i = 1; i < 20; ++i) { | 390 for (int i = 1; i < 20; ++i) { |
297 typedef_ = new Typedef('C$i', new TypedefType(typedef_)); | 391 typedef_ = new Typedef('C$i', new TypedefType(typedef_)); |
298 test.enclosingLibrary.addTypedef(typedef_); | 392 test.enclosingLibrary.addTypedef(typedef_); |
299 } | 393 } |
300 first.type = new TypedefType(typedef_); | 394 first.type = new TypedefType(typedef_); |
301 }); | 395 }); |
302 positiveTest('Valid typedef Foo<T extends C> = C<T>', (TestHarness test) { | 396 positiveTest('Valid typedef Foo<T extends C> = C<T>', (TestHarness test) { |
(...skipping 18 matching lines...) Expand all Loading... |
321 var foo = | 415 var foo = |
322 new Typedef('Foo', const DynamicType(), typeParameters: [fooParam]); | 416 new Typedef('Foo', const DynamicType(), typeParameters: [fooParam]); |
323 var barParam = new TypeParameter('T', null); | 417 var barParam = new TypeParameter('T', null); |
324 barParam.bound = new TypedefType(foo, [new TypeParameterType(barParam)]); | 418 barParam.bound = new TypedefType(foo, [new TypeParameterType(barParam)]); |
325 var bar = new Typedef('Bar', | 419 var bar = new Typedef('Bar', |
326 new InterfaceType(test.otherClass, [new TypeParameterType(barParam)]), | 420 new InterfaceType(test.otherClass, [new TypeParameterType(barParam)]), |
327 typeParameters: [barParam]); | 421 typeParameters: [barParam]); |
328 test.enclosingLibrary.addTypedef(foo); | 422 test.enclosingLibrary.addTypedef(foo); |
329 test.enclosingLibrary.addTypedef(bar); | 423 test.enclosingLibrary.addTypedef(bar); |
330 }); | 424 }); |
331 negativeTest('Invalid typedefs Foo<T extends Bar<T>>, Bar<T extends Foo<T>>', | 425 negativeTest( |
332 (TestHarness test) { | 426 'Invalid typedefs Foo<T extends Bar<T>>, Bar<T extends Foo<T>>', |
| 427 "The typedef 'typedef Foo<T extends test_lib::Bar<T>> = dynamic;\n'" |
| 428 " refers to itself", (TestHarness test) { |
333 var fooParam = test.makeTypeParameter('T'); | 429 var fooParam = test.makeTypeParameter('T'); |
334 var foo = | 430 var foo = |
335 new Typedef('Foo', const DynamicType(), typeParameters: [fooParam]); | 431 new Typedef('Foo', const DynamicType(), typeParameters: [fooParam]); |
336 var barParam = new TypeParameter('T', null); | 432 var barParam = new TypeParameter('T', null); |
337 barParam.bound = new TypedefType(foo, [new TypeParameterType(barParam)]); | 433 barParam.bound = new TypedefType(foo, [new TypeParameterType(barParam)]); |
338 var bar = new Typedef('Bar', | 434 var bar = new Typedef('Bar', |
339 new InterfaceType(test.otherClass, [new TypeParameterType(barParam)]), | 435 new InterfaceType(test.otherClass, [new TypeParameterType(barParam)]), |
340 typeParameters: [barParam]); | 436 typeParameters: [barParam]); |
341 fooParam.bound = new TypedefType(bar, [new TypeParameterType(fooParam)]); | 437 fooParam.bound = new TypedefType(bar, [new TypeParameterType(fooParam)]); |
342 test.enclosingLibrary.addTypedef(foo); | 438 test.enclosingLibrary.addTypedef(foo); |
343 test.enclosingLibrary.addTypedef(bar); | 439 test.enclosingLibrary.addTypedef(bar); |
344 }); | 440 }); |
345 negativeTest('Invalid typedef Foo<T extends Foo<dynamic> = C<T>', | 441 negativeTest( |
346 (TestHarness test) { | 442 'Invalid typedef Foo<T extends Foo<dynamic> = C<T>', |
| 443 "The typedef 'typedef Foo<T extends test_lib::Foo<dynamic>> = " |
| 444 "test_lib::OtherClass<T>;\n'" |
| 445 " refers to itself", (TestHarness test) { |
347 var param = new TypeParameter('T', null); | 446 var param = new TypeParameter('T', null); |
348 var foo = new Typedef('Foo', | 447 var foo = new Typedef('Foo', |
349 new InterfaceType(test.otherClass, [new TypeParameterType(param)]), | 448 new InterfaceType(test.otherClass, [new TypeParameterType(param)]), |
350 typeParameters: [param]); | 449 typeParameters: [param]); |
351 param.bound = new TypedefType(foo, [const DynamicType()]); | 450 param.bound = new TypedefType(foo, [const DynamicType()]); |
352 test.enclosingLibrary.addTypedef(foo); | 451 test.enclosingLibrary.addTypedef(foo); |
353 }); | 452 }); |
354 negativeTest('Typedef arity error', (TestHarness test) { | 453 negativeTest( |
| 454 'Typedef arity error', |
| 455 "The typedef type test_lib::Foo provides 0 type arguments" |
| 456 " but the typedef declares 1 parameters.", (TestHarness test) { |
355 var param = test.makeTypeParameter('T'); | 457 var param = test.makeTypeParameter('T'); |
356 var foo = | 458 var foo = |
357 new Typedef('Foo', test.otherClass.rawType, typeParameters: [param]); | 459 new Typedef('Foo', test.otherClass.rawType, typeParameters: [param]); |
358 var field = new Field(new Name('field'), type: new TypedefType(foo, [])); | 460 var field = new Field(new Name('field'), |
| 461 type: new TypedefType(foo, []), isStatic: true); |
359 test.enclosingLibrary.addTypedef(foo); | 462 test.enclosingLibrary.addTypedef(foo); |
360 test.enclosingLibrary.addMember(field); | 463 test.enclosingLibrary.addMember(field); |
361 }); | 464 }); |
362 negativeTest('Dangling typedef reference', (TestHarness test) { | 465 negativeTest( |
| 466 'Dangling typedef reference', |
| 467 "Dangling reference to 'typedef Foo = test_lib::OtherClass<dynamic>;\n'" |
| 468 ", parent is: 'null'", (TestHarness test) { |
363 var foo = new Typedef('Foo', test.otherClass.rawType, typeParameters: []); | 469 var foo = new Typedef('Foo', test.otherClass.rawType, typeParameters: []); |
364 var field = new Field(new Name('field'), type: new TypedefType(foo, [])); | 470 var field = new Field(new Name('field'), |
| 471 type: new TypedefType(foo, []), isStatic: true); |
| 472 test.enclosingLibrary.addMember(field); |
| 473 }); |
| 474 negativeTest('Non-static top-level field', |
| 475 "The top-level field 'field' should be static", (TestHarness test) { |
| 476 var field = new Field(new Name('field')); |
365 test.enclosingLibrary.addMember(field); | 477 test.enclosingLibrary.addMember(field); |
366 }); | 478 }); |
367 } | 479 } |
368 | 480 |
369 checkHasError(Program program) { | 481 checkHasError(Program program, Matcher matcher) { |
370 bool passed = false; | |
371 try { | 482 try { |
372 verifyProgram(program); | 483 verifyProgram(program); |
373 passed = true; | 484 } on VerificationError catch (e) { |
374 } catch (e) {} | 485 expect(e.details, matcher); |
375 if (passed) { | 486 return; |
376 fail('Failed to reject invalid program:\n${programToString(program)}'); | |
377 } | 487 } |
| 488 fail('Failed to reject invalid program:\n${programToString(program)}'); |
378 } | 489 } |
379 | 490 |
380 class TestHarness { | 491 class TestHarness { |
381 Program program; | 492 Program program; |
382 Class objectClass; | 493 Class objectClass; |
383 Library stubLibrary; | 494 Library stubLibrary; |
384 | 495 |
385 TypeParameter classTypeParameter; | 496 TypeParameter classTypeParameter; |
386 | 497 |
387 Library enclosingLibrary; | 498 Library enclosingLibrary; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 new FunctionNode(new EmptyStatement())); | 564 new FunctionNode(new EmptyStatement())); |
454 enclosingClass.addMember(enclosingMember); | 565 enclosingClass.addMember(enclosingMember); |
455 otherClass = new Class( | 566 otherClass = new Class( |
456 name: 'OtherClass', | 567 name: 'OtherClass', |
457 typeParameters: [makeTypeParameter('OtherT')], | 568 typeParameters: [makeTypeParameter('OtherT')], |
458 supertype: objectClass.asRawSupertype); | 569 supertype: objectClass.asRawSupertype); |
459 enclosingLibrary.addClass(otherClass); | 570 enclosingLibrary.addClass(otherClass); |
460 } | 571 } |
461 } | 572 } |
462 | 573 |
463 negativeTest(String name, TreeNode makeTestCase(TestHarness test)) { | 574 negativeTest(String name, matcher, TreeNode makeTestCase(TestHarness test)) { |
| 575 if (matcher is String) { |
| 576 matcher = equals(matcher); |
| 577 } |
464 test(name, () { | 578 test(name, () { |
465 var test = new TestHarness(); | 579 var test = new TestHarness(); |
466 test.addNode(makeTestCase(test)); | 580 test.addNode(makeTestCase(test)); |
467 checkHasError(test.program); | 581 checkHasError(test.program, matcher); |
468 }); | 582 }); |
469 } | 583 } |
470 | 584 |
471 positiveTest(String name, TreeNode makeTestCase(TestHarness test)) { | 585 positiveTest(String name, TreeNode makeTestCase(TestHarness test)) { |
472 test(name, () { | 586 test(name, () { |
473 var test = new TestHarness(); | 587 var test = new TestHarness(); |
474 test.addNode(makeTestCase(test)); | 588 test.addNode(makeTestCase(test)); |
475 verifyProgram(test.program); | 589 verifyProgram(test.program); |
476 }); | 590 }); |
477 } | 591 } |
OLD | NEW |