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 377f2ca7d1d3a197991de1d2e026a3afaa1d3f2a..8a69ec5d9a3b2a8422c60e1ce19b8fec18784e1b 100644 |
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
@@ -14,7 +14,7 @@ import '../parser/identifier_context.dart' show IdentifierContext; |
import 'package:front_end/src/fasta/builder/ast_factory.dart' show AstFactory; |
import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart' |
- show KernelField, KernelVariableDeclaration; |
+ show KernelField; |
import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart' |
show FieldNode; |
@@ -22,6 +22,9 @@ import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart' |
import 'package:front_end/src/fasta/type_inference/type_inferrer.dart' |
show TypeInferrer; |
+import 'package:front_end/src/fasta/type_inference/type_promotion.dart' |
+ show TypePromoter; |
+ |
import 'package:kernel/ast.dart'; |
import 'package:kernel/clone.dart' show CloneVisitor; |
@@ -90,11 +93,15 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
@override |
final Uri uri; |
- final TypeInferrer<Statement, Expression, KernelVariableDeclaration, |
- KernelField> _typeInferrer; |
+ final TypeInferrer<Statement, Expression, VariableDeclaration, KernelField> |
+ _typeInferrer; |
+ @override |
final AstFactory astFactory; |
+ @override |
+ final TypePromoter<Expression, VariableDeclaration> typePromoter; |
+ |
/// If not `null`, dependencies on fields are accumulated into this list. |
/// |
/// If `null`, no dependency information is recorded. |
@@ -156,6 +163,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
isDartLibrary = library.uri.scheme == "dart", |
needsImplicitSuperInitializer = |
coreTypes.objectClass != classBuilder?.cls, |
+ typePromoter = _typeInferrer.typePromoter, |
super(scope); |
bool get hasParserError => recoverableErrors.isNotEmpty; |
@@ -455,6 +463,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
void finishFunction( |
FormalParameters formals, AsyncMarker asyncModifier, Statement body) { |
debugEvent("finishFunction"); |
+ typePromoter.finished(); |
_typeInferrer.inferStatement(body); |
KernelFunctionBuilder builder = member; |
builder.body = body; |
@@ -529,7 +538,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
@override |
void endExpressionStatement(Token token) { |
debugEvent("ExpressionStatement"); |
- push(new ExpressionStatement(popForEffect())); |
+ push(astFactory.expressionStatement(popForEffect())); |
} |
@override |
@@ -1042,11 +1051,26 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
} |
@override |
+ void beginThenStatement(Token token) { |
+ Expression condition = popForValue(); |
+ typePromoter.enterThen(condition); |
+ push(condition); |
+ super.beginThenStatement(token); |
+ } |
+ |
+ @override |
+ void endThenStatement(Token token) { |
+ typePromoter.enterElse(); |
+ super.endThenStatement(token); |
+ } |
+ |
+ @override |
void endIfStatement(Token ifToken, Token elseToken) { |
Statement elsePart = popStatementIfNotNull(elseToken); |
Statement thenPart = popStatement(); |
Expression condition = popForValue(); |
- push(new IfStatement(condition, thenPart, elsePart)); |
+ typePromoter.exitConditional(); |
+ push(astFactory.ifStatement(condition, thenPart, elsePart)); |
} |
@override |
@@ -1070,7 +1094,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
bool isConst = (currentLocalVariableModifiers & constMask) != 0; |
bool isFinal = (currentLocalVariableModifiers & finalMask) != 0; |
assert(isConst == constantExpressionRequired); |
- push(astFactory.variableDeclaration(identifier.name, identifier.fileOffset, |
+ push(astFactory.variableDeclaration( |
+ identifier.name, identifier.fileOffset, functionNestingLevel, |
initializer: initializer, |
type: currentLocalVariableType, |
isFinal: isFinal, |
@@ -1210,7 +1235,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
} else if (variableOrExpression == null) { |
// Do nothing. |
} else if (variableOrExpression is Expression) { |
- begin = new ExpressionStatement(variableOrExpression); |
+ begin = astFactory.expressionStatement(variableOrExpression); |
} else { |
return internalError("Unhandled: ${variableOrExpression.runtimeType}"); |
} |
@@ -1460,13 +1485,15 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
void handleIsOperator(Token operator, Token not, Token endToken) { |
debugEvent("IsOperator"); |
DartType type = pop(); |
- Expression expression = popForValue(); |
- expression = new IsExpression(expression, type) |
- ..fileOffset = operator.charOffset; |
- if (not != null) { |
- expression = new Not(expression); |
+ Expression operand = popForValue(); |
+ bool isInverted = not != null; |
+ Expression isExpression = |
+ astFactory.isExpression(operand, type, operator.charOffset, isInverted); |
+ if (operand is VariableGet) { |
+ typePromoter.handleIsCheck(isExpression, isInverted, operand.variable, |
+ type, functionNestingLevel); |
} |
- push(expression); |
+ push(isExpression); |
} |
@override |
@@ -1534,7 +1561,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
thisKeyword.charOffset); |
} |
type = field.target.type ?? const DynamicType(); |
- variable = astFactory.variableDeclaration(name.name, name.fileOffset, |
+ variable = astFactory.variableDeclaration( |
+ name.name, name.fileOffset, functionNestingLevel, |
type: type, |
initializer: name.initializer, |
isFinal: isFinal, |
@@ -1544,7 +1572,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
name.fileOffset, "'${name.name}' isn't a field in this class."); |
} |
} |
- variable ??= astFactory.variableDeclaration(name.name, name.fileOffset, |
+ variable ??= astFactory.variableDeclaration( |
+ name.name, name.fileOffset, functionNestingLevel, |
type: type ?? const DynamicType(), |
initializer: name.initializer, |
isFinal: isFinal, |
@@ -2007,8 +2036,9 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
void endFunctionName(Token beginToken, Token token) { |
debugEvent("FunctionName"); |
Identifier name = pop(); |
- VariableDeclaration variable = astFactory |
- .variableDeclaration(name.name, name.fileOffset, isFinal: true); |
+ VariableDeclaration variable = astFactory.variableDeclaration( |
+ name.name, name.fileOffset, functionNestingLevel, |
+ isFinal: true); |
push(new FunctionDeclaration( |
variable, new FunctionNode(new InvalidStatement())) |
..fileOffset = beginToken.charOffset); |
@@ -2088,7 +2118,7 @@ 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(astFactory.functionExpression(function, beginToken.charOffset)); |
} |
@override |
@@ -2154,7 +2184,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
/// } |
variable = new VariableDeclaration.forValue(null); |
body = combineStatements( |
- new ExpressionStatement(lvalue |
+ astFactory.expressionStatement(lvalue |
.buildAssignment(new VariableGet(variable), voidContext: true)), |
body); |
} else { |
@@ -2216,7 +2246,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
void endRethrowStatement(Token throwToken, Token endToken) { |
debugEvent("RethrowStatement"); |
if (inCatchBlock) { |
- push(new ExpressionStatement( |
+ push(astFactory.expressionStatement( |
new Rethrow()..fileOffset = throwToken.charOffset)); |
} else { |
push(buildCompileTimeErrorStatement( |
@@ -2525,7 +2555,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
} |
Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { |
- return new ExpressionStatement(buildCompileTimeError(error, charOffset)); |
+ return astFactory |
+ .expressionStatement(buildCompileTimeError(error, charOffset)); |
} |
@override |