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; |
+ } |
} |