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 |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2f064e4a34c313e8eb331dab345f412b74872262 |
--- /dev/null |
+++ b/pkg/front_end/lib/src/fasta/builder/shadow_ast.dart |
@@ -0,0 +1,195 @@ |
+import 'package:front_end/src/fasta/type_inference/local_type_inferrer.dart'; |
+import 'package:kernel/ast.dart' show DartType, InterfaceType; |
+import 'package:kernel/core_types.dart'; |
+ |
+abstract class Block implements Statement { |
+ Iterable<Statement> get shadowStatements; |
+ |
+ @override |
+ void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context) { |
+ for (var statement in shadowStatements) { |
+ statement.shadowInfer(inferrer, context); |
+ } |
+ } |
+} |
+ |
+abstract class Expression { |
+ DartType shadowInfer( |
+ LocalTypeInferrer inferrer, DartType context, bool typeNeeded); |
+} |
+ |
+abstract class FunctionExpression implements Expression { |
+ void set shadowInferredReturnType(DartType type); |
+ |
+ Statement get shadowBody; |
+ |
+ bool get shadowIsAsync; |
+ |
+ bool get shadowIsExpressionFunction; |
+ |
+ bool get shadowIsGenerator; |
+ |
+ DartType shadowMakeFunctionType(); |
+ |
+ @override |
+ DartType shadowInfer( |
+ LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
+ // TODO(paulberry): infer argument types and type parameters. |
+ // TODO(paulberry): full support for generators. |
+ Statement 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.shadowInferredReturnType = inferredReturnType; |
+ } |
+ if (typeNeeded) { |
+ return shadowMakeFunctionType(); |
+ } else { |
+ return null; |
+ } |
+ } |
+} |
+ |
+abstract class IntLiteral implements Expression { |
+ @override |
+ DartType shadowInfer( |
+ LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
+ return typeNeeded ? inferrer.coreTypes.intClass.rawType : null; |
+ } |
+} |
+ |
+abstract class ListLiteral implements Expression { |
+ DartType get declaredTypeArgumentForInference; |
+ |
+ Iterable<Expression> get expressionsForInference; |
+ |
+ void set inferredTypeArgument(DartType type); |
+ |
+ @override |
+ DartType shadowInfer( |
+ LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
+ DartType declaredTypeArgument = declaredTypeArgumentForInference; |
+ 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'); |
scheglov
2017/03/24 15:38:10
If I understand correctly, "context" will be Itera
Paul Berry
2017/03/24 17:59:50
You are correct. This entire method is a hack tha
|
+ } |
+ } |
+ DartType inferredTypeArgument = typeArgumentContext; |
+ bool typeArgumentNeeded = inferredTypeArgument == null; |
+ for (Expression e in expressionsForInference) { |
+ 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.inferredTypeArgument = inferredTypeArgument; |
+ } |
+ if (typeNeeded) { |
+ return new InterfaceType( |
+ inferrer.coreTypes.listClass, <DartType>[inferredTypeArgument]); |
+ } else { |
+ return null; |
+ } |
+ } |
+} |
+ |
+abstract class NullLiteral implements Expression { |
+ @override |
+ DartType shadowInfer( |
+ LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
+ return typeNeeded ? inferrer.coreTypes.nullClass.rawType : null; |
+ } |
+} |
+ |
+abstract class ReturnStatement implements Statement { |
+ Expression get expressionForInference; |
+ |
+ @override |
+ void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context) { |
+ DartType expressionContext = null; // TODO(paulberry): probably wrong. |
+ bool expressionTypeNeeded = |
+ context.returnTypeNeeded && !context.isGenerator; |
+ DartType expressionType = expressionForInference.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; |
+ } |
+ } |
+} |
+ |
+abstract class Statement { |
+ void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context); |
+} |
+ |
+abstract class VariableDeclaration implements Statement { |
+ DartType get shadowDeclaredType; |
+ |
+ DartType get shadowInferredType; |
+ |
+ void set shadowInferredType(DartType type); |
+ |
+ Expression get shadowInitializer; |
+ |
+ @override |
+ void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context) { |
+ Expression initializer = shadowInitializer; |
+ if (initializer != null) { |
+ DartType type = shadowDeclaredType; |
+ DartType inferredType = |
+ initializer.shadowInfer(inferrer, type, type == null); |
+ if (type == null) { |
+ this.shadowInferredType = inferredType; |
+ } |
+ } |
+ } |
+} |
+ |
+abstract class VariableGet implements Expression { |
+ VariableDeclaration get shadowDeclaration; |
+ |
+ @override |
+ DartType shadowInfer( |
+ LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
+ return typeNeeded ? shadowDeclaration.shadowInferredType : null; |
+ } |
+} |