| Index: pkg/kernel/lib/type_checker.dart
|
| diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
|
| index ab0351eb40b59ace8f18901b52027ecb27e0d356..45159b2d953bdb9330a6856470d6e1fadab948bd 100644
|
| --- a/pkg/kernel/lib/type_checker.dart
|
| +++ b/pkg/kernel/lib/type_checker.dart
|
| @@ -85,6 +85,16 @@ abstract class TypeChecker {
|
| /// [where] is an AST node indicating roughly where the check is required.
|
| void checkAssignable(TreeNode where, DartType from, DartType to);
|
|
|
| + /// Checks that [expression], which has type [from], can be assigned to [to].
|
| + ///
|
| + /// Should return a downcast if necessary, or [expression] if no cast is
|
| + /// needed.
|
| + Expression checkAndDowncastExpression(
|
| + Expression expression, DartType from, DartType to) {
|
| + checkAssignable(expression, from, to);
|
| + return expression;
|
| + }
|
| +
|
| /// Indicates that type checking failed.
|
| void fail(TreeNode where, String message);
|
| }
|
| @@ -108,8 +118,16 @@ class TypeCheckingVisitor
|
| checker.checkAssignable(where, from, to);
|
| }
|
|
|
| - void checkAssignableExpression(Expression from, DartType to) {
|
| - checker.checkAssignable(from, visitExpression(from), to);
|
| + Expression checkAndDowncastExpression(Expression from, DartType to) {
|
| + var parent = from.parent;
|
| + var type = visitExpression(from);
|
| + var result = checker.checkAndDowncastExpression(from, type, to);
|
| + result.parent = parent;
|
| + return result;
|
| + }
|
| +
|
| + void checkExpressionNoDowncast(Expression expression, DartType to) {
|
| + checkAssignable(expression, visitExpression(expression), to);
|
| }
|
|
|
| void fail(TreeNode node, String message) {
|
| @@ -146,7 +164,8 @@ class TypeCheckingVisitor
|
|
|
| visitField(Field node) {
|
| if (node.initializer != null) {
|
| - checkAssignableExpression(node.initializer, node.type);
|
| + node.initializer =
|
| + checkAndDowncastExpression(node.initializer, node.type);
|
| }
|
| }
|
|
|
| @@ -188,7 +207,8 @@ class TypeCheckingVisitor
|
|
|
| void handleOptionalParameter(VariableDeclaration parameter) {
|
| if (parameter.initializer != null) {
|
| - checkAssignableExpression(parameter.initializer, parameter.type);
|
| + // Default parameter values cannot be downcast.
|
| + checkExpressionNoDowncast(parameter.initializer, parameter.type);
|
| }
|
| }
|
|
|
| @@ -255,7 +275,8 @@ class TypeCheckingVisitor
|
| var expectedType = substitution.substituteType(
|
| function.positionalParameters[i].type,
|
| contravariant: true);
|
| - checkAssignableExpression(arguments.positional[i], expectedType);
|
| + arguments.positional[i] =
|
| + checkAndDowncastExpression(arguments.positional[i], expectedType);
|
| }
|
| for (int i = 0; i < arguments.named.length; ++i) {
|
| var argument = arguments.named[i];
|
| @@ -265,7 +286,8 @@ class TypeCheckingVisitor
|
| var expectedType = substitution.substituteType(
|
| function.namedParameters[j].type,
|
| contravariant: true);
|
| - checkAssignableExpression(argument.value, expectedType);
|
| + argument.value =
|
| + checkAndDowncastExpression(argument.value, expectedType);
|
| found = true;
|
| break;
|
| }
|
| @@ -344,9 +366,11 @@ class TypeCheckingVisitor
|
|
|
| @override
|
| DartType visitConditionalExpression(ConditionalExpression node) {
|
| - checkAssignableExpression(node.condition, environment.boolType);
|
| - checkAssignableExpression(node.then, node.staticType);
|
| - checkAssignableExpression(node.otherwise, node.staticType);
|
| + node.condition =
|
| + checkAndDowncastExpression(node.condition, environment.boolType);
|
| + node.then = checkAndDowncastExpression(node.then, node.staticType);
|
| + node.otherwise =
|
| + checkAndDowncastExpression(node.otherwise, node.staticType);
|
| return node.staticType;
|
| }
|
|
|
| @@ -419,24 +443,25 @@ class TypeCheckingVisitor
|
|
|
| @override
|
| DartType visitListLiteral(ListLiteral node) {
|
| - for (var item in node.expressions) {
|
| - checkAssignableExpression(item, node.typeArgument);
|
| + for (int i = 0; i < node.expressions.length; ++i) {
|
| + node.expressions[i] =
|
| + checkAndDowncastExpression(node.expressions[i], node.typeArgument);
|
| }
|
| return environment.literalListType(node.typeArgument);
|
| }
|
|
|
| @override
|
| DartType visitLogicalExpression(LogicalExpression node) {
|
| - checkAssignableExpression(node.left, environment.boolType);
|
| - checkAssignableExpression(node.right, environment.boolType);
|
| + node.left = checkAndDowncastExpression(node.left, environment.boolType);
|
| + node.right = checkAndDowncastExpression(node.right, environment.boolType);
|
| return environment.boolType;
|
| }
|
|
|
| @override
|
| DartType visitMapLiteral(MapLiteral node) {
|
| for (var entry in node.entries) {
|
| - checkAssignableExpression(entry.key, node.keyType);
|
| - checkAssignableExpression(entry.value, node.valueType);
|
| + entry.key = checkAndDowncastExpression(entry.key, node.keyType);
|
| + entry.value = checkAndDowncastExpression(entry.value, node.valueType);
|
| }
|
| return environment.literalMapType(node.keyType, node.valueType);
|
| }
|
| @@ -467,7 +492,8 @@ class TypeCheckingVisitor
|
| var expectedType = instantiation.substituteType(
|
| function.positionalParameters[i],
|
| contravariant: true);
|
| - checkAssignableExpression(arguments.positional[i], expectedType);
|
| + arguments.positional[i] =
|
| + checkAndDowncastExpression(arguments.positional[i], expectedType);
|
| }
|
| for (int i = 0; i < arguments.named.length; ++i) {
|
| var argument = arguments.named[i];
|
| @@ -477,7 +503,8 @@ class TypeCheckingVisitor
|
| var expectedType = instantiation.substituteType(
|
| function.namedParameters[j].type,
|
| contravariant: true);
|
| - checkAssignableExpression(argument.value, expectedType);
|
| + argument.value =
|
| + checkAndDowncastExpression(argument.value, expectedType);
|
| found = true;
|
| break;
|
| }
|
| @@ -674,7 +701,8 @@ class TypeCheckingVisitor
|
| @override
|
| visitDoStatement(DoStatement node) {
|
| visitStatement(node.body);
|
| - checkAssignableExpression(node.condition, environment.boolType);
|
| + node.condition =
|
| + checkAndDowncastExpression(node.condition, environment.boolType);
|
| }
|
|
|
| @override
|
| @@ -700,23 +728,27 @@ class TypeCheckingVisitor
|
| }
|
|
|
| static final Name iteratorName = new Name('iterator');
|
| - static final Name nextName = new Name('next');
|
| + static final Name currentName = new Name('current');
|
|
|
| DartType getIterableElementType(DartType iterable) {
|
| if (iterable is InterfaceType) {
|
| var iteratorGetter =
|
| hierarchy.getInterfaceMember(iterable.classNode, iteratorName);
|
| if (iteratorGetter == null) return const DynamicType();
|
| + var castedIterable = hierarchy.getTypeAsInstanceOf(
|
| + iterable, iteratorGetter.enclosingClass);
|
| var iteratorType = Substitution
|
| - .fromInterfaceType(iterable)
|
| + .fromInterfaceType(castedIterable)
|
| .substituteType(iteratorGetter.getterType);
|
| if (iteratorType is InterfaceType) {
|
| - var nextGetter =
|
| - hierarchy.getInterfaceMember(iteratorType.classNode, nextName);
|
| - if (nextGetter == null) return const DynamicType();
|
| + var currentGetter =
|
| + hierarchy.getInterfaceMember(iteratorType.classNode, currentName);
|
| + if (currentGetter == null) return const DynamicType();
|
| + var castedIteratorType = hierarchy.getTypeAsInstanceOf(
|
| + iteratorType, currentGetter.enclosingClass);
|
| return Substitution
|
| - .fromInterfaceType(iteratorType)
|
| - .substituteType(nextGetter.getterType);
|
| + .fromInterfaceType(castedIteratorType)
|
| + .substituteType(currentGetter.getterType);
|
| }
|
| }
|
| return const DynamicType();
|
| @@ -736,7 +768,8 @@ class TypeCheckingVisitor
|
| visitForStatement(ForStatement node) {
|
| node.variables.forEach(visitVariableDeclaration);
|
| if (node.condition != null) {
|
| - checkAssignableExpression(node.condition, environment.boolType);
|
| + node.condition =
|
| + checkAndDowncastExpression(node.condition, environment.boolType);
|
| }
|
| node.updates.forEach(visitExpression);
|
| visitStatement(node.body);
|
| @@ -749,7 +782,8 @@ class TypeCheckingVisitor
|
|
|
| @override
|
| visitIfStatement(IfStatement node) {
|
| - checkAssignableExpression(node.condition, environment.boolType);
|
| + node.condition =
|
| + checkAndDowncastExpression(node.condition, environment.boolType);
|
| visitStatement(node.then);
|
| if (node.otherwise != null) {
|
| visitStatement(node.otherwise);
|
| @@ -805,13 +839,15 @@ class TypeCheckingVisitor
|
| @override
|
| visitVariableDeclaration(VariableDeclaration node) {
|
| if (node.initializer != null) {
|
| - checkAssignableExpression(node.initializer, node.type);
|
| + node.initializer =
|
| + checkAndDowncastExpression(node.initializer, node.type);
|
| }
|
| }
|
|
|
| @override
|
| visitWhileStatement(WhileStatement node) {
|
| - checkAssignableExpression(node.condition, environment.boolType);
|
| + node.condition =
|
| + checkAndDowncastExpression(node.condition, environment.boolType);
|
| visitStatement(node.body);
|
| }
|
|
|
| @@ -832,13 +868,14 @@ class TypeCheckingVisitor
|
| fail(node.expression, '$type is not an instance of $container');
|
| }
|
| } else {
|
| - checkAssignableExpression(node.expression, environment.yieldType);
|
| + node.expression =
|
| + checkAndDowncastExpression(node.expression, environment.yieldType);
|
| }
|
| }
|
|
|
| @override
|
| visitFieldInitializer(FieldInitializer node) {
|
| - checkAssignableExpression(node.value, node.field.type);
|
| + node.value = checkAndDowncastExpression(node.value, node.field.type);
|
| }
|
|
|
| @override
|
| @@ -850,7 +887,8 @@ class TypeCheckingVisitor
|
| @override
|
| visitSuperInitializer(SuperInitializer node) {
|
| handleCall(node.arguments, node.target.function,
|
| - typeParameters: const <TypeParameter>[]);
|
| + typeParameters: const <TypeParameter>[],
|
| + receiver: getSuperReceiverType(node.target));
|
| }
|
|
|
| @override
|
|
|