| Index: pkg/kernel/test/type_propagation_selfcheck.dart
|
| diff --git a/pkg/kernel/test/type_propagation_selfcheck.dart b/pkg/kernel/test/type_propagation_selfcheck.dart
|
| deleted file mode 100644
|
| index e83e4b7f86f9ac2645901586fca52440384dab4c..0000000000000000000000000000000000000000
|
| --- a/pkg/kernel/test/type_propagation_selfcheck.dart
|
| +++ /dev/null
|
| @@ -1,183 +0,0 @@
|
| -// 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.
|
| -library kernel.type_propagation.selfcheck;
|
| -
|
| -import 'dart:io';
|
| -import 'package:kernel/core_types.dart';
|
| -import 'package:kernel/kernel.dart';
|
| -import 'package:kernel/type_propagation/type_propagation.dart';
|
| -
|
| -const String usage = '''
|
| -Usage: selfcheck input.dill output.dill
|
| -
|
| -Runs type propagation on the given program and inserts dynamic checks
|
| -to verify that all the propagated types are correct.
|
| -''';
|
| -
|
| -main(List<String> args) {
|
| - if (args.length != 2) {
|
| - print(usage);
|
| - exit(1);
|
| - }
|
| - var program = loadProgramFromBinary(args[0]);
|
| - var typePropagation = new TypePropagation(program);
|
| - new SelfCheckTransformer(typePropagation).transform(program);
|
| - writeProgramToBinary(program, args[1]);
|
| -}
|
| -
|
| -class SelfCheckTransformer {
|
| - final TypePropagation typePropagation;
|
| - Member currentMember;
|
| -
|
| - CoreTypes get coreTypes => typePropagation.builder.coreTypes;
|
| -
|
| - SelfCheckTransformer(this.typePropagation);
|
| -
|
| - void transform(Program program) {
|
| - for (var library in program.libraries) {
|
| - library.procedures.forEach(transformProcedure);
|
| - library.fields.forEach(transformField);
|
| - for (var class_ in library.classes) {
|
| - class_.procedures.forEach(transformProcedure);
|
| - class_.fields.forEach(transformField);
|
| - class_.constructors.forEach(transformConstructor);
|
| - }
|
| - }
|
| - }
|
| -
|
| - void transformProcedure(Procedure node) {
|
| - currentMember = node;
|
| - transformFunction(node.function, checkReturn: true);
|
| - }
|
| -
|
| - void transformConstructor(Constructor node) {
|
| - currentMember = node;
|
| - transformFunction(node.function, checkReturn: false);
|
| - }
|
| -
|
| - void transformField(Field node) {
|
| - // TODO(asgerf): To check this, we could wrap with a getter/setter pair
|
| - // and instrument constructor initializers. But for now we don't do
|
| - // anything for fields.
|
| - }
|
| -
|
| - void transformFunction(FunctionNode node, {bool checkReturn}) {
|
| - if (node.body == null) return; // Nothing to check if there is no body.
|
| - List<Statement> newStatements = <Statement>[];
|
| - for (VariableDeclaration parameter in node.positionalParameters) {
|
| - InferredValue value = typePropagation.getParameterValue(parameter);
|
| - newStatements.add(makeCheck(parameter, value));
|
| - }
|
| - for (VariableDeclaration parameter in node.namedParameters) {
|
| - InferredValue value = typePropagation.getParameterValue(parameter);
|
| - newStatements.add(makeCheck(parameter, value));
|
| - }
|
| - newStatements.add(node.body);
|
| - node.body = new Block(newStatements)..parent = node;
|
| - // TODO(asgerf): Also check return value.
|
| - }
|
| -
|
| - /// Make a statement that throws if the value in [variable] is not in the
|
| - /// value set implied by [expected].
|
| - Statement makeCheck(VariableDeclaration variable, InferredValue expected) {
|
| - Expression condition = new LogicalExpression(
|
| - makeBaseClassCheck(variable, expected),
|
| - '&&',
|
| - makeBitmaskCheck(variable, expected));
|
| - return new IfStatement(
|
| - new Not(condition),
|
| - new ExpressionStatement(new Throw(new StringConcatenation([
|
| - new StringLiteral(
|
| - 'Unexpected value in $currentMember::${variable.name}: '),
|
| - new VariableGet(variable)
|
| - ]))),
|
| - null);
|
| - }
|
| -
|
| - /// Makes an expression that returns `false` if the base class relation or
|
| - /// nullability is not satisfied by the value in [variable],
|
| - Expression makeBaseClassCheck(
|
| - VariableDeclaration variable, InferredValue expected) {
|
| - Expression condition;
|
| - switch (expected.baseClassKind) {
|
| - case BaseClassKind.None:
|
| - condition = new BoolLiteral(false);
|
| - break;
|
| -
|
| - case BaseClassKind.Exact:
|
| - if (expected.baseClass.typeParameters.isNotEmpty) {
|
| - // TODO(asgerf): For this we need a way to get the raw concrete type
|
| - // of an object. For now, just emit the less accurate subtype
|
| - // check.
|
| - condition = new IsExpression(
|
| - new VariableGet(variable), expected.baseClass.rawType);
|
| - } else {
|
| - // Check `value.runtimeType == C`.
|
| - var runtimeType = new PropertyGet(
|
| - new VariableGet(variable), new Name('runtimeType'));
|
| - condition = new MethodInvocation(runtimeType, new Name('=='),
|
| - new Arguments([new TypeLiteral(expected.baseClass.rawType)]));
|
| - }
|
| - break;
|
| -
|
| - case BaseClassKind.Subclass:
|
| - case BaseClassKind.Subtype:
|
| - // TODO(asgerf): For subclass checks, we should check more precisely
|
| - // that is it a subclass, but for now just emit a subtype check.
|
| - condition = new IsExpression(
|
| - new VariableGet(variable), expected.baseClass.rawType);
|
| - break;
|
| - }
|
| - // Always allow 'null'. The base class relation should always permit 'null'
|
| - // as a possible value, but the checks generated above disallow it.
|
| - var nullCheck = makeIsNull(new VariableGet(variable));
|
| - return new LogicalExpression(nullCheck, '||', condition);
|
| - }
|
| -
|
| - Expression makeIsNull(Expression value) {
|
| - return new MethodInvocation(
|
| - value, new Name('=='), new Arguments([new NullLiteral()]));
|
| - }
|
| -
|
| - /// Makes an expression that returns `false` if the value bits other than
|
| - /// [ValueBit.null_] are not satisfied by the value in [variable],
|
| - Expression makeBitmaskCheck(
|
| - VariableDeclaration variable, InferredValue expected) {
|
| - if (expected.valueBits == 0) return new BoolLiteral(false);
|
| -
|
| - // List of conditions that all must hold. For each zero bit we know that
|
| - // type of value is not allowed to occur.
|
| - List<Expression> allChecks = <Expression>[];
|
| -
|
| - // List of condition of which one must hold. This is used for checking the
|
| - // [ValueBit.other] bit. For each one bit, we know that type of value
|
| - // is allowed to occur. We use this because it is hard to check directly
|
| - // that a value is of the 'other' type.
|
| - bool disallowOtherValues = expected.valueBits & ValueBit.other == 0;
|
| - List<Expression> anyChecks = disallowOtherValues ? <Expression>[] : null;
|
| -
|
| - void checkType(int bit, DartType type) {
|
| - if (expected.valueBits & bit == 0) {
|
| - allChecks
|
| - .add(new Not(new IsExpression(new VariableGet(variable), type)));
|
| - } else if (disallowOtherValues) {
|
| - anyChecks.add(new IsExpression(new VariableGet(variable), type));
|
| - }
|
| - }
|
| -
|
| - checkType(ValueBit.integer, coreTypes.intClass.rawType);
|
| - checkType(ValueBit.double_, coreTypes.doubleClass.rawType);
|
| - checkType(ValueBit.string, coreTypes.stringClass.rawType);
|
| - checkType(ValueBit.null_, coreTypes.nullClass.rawType);
|
| -
|
| - if (disallowOtherValues) {
|
| - Expression any =
|
| - anyChecks.reduce((e1, e2) => new LogicalExpression(e1, '||', e2));
|
| - allChecks.add(any);
|
| - }
|
| - return allChecks.isEmpty
|
| - ? new BoolLiteral(true)
|
| - : allChecks.reduce((e1, e2) => new LogicalExpression(e1, '&&', e2));
|
| - }
|
| -}
|
|
|