| 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 import 'package:kernel/ast.dart'; | 4 import 'package:kernel/ast.dart'; |
| 5 import 'package:kernel/text/ast_to_text.dart'; | 5 import 'package:kernel/text/ast_to_text.dart'; |
| 6 import 'package:kernel/verifier.dart'; | 6 import 'package:kernel/verifier.dart'; |
| 7 import 'package:test/test.dart'; | 7 import 'package:test/test.dart'; |
| 8 | 8 |
| 9 /// Checks that the verifier correctly find errors in invalid programs. | 9 /// Checks that the verifier correctly find errors in invalid programs. |
| 10 /// | 10 /// |
| 11 /// The frontend should never generate invalid programs, so we have to test | 11 /// The frontend should never generate invalid programs, so we have to test |
| 12 /// these by manually constructing invalid ASTs. | 12 /// these by manually constructing invalid ASTs. |
| 13 /// | 13 /// |
| 14 /// We mostly test negative cases here, as we get plenty of positive cases by | 14 /// We mostly test negative cases here, as we get plenty of positive cases by |
| 15 /// compiling the Dart test suite with the verifier enabled. | 15 /// compiling the Dart test suite with the verifier enabled. |
| 16 main() { | 16 main() { |
| 17 positiveTest('Test harness has no errors', () { | 17 positiveTest('Test harness has no errors', (TestHarness test) { |
| 18 return new NullLiteral(); | 18 return new NullLiteral(); |
| 19 }); | 19 }); |
| 20 negativeTest('VariableGet out of scope', () { | 20 negativeTest('VariableGet out of scope', (TestHarness test) { |
| 21 return new VariableGet(makeVariable()); | 21 return new VariableGet(test.makeVariable()); |
| 22 }); | 22 }); |
| 23 negativeTest('VariableSet out of scope', () { | 23 negativeTest('VariableSet out of scope', (TestHarness test) { |
| 24 return new VariableSet(makeVariable(), new NullLiteral()); | 24 return new VariableSet(test.makeVariable(), new NullLiteral()); |
| 25 }); | 25 }); |
| 26 negativeTest('Variable block scope', () { | 26 negativeTest('Variable block scope', (TestHarness test) { |
| 27 VariableDeclaration variable = makeVariable(); | 27 VariableDeclaration variable = test.makeVariable(); |
| 28 return new Block([ | 28 return new Block([ |
| 29 new Block([variable]), | 29 new Block([variable]), |
| 30 new ReturnStatement(new VariableGet(variable)) | 30 new ReturnStatement(new VariableGet(variable)) |
| 31 ]); | 31 ]); |
| 32 }); | 32 }); |
| 33 negativeTest('Variable let scope', () { | 33 negativeTest('Variable let scope', (TestHarness test) { |
| 34 VariableDeclaration variable = makeVariable(); | 34 VariableDeclaration variable = test.makeVariable(); |
| 35 return new LogicalExpression(new Let(variable, new VariableGet(variable)), | 35 return new LogicalExpression(new Let(variable, new VariableGet(variable)), |
| 36 '&&', new VariableGet(variable)); | 36 '&&', new VariableGet(variable)); |
| 37 }); | 37 }); |
| 38 negativeTest('Variable redeclared', () { | 38 negativeTest('Variable redeclared', (TestHarness test) { |
| 39 VariableDeclaration variable = makeVariable(); | 39 VariableDeclaration variable = test.makeVariable(); |
| 40 return new Block([variable, variable]); | 40 return new Block([variable, variable]); |
| 41 }); | 41 }); |
| 42 negativeTest('Member redeclared', () { | 42 negativeTest('Member redeclared', (TestHarness test) { |
| 43 Field field = new Field(new Name('field'), initializer: new NullLiteral()); | 43 Field field = new Field(new Name('field'), initializer: new NullLiteral()); |
| 44 return new Class( | 44 return new Class( |
| 45 name: 'Test', | 45 name: 'Test', |
| 46 supertype: objectClass.asRawSupertype, | 46 supertype: test.objectClass.asRawSupertype, |
| 47 fields: [field, field]); | 47 fields: [field, field]); |
| 48 }); | 48 }); |
| 49 negativeTest('Class redeclared', () { | 49 negativeTest('Class redeclared', (TestHarness test) { |
| 50 return otherClass; // Test harness also adds otherClass to program. | 50 return test.otherClass; // Test harness also adds otherClass to program. |
| 51 }); | 51 }); |
| 52 negativeTest('Class type parameter redeclared', () { | 52 negativeTest('Class type parameter redeclared', (TestHarness test) { |
| 53 var parameter = makeTypeParameter(); | 53 var parameter = test.makeTypeParameter(); |
| 54 return new Class( | 54 return new Class( |
| 55 name: 'Test', | 55 name: 'Test', |
| 56 supertype: objectClass.asRawSupertype, | 56 supertype: test.objectClass.asRawSupertype, |
| 57 typeParameters: [parameter, parameter]); | 57 typeParameters: [parameter, parameter]); |
| 58 }); | 58 }); |
| 59 negativeTest('Member type parameter redeclared', () { | 59 negativeTest('Member type parameter redeclared', (TestHarness test) { |
| 60 var parameter = makeTypeParameter(); | 60 var parameter = test.makeTypeParameter(); |
| 61 return new Procedure( | 61 return new Procedure( |
| 62 new Name('test'), | 62 new Name('bar'), |
| 63 ProcedureKind.Method, | 63 ProcedureKind.Method, |
| 64 new FunctionNode(new ReturnStatement(new NullLiteral()), | 64 new FunctionNode(new ReturnStatement(new NullLiteral()), |
| 65 typeParameters: [parameter, parameter])); | 65 typeParameters: [parameter, parameter])); |
| 66 }); | 66 }); |
| 67 negativeTest('Type parameter out of scope', () { | 67 negativeTest('Type parameter out of scope', (TestHarness test) { |
| 68 var parameter = makeTypeParameter(); | 68 var parameter = test.makeTypeParameter(); |
| 69 return new ListLiteral([], typeArgument: new TypeParameterType(parameter)); | 69 return new ListLiteral([], typeArgument: new TypeParameterType(parameter)); |
| 70 }); | 70 }); |
| 71 negativeTest('Class type parameter from another class', () { | 71 negativeTest('Class type parameter from another class', (TestHarness test) { |
| 72 return new TypeLiteral(new TypeParameterType(otherClass.typeParameters[0])); | 72 return new TypeLiteral( |
| 73 new TypeParameterType(test.otherClass.typeParameters[0])); |
| 73 }); | 74 }); |
| 74 negativeTest('Class type parameter in static method', () { | 75 negativeTest('Class type parameter in static method', (TestHarness test) { |
| 75 return new Procedure( | 76 return new Procedure( |
| 76 new Name('test'), | 77 new Name('bar'), |
| 77 ProcedureKind.Method, | 78 ProcedureKind.Method, |
| 78 new FunctionNode(new ReturnStatement( | 79 new FunctionNode(new ReturnStatement( |
| 79 new TypeLiteral(new TypeParameterType(classTypeParameter)))), | 80 new TypeLiteral(new TypeParameterType(test.classTypeParameter)))), |
| 80 isStatic: true); | 81 isStatic: true); |
| 81 }); | 82 }); |
| 82 negativeTest('Class type parameter in static field', () { | 83 negativeTest('Class type parameter in static field', (TestHarness test) { |
| 83 return new Field(new Name('field'), | 84 return new Field(new Name('field'), |
| 84 initializer: new TypeLiteral(new TypeParameterType(classTypeParameter)), | 85 initializer: |
| 86 new TypeLiteral(new TypeParameterType(test.classTypeParameter)), |
| 85 isStatic: true); | 87 isStatic: true); |
| 86 }); | 88 }); |
| 87 negativeTest('Method type parameter out of scope', () { | 89 negativeTest('Method type parameter out of scope', (TestHarness test) { |
| 88 var parameter = makeTypeParameter(); | 90 var parameter = test.makeTypeParameter(); |
| 89 return new Class( | 91 return new Class( |
| 90 name: 'Test', | 92 name: 'Test', |
| 91 supertype: objectClass.asRawSupertype, | 93 supertype: test.objectClass.asRawSupertype, |
| 92 procedures: [ | 94 procedures: [ |
| 93 new Procedure( | 95 new Procedure( |
| 94 new Name('generic'), | 96 new Name('generic'), |
| 95 ProcedureKind.Method, | 97 ProcedureKind.Method, |
| 96 new FunctionNode(new EmptyStatement(), | 98 new FunctionNode(new EmptyStatement(), |
| 97 typeParameters: [parameter])), | 99 typeParameters: [parameter])), |
| 98 new Procedure( | 100 new Procedure( |
| 99 new Name('use'), | 101 new Name('use'), |
| 100 ProcedureKind.Method, | 102 ProcedureKind.Method, |
| 101 new FunctionNode(new ReturnStatement( | 103 new FunctionNode(new ReturnStatement( |
| 102 new TypeLiteral(new TypeParameterType(parameter))))) | 104 new TypeLiteral(new TypeParameterType(parameter))))) |
| 103 ]); | 105 ]); |
| 104 }); | 106 }); |
| 105 negativeTest('Interface type arity too low', () { | 107 negativeTest('Interface type arity too low', (TestHarness test) { |
| 106 return new TypeLiteral(new InterfaceType(otherClass, [])); | 108 return new TypeLiteral(new InterfaceType(test.otherClass, [])); |
| 107 }); | 109 }); |
| 108 negativeTest('Interface type arity too high', () { | 110 negativeTest('Interface type arity too high', (TestHarness test) { |
| 109 return new TypeLiteral( | 111 return new TypeLiteral(new InterfaceType( |
| 110 new InterfaceType(otherClass, [new DynamicType(), new DynamicType()])); | 112 test.otherClass, [new DynamicType(), new DynamicType()])); |
| 111 }); | 113 }); |
| 112 negativeTest('Dangling interface type', () { | 114 negativeTest('Dangling interface type', (TestHarness test) { |
| 113 return new TypeLiteral(new InterfaceType(new Class())); | 115 var orphan = new Class(); |
| 116 return new TypeLiteral(new InterfaceType(orphan)); |
| 114 }); | 117 }); |
| 115 negativeTest('Dangling field get', () { | 118 negativeTest('Dangling field get', (TestHarness test) { |
| 116 return new DirectPropertyGet(new NullLiteral(), new Field(new Name('foo'))); | 119 var orphan = new Field(new Name('foo')); |
| 120 return new DirectPropertyGet(new NullLiteral(), orphan); |
| 117 }); | 121 }); |
| 118 negativeTest('Missing block parent pointer', () { | 122 negativeTest('Missing block parent pointer', (TestHarness test) { |
| 119 var block = new Block([]); | 123 var block = new Block([]); |
| 120 block.statements.add(new ReturnStatement()); | 124 block.statements.add(new ReturnStatement()); |
| 121 return block; | 125 return block; |
| 122 }); | 126 }); |
| 123 negativeTest('Missing function parent pointer', () { | 127 negativeTest('Missing function parent pointer', (TestHarness test) { |
| 124 var procedure = new Procedure(new Name('test'), ProcedureKind.Method, null); | 128 var procedure = new Procedure(new Name('bar'), ProcedureKind.Method, null); |
| 125 procedure.function = new FunctionNode(new EmptyStatement()); | 129 procedure.function = new FunctionNode(new EmptyStatement()); |
| 126 return procedure; | 130 return procedure; |
| 127 }); | 131 }); |
| 128 negativeTest('StaticGet without target', () { | 132 negativeTest('StaticGet without target', (TestHarness test) { |
| 129 return new StaticGet(null); | 133 return new StaticGet(null); |
| 130 }); | 134 }); |
| 131 negativeTest('StaticSet without target', () { | 135 negativeTest('StaticSet without target', (TestHarness test) { |
| 132 return new StaticSet(null, new NullLiteral()); | 136 return new StaticSet(null, new NullLiteral()); |
| 133 }); | 137 }); |
| 134 negativeTest('StaticInvocation without target', () { | 138 negativeTest('StaticInvocation without target', (TestHarness test) { |
| 135 return new StaticInvocation(null, new Arguments.empty()); | 139 return new StaticInvocation(null, new Arguments.empty()); |
| 136 }); | 140 }); |
| 137 positiveTest('Correct StaticInvocation', () { | 141 positiveTest('Correct StaticInvocation', (TestHarness test) { |
| 138 var method = new Procedure(new Name('test'), ProcedureKind.Method, null, | 142 var method = new Procedure( |
| 143 new Name('foo'), |
| 144 ProcedureKind.Method, |
| 145 new FunctionNode(new EmptyStatement(), |
| 146 positionalParameters: [new VariableDeclaration('p')]), |
| 139 isStatic: true); | 147 isStatic: true); |
| 140 method.function = new FunctionNode( | 148 test.enclosingClass.addMember(method); |
| 141 new ReturnStatement( | 149 return new StaticInvocation(method, new Arguments([new NullLiteral()])); |
| 142 new StaticInvocation(method, new Arguments([new NullLiteral()]))), | |
| 143 positionalParameters: [new VariableDeclaration('p')])..parent = method; | |
| 144 return new Class( | |
| 145 name: 'Test', | |
| 146 supertype: objectClass.asRawSupertype, | |
| 147 procedures: [method]); | |
| 148 }); | 150 }); |
| 149 negativeTest('StaticInvocation with too many parameters', () { | 151 negativeTest('StaticInvocation with too many parameters', (TestHarness test) { |
| 150 var method = new Procedure(new Name('test'), ProcedureKind.Method, null, | 152 var method = new Procedure(new Name('bar'), ProcedureKind.Method, |
| 153 new FunctionNode(new EmptyStatement()), |
| 151 isStatic: true); | 154 isStatic: true); |
| 152 method.function = new FunctionNode(new ReturnStatement( | 155 test.enclosingClass.addMember(method); |
| 153 new StaticInvocation(method, new Arguments([new NullLiteral()])))) | 156 return new StaticInvocation(method, new Arguments([new NullLiteral()])); |
| 154 ..parent = method; | |
| 155 return new Class( | |
| 156 name: 'Test', | |
| 157 supertype: objectClass.asRawSupertype, | |
| 158 procedures: [method]); | |
| 159 }); | 157 }); |
| 160 negativeTest('StaticInvocation with too few parameters', () { | 158 negativeTest('StaticInvocation with too few parameters', (TestHarness test) { |
| 161 var method = new Procedure(new Name('test'), ProcedureKind.Method, null, | 159 var method = new Procedure( |
| 160 new Name('bar'), |
| 161 ProcedureKind.Method, |
| 162 new FunctionNode(new EmptyStatement(), |
| 163 positionalParameters: [new VariableDeclaration('p')]), |
| 162 isStatic: true); | 164 isStatic: true); |
| 163 method.function = new FunctionNode( | 165 test.enclosingClass.addMember(method); |
| 164 new ReturnStatement( | 166 return new StaticInvocation(method, new Arguments.empty()); |
| 165 new StaticInvocation(method, new Arguments.empty())), | |
| 166 positionalParameters: [new VariableDeclaration('p')])..parent = method; | |
| 167 return new Class( | |
| 168 name: 'Test', | |
| 169 supertype: objectClass.asRawSupertype, | |
| 170 procedures: [method]); | |
| 171 }); | 167 }); |
| 172 negativeTest('StaticInvocation with unmatched named parameter', () { | 168 negativeTest('StaticInvocation with unmatched named parameter', |
| 173 var method = new Procedure(new Name('test'), ProcedureKind.Method, null, | 169 (TestHarness test) { |
| 170 var method = new Procedure(new Name('bar'), ProcedureKind.Method, |
| 171 new FunctionNode(new EmptyStatement()), |
| 174 isStatic: true); | 172 isStatic: true); |
| 175 method.function = new FunctionNode(new ReturnStatement(new StaticInvocation( | 173 test.enclosingClass.addMember(method); |
| 174 return new StaticInvocation( |
| 176 method, | 175 method, |
| 177 new Arguments([], | 176 new Arguments([], |
| 178 named: [new NamedExpression('p', new NullLiteral())])))) | 177 named: [new NamedExpression('p', new NullLiteral())])); |
| 179 ..parent = method; | 178 }); |
| 180 return new Class( | 179 negativeTest('StaticInvocation with missing type argument', |
| 180 (TestHarness test) { |
| 181 var method = new Procedure( |
| 182 new Name('bar'), |
| 183 ProcedureKind.Method, |
| 184 new FunctionNode(new EmptyStatement(), |
| 185 typeParameters: [test.makeTypeParameter()]), |
| 186 isStatic: true); |
| 187 test.enclosingClass.addMember(method); |
| 188 return new StaticInvocation(method, new Arguments.empty()); |
| 189 }); |
| 190 negativeTest('ConstructorInvocation with missing type argument', |
| 191 (TestHarness test) { |
| 192 var class_ = new Class( |
| 181 name: 'Test', | 193 name: 'Test', |
| 182 supertype: objectClass.asRawSupertype, | 194 typeParameters: [test.makeTypeParameter()], |
| 183 procedures: [method]); | 195 supertype: test.objectClass.asRawSupertype); |
| 184 }); | 196 test.enclosingLibrary.addClass(class_); |
| 185 negativeTest('StaticInvocation with missing type argument', () { | 197 var constructor = new Constructor(new FunctionNode(new EmptyStatement()), |
| 186 var method = new Procedure(new Name('test'), ProcedureKind.Method, null, | 198 name: new Name('foo')); |
| 187 isStatic: true); | 199 test.enclosingClass.addMember(constructor); |
| 188 method.function = new FunctionNode( | 200 return new ConstructorInvocation(constructor, new Arguments.empty()); |
| 189 new ReturnStatement( | |
| 190 new StaticInvocation(method, new Arguments.empty())), | |
| 191 typeParameters: [makeTypeParameter()])..parent = method; | |
| 192 return new Class( | |
| 193 name: 'Test', | |
| 194 supertype: objectClass.asRawSupertype, | |
| 195 procedures: [method]); | |
| 196 }); | |
| 197 negativeTest('ConstructorInvocation with missing type argument', () { | |
| 198 var constructor = new Constructor(null); | |
| 199 constructor.function = new FunctionNode(new ReturnStatement( | |
| 200 new ConstructorInvocation(constructor, new Arguments.empty()))) | |
| 201 ..parent = constructor; | |
| 202 return new Class( | |
| 203 name: 'Test', | |
| 204 typeParameters: [makeTypeParameter()], | |
| 205 supertype: objectClass.asRawSupertype, | |
| 206 constructors: [constructor]); | |
| 207 }); | 201 }); |
| 208 } | 202 } |
| 209 | 203 |
| 210 checkHasError(Program program) { | 204 checkHasError(Program program) { |
| 211 bool passed = false; | 205 bool passed = false; |
| 212 try { | 206 try { |
| 213 verifyProgram(program); | 207 verifyProgram(program); |
| 214 passed = true; | 208 passed = true; |
| 215 } catch (e) {} | 209 } catch (e) {} |
| 216 if (passed) { | 210 if (passed) { |
| 217 fail('Failed to reject invalid program:\n${programToString(program)}'); | 211 fail('Failed to reject invalid program:\n${programToString(program)}'); |
| 218 } | 212 } |
| 219 } | 213 } |
| 220 | 214 |
| 221 Class objectClass = new Class(name: 'Object'); | 215 class TestHarness { |
| 216 Program program; |
| 217 Class objectClass; |
| 218 Library stubLibrary; |
| 222 | 219 |
| 223 Library stubLibrary = new Library(Uri.parse('dart:core')) | 220 TypeParameter classTypeParameter; |
| 224 ..addClass(objectClass); | |
| 225 | 221 |
| 226 TypeParameter classTypeParameter = makeTypeParameter('T'); | 222 Library enclosingLibrary; |
| 223 Class enclosingClass; |
| 224 Procedure enclosingMember; |
| 227 | 225 |
| 228 Class otherClass = new Class( | 226 Class otherClass; |
| 229 name: 'OtherClass', | |
| 230 typeParameters: [makeTypeParameter('OtherT')], | |
| 231 supertype: objectClass.asRawSupertype); | |
| 232 | 227 |
| 233 Program makeProgram(TreeNode makeBody()) { | 228 void addNode(TreeNode node) { |
| 234 var node = makeBody(); | 229 if (node is Expression) { |
| 235 if (node is Expression) { | 230 addExpression(node); |
| 236 node = new ReturnStatement(node); | 231 } else if (node is Statement) { |
| 232 addStatement(node); |
| 233 } else if (node is Member) { |
| 234 addClassMember(node); |
| 235 } else if (node is Class) { |
| 236 addClass(node); |
| 237 } |
| 237 } | 238 } |
| 238 if (node is Statement) { | 239 |
| 239 node = new FunctionNode(node); | 240 void addExpression(Expression node) { |
| 241 addStatement(new ReturnStatement(node)); |
| 240 } | 242 } |
| 241 if (node is FunctionNode) { | 243 |
| 242 node = new Procedure(new Name('test'), ProcedureKind.Method, node); | 244 void addStatement(Statement node) { |
| 245 var function = enclosingMember.function; |
| 246 function.body = node..parent = function; |
| 243 } | 247 } |
| 244 if (node is Member) { | 248 |
| 245 node = new Class( | 249 void addClassMember(Member node) { |
| 246 name: 'Test', | 250 enclosingClass.addMember(node); |
| 251 } |
| 252 |
| 253 void addTopLevelMember(Member node) { |
| 254 enclosingLibrary.addMember(node); |
| 255 } |
| 256 |
| 257 void addClass(Class node) { |
| 258 enclosingLibrary.addClass(node); |
| 259 } |
| 260 |
| 261 VariableDeclaration makeVariable() => new VariableDeclaration(null); |
| 262 |
| 263 TypeParameter makeTypeParameter([String name]) { |
| 264 return new TypeParameter(name, new InterfaceType(objectClass)); |
| 265 } |
| 266 |
| 267 TestHarness() { |
| 268 setupProgram(); |
| 269 } |
| 270 |
| 271 void setupProgram() { |
| 272 program = new Program(); |
| 273 stubLibrary = new Library(Uri.parse('dart:core')); |
| 274 program.libraries.add(stubLibrary..parent = program); |
| 275 stubLibrary.name = 'dart.core'; |
| 276 objectClass = new Class(name: 'Object'); |
| 277 stubLibrary.addClass(objectClass); |
| 278 enclosingLibrary = new Library(Uri.parse('file://test.dart')); |
| 279 program.libraries.add(enclosingLibrary..parent = program); |
| 280 enclosingLibrary.name = 'test_lib'; |
| 281 classTypeParameter = makeTypeParameter('T'); |
| 282 enclosingClass = new Class( |
| 283 name: 'TestClass', |
| 247 typeParameters: [classTypeParameter], | 284 typeParameters: [classTypeParameter], |
| 248 supertype: objectClass.asRawSupertype)..addMember(node); | 285 supertype: objectClass.asRawSupertype); |
| 286 enclosingLibrary.addClass(enclosingClass); |
| 287 enclosingMember = new Procedure(new Name('test'), ProcedureKind.Method, |
| 288 new FunctionNode(new EmptyStatement())); |
| 289 enclosingClass.addMember(enclosingMember); |
| 290 otherClass = new Class( |
| 291 name: 'OtherClass', |
| 292 typeParameters: [makeTypeParameter('OtherT')], |
| 293 supertype: objectClass.asRawSupertype); |
| 294 enclosingLibrary.addClass(otherClass); |
| 249 } | 295 } |
| 250 if (node is Class) { | |
| 251 node = | |
| 252 new Library(Uri.parse('test.dart'), classes: <Class>[node, otherClass]); | |
| 253 } | |
| 254 if (node is Library) { | |
| 255 node = new Program(<Library>[node, stubLibrary]); | |
| 256 } | |
| 257 assert(node is Program); | |
| 258 return node; | |
| 259 } | 296 } |
| 260 | 297 |
| 261 negativeTest(String name, TreeNode makeBody()) { | 298 negativeTest(String name, TreeNode makeTestCase(TestHarness test)) { |
| 262 test(name, () { | 299 test(name, () { |
| 263 checkHasError(makeProgram(makeBody)); | 300 var test = new TestHarness(); |
| 301 test.addNode(makeTestCase(test)); |
| 302 checkHasError(test.program); |
| 264 }); | 303 }); |
| 265 } | 304 } |
| 266 | 305 |
| 267 positiveTest(String name, TreeNode makeBody()) { | 306 positiveTest(String name, TreeNode makeTestCase(TestHarness test)) { |
| 268 test(name, () { | 307 test(name, () { |
| 269 verifyProgram(makeProgram(makeBody)); | 308 var test = new TestHarness(); |
| 309 test.addNode(makeTestCase(test)); |
| 310 verifyProgram(test.program); |
| 270 }); | 311 }); |
| 271 } | 312 } |
| 272 | |
| 273 VariableDeclaration makeVariable() => new VariableDeclaration(null); | |
| 274 | |
| 275 TypeParameter makeTypeParameter([String name]) { | |
| 276 return new TypeParameter(name, new InterfaceType(objectClass)); | |
| 277 } | |
| OLD | NEW |