Chromium Code Reviews| 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; |
| + } |
| +} |