| Index: pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| index 53720473f23579c02ad899ad9998fa3645077bdf..37e98e1a4ff1349b82c78d55af668c02e7217bfb 100644
|
| --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| @@ -10,6 +10,10 @@ import '../parser/error_kind.dart' show ErrorKind;
|
|
|
| import '../parser/identifier_context.dart' show IdentifierContext;
|
|
|
| +import 'package:front_end/src/fasta/builder/ast_factory.dart';
|
| +import 'package:front_end/src/fasta/kernel/ast_factory.dart' as kernel;
|
| +import 'package:front_end/src/fasta/type_inference/local_type_inferrer.dart';
|
| +import 'shadow_ast.dart' as shadow;
|
| import 'package:kernel/ast.dart';
|
|
|
| import 'package:kernel/clone.dart' show CloneVisitor;
|
| @@ -128,19 +132,28 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| // from VM engineers. TODO(ahe): Does this still apply?
|
| int currentLocalVariableModifiers = -1;
|
|
|
| + final AstFactory _ast = new kernel.AstFactory();
|
| +
|
| + final LocalTypeInferrer _typeInferrer;
|
| +
|
| + OldFunctionContext _functionContext;
|
| +
|
| BodyBuilder(
|
| KernelLibraryBuilder library,
|
| this.member,
|
| Scope scope,
|
| this.formalParameterScope,
|
| this.hierarchy,
|
| - this.coreTypes,
|
| + CoreTypes coreTypes,
|
| this.classBuilder,
|
| this.isInstanceMember,
|
| this.uri)
|
| - : enclosingScope = scope,
|
| + : coreTypes = coreTypes,
|
| + enclosingScope = scope,
|
| library = library,
|
| isDartLibrary = library.uri.scheme == "dart",
|
| + // TODO(paulberry): put this behind a flag.
|
| + _typeInferrer = new LocalTypeInferrer(coreTypes),
|
| super(scope);
|
|
|
| bool get hasParserError => recoverableErrors.isNotEmpty;
|
| @@ -214,9 +227,9 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| return toValue(node);
|
| }
|
|
|
| - List<Expression> popListForValue(int n) {
|
| - List<Expression> list =
|
| - new List<Expression>.filled(n, null, growable: true);
|
| + List<shadow.Expression> popListForValue(int n) {
|
| + List<shadow.Expression> list =
|
| + new List<shadow.Expression>.filled(n, null, growable: true);
|
| for (int i = n - 1; i >= 0; i--) {
|
| list[i] = popForValue();
|
| }
|
| @@ -232,7 +245,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| return list;
|
| }
|
|
|
| - Block popBlock(int count, int charOffset) {
|
| + shadow.Block popBlock(int count, int charOffset) {
|
| List<dynamic /*Statement | List<Statement>*/ > statements =
|
| popList(count) ?? <Statement>[];
|
| List<Statement> copy;
|
| @@ -247,7 +260,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| copy.add(statement);
|
| }
|
| }
|
| - return new Block(copy ?? statements)..fileOffset = charOffset;
|
| + return _ast.block(copy ?? statements, charOffset);
|
| }
|
|
|
| Statement popStatementIfNotNull(Object value) {
|
| @@ -444,8 +457,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| }
|
|
|
| @override
|
| - void finishFunction(
|
| - FormalParameters formals, AsyncMarker asyncModifier, Statement body) {
|
| + void finishFunction(FormalParameters formals, AsyncMarker asyncModifier,
|
| + shadow.Statement body) {
|
| debugEvent("finishFunction");
|
| KernelFunctionBuilder builder = member;
|
| if (builder is KernelConstructorBuilder) {
|
| @@ -459,6 +472,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| } else {
|
| internalError("Unhandled: ${builder.runtimeType}");
|
| }
|
| + _typeInferrer.inferBody(body);
|
| builder.body = body;
|
| if (formals?.optional != null) {
|
| Iterator<FormalParameterBuilder> formalBuilders =
|
| @@ -921,8 +935,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| @override
|
| void handleLiteralInt(Token token) {
|
| debugEvent("LiteralInt");
|
| - push(
|
| - new IntLiteral(int.parse(token.lexeme))..fileOffset = token.charOffset);
|
| + push(_ast.intLiteral(int.parse(token.lexeme), token.charOffset));
|
| }
|
|
|
| @override
|
| @@ -941,12 +954,13 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| void endReturnStatement(
|
| bool hasExpression, Token beginToken, Token endToken) {
|
| debugEvent("ReturnStatement");
|
| - Expression expression = hasExpression ? popForValue() : null;
|
| + shadow.Expression expression = hasExpression ? popForValue() : null;
|
| if (expression != null && inConstructor) {
|
| push(buildCompileTimeErrorStatement(
|
| "Can't return from a constructor.", beginToken.charOffset));
|
| } else {
|
| - push(new ReturnStatement(expression)..fileOffset = beginToken.charOffset);
|
| + push(_ast.returnStatement(expression, beginToken.charOffset));
|
| + _typeInferrer.recordReturnStatement(_functionContext, expression);
|
| }
|
| }
|
|
|
| @@ -972,18 +986,22 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| pushNewLocalVariable(null);
|
| }
|
|
|
| - void pushNewLocalVariable(Expression initializer,
|
| + void pushNewLocalVariable(shadow.Expression initializer,
|
| {int equalsCharOffset: TreeNode.noOffset}) {
|
| Identifier identifier = pop();
|
| assert(currentLocalVariableModifiers != -1);
|
| bool isConst = (currentLocalVariableModifiers & constMask) != 0;
|
| bool isFinal = (currentLocalVariableModifiers & finalMask) != 0;
|
| assert(isConst == constantExpressionRequired);
|
| - push(new VariableDeclaration(identifier.name,
|
| + var variable = _ast.variableDeclaration(identifier.name,
|
| initializer: initializer,
|
| - type: currentLocalVariableType ?? const DynamicType(),
|
| + type: currentLocalVariableType,
|
| isFinal: isFinal,
|
| - isConst: isConst)..fileEqualsOffset = equalsCharOffset);
|
| + isConst: isConst,
|
| + charOffset: equalsCharOffset);
|
| + _typeInferrer.finishVariableDeclaration(
|
| + currentLocalVariableType, initializer, variable);
|
| + push(variable);
|
| }
|
|
|
| @override
|
| @@ -1143,26 +1161,26 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| void handleAsyncModifier(Token asyncToken, Token starToken) {
|
| debugEvent("AsyncModifier");
|
| push(asyncMarkerFromTokens(asyncToken, starToken));
|
| + _functionContext?.recordAsyncModifier(asyncToken != null);
|
| }
|
|
|
| @override
|
| void handleLiteralList(
|
| int count, Token beginToken, Token constKeyword, Token endToken) {
|
| debugEvent("LiteralList");
|
| - List<Expression> expressions = popListForValue(count);
|
| + List<shadow.Expression> expressions = popListForValue(count);
|
| List<DartType> typeArguments = pop();
|
| - DartType typeArgument = const DynamicType();
|
| + DartType typeArgument;
|
| if (typeArguments != null) {
|
| typeArgument = typeArguments.first;
|
| if (typeArguments.length > 1) {
|
| - typeArgument = const DynamicType();
|
| + typeArgument = null;
|
| warning(
|
| "Too many type arguments on List literal.", beginToken.charOffset);
|
| }
|
| }
|
| - push(new ListLiteral(expressions,
|
| - typeArgument: typeArgument, isConst: constKeyword != null)
|
| - ..fileOffset = constKeyword?.charOffset ?? beginToken.charOffset);
|
| + push(_ast.listLiteral(expressions, typeArgument, constKeyword != null,
|
| + constKeyword?.charOffset ?? beginToken.charOffset));
|
| }
|
|
|
| @override
|
| @@ -1183,7 +1201,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| @override
|
| void handleLiteralNull(Token token) {
|
| debugEvent("LiteralNull");
|
| - push(new NullLiteral()..fileOffset = token.charOffset);
|
| + push(_ast.nullLiteral(token.charOffset));
|
| }
|
|
|
| @override
|
| @@ -1405,7 +1423,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| DartType type = pop();
|
| pop(); // Modifiers.
|
| ignore(Unhandled.Metadata);
|
| - VariableDeclaration variable;
|
| + shadow.VariableDeclaration variable;
|
| if (!inCatchClause && functionNestingLevel == 0) {
|
| dynamic builder = formalParameterScope.lookup(name.name, charOffset, uri);
|
| if (builder == null) {
|
| @@ -1426,16 +1444,19 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| thisKeyword.charOffset);
|
| }
|
| type = field.target.type ?? const DynamicType();
|
| - variable = new VariableDeclaration(name.name,
|
| - type: type, initializer: name.initializer);
|
| + variable = _ast.variableDeclaration(name.name,
|
| + type: type,
|
| + initializer: name.initializer as shadow.Expression,
|
| + charOffset: name.fileOffset);
|
| } else {
|
| addCompileTimeError(
|
| name.fileOffset, "'${name.name}' isn't a field in this class.");
|
| }
|
| }
|
| - variable ??= new VariableDeclaration(name.name,
|
| - type: type ?? const DynamicType(),
|
| - initializer: name.initializer)..fileOffset = name.fileOffset;
|
| + variable ??= _ast.variableDeclaration(name.name,
|
| + type: type,
|
| + initializer: name.initializer as shadow.Expression,
|
| + charOffset: name.fileOffset);
|
| push(variable);
|
| }
|
|
|
| @@ -1501,6 +1522,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| enterLocalScope(formals.computeFormalParameterScope(
|
| scope, member ?? classBuilder ?? library));
|
| }
|
| + formals.recordTypeInferenceTo(_functionContext);
|
| }
|
|
|
| @override
|
| @@ -1878,11 +1900,12 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| enterLocalScope();
|
| }
|
|
|
| - void enterFunction() {
|
| + void enterFunction(bool isNamed) {
|
| debugEvent("enterFunction");
|
| functionNestingLevel++;
|
| push(switchScope ?? NullValue.SwitchScope);
|
| switchScope = null;
|
| + _functionContext = _typeInferrer.nestFunctionContext(_functionContext);
|
| }
|
|
|
| void exitFunction() {
|
| @@ -1894,13 +1917,13 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| @override
|
| void beginFunction(Token token) {
|
| debugEvent("beginFunction");
|
| - enterFunction();
|
| + enterFunction(true);
|
| }
|
|
|
| @override
|
| void beginUnnamedFunction(Token token) {
|
| debugEvent("beginUnnamedFunction");
|
| - enterFunction();
|
| + enterFunction(false);
|
| }
|
|
|
| @override
|
| @@ -1946,7 +1969,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| typeParameters: typeParameters, asyncMarker: asyncModifier)
|
| ..fileOffset = beginToken.charOffset
|
| ..fileEndOffset = token.charOffset);
|
| - push(new FunctionExpression(function)..fileOffset = beginToken.charOffset);
|
| + push(new shadow.FunctionExpression(function)
|
| + ..fileOffset = beginToken.charOffset);
|
| }
|
|
|
| @override
|
| @@ -2837,6 +2861,21 @@ class FormalParameters {
|
| }
|
| return new Scope(local, parent, isModifiable: false);
|
| }
|
| +
|
| + void recordTypeInferenceTo(OldFunctionContext functionContext) {
|
| + if (functionContext == null) return;
|
| + int requiredParameterCount = required.length;
|
| + var positionalFormals = <shadow.VariableDeclaration>[];
|
| + var namedFormals = const <shadow.VariableDeclaration>[];
|
| + for (VariableDeclaration parameter in required) {
|
| + positionalFormals.add(parameter);
|
| + }
|
| + if (optional != null) {
|
| + throw new UnimplementedError();
|
| + }
|
| + functionContext.recordFormals(
|
| + requiredParameterCount, positionalFormals, namedFormals);
|
| + }
|
| }
|
|
|
| /// Returns a block like this:
|
|
|