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: |