| Index: pkg/front_end/lib/src/fasta/builder/shadow_ast.dart
|
| diff --git a/pkg/front_end/lib/src/fasta/builder/shadow_ast.dart b/pkg/front_end/lib/src/fasta/builder/shadow_ast.dart
|
| index 6976d7bc62fc3af3d3aefd939544c46e5c6e5da7..914380725dc31efc86060fb5419c569a53bcfe10 100644
|
| --- a/pkg/front_end/lib/src/fasta/builder/shadow_ast.dart
|
| +++ b/pkg/front_end/lib/src/fasta/builder/shadow_ast.dart
|
| @@ -2,6 +2,8 @@
|
| // 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:front_end/src/fasta/type_inference/local_type_inferrer.dart';
|
| +
|
| /// This file declares mixins which can be used to create a shadow hierarchy
|
| /// of either the kernel or the analyzer AST representations.
|
| ///
|
| @@ -14,19 +16,27 @@
|
| /// Note that the analyzer AST representation closely parallels Dart syntax,
|
| /// whereas the kernel AST representation is desugared. The classes in the
|
| /// shadow hierarchy represent the full language (prior to desugaring).
|
| -import 'package:kernel/ast.dart' show DartType;
|
| +import 'package:kernel/ast.dart' show DartType, DynamicType, InterfaceType;
|
| +import 'package:kernel/core_types.dart';
|
|
|
| /// Shadow mixin representing a statement block.
|
| abstract class ShadowBlock implements ShadowStatement {
|
| /// Iterates through the statements contained in the block.
|
| Iterable<ShadowStatement> get shadowStatements;
|
| +
|
| + @override
|
| + void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context) {
|
| + for (var statement in shadowStatements) {
|
| + statement.shadowInfer(inferrer, context);
|
| + }
|
| + }
|
| }
|
|
|
| /// Common interface for shadow mixins representing expressions.
|
| -///
|
| -/// TODO(paulberry): add an abstract `shadowInfer` method here to do type
|
| -/// inference.
|
| -abstract class ShadowExpression {}
|
| +abstract class ShadowExpression {
|
| + DartType shadowInfer(
|
| + LocalTypeInferrer inferrer, DartType context, bool typeNeeded);
|
| +}
|
|
|
| /// Shadow mixin representing a function expression.
|
| abstract class ShadowFunctionExpression implements ShadowExpression {
|
| @@ -52,10 +62,49 @@ abstract class ShadowFunctionExpression implements ShadowExpression {
|
| ///
|
| /// Intended for use by type inference.
|
| void set shadowReturnType(DartType type);
|
| +
|
| + @override
|
| + DartType shadowInfer(
|
| + LocalTypeInferrer inferrer, DartType context, bool typeNeeded) {
|
| + // TODO(paulberry): infer argument types and type parameters.
|
| + // TODO(paulberry): full support for generators.
|
| + var body = shadowBody;
|
| + // TODO(paulberry): Dart 1.0 rules say we only need to set the function
|
| + // node's return type if it uses expression syntax. Does that make sense
|
| + // for Dart 2.0?
|
| + bool needToSetReturnType = shadowIsExpressionFunction;
|
| + bool returnTypeNeeded = typeNeeded || needToSetReturnType;
|
| + bool isAsync = shadowIsAsync;
|
| + var functionContext = new FunctionContext(
|
| + inferrer, returnTypeNeeded, isAsync, shadowIsGenerator);
|
| + body.shadowInfer(inferrer, functionContext);
|
| + DartType inferredReturnType;
|
| + if (needToSetReturnType || typeNeeded) {
|
| + inferredReturnType = functionContext.inferredReturnType;
|
| + if (isAsync) {
|
| + inferredReturnType = new InterfaceType(
|
| + inferrer.coreTypes.futureClass, <DartType>[inferredReturnType]);
|
| + }
|
| + }
|
| + if (needToSetReturnType) {
|
| + this.shadowReturnType = inferredReturnType;
|
| + }
|
| + if (typeNeeded) {
|
| + return shadowFunctionType;
|
| + } else {
|
| + return null;
|
| + }
|
| + }
|
| }
|
|
|
| /// Shadow mixin representing an integer literal.
|
| -abstract class ShadowIntLiteral implements ShadowExpression {}
|
| +abstract class ShadowIntLiteral implements ShadowExpression {
|
| + @override
|
| + DartType shadowInfer(
|
| + LocalTypeInferrer inferrer, DartType context, bool typeNeeded) {
|
| + return typeNeeded ? inferrer.coreTypes.intClass.rawType : null;
|
| + }
|
| +}
|
|
|
| /// Shadow mixin representing a list literal.
|
| abstract class ShadowListLiteral implements ShadowExpression {
|
| @@ -71,23 +120,92 @@ abstract class ShadowListLiteral implements ShadowExpression {
|
| ///
|
| /// Intended for use by type inference.
|
| void set shadowTypeArgument(DartType type);
|
| +
|
| + @override
|
| + DartType shadowInfer(
|
| + LocalTypeInferrer inferrer, DartType context, bool typeNeeded) {
|
| + DartType declaredTypeArgument = shadowTypeArgument;
|
| + DartType typeArgumentContext = declaredTypeArgument;
|
| + if (typeArgumentContext == null) {
|
| + if (context is InterfaceType &&
|
| + context.classNode == inferrer.coreTypes.listClass &&
|
| + context.typeArguments.length == 1) {
|
| + typeArgumentContext = context.typeArguments[0];
|
| + } else if (context != null) {
|
| + // TODO(paulberry): report an error?
|
| + throw new UnimplementedError('$context');
|
| + }
|
| + }
|
| + DartType inferredTypeArgument = typeArgumentContext;
|
| + bool typeArgumentNeeded = inferredTypeArgument == null;
|
| + for (ShadowExpression e in shadowExpressions) {
|
| + DartType t =
|
| + e.shadowInfer(inferrer, typeArgumentContext, typeArgumentNeeded);
|
| + if (typeArgumentNeeded) {
|
| + inferredTypeArgument = inferrer.union(inferredTypeArgument, t);
|
| + }
|
| + }
|
| + if (inferredTypeArgument == null) {
|
| + // Empty list.
|
| + throw new UnimplementedError();
|
| + }
|
| + if (declaredTypeArgument == null) {
|
| + this.shadowTypeArgument = inferredTypeArgument;
|
| + }
|
| + if (typeNeeded) {
|
| + return new InterfaceType(
|
| + inferrer.coreTypes.listClass, <DartType>[inferredTypeArgument]);
|
| + } else {
|
| + return null;
|
| + }
|
| + }
|
| }
|
|
|
| /// Shadow mixin representing a null literal.
|
| -abstract class ShadowNullLiteral implements ShadowExpression {}
|
| +abstract class ShadowNullLiteral implements ShadowExpression {
|
| + @override
|
| + DartType shadowInfer(
|
| + LocalTypeInferrer inferrer, DartType context, bool typeNeeded) {
|
| + return typeNeeded ? inferrer.coreTypes.nullClass.rawType : null;
|
| + }
|
| +}
|
|
|
| /// Shadow mixin representing a return statement.
|
| abstract class ShadowReturnStatement implements ShadowStatement {
|
| /// Gets the expression being returned, or `null` if this is a bare "return"
|
| /// statement.
|
| ShadowExpression get shadowExpression;
|
| +
|
| + @override
|
| + void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context) {
|
| + DartType expressionContext = null; // TODO(paulberry): probably wrong.
|
| + bool expressionTypeNeeded =
|
| + context.returnTypeNeeded && !context.isGenerator;
|
| + DartType expressionType = shadowExpression.shadowInfer(
|
| + inferrer, expressionContext, expressionTypeNeeded);
|
| + if (expressionTypeNeeded) {
|
| + if (context.isAsync) {
|
| + expressionType = _unwrapFuture(inferrer.coreTypes, expressionType);
|
| + }
|
| + context.recordReturnType(expressionType);
|
| + }
|
| + }
|
| +
|
| + DartType _unwrapFuture(CoreTypes coreTypes, DartType type) {
|
| + // TODO(paulberry): replace with a full implementation of what's in the spec
|
| + // (e.g. handle types derived from Future). Also probably move to Kernel.
|
| + if (type is InterfaceType && type.classNode == coreTypes.futureClass) {
|
| + return type.typeArguments[0];
|
| + } else {
|
| + return type;
|
| + }
|
| + }
|
| }
|
|
|
| /// Common interface for shadow mixins representing statements.
|
| -///
|
| -/// TODO(paulberry): add an abstract `shadowInfer` method here to do type
|
| -/// inference.
|
| -abstract class ShadowStatement {}
|
| +abstract class ShadowStatement {
|
| + void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context);
|
| +}
|
|
|
| /// Shadow mixin representing a declaration of a single variable.
|
| abstract class ShadowVariableDeclaration implements ShadowStatement {
|
| @@ -103,10 +221,31 @@ abstract class ShadowVariableDeclaration implements ShadowStatement {
|
| ///
|
| /// Intended for use by type inference.
|
| void set shadowType(DartType type);
|
| +
|
| + @override
|
| + void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context) {
|
| + var initializer = shadowInitializer;
|
| + if (initializer != null) {
|
| + var type = shadowType;
|
| + var inferredType = initializer.shadowInfer(inferrer, type, type == null);
|
| + if (type == null) {
|
| + this.shadowType = inferredType;
|
| + }
|
| + }
|
| + }
|
| }
|
|
|
| /// Shadow mixin representing a "read" reference to a variable.
|
| abstract class ShadowVariableGet implements ShadowExpression {
|
| /// Gets the variable declaration which is being referenced.
|
| ShadowVariableDeclaration get shadowDeclaration;
|
| +
|
| + @override
|
| + DartType shadowInfer(
|
| + LocalTypeInferrer inferrer, DartType context, bool typeNeeded) {
|
| + // TODO(paulberry): make the "?? const DynamicType()" unnecessary.
|
| + return typeNeeded
|
| + ? (shadowDeclaration.shadowType ?? const DynamicType())
|
| + : null;
|
| + }
|
| }
|
|
|