| Index: pkg/kernel/test/verify_test.dart
|
| diff --git a/pkg/kernel/test/verify_test.dart b/pkg/kernel/test/verify_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..67a7e9623662f2ad6fac17252225e1425ecacd1b
|
| --- /dev/null
|
| +++ b/pkg/kernel/test/verify_test.dart
|
| @@ -0,0 +1,166 @@
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +import 'package:kernel/ast.dart';
|
| +import 'package:kernel/text/ast_to_text.dart';
|
| +import 'package:kernel/verifier.dart';
|
| +import 'package:test/test.dart';
|
| +
|
| +/// Checks that the sanity checks correctly find errors in invalid programs.
|
| +///
|
| +/// The frontend should never generate invalid programs, so we have to test
|
| +/// these by manually constructing invalid ASTs.
|
| +///
|
| +/// We only test negative cases here, as we get plenty of positive cases by
|
| +/// compiling the Dart test suite with sanity checks enabled.
|
| +main() {
|
| + negativeTest('VariableGet out of scope', () {
|
| + return new VariableGet(makeVariable());
|
| + });
|
| + negativeTest('VariableSet out of scope', () {
|
| + return new VariableSet(makeVariable(), new NullLiteral());
|
| + });
|
| + negativeTest('Variable block scope', () {
|
| + VariableDeclaration variable = makeVariable();
|
| + return new Block([
|
| + new Block([variable]),
|
| + new ReturnStatement(new VariableGet(variable))
|
| + ]);
|
| + });
|
| + negativeTest('Variable let scope', () {
|
| + VariableDeclaration variable = makeVariable();
|
| + return new LogicalExpression(new Let(variable, new VariableGet(variable)),
|
| + '&&', new VariableGet(variable));
|
| + });
|
| + negativeTest('Variable redeclared', () {
|
| + VariableDeclaration variable = makeVariable();
|
| + return new Block([variable, variable]);
|
| + });
|
| + negativeTest('Member redeclared', () {
|
| + Field field = new Field(new Name('field'), initializer: new NullLiteral());
|
| + return new Class(
|
| + name: 'Test',
|
| + supertype: objectClass.asRawSupertype,
|
| + fields: [field, field]);
|
| + });
|
| + negativeTest('Type parameter out of scope', () {
|
| + var parameter = makeTypeParameter();
|
| + return new ListLiteral([], typeArgument: new TypeParameterType(parameter));
|
| + });
|
| + negativeTest('Class type parameter from another class', () {
|
| + return new TypeLiteral(new TypeParameterType(otherClass.typeParameters[0]));
|
| + });
|
| + negativeTest('Class type parameter in static method', () {
|
| + return new Procedure(
|
| + new Name('test'),
|
| + ProcedureKind.Method,
|
| + new FunctionNode(new ReturnStatement(
|
| + new TypeLiteral(new TypeParameterType(classTypeParameter)))),
|
| + isStatic: true);
|
| + });
|
| + negativeTest('Class type parameter in static field', () {
|
| + return new Field(new Name('field'),
|
| + initializer: new TypeLiteral(new TypeParameterType(classTypeParameter)),
|
| + isStatic: true);
|
| + });
|
| + negativeTest('Method type parameter out of scope', () {
|
| + var parameter = makeTypeParameter();
|
| + return new Class(
|
| + name: 'Test',
|
| + supertype: objectClass.asRawSupertype,
|
| + procedures: [
|
| + new Procedure(
|
| + new Name('generic'),
|
| + ProcedureKind.Method,
|
| + new FunctionNode(new EmptyStatement(),
|
| + typeParameters: [parameter])),
|
| + new Procedure(
|
| + new Name('use'),
|
| + ProcedureKind.Method,
|
| + new FunctionNode(new ReturnStatement(
|
| + new TypeLiteral(new TypeParameterType(parameter)))))
|
| + ]);
|
| + });
|
| + negativeTest('Interface type arity too low', () {
|
| + return new TypeLiteral(new InterfaceType(otherClass, []));
|
| + });
|
| + negativeTest('Interface type arity too high', () {
|
| + return new TypeLiteral(
|
| + new InterfaceType(otherClass, [new DynamicType(), new DynamicType()]));
|
| + });
|
| + negativeTest('Dangling interface type', () {
|
| + return new TypeLiteral(new InterfaceType(new Class()));
|
| + });
|
| + negativeTest('Dangling field get', () {
|
| + return new DirectPropertyGet(new NullLiteral(), new Field(new Name('foo')));
|
| + });
|
| + negativeTest('Missing block parent pointer', () {
|
| + var block = new Block([]);
|
| + block.statements.add(new ReturnStatement());
|
| + return block;
|
| + });
|
| + negativeTest('Missing function parent pointer', () {
|
| + var procedure = new Procedure(new Name('test'), ProcedureKind.Method, null);
|
| + procedure.function = new FunctionNode(new EmptyStatement());
|
| + return procedure;
|
| + });
|
| +}
|
| +
|
| +checkHasError(Program program) {
|
| + bool passed = false;
|
| + try {
|
| + verifyProgram(program);
|
| + passed = true;
|
| + } catch (e) {}
|
| + if (passed) {
|
| + fail('Failed to reject invalid program:\n${programToString(program)}');
|
| + }
|
| +}
|
| +
|
| +Class objectClass = new Class(name: 'Object');
|
| +
|
| +Library stubLibrary = new Library(Uri.parse('dart:core'))
|
| + ..addClass(objectClass);
|
| +
|
| +TypeParameter classTypeParameter = makeTypeParameter('T');
|
| +
|
| +Class otherClass = new Class(
|
| + name: 'OtherClass',
|
| + typeParameters: [makeTypeParameter('OtherT')],
|
| + supertype: objectClass.asRawSupertype);
|
| +
|
| +negativeTest(String name, TreeNode makeBody()) {
|
| + test(name, () {
|
| + var node = makeBody();
|
| + if (node is Expression) {
|
| + node = new ReturnStatement(node);
|
| + }
|
| + if (node is Statement) {
|
| + node = new FunctionNode(node);
|
| + }
|
| + if (node is FunctionNode) {
|
| + node = new Procedure(new Name('test'), ProcedureKind.Method, node);
|
| + }
|
| + if (node is Member) {
|
| + node = new Class(
|
| + name: 'Test',
|
| + typeParameters: [classTypeParameter],
|
| + supertype: objectClass.asRawSupertype)..addMember(node);
|
| + }
|
| + if (node is Class) {
|
| + node = new Library(Uri.parse('test.dart'),
|
| + classes: <Class>[node, otherClass]);
|
| + }
|
| + if (node is Library) {
|
| + node = new Program(<Library>[node, stubLibrary]);
|
| + }
|
| + assert(node is Program);
|
| + checkHasError(node);
|
| + });
|
| +}
|
| +
|
| +VariableDeclaration makeVariable() => new VariableDeclaration(null);
|
| +
|
| +TypeParameter makeTypeParameter([String name]) {
|
| + return new TypeParameter(name, new InterfaceType(objectClass));
|
| +}
|
|
|