mirror of
https://github.com/dart-lang/sdk
synced 2024-10-01 19:29:09 +00:00
[cfe] Stop passing local scope on the stack
This a LocalStack extension type for using a list as a typed stack and uses this for local scopes in the body builder, instead of passing the local scopes through the listener stack. This also removes the need for LocalScope.parent TEST=existing Change-Id: I536c63258e4196a1582e9a1d73489adcfdaa6698 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/376400 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com> Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
parent
11827c81b3
commit
c4368b3cd7
|
@ -11,8 +11,6 @@ abstract class LocalScope implements LookupScope {
|
|||
@override
|
||||
ScopeKind get kind;
|
||||
|
||||
LocalScope? get parent;
|
||||
|
||||
LocalScope createNestedScope(
|
||||
{required String debugName, required ScopeKind kind});
|
||||
|
||||
|
@ -161,13 +159,8 @@ mixin LocalScopeMixin implements LocalScope {
|
|||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
LocalScope? get parent => _parent;
|
||||
}
|
||||
|
||||
mixin LabelScopeMixin implements LocalScope {}
|
||||
|
||||
final class LocalScopeImpl extends BaseLocalScope
|
||||
with LocalScopeMixin, SwitchScopeMixin
|
||||
implements LocalScope, SwitchScope {
|
||||
|
@ -382,9 +375,6 @@ final class EnclosingLocalScope extends BaseLocalScope
|
|||
return _scope.lookupSetter(name, charOffset, uri);
|
||||
}
|
||||
|
||||
@override
|
||||
LocalScope? get parent => null;
|
||||
|
||||
@override
|
||||
String toString() => "$runtimeType(${kind},$_scope)";
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ import '../type_inference/inference_results.dart'
|
|||
import '../type_inference/type_inferrer.dart'
|
||||
show TypeInferrer, InferredFunctionBody;
|
||||
import '../type_inference/type_schema.dart' show UnknownType;
|
||||
import '../util/local_stack.dart';
|
||||
import '../util/helpers.dart';
|
||||
import 'benchmarker.dart' show Benchmarker;
|
||||
import 'body_builder_context.dart';
|
||||
|
@ -418,7 +419,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
|
||||
final List<TypeParameter>? thisTypeParameters;
|
||||
|
||||
LocalScope scope;
|
||||
LocalStack<LocalScope> _localScopes;
|
||||
|
||||
Set<VariableDeclaration>? declaredInCurrentGuard;
|
||||
|
||||
|
@ -444,7 +445,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
needsImplicitSuperInitializer =
|
||||
context.needsImplicitSuperInitializer(coreTypes),
|
||||
benchmarker = libraryBuilder.loader.target.benchmarker,
|
||||
this.scope = enclosingScope {
|
||||
_localScopes = new LocalStack([enclosingScope]) {
|
||||
Iterator<VariableBuilder>? iterator =
|
||||
formalParameterScope?.filteredIterator<VariableBuilder>(
|
||||
includeDuplicates: false, includeAugmentations: false);
|
||||
|
@ -493,6 +494,8 @@ class BodyBuilder extends StackListenerImpl
|
|||
.createLocalTypeInferrer(
|
||||
fileUri, bodyBuilderContext.thisType, library, null));
|
||||
|
||||
LocalScope get _localScope => _localScopes.current;
|
||||
|
||||
@override
|
||||
LibraryFeatures get libraryFeatures => libraryBuilder.libraryFeatures;
|
||||
|
||||
|
@ -522,40 +525,31 @@ class BodyBuilder extends StackListenerImpl
|
|||
}
|
||||
|
||||
void enterLocalScope(LocalScope localScope) {
|
||||
push(scope);
|
||||
scope = localScope;
|
||||
if (scope.kind == ScopeKind.functionBody) {
|
||||
_localScopes.push(localScope);
|
||||
if (_localScope.kind == ScopeKind.functionBody) {
|
||||
_inBodyCount++;
|
||||
}
|
||||
assert(checkState(null, [
|
||||
ValueKinds.Scope,
|
||||
]));
|
||||
}
|
||||
|
||||
void createAndEnterLocalScope(
|
||||
{required String debugName, required ScopeKind kind}) {
|
||||
push(scope);
|
||||
scope = scope.createNestedScope(debugName: debugName, kind: kind);
|
||||
_localScopes
|
||||
.push(_localScope.createNestedScope(debugName: debugName, kind: kind));
|
||||
if (kind == ScopeKind.functionBody) {
|
||||
_inBodyCount++;
|
||||
}
|
||||
assert(checkState(null, [
|
||||
ValueKinds.Scope,
|
||||
]));
|
||||
}
|
||||
|
||||
void exitLocalScope({List<ScopeKind>? expectedScopeKinds}) {
|
||||
assert(checkState(null, [
|
||||
ValueKinds.Scope,
|
||||
]));
|
||||
assert(
|
||||
expectedScopeKinds == null || expectedScopeKinds.contains(scope.kind),
|
||||
expectedScopeKinds == null ||
|
||||
expectedScopeKinds.contains(_localScope.kind),
|
||||
// Coverage-ignore(suite): Not run.
|
||||
"Expected the current scope to be one of the kinds "
|
||||
"${expectedScopeKinds.map((k) => "'${k}'").join(", ")}, "
|
||||
"but got '${scope.kind}'.");
|
||||
if (isGuardScope(scope) && declaredInCurrentGuard != null) {
|
||||
for (Builder builder in scope.localMembers) {
|
||||
"but got '${_localScope.kind}'.");
|
||||
if (isGuardScope(_localScope) && declaredInCurrentGuard != null) {
|
||||
for (Builder builder in _localScope.localMembers) {
|
||||
if (builder is VariableBuilder) {
|
||||
declaredInCurrentGuard!.remove(builder.variable);
|
||||
}
|
||||
|
@ -564,10 +558,10 @@ class BodyBuilder extends StackListenerImpl
|
|||
declaredInCurrentGuard = null;
|
||||
}
|
||||
}
|
||||
if (scope.kind == ScopeKind.functionBody) {
|
||||
if (_localScope.kind == ScopeKind.functionBody) {
|
||||
_inBodyCount--;
|
||||
}
|
||||
scope = pop() as LocalScope;
|
||||
_localScopes.pop();
|
||||
}
|
||||
|
||||
void enterBreakTarget(int charOffset, [JumpTarget? target]) {
|
||||
|
@ -831,7 +825,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
|
||||
void enterSwitchScope() {
|
||||
push(switchScope ?? NullValues.SwitchScope);
|
||||
switchScope = scope.switchScope;
|
||||
switchScope = _localScope.switchScope;
|
||||
}
|
||||
|
||||
void exitSwitchScope() {
|
||||
|
@ -1199,7 +1193,8 @@ class BodyBuilder extends StackListenerImpl
|
|||
}
|
||||
|
||||
void prepareInitializers() {
|
||||
scope = _context.computeFormalParameterInitializerScope(scope);
|
||||
_localScopes
|
||||
.push(_context.computeFormalParameterInitializerScope(_localScope));
|
||||
if (_context.isConstructor) {
|
||||
_context.prepareInitializers();
|
||||
if (_context.formals != null) {
|
||||
|
@ -1238,9 +1233,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
debugEvent("NoInitializers");
|
||||
if (functionNestingLevel == 0) {
|
||||
prepareInitializers();
|
||||
scope = formalParameterScope ??
|
||||
_localScopes.push(formalParameterScope ??
|
||||
new FixedLocalScope(
|
||||
kind: ScopeKind.initializers, debugName: "initializers");
|
||||
kind: ScopeKind.initializers, debugName: "initializers"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1257,9 +1252,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
void endInitializers(int count, Token beginToken, Token endToken) {
|
||||
debugEvent("Initializers");
|
||||
if (functionNestingLevel == 0) {
|
||||
scope = formalParameterScope ??
|
||||
_localScopes.push(formalParameterScope ??
|
||||
new FixedLocalScope(
|
||||
kind: ScopeKind.initializers, debugName: "initializers");
|
||||
kind: ScopeKind.initializers, debugName: "initializers"));
|
||||
}
|
||||
inConstructorInitializer = false;
|
||||
}
|
||||
|
@ -1932,7 +1927,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
}, growable: false);
|
||||
enterLocalScope(new FormalParameters(formals, fileOffset, noLength, uri)
|
||||
.computeFormalParameterScope(
|
||||
scope,
|
||||
_localScope,
|
||||
this,
|
||||
wildcardVariablesEnabled: libraryFeatures.wildcardVariables.isEnabled,
|
||||
));
|
||||
|
@ -2419,9 +2414,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
void handleParenthesizedCondition(Token token, Token? case_, Token? when) {
|
||||
debugEvent("ParenthesizedCondition");
|
||||
if (case_ != null) {
|
||||
// ignore: unused_local_variable
|
||||
Expression? guard;
|
||||
LocalScope? scope;
|
||||
if (when != null) {
|
||||
assert(checkState(token, [
|
||||
unionOfKinds([
|
||||
|
@ -2429,7 +2422,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
ValueKinds.Generator,
|
||||
ValueKinds.ProblemBuilder,
|
||||
]),
|
||||
ValueKinds.Scope,
|
||||
unionOfKinds([
|
||||
ValueKinds.Expression,
|
||||
ValueKinds.Pattern,
|
||||
|
@ -2441,7 +2433,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
]),
|
||||
]));
|
||||
guard = popForValue();
|
||||
scope = pop() as LocalScope;
|
||||
}
|
||||
assert(checkState(token, [
|
||||
unionOfKinds([
|
||||
|
@ -2458,9 +2449,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
libraryFeatures.patterns, case_.charOffset, case_.charCount);
|
||||
Pattern pattern = toPattern(pop());
|
||||
Expression expression = popForValue();
|
||||
if (scope != null) {
|
||||
push(scope);
|
||||
}
|
||||
push(new Condition(expression,
|
||||
forest.createPatternGuard(expression.fileOffset, pattern, guard)));
|
||||
} else {
|
||||
|
@ -2666,38 +2654,15 @@ class BodyBuilder extends StackListenerImpl
|
|||
void beginCaseExpression(Token caseKeyword) {
|
||||
debugEvent("beginCaseExpression");
|
||||
|
||||
// Case heads can be preceded by labels. The scope that we need to exit lies
|
||||
// under the labels on the stack.
|
||||
List<Label>? labels;
|
||||
Object? value;
|
||||
do {
|
||||
assert(checkState(caseKeyword, [
|
||||
unionOfKinds([ValueKinds.Label, ValueKinds.Scope])
|
||||
]));
|
||||
value = pop();
|
||||
if (value is Label) {
|
||||
(labels ??= <Label>[]).add(value);
|
||||
}
|
||||
} while (value is! LocalScope);
|
||||
push(value);
|
||||
|
||||
// Scope of the preceding case head or a sentinel if it's the first head.
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
|
||||
|
||||
// Return labels back on the stack.
|
||||
if (labels != null) {
|
||||
for (int i = labels.length - 1; i >= 0; i--) {
|
||||
push(labels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
createAndEnterLocalScope(debugName: "case-head", kind: ScopeKind.caseHead);
|
||||
super.push(constantContext);
|
||||
if (!libraryFeatures.patterns.isEnabled) {
|
||||
constantContext = ConstantContext.inferred;
|
||||
}
|
||||
assert(checkState(
|
||||
caseKeyword, [ValueKinds.ConstantContext, ValueKinds.Scope]));
|
||||
assert(checkState(caseKeyword, [ValueKinds.ConstantContext]));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -2717,7 +2682,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
ValueKinds.Pattern,
|
||||
]),
|
||||
ValueKinds.ConstantContext,
|
||||
ValueKinds.Scope,
|
||||
]));
|
||||
|
||||
Expression? guard;
|
||||
|
@ -2726,12 +2690,11 @@ class BodyBuilder extends StackListenerImpl
|
|||
}
|
||||
Object? value = pop();
|
||||
constantContext = pop() as ConstantContext;
|
||||
LocalScope headScope = pop() as LocalScope;
|
||||
assert(
|
||||
headScope.kind == ScopeKind.switchBlock,
|
||||
_localScopes.previous.kind == ScopeKind.switchBlock,
|
||||
// Coverage-ignore(suite): Not run.
|
||||
"Expected to have scope kind ${ScopeKind.switchBlock}, "
|
||||
"but got ${headScope.kind}.");
|
||||
"but got ${_localScopes.previous.kind}.");
|
||||
if (value is Pattern) {
|
||||
super.push(new ExpressionOrPatternGuardCase.patternGuard(
|
||||
caseKeyword.charOffset,
|
||||
|
@ -2746,9 +2709,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
super.push(new ExpressionOrPatternGuardCase.expression(
|
||||
caseKeyword.charOffset, expression));
|
||||
}
|
||||
push(headScope);
|
||||
assert(checkState(
|
||||
colon, [ValueKinds.Scope, ValueKinds.ExpressionOrPatternGuardCase]));
|
||||
assert(checkState(colon, [ValueKinds.ExpressionOrPatternGuardCase]));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -2834,10 +2795,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
ValueKinds.ProblemBuilder,
|
||||
ValueKinds.Pattern,
|
||||
]),
|
||||
ValueKinds.Scope,
|
||||
]));
|
||||
Object pattern = pop()!;
|
||||
ScopeKind scopeKind = scope.kind;
|
||||
ScopeKind scopeKind = _localScope.kind;
|
||||
|
||||
exitLocalScope(expectedScopeKinds: const [
|
||||
ScopeKind.pattern,
|
||||
|
@ -2854,12 +2814,12 @@ class BodyBuilder extends StackListenerImpl
|
|||
// enclosing scope only if that enclosing scope is a pattern scope as well,
|
||||
// that is, if its kind is [ScopeKind.pattern] or
|
||||
// [ScopeKind.orPatternRight].
|
||||
bool enclosingScopeIsPatternScope = scope.kind == ScopeKind.pattern ||
|
||||
scope.kind == ScopeKind.orPatternRight;
|
||||
bool enclosingScopeIsPatternScope = _localScope.kind == ScopeKind.pattern ||
|
||||
_localScope.kind == ScopeKind.orPatternRight;
|
||||
if (scopeKind != ScopeKind.orPatternRight && enclosingScopeIsPatternScope) {
|
||||
if (pattern is Pattern) {
|
||||
for (VariableDeclaration variable in pattern.declaredVariables) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2877,7 +2837,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
ValueKinds.ProblemBuilder,
|
||||
ValueKinds.Pattern,
|
||||
]),
|
||||
ValueKinds.Scope,
|
||||
]));
|
||||
|
||||
// In case of the binary-or pattern, its LHS and RHS should contain
|
||||
|
@ -2960,7 +2919,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
leftVariable.fileOffset, leftVariable.name!)
|
||||
];
|
||||
for (VariableDeclaration variable in jointVariables) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
typeInferrer.assignedVariables.declare(variable);
|
||||
}
|
||||
push(forest.createOrPattern(token.charOffset, left, right,
|
||||
|
@ -3339,11 +3298,11 @@ class BodyBuilder extends StackListenerImpl
|
|||
debugEvent("handleIdentifier");
|
||||
if (context.isScopeReference) {
|
||||
assert(!inInitializerLeftHandSide ||
|
||||
this.scope == enclosingScope ||
|
||||
this.scope.parent == enclosingScope);
|
||||
_localScopes.current == enclosingScope ||
|
||||
_localScopes.previous == enclosingScope);
|
||||
// This deals with this kind of initializer: `C(a) : a = a;`
|
||||
LocalScope scope =
|
||||
inInitializerLeftHandSide ? enclosingScope : this.scope;
|
||||
inInitializerLeftHandSide ? enclosingScope : this._localScope;
|
||||
push(scopeLookup(scope, token));
|
||||
} else {
|
||||
if (!context.inDeclaration &&
|
||||
|
@ -3827,7 +3786,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
createAndEnterLocalScope(
|
||||
debugName: "if-case-head", kind: ScopeKind.ifCaseHead);
|
||||
for (VariableDeclaration variable in pattern.declaredVariables) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3846,8 +3805,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
Condition condition = pop() as Condition;
|
||||
PatternGuard? patternGuard = condition.patternGuard;
|
||||
if (patternGuard != null && patternGuard.guard != null) {
|
||||
assert(checkState(token, [ValueKinds.Scope]));
|
||||
LocalScope thenScope = scope.createNestedScope(
|
||||
LocalScope thenScope = _localScope.createNestedScope(
|
||||
debugName: "then body", kind: ScopeKind.statementLocalScope);
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.ifCaseHead]);
|
||||
push(condition);
|
||||
|
@ -3861,9 +3819,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
debugName: "if-case-head", kind: ScopeKind.ifCaseHead);
|
||||
for (VariableDeclaration variable
|
||||
in patternGuard.pattern.declaredVariables) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
LocalScope thenScope = scope.createNestedScope(
|
||||
LocalScope thenScope = _localScope.createNestedScope(
|
||||
debugName: "then body", kind: ScopeKind.statementLocalScope);
|
||||
exitLocalScope();
|
||||
enterLocalScope(thenScope);
|
||||
|
@ -4054,7 +4012,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
// TODO(kallentu): Emit better error on lookup, rather than not adding it to
|
||||
// the scope.
|
||||
if (!(libraryFeatures.wildcardVariables.isEnabled && variable.isWildcard)) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4095,7 +4053,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
return;
|
||||
}
|
||||
VariableDeclaration variable = node as VariableDeclaration;
|
||||
if (variable.isWildcard && scope.kind != ScopeKind.forStatement) {
|
||||
if (variable.isWildcard && _localScope.kind != ScopeKind.forStatement) {
|
||||
// Wildcard variable declarations can be removed, except for the ones in
|
||||
// for loops. This logic turns them into `ExpressionStatement`s or
|
||||
// `EmptyStatement`s so the backends don't need to allocate space for
|
||||
|
@ -4128,7 +4086,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
push(new ParserRecovery(offsetForToken(endToken)));
|
||||
return;
|
||||
}
|
||||
if (scope.kind != ScopeKind.forStatement) {
|
||||
if (_localScope.kind != ScopeKind.forStatement) {
|
||||
// Wildcard variable declarations can be removed, except for the ones in
|
||||
// for loops. This logic turns them into `ExpressionStatement`s or
|
||||
// `EmptyStatement`s so the backends don't need to allocate space for
|
||||
|
@ -4248,14 +4206,8 @@ class BodyBuilder extends StackListenerImpl
|
|||
}
|
||||
|
||||
void enterLoop(int charOffset) {
|
||||
if (peek() is LabelTarget) {
|
||||
LabelTarget target = peek() as LabelTarget;
|
||||
enterBreakTarget(charOffset, target.breakTarget);
|
||||
enterContinueTarget(charOffset, target.continueTarget);
|
||||
} else {
|
||||
enterBreakTarget(charOffset);
|
||||
enterContinueTarget(charOffset);
|
||||
}
|
||||
enterBreakTarget(charOffset);
|
||||
enterContinueTarget(charOffset);
|
||||
}
|
||||
|
||||
void exitLoopOrSwitch(Statement statement) {
|
||||
|
@ -4371,9 +4323,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
if (pattern is Pattern) {
|
||||
pop(); // Metadata.
|
||||
for (VariableDeclaration variable in pattern.declaredVariables) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
LocalScope forScope = scope.createNestedScope(
|
||||
LocalScope forScope = _localScope.createNestedScope(
|
||||
debugName: "pattern-for internal variables",
|
||||
kind: ScopeKind.forStatement);
|
||||
exitLocalScope();
|
||||
|
@ -4401,7 +4353,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
isFinal: isFinal);
|
||||
internalVariables.add(internalVariable);
|
||||
|
||||
declareVariable(internalVariable, scope);
|
||||
declareVariable(internalVariable, _localScope);
|
||||
typeInferrer.assignedVariables.declare(internalVariable);
|
||||
}
|
||||
push(intermediateVariables);
|
||||
|
@ -5315,16 +5267,16 @@ class BodyBuilder extends StackListenerImpl
|
|||
void enterNominalVariablesScope(
|
||||
List<NominalVariableBuilder>? nominalVariableBuilders) {
|
||||
debugEvent("enterNominalVariableScope");
|
||||
enterLocalScope(scope.createNestedScope(
|
||||
enterLocalScope(_localScope.createNestedScope(
|
||||
debugName: "function-type scope", kind: ScopeKind.typeParameters));
|
||||
if (nominalVariableBuilders != null) {
|
||||
for (NominalVariableBuilder builder in nominalVariableBuilders) {
|
||||
if (builder.isWildcard) continue;
|
||||
String name = builder.name;
|
||||
NominalVariableBuilder? existing = scope.lookupLocalMember(name,
|
||||
NominalVariableBuilder? existing = _localScope.lookupLocalMember(name,
|
||||
setter: false) as NominalVariableBuilder?;
|
||||
if (existing == null) {
|
||||
scope.addLocalMember(name, builder, setter: false);
|
||||
_localScope.addLocalMember(name, builder, setter: false);
|
||||
} else {
|
||||
// Coverage-ignore-block(suite): Not run.
|
||||
reportDuplicatedDeclaration(existing, name, builder.charOffset);
|
||||
|
@ -5336,16 +5288,17 @@ class BodyBuilder extends StackListenerImpl
|
|||
void enterStructuralVariablesScope(
|
||||
List<StructuralVariableBuilder>? structuralVariableBuilders) {
|
||||
debugEvent("enterStructuralVariableScope");
|
||||
enterLocalScope(scope.createNestedScope(
|
||||
enterLocalScope(_localScope.createNestedScope(
|
||||
debugName: "function-type scope", kind: ScopeKind.typeParameters));
|
||||
if (structuralVariableBuilders != null) {
|
||||
for (StructuralVariableBuilder builder in structuralVariableBuilders) {
|
||||
if (builder.isWildcard) continue;
|
||||
String name = builder.name;
|
||||
StructuralVariableBuilder? existing = scope.lookupLocalMember(name,
|
||||
setter: false) as StructuralVariableBuilder?;
|
||||
StructuralVariableBuilder? existing =
|
||||
_localScope.lookupLocalMember(name, setter: false)
|
||||
as StructuralVariableBuilder?;
|
||||
if (existing == null) {
|
||||
scope.addLocalMember(name, builder, setter: false);
|
||||
_localScope.addLocalMember(name, builder, setter: false);
|
||||
} else {
|
||||
// Coverage-ignore-block(suite): Not run.
|
||||
reportDuplicatedDeclaration(existing, name, builder.charOffset);
|
||||
|
@ -5869,7 +5822,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
if ((inCatchClause || functionNestingLevel != 0) &&
|
||||
kind != MemberKind.GeneralizedFunctionType) {
|
||||
enterLocalScope(formals.computeFormalParameterScope(
|
||||
scope,
|
||||
_localScope,
|
||||
this,
|
||||
wildcardVariablesEnabled: libraryFeatures.wildcardVariables.isEnabled,
|
||||
));
|
||||
|
@ -7101,7 +7054,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
PatternGuard? patternGuard = condition.patternGuard;
|
||||
if (patternGuard != null) {
|
||||
if (patternGuard.guard != null) {
|
||||
LocalScope thenScope = scope.createNestedScope(
|
||||
LocalScope thenScope = _localScope.createNestedScope(
|
||||
debugName: "then-control-flow", kind: ScopeKind.ifElement);
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.ifCaseHead]);
|
||||
enterLocalScope(thenScope);
|
||||
|
@ -7110,9 +7063,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
debugName: "if-case-head", kind: ScopeKind.ifCaseHead);
|
||||
for (VariableDeclaration variable
|
||||
in patternGuard.pattern.declaredVariables) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
LocalScope thenScope = scope.createNestedScope(
|
||||
LocalScope thenScope = _localScope.createNestedScope(
|
||||
debugName: "then-control-flow", kind: ScopeKind.ifElement);
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.ifCaseHead]);
|
||||
enterLocalScope(thenScope);
|
||||
|
@ -7164,7 +7117,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
ValueKinds.MapLiteralEntry,
|
||||
]),
|
||||
ValueKinds.Condition,
|
||||
ValueKinds.Scope,
|
||||
ValueKinds.Token,
|
||||
]));
|
||||
|
||||
|
@ -7473,7 +7425,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
..fileOffset = name.nameOffset;
|
||||
// TODO(ahe): Why are we looking up in local scope, but declaring in parent
|
||||
// scope?
|
||||
Builder? existing = scope.lookupLocalMember(name.name, setter: false);
|
||||
Builder? existing = _localScope.lookupLocalMember(name.name, setter: false);
|
||||
if (existing != null) {
|
||||
// Coverage-ignore-block(suite): Not run.
|
||||
reportDuplicatedDeclaration(existing, name.name, name.nameOffset);
|
||||
|
@ -7484,7 +7436,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
dummyFunctionNode)
|
||||
..fileOffset = beginToken.charOffset);
|
||||
if (!(libraryFeatures.wildcardVariables.isEnabled && variable.isWildcard)) {
|
||||
declareVariable(variable, scope.parent!);
|
||||
declareVariable(variable, _localScopes.previous);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7510,7 +7462,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
/* inCatchBlock */ ValueKinds.Bool,
|
||||
/* switch scope */ ValueKinds.SwitchScopeOrNull,
|
||||
/* function type variables */ ValueKinds.NominalVariableListOrNull,
|
||||
/* function block scope */ ValueKinds.Scope,
|
||||
]));
|
||||
debugEvent("exitFunction");
|
||||
functionNestingLevel--;
|
||||
|
@ -7643,12 +7594,10 @@ class BodyBuilder extends StackListenerImpl
|
|||
assert(checkState(beginToken, [
|
||||
/* body */ ValueKinds.StatementOrNull,
|
||||
/* async marker */ ValueKinds.AsyncMarker,
|
||||
/* function type scope */ ValueKinds.Scope,
|
||||
/* formal parameters */ ValueKinds.FormalParameters,
|
||||
/* inCatchBlock */ ValueKinds.Bool,
|
||||
/* switch scope */ ValueKinds.SwitchScopeOrNull,
|
||||
/* function type variables */ ValueKinds.NominalVariableListOrNull,
|
||||
/* function block scope */ ValueKinds.Scope,
|
||||
]));
|
||||
Statement body = popNullableStatement() ??
|
||||
// In erroneous cases, there might not be function body. In such cases
|
||||
|
@ -7742,8 +7691,8 @@ class BodyBuilder extends StackListenerImpl
|
|||
|
||||
@override
|
||||
void beginForInExpression(Token token) {
|
||||
if (scope.parent != null) {
|
||||
enterLocalScope(scope.parent!);
|
||||
if (_localScopes.hasPrevious) {
|
||||
enterLocalScope(_localScopes.previous);
|
||||
} else {
|
||||
// Coverage-ignore-block(suite): Not run.
|
||||
createAndEnterLocalScope(
|
||||
|
@ -7785,7 +7734,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
bool isFinal = patternKeyword?.lexeme == 'final';
|
||||
for (VariableDeclaration variable in pattern.declaredVariables) {
|
||||
variable.isFinal |= isFinal;
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8043,12 +7992,12 @@ class BodyBuilder extends StackListenerImpl
|
|||
debugEvent("beginLabeledStatement");
|
||||
List<Label>? labels = const FixedNullableList<Label>()
|
||||
.popNonNullable(stack, labelCount, dummyLabel);
|
||||
enterLocalScope(scope.createNestedLabelScope());
|
||||
enterLocalScope(_localScope.createNestedLabelScope());
|
||||
LabelTarget target =
|
||||
new LabelTarget(functionNestingLevel, uri, token.charOffset);
|
||||
if (labels != null) {
|
||||
for (Label label in labels) {
|
||||
scope.declareLabel(label.name, target);
|
||||
_localScope.declareLabel(label.name, target);
|
||||
}
|
||||
}
|
||||
push(target);
|
||||
|
@ -8060,6 +8009,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
Statement statement = pop() as Statement;
|
||||
LabelTarget target = pop() as LabelTarget;
|
||||
exitLocalScope();
|
||||
// TODO(johnniwinther): Split the handling of breaks and continue.
|
||||
if (target.breakTarget.hasUsers || target.continueTarget.hasUsers) {
|
||||
if (forest.isVariablesDeclaration(statement)) {
|
||||
internalProblem(
|
||||
|
@ -8076,10 +8026,17 @@ class BodyBuilder extends StackListenerImpl
|
|||
if (continueStatements != null) {
|
||||
for (BreakStatementImpl continueStatement in continueStatements) {
|
||||
continueStatement.targetStatement = statement;
|
||||
Statement body = statement.body;
|
||||
if (body is! ForStatement &&
|
||||
body is! DoStatement &&
|
||||
body is! WhileStatement) {
|
||||
Statement labelStatementBody = statement.body;
|
||||
if (labelStatementBody is LoopStatement) {
|
||||
Statement loopBody = labelStatementBody.body;
|
||||
if (loopBody is LabeledStatement) {
|
||||
continueStatement.target = loopBody;
|
||||
} else {
|
||||
labelStatementBody.body = continueStatement.target = forest
|
||||
.createLabeledStatement(labelStatementBody.body)
|
||||
..parent = labelStatementBody;
|
||||
}
|
||||
} else {
|
||||
push(buildProblemStatement(
|
||||
fasta.messageContinueLabelInvalid, continueStatement.fileOffset,
|
||||
length: 8));
|
||||
|
@ -8274,11 +8231,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
unionOfKinds([
|
||||
ValueKinds.Label,
|
||||
ValueKinds.ExpressionOrPatternGuardCase,
|
||||
ValueKinds.Scope,
|
||||
]),
|
||||
count)));
|
||||
|
||||
LocalScope? switchCaseScope;
|
||||
List<Label>? labels =
|
||||
labelCount == 0 ? null : new List<Label>.filled(labelCount, dummyLabel);
|
||||
int labelIndex = labelCount - 1;
|
||||
|
@ -8289,39 +8244,37 @@ class BodyBuilder extends StackListenerImpl
|
|||
growable: true);
|
||||
int expressionOrPatternIndex = expressionCount - 1;
|
||||
|
||||
for (int i = 0; i < count + 1; i++) {
|
||||
Object? value = peek();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Object? value = pop();
|
||||
if (value is Label) {
|
||||
labels![labelIndex--] = value;
|
||||
pop();
|
||||
} else if (value is LocalScope) {
|
||||
assert(switchCaseScope == null);
|
||||
if (expressionCount == 1) {
|
||||
// The single-head case. The scope of the head should be remembered
|
||||
// and reused later; it already contains the declared pattern
|
||||
// variables.
|
||||
switchCaseScope = scope;
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
|
||||
} else {
|
||||
// The multi-head or "default" case. The scope of the last head should
|
||||
// be exited, and the new scope for the joint variables should be
|
||||
// created.
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
|
||||
switchCaseScope = scope.createNestedScope(
|
||||
debugName: "joint-variables", kind: ScopeKind.jointVariables);
|
||||
}
|
||||
} else {
|
||||
expressionOrPatterns[expressionOrPatternIndex--] =
|
||||
value as ExpressionOrPatternGuardCase;
|
||||
if (value.patternGuard != null) {
|
||||
containsPatterns = true;
|
||||
}
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
LocalScope switchCaseScope;
|
||||
if (expressionCount == 1) {
|
||||
// The single-head case. The scope of the head should be remembered
|
||||
// and reused later; it already contains the declared pattern
|
||||
// variables.
|
||||
switchCaseScope = _localScope;
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
|
||||
} else {
|
||||
// The multi-head or "default" case. The scope of the last head should
|
||||
// be exited, and the new scope for the joint variables should be
|
||||
// created.
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
|
||||
switchCaseScope = _localScope.createNestedScope(
|
||||
debugName: "joint-variables", kind: ScopeKind.jointVariables);
|
||||
}
|
||||
|
||||
// ignore: unrelated_type_equality_checks
|
||||
assert(scope == switchScope);
|
||||
assert(_localScope == switchScope);
|
||||
|
||||
if (labels != null) {
|
||||
for (Label label in labels) {
|
||||
|
@ -8337,7 +8290,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
labelName.length);
|
||||
}
|
||||
} else {
|
||||
scope.declareLabel(
|
||||
_localScope.declareLabel(
|
||||
labelName, createGotoTarget(beginToken.charOffset));
|
||||
}
|
||||
}
|
||||
|
@ -8349,7 +8302,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
List<VariableDeclaration>? jointPatternVariables;
|
||||
List<VariableDeclaration>? jointPatternVariablesWithMismatchingFinality;
|
||||
List<VariableDeclaration>? jointPatternVariablesNotInAll;
|
||||
enterLocalScope(switchCaseScope!);
|
||||
enterLocalScope(switchCaseScope);
|
||||
if (expressionCount > 1) {
|
||||
for (int i = 0; i < expressionOrPatterns.length; i++) {
|
||||
ExpressionOrPatternGuardCase expressionOrPattern =
|
||||
|
@ -8414,18 +8367,18 @@ class BodyBuilder extends StackListenerImpl
|
|||
jointPatternVariables = null;
|
||||
} else {
|
||||
for (VariableDeclaration jointVariable in jointPatternVariables) {
|
||||
assert(scope.kind == ScopeKind.jointVariables);
|
||||
declareVariable(jointVariable, scope);
|
||||
assert(_localScope.kind == ScopeKind.jointVariables);
|
||||
declareVariable(jointVariable, _localScope);
|
||||
typeInferrer.assignedVariables.declare(jointVariable);
|
||||
}
|
||||
}
|
||||
}
|
||||
switchCaseScope = scope.createNestedScope(
|
||||
switchCaseScope = _localScope.createNestedScope(
|
||||
debugName: "switch case", kind: ScopeKind.switchCase);
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.jointVariables]);
|
||||
enterLocalScope(switchCaseScope);
|
||||
} else if (expressionCount == 1) {
|
||||
switchCaseScope = scope.createNestedScope(
|
||||
switchCaseScope = _localScope.createNestedScope(
|
||||
debugName: "switch case", kind: ScopeKind.switchCase);
|
||||
exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
|
||||
enterLocalScope(switchCaseScope);
|
||||
|
@ -8439,11 +8392,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
debugName: "switch-case-body", kind: ScopeKind.switchCaseBody);
|
||||
|
||||
assert(checkState(beginToken, [
|
||||
ValueKinds.Scope,
|
||||
ValueKinds.VariableDeclarationListOrNull,
|
||||
ValueKinds.VariableDeclarationListOrNull,
|
||||
ValueKinds.VariableDeclarationListOrNull,
|
||||
ValueKinds.Scope,
|
||||
ValueKinds.LabelListOrNull,
|
||||
ValueKinds.Bool,
|
||||
ValueKinds.ExpressionOrPatternGuardCaseList,
|
||||
|
@ -8468,7 +8419,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
Object? pattern = peek();
|
||||
if (pattern is Pattern) {
|
||||
for (VariableDeclaration variable in pattern.declaredVariables) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
}
|
||||
push(constantContext);
|
||||
|
@ -8508,7 +8459,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
Object? pattern = peek();
|
||||
if (pattern is Pattern) {
|
||||
for (VariableDeclaration variable in pattern.declaredVariables) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8525,11 +8476,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
debugEvent("SwitchCase");
|
||||
assert(checkState(beginToken, [
|
||||
...repeatedKind(ValueKinds.Statement, statementCount),
|
||||
ValueKinds.Scope,
|
||||
ValueKinds.VariableDeclarationListOrNull,
|
||||
ValueKinds.VariableDeclarationListOrNull,
|
||||
ValueKinds.VariableDeclarationListOrNull,
|
||||
ValueKinds.Scope,
|
||||
ValueKinds.LabelListOrNull,
|
||||
ValueKinds.Bool,
|
||||
ValueKinds.ExpressionOrPatternGuardCaseList,
|
||||
|
@ -8552,12 +8501,12 @@ class BodyBuilder extends StackListenerImpl
|
|||
// specifically in the body of the case, as opposed to, for example, the
|
||||
// guard in one of the heads of the case.
|
||||
assert(
|
||||
scope.kind == ScopeKind.switchCase ||
|
||||
scope.kind == ScopeKind.jointVariables,
|
||||
_localScope.kind == ScopeKind.switchCase ||
|
||||
_localScope.kind == ScopeKind.jointVariables,
|
||||
// Coverage-ignore(suite): Not run.
|
||||
"Expected the current scope to be of kind '${ScopeKind.switchCase}' "
|
||||
"or '${ScopeKind.jointVariables}', but got '${scope.kind}.");
|
||||
Map<String, List<int>>? usedNamesOffsets = scope.usedNames;
|
||||
"or '${ScopeKind.jointVariables}', but got '${_localScope.kind}.");
|
||||
Map<String, List<int>>? usedNamesOffsets = _localScope.usedNames;
|
||||
|
||||
bool hasDefaultOrLabels = defaultKeyword != null || labelCount > 0;
|
||||
|
||||
|
@ -8685,7 +8634,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
createAndEnterLocalScope(
|
||||
debugName: "case-head", kind: ScopeKind.caseHead); // Sentinel scope.
|
||||
assert(checkState(beginToken, [
|
||||
ValueKinds.Scope,
|
||||
ValueKinds.LabelListOrNull,
|
||||
ValueKinds.SwitchCase,
|
||||
]));
|
||||
|
@ -8700,7 +8648,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
/* containsPatterns */ ValueKinds.Bool,
|
||||
/* break target = */ ValueKinds.BreakTarget,
|
||||
/* switch scope = */ ValueKinds.SwitchScopeOrNull,
|
||||
/* local scope = */ ValueKinds.Scope,
|
||||
/* expression = */ ValueKinds.Condition,
|
||||
]));
|
||||
List<List<Statement>?> labelUsers = pop() as List<List<Statement>?>;
|
||||
|
@ -8788,7 +8735,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
debugName: "switch-expression-case", kind: ScopeKind.caseHead);
|
||||
if (pattern is Pattern) {
|
||||
for (VariableDeclaration variable in pattern.declaredVariables) {
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
}
|
||||
push(pattern);
|
||||
|
@ -8816,7 +8763,6 @@ class BodyBuilder extends StackListenerImpl
|
|||
ValueKinds.ProblemBuilder,
|
||||
ValueKinds.Pattern,
|
||||
]),
|
||||
ValueKinds.Scope,
|
||||
]));
|
||||
|
||||
Expression expression = popForValue();
|
||||
|
@ -8869,13 +8815,12 @@ class BodyBuilder extends StackListenerImpl
|
|||
@override
|
||||
void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
|
||||
debugEvent("SwitchBlock");
|
||||
assert(checkState(beginToken, [
|
||||
ValueKinds.Scope,
|
||||
...repeatedKinds([
|
||||
ValueKinds.LabelListOrNull,
|
||||
ValueKinds.SwitchCase,
|
||||
], caseCount)
|
||||
]));
|
||||
assert(checkState(
|
||||
beginToken,
|
||||
repeatedKinds([
|
||||
ValueKinds.LabelListOrNull,
|
||||
ValueKinds.SwitchCase,
|
||||
], caseCount)));
|
||||
|
||||
exitLocalScope(expectedScopeKinds: const [
|
||||
ScopeKind.caseHead
|
||||
|
@ -8940,7 +8885,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
if (hasTarget) {
|
||||
identifier = pop() as Identifier;
|
||||
name = identifier.name;
|
||||
target = scope.lookupLabel(name);
|
||||
target = _localScope.lookupLabel(name);
|
||||
}
|
||||
if (target == null && name == null) {
|
||||
push(problemInLoopOrSwitch = buildProblemStatement(
|
||||
|
@ -8996,7 +8941,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
if (hasTarget) {
|
||||
identifier = pop() as Identifier;
|
||||
name = identifier.name;
|
||||
target = scope.lookupLabel(identifier.name);
|
||||
target = _localScope.lookupLabel(identifier.name);
|
||||
if (target == null) {
|
||||
if (switchScope == null) {
|
||||
push(buildProblemStatement(
|
||||
|
@ -10011,7 +9956,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
libraryFeatures.patterns, variable.charOffset, variable.charCount);
|
||||
assert(variable.lexeme != '_');
|
||||
Pattern pattern;
|
||||
Expression variableUse = toValue(scopeLookup(scope, variable));
|
||||
Expression variableUse = toValue(scopeLookup(_localScope, variable));
|
||||
if (variableUse is VariableGet) {
|
||||
VariableDeclaration variableDeclaration = variableUse.variable;
|
||||
pattern = forest.createAssignedVariablePattern(
|
||||
|
@ -10053,7 +9998,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
Modifier.validateVarFinalOrConst(keyword?.lexeme) == finalMask);
|
||||
pattern = forest.createVariablePattern(
|
||||
variable.charOffset, patternType, declaredVariable);
|
||||
declareVariable(declaredVariable, scope);
|
||||
declareVariable(declaredVariable, _localScope);
|
||||
typeInferrer.assignedVariables.declare(declaredVariable);
|
||||
}
|
||||
push(pattern);
|
||||
|
@ -10144,7 +10089,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
for (VariableDeclaration variable in pattern.declaredVariables) {
|
||||
variable.isFinal = isFinal;
|
||||
variable.hasDeclaredInitializer = true;
|
||||
declareVariable(variable, scope);
|
||||
declareVariable(variable, _localScope);
|
||||
}
|
||||
// TODO(johnniwinther,cstefantsova): Handle metadata.
|
||||
pop(NullValues.Metadata) as List<Expression>?;
|
||||
|
|
|
@ -182,7 +182,6 @@ class ValueKinds {
|
|||
static const ValueKind RecordTypeFieldBuilderListOrNull =
|
||||
const SingleValueKind<List<type.RecordTypeFieldBuilder>>(
|
||||
NullValues.RecordTypeFieldList);
|
||||
static const ValueKind Scope = const SingleValueKind<type.LocalScope>();
|
||||
static const ValueKind Selector = const SingleValueKind<type.Selector>();
|
||||
static const ValueKind SwitchCase = const SingleValueKind<type.SwitchCase>();
|
||||
static const ValueKind SwitchCaseList =
|
||||
|
|
64
pkg/front_end/lib/src/util/local_stack.dart
Normal file
64
pkg/front_end/lib/src/util/local_stack.dart
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
/// Extension type that uses a list as a stack.
|
||||
extension type LocalStack<T>(List<T> _list) {
|
||||
/// Return `true` if the stack is not empty.
|
||||
///
|
||||
/// ```
|
||||
/// DartDocTest(LocalStack<int>([]).hasCurrent, false)
|
||||
/// DartDocTest(LocalStack<int>([0]).hasCurrent, true)
|
||||
/// DartDocTest(LocalStack<int>([0, 1]).hasCurrent, true)
|
||||
/// ```
|
||||
bool get hasCurrent => _list.isNotEmpty;
|
||||
|
||||
/// Return the current top of the stack.
|
||||
///
|
||||
/// ```
|
||||
/// DartDocTest(LocalStack<int>([0]).current, 0)
|
||||
/// DartDocTest(LocalStack<int>([0, 1]).current, 1)
|
||||
/// ```
|
||||
T get current => _list.last;
|
||||
|
||||
/// Return `true` if the stack has more than one element.
|
||||
///
|
||||
/// ```
|
||||
/// DartDocTest(LocalStack<int>([]).hasPrevious, false)
|
||||
/// DartDocTest(LocalStack<int>([0]).hasPrevious, false)
|
||||
/// DartDocTest(LocalStack<int>([0, 1]).hasPrevious, true)
|
||||
/// ```
|
||||
bool get hasPrevious => _list.length > 1;
|
||||
|
||||
/// Returns the second-most element on the stack.
|
||||
///
|
||||
/// ```
|
||||
/// DartDocTest(LocalStack<int>([0, 1]).previous, 0)
|
||||
/// DartDocTest(LocalStack<int>([0, 1, 2]).previous, 1)
|
||||
/// ```
|
||||
T get previous => _list[_list.length - 2];
|
||||
|
||||
/// Puts [element] on the top of the stack.
|
||||
///
|
||||
/// ```
|
||||
/// DartDocTest((LocalStack<int>([])..push(0)).current, 0)
|
||||
/// DartDocTest((LocalStack<int>([])..push(0)..push(1)).current, 1)
|
||||
/// DartDocTest(
|
||||
/// (LocalStack<int>([])..push(0)..pop()..push(1)).hasPrevious,
|
||||
/// false
|
||||
/// )
|
||||
/// ```
|
||||
void push(T element) {
|
||||
_list.add(element);
|
||||
}
|
||||
|
||||
/// Pops the top of the stack.
|
||||
///
|
||||
/// ```
|
||||
/// DartDocTest(LocalStack<int>([0]).pop(), 0)
|
||||
/// DartDocTest((LocalStack<int>([0, 1, 2])..pop()).pop(), 1)
|
||||
/// ```
|
||||
T pop() {
|
||||
return _list.removeLast();
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ name: front_end
|
|||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ^3.2.0-0
|
||||
sdk: ^3.3.0-0
|
||||
|
||||
# Use 'any' constraints here; we get our versions from the DEPS file.
|
||||
dependencies:
|
||||
|
|
|
@ -163,10 +163,10 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
|
|||
hitCount: 25,
|
||||
missCount: 0,
|
||||
),
|
||||
// 85.8267716535433%.
|
||||
// 84.0%.
|
||||
"package:front_end/src/base/local_scope.dart": (
|
||||
hitCount: 109,
|
||||
missCount: 18,
|
||||
hitCount: 105,
|
||||
missCount: 20,
|
||||
),
|
||||
// 100.0%.
|
||||
"package:front_end/src/base/messages.dart": (
|
||||
|
@ -193,10 +193,10 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
|
|||
hitCount: 246,
|
||||
missCount: 0,
|
||||
),
|
||||
// 91.14219114219114%.
|
||||
// 97.1141781681305%.
|
||||
"package:front_end/src/base/scope.dart": (
|
||||
hitCount: 782,
|
||||
missCount: 76,
|
||||
hitCount: 774,
|
||||
missCount: 23,
|
||||
),
|
||||
// 100.0%.
|
||||
"package:front_end/src/base/ticker.dart": (
|
||||
|
@ -468,9 +468,9 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
|
|||
hitCount: 0,
|
||||
missCount: 0,
|
||||
),
|
||||
// 99.38763884933067%.
|
||||
// 99.38501144164759%.
|
||||
"package:front_end/src/kernel/body_builder.dart": (
|
||||
hitCount: 6979,
|
||||
hitCount: 6949,
|
||||
missCount: 43,
|
||||
),
|
||||
// 100.0%.
|
||||
|
@ -974,6 +974,11 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
|
|||
hitCount: 20,
|
||||
missCount: 0,
|
||||
),
|
||||
// 86.66666666666667%.
|
||||
"package:front_end/src/util/local_stack.dart": (
|
||||
hitCount: 13,
|
||||
missCount: 2,
|
||||
),
|
||||
// 100.0%.
|
||||
"package:front_end/src/util/parser_ast.dart": (
|
||||
hitCount: 78,
|
||||
|
|
|
@ -1,9 +1,35 @@
|
|||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
main() {
|
||||
L:
|
||||
{
|
||||
for (var i in []) {
|
||||
continue L;
|
||||
continue L; // Error
|
||||
}
|
||||
}
|
||||
1;
|
||||
|
||||
alias:
|
||||
label:
|
||||
for (var i in []) {
|
||||
if (i == 0) {
|
||||
continue label; // Ok
|
||||
} else {
|
||||
continue alias; // Ok
|
||||
}
|
||||
}
|
||||
|
||||
alias2:
|
||||
{
|
||||
label2:
|
||||
for (var i in []) {
|
||||
if (i == 0) {
|
||||
continue label2; // Ok
|
||||
} else {
|
||||
continue alias2; // Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,34 @@ library;
|
|||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/continue_label_invalid.dart:5:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
// continue L;
|
||||
// pkg/front_end/testcases/general/continue_label_invalid.dart:9:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
// continue L; // Error
|
||||
// ^^^^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/continue_label_invalid.dart:31:9: Error: A 'continue' label must be on a loop or a switch member.
|
||||
// continue alias2; // Error
|
||||
// ^^^^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/continue_label_invalid.dart:5:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
continue L;
|
||||
invalid-expression "pkg/front_end/testcases/general/continue_label_invalid.dart:9:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
continue L; // Error
|
||||
^^^^^^^^";
|
||||
1;
|
||||
#L1:
|
||||
for (dynamic i in <dynamic>[])
|
||||
#L2:
|
||||
{
|
||||
if(i =={core::Object::==}{(core::Object) → core::bool} 0) {
|
||||
break #L2;
|
||||
}
|
||||
else {
|
||||
break #L2;
|
||||
}
|
||||
}
|
||||
invalid-expression "pkg/front_end/testcases/general/continue_label_invalid.dart:31:9: Error: A 'continue' label must be on a loop or a switch member.
|
||||
continue alias2; // Error
|
||||
^^^^^^^^";
|
||||
}
|
||||
|
|
|
@ -2,15 +2,34 @@ library;
|
|||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/continue_label_invalid.dart:5:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
// continue L;
|
||||
// pkg/front_end/testcases/general/continue_label_invalid.dart:9:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
// continue L; // Error
|
||||
// ^^^^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/continue_label_invalid.dart:31:9: Error: A 'continue' label must be on a loop or a switch member.
|
||||
// continue alias2; // Error
|
||||
// ^^^^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/continue_label_invalid.dart:5:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
continue L;
|
||||
invalid-expression "pkg/front_end/testcases/general/continue_label_invalid.dart:9:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
continue L; // Error
|
||||
^^^^^^^^";
|
||||
1;
|
||||
#L1:
|
||||
for (dynamic i in <dynamic>[])
|
||||
#L2:
|
||||
{
|
||||
if(i =={core::Object::==}{(core::Object) → core::bool} 0) {
|
||||
break #L2;
|
||||
}
|
||||
else {
|
||||
break #L2;
|
||||
}
|
||||
}
|
||||
invalid-expression "pkg/front_end/testcases/general/continue_label_invalid.dart:31:9: Error: A 'continue' label must be on a loop or a switch member.
|
||||
continue alias2; // Error
|
||||
^^^^^^^^";
|
||||
}
|
||||
|
|
|
@ -2,15 +2,39 @@ library;
|
|||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/general/continue_label_invalid.dart:5:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
// continue L;
|
||||
// pkg/front_end/testcases/general/continue_label_invalid.dart:9:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
// continue L; // Error
|
||||
// ^^^^^^^^
|
||||
//
|
||||
// pkg/front_end/testcases/general/continue_label_invalid.dart:31:9: Error: A 'continue' label must be on a loop or a switch member.
|
||||
// continue alias2; // Error
|
||||
// ^^^^^^^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
invalid-expression "pkg/front_end/testcases/general/continue_label_invalid.dart:5:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
continue L;
|
||||
invalid-expression "pkg/front_end/testcases/general/continue_label_invalid.dart:9:7: Error: A 'continue' label must be on a loop or a switch member.
|
||||
continue L; // Error
|
||||
^^^^^^^^";
|
||||
1;
|
||||
#L1:
|
||||
{
|
||||
synthesized core::Iterator<dynamic> :sync-for-iterator = core::_GrowableList::•<dynamic>(0).{core::Iterable::iterator}{core::Iterator<dynamic>};
|
||||
for (; :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
|
||||
dynamic i = :sync-for-iterator.{core::Iterator::current}{dynamic};
|
||||
#L2:
|
||||
{
|
||||
if(i =={core::Object::==}{(core::Object) → core::bool} 0) {
|
||||
break #L2;
|
||||
}
|
||||
else {
|
||||
break #L2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
invalid-expression "pkg/front_end/testcases/general/continue_label_invalid.dart:31:9: Error: A 'continue' label must be on a loop or a switch member.
|
||||
continue alias2; // Error
|
||||
^^^^^^^^";
|
||||
}
|
||||
|
|
13
pkg/front_end/testcases/general/continue_loop.dart
Normal file
13
pkg/front_end/testcases/general/continue_loop.dart
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
main() {
|
||||
int i = 0;
|
||||
OUTER:
|
||||
while (i++ < 10) {
|
||||
if (i < 5) continue OUTER;
|
||||
break OUTER;
|
||||
}
|
||||
if (i != 5) throw 'Expected 5, actual $i';
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
core::int i = 0;
|
||||
#L1:
|
||||
while ((let final core::int #t1 = i in let final core::int #t2 = i = #t1.{core::num::+}(1){(core::num) → core::int} in #t1).{core::num::<}(10){(core::num) → core::bool})
|
||||
#L2:
|
||||
{
|
||||
if(i.{core::num::<}(5){(core::num) → core::bool})
|
||||
break #L2;
|
||||
break #L1;
|
||||
}
|
||||
if(!(i =={core::num::==}{(core::Object) → core::bool} 5))
|
||||
throw "Expected 5, actual ${i}";
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
core::int i = 0;
|
||||
#L1:
|
||||
while ((let final core::int #t1 = i in let final core::int #t2 = i = #t1.{core::num::+}(1){(core::num) → core::int} in #t1).{core::num::<}(10){(core::num) → core::bool})
|
||||
#L2:
|
||||
{
|
||||
if(i.{core::num::<}(5){(core::num) → core::bool})
|
||||
break #L2;
|
||||
break #L1;
|
||||
}
|
||||
if(!(i =={core::num::==}{(core::Object) → core::bool} 5))
|
||||
throw "Expected 5, actual ${i}";
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
library;
|
||||
import self as self;
|
||||
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,17 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
core::int i = 0;
|
||||
#L1:
|
||||
while ((let final core::int #t1 = i in let final core::int #t2 = i = #t1.{core::num::+}(1){(core::num) → core::int} in #t1).{core::num::<}(10){(core::num) → core::bool})
|
||||
#L2:
|
||||
{
|
||||
if(i.{core::num::<}(5){(core::num) → core::bool})
|
||||
break #L2;
|
||||
break #L1;
|
||||
}
|
||||
if(!(i =={core::num::==}{(core::Object) → core::bool} 5))
|
||||
throw "Expected 5, actual ${i}";
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
main() {}
|
|
@ -0,0 +1 @@
|
|||
main() {}
|
12
pkg/front_end/testcases/general/labeled_loop_break.dart
Normal file
12
pkg/front_end/testcases/general/labeled_loop_break.dart
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
main() {
|
||||
int i = 0;
|
||||
OUTER:
|
||||
while (i++ < 10) {
|
||||
if (i > 5) break OUTER;
|
||||
}
|
||||
if (i != 6) throw 'Expected 5, actual $i';
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
core::int i = 0;
|
||||
#L1:
|
||||
while ((let final core::int #t1 = i in let final core::int #t2 = i = #t1.{core::num::+}(1){(core::num) → core::int} in #t1).{core::num::<}(10){(core::num) → core::bool}) {
|
||||
if(i.{core::num::>}(5){(core::num) → core::bool})
|
||||
break #L1;
|
||||
}
|
||||
if(!(i =={core::num::==}{(core::Object) → core::bool} 6))
|
||||
throw "Expected 5, actual ${i}";
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
core::int i = 0;
|
||||
#L1:
|
||||
while ((let final core::int #t1 = i in let final core::int #t2 = i = #t1.{core::num::+}(1){(core::num) → core::int} in #t1).{core::num::<}(10){(core::num) → core::bool}) {
|
||||
if(i.{core::num::>}(5){(core::num) → core::bool})
|
||||
break #L1;
|
||||
}
|
||||
if(!(i =={core::num::==}{(core::Object) → core::bool} 6))
|
||||
throw "Expected 5, actual ${i}";
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
library;
|
||||
import self as self;
|
||||
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,14 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
core::int i = 0;
|
||||
#L1:
|
||||
while ((let final core::int #t1 = i in let final core::int #t2 = i = #t1.{core::num::+}(1){(core::num) → core::int} in #t1).{core::num::<}(10){(core::num) → core::bool}) {
|
||||
if(i.{core::num::>}(5){(core::num) → core::bool})
|
||||
break #L1;
|
||||
}
|
||||
if(!(i =={core::num::==}{(core::Object) → core::bool} 6))
|
||||
throw "Expected 5, actual ${i}";
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
main() {}
|
|
@ -0,0 +1 @@
|
|||
main() {}
|
15
pkg/front_end/testcases/general/labeled_loop_continue.dart
Normal file
15
pkg/front_end/testcases/general/labeled_loop_continue.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
main() {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
OUTER:
|
||||
while (++i < 10) {
|
||||
if (i < 4) continue OUTER;
|
||||
j++;
|
||||
}
|
||||
if (i != 10) throw 'Expected i=10, actual $i';
|
||||
if (j != 6) throw 'Expected j=6, actual $j';
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
core::int i = 0;
|
||||
core::int j = 0;
|
||||
#L1:
|
||||
while ((i = i.{core::num::+}(1){(core::num) → core::int}).{core::num::<}(10){(core::num) → core::bool})
|
||||
#L2:
|
||||
{
|
||||
if(i.{core::num::<}(4){(core::num) → core::bool})
|
||||
break #L2;
|
||||
j = j.{core::num::+}(1){(core::num) → core::int};
|
||||
}
|
||||
if(!(i =={core::num::==}{(core::Object) → core::bool} 10))
|
||||
throw "Expected i=10, actual ${i}";
|
||||
if(!(j =={core::num::==}{(core::Object) → core::bool} 6))
|
||||
throw "Expected j=6, actual ${j}";
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
core::int i = 0;
|
||||
core::int j = 0;
|
||||
#L1:
|
||||
while ((i = i.{core::num::+}(1){(core::num) → core::int}).{core::num::<}(10){(core::num) → core::bool})
|
||||
#L2:
|
||||
{
|
||||
if(i.{core::num::<}(4){(core::num) → core::bool})
|
||||
break #L2;
|
||||
j = j.{core::num::+}(1){(core::num) → core::int};
|
||||
}
|
||||
if(!(i =={core::num::==}{(core::Object) → core::bool} 10))
|
||||
throw "Expected i=10, actual ${i}";
|
||||
if(!(j =={core::num::==}{(core::Object) → core::bool} 6))
|
||||
throw "Expected j=6, actual ${j}";
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
library;
|
||||
import self as self;
|
||||
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,20 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method main() → dynamic {
|
||||
core::int i = 0;
|
||||
core::int j = 0;
|
||||
#L1:
|
||||
while ((i = i.{core::num::+}(1){(core::num) → core::int}).{core::num::<}(10){(core::num) → core::bool})
|
||||
#L2:
|
||||
{
|
||||
if(i.{core::num::<}(4){(core::num) → core::bool})
|
||||
break #L2;
|
||||
j = j.{core::num::+}(1){(core::num) → core::int};
|
||||
}
|
||||
if(!(i =={core::num::==}{(core::Object) → core::bool} 10))
|
||||
throw "Expected i=10, actual ${i}";
|
||||
if(!(j =={core::num::==}{(core::Object) → core::bool} 6))
|
||||
throw "Expected j=6, actual ${j}";
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
main() {}
|
|
@ -0,0 +1 @@
|
|||
main() {}
|
|
@ -9490,8 +9490,15 @@ class BreakStatement extends Statement {
|
|||
}
|
||||
}
|
||||
|
||||
class WhileStatement extends Statement {
|
||||
/// Common interface for loop statements.
|
||||
abstract interface class LoopStatement implements Statement {
|
||||
abstract Statement body;
|
||||
}
|
||||
|
||||
class WhileStatement extends Statement implements LoopStatement {
|
||||
Expression condition;
|
||||
|
||||
@override
|
||||
Statement body;
|
||||
|
||||
WhileStatement(this.condition, this.body) {
|
||||
|
@ -9542,8 +9549,10 @@ class WhileStatement extends Statement {
|
|||
}
|
||||
}
|
||||
|
||||
class DoStatement extends Statement {
|
||||
class DoStatement extends Statement implements LoopStatement {
|
||||
@override
|
||||
Statement body;
|
||||
|
||||
Expression condition;
|
||||
|
||||
DoStatement(this.body, this.condition) {
|
||||
|
@ -9595,10 +9604,12 @@ class DoStatement extends Statement {
|
|||
}
|
||||
}
|
||||
|
||||
class ForStatement extends Statement {
|
||||
class ForStatement extends Statement implements LoopStatement {
|
||||
final List<VariableDeclaration> variables; // May be empty, but not null.
|
||||
Expression? condition; // May be null.
|
||||
final List<Expression> updates; // May be empty, but not null.
|
||||
|
||||
@override
|
||||
Statement body;
|
||||
|
||||
ForStatement(this.variables, this.condition, this.updates, this.body) {
|
||||
|
@ -9673,7 +9684,7 @@ class ForStatement extends Statement {
|
|||
}
|
||||
}
|
||||
|
||||
class ForInStatement extends Statement {
|
||||
class ForInStatement extends Statement implements LoopStatement {
|
||||
/// Offset in the source file it comes from.
|
||||
///
|
||||
/// Valid values are from 0 and up, or -1 ([TreeNode.noOffset]) if the file
|
||||
|
@ -9685,7 +9696,10 @@ class ForInStatement extends Statement {
|
|||
|
||||
VariableDeclaration variable; // Has no initializer.
|
||||
Expression iterable;
|
||||
|
||||
@override
|
||||
Statement body;
|
||||
|
||||
bool isAsync; // True if this is an 'await for' loop.
|
||||
|
||||
ForInStatement(this.variable, this.iterable, this.body,
|
||||
|
|
|
@ -144,8 +144,9 @@ static method main() → void {
|
|||
#L9:
|
||||
{
|
||||
final self::MyFinalizable finalizable9 = new self::MyFinalizable::•();
|
||||
#L10:
|
||||
for (core::int j = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] j.{core::num::<}(10){(core::num) → core::bool}; j = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] j.{core::num::+}(1){(core::num) → core::int})
|
||||
#L10:
|
||||
#L11:
|
||||
{
|
||||
final self::MyFinalizable finalizable10 = new self::MyFinalizable::•();
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart.core::DateTime.millisecondsSinceEpoch] [@vm.inferred-type.metadata=int] new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 42) {
|
||||
|
@ -165,7 +166,7 @@ static method main() → void {
|
|||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart.core::DateTime.millisecondsSinceEpoch] [@vm.inferred-type.metadata=int] new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 1) {
|
||||
{
|
||||
_in::reachabilityFence(finalizable10);
|
||||
break #L10;
|
||||
break #L11;
|
||||
}
|
||||
}
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart.core::DateTime.millisecondsSinceEpoch] [@vm.inferred-type.metadata=int] new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 3) {
|
||||
|
@ -179,23 +180,23 @@ static method main() → void {
|
|||
}
|
||||
_in::reachabilityFence(finalizable9);
|
||||
}
|
||||
#L11:
|
||||
#L12:
|
||||
{
|
||||
final self::MyFinalizable finalizable11 = new self::MyFinalizable::•();
|
||||
#L12:
|
||||
#L13:
|
||||
{
|
||||
final self::MyFinalizable finalizable12 = new self::MyFinalizable::•();
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart.core::DateTime.millisecondsSinceEpoch] [@vm.inferred-type.metadata=int] new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 1) {
|
||||
{
|
||||
_in::reachabilityFence(finalizable11);
|
||||
_in::reachabilityFence(finalizable12);
|
||||
break #L11;
|
||||
break #L12;
|
||||
}
|
||||
}
|
||||
if([@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart.core::DateTime.millisecondsSinceEpoch] [@vm.inferred-type.metadata=int] new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 3) {
|
||||
{
|
||||
_in::reachabilityFence(finalizable12);
|
||||
break #L12;
|
||||
break #L13;
|
||||
}
|
||||
}
|
||||
_in::reachabilityFence(finalizable12);
|
||||
|
|
|
@ -142,8 +142,9 @@ static method main() → void {
|
|||
#L9:
|
||||
{
|
||||
final self::MyFinalizable finalizable9 = new self::MyFinalizable::•();
|
||||
#L10:
|
||||
for (core::int j = 0; j.{core::num::<}(10){(core::num) → core::bool}; j = j.{core::num::+}(1){(core::num) → core::int})
|
||||
#L10:
|
||||
#L11:
|
||||
{
|
||||
final self::MyFinalizable finalizable10 = new self::MyFinalizable::•();
|
||||
if(new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 42) {
|
||||
|
@ -163,7 +164,7 @@ static method main() → void {
|
|||
if(new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 1) {
|
||||
{
|
||||
_in::reachabilityFence(finalizable10);
|
||||
break #L10;
|
||||
break #L11;
|
||||
}
|
||||
}
|
||||
if(new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 3) {
|
||||
|
@ -177,23 +178,23 @@ static method main() → void {
|
|||
}
|
||||
_in::reachabilityFence(finalizable9);
|
||||
}
|
||||
#L11:
|
||||
#L12:
|
||||
{
|
||||
final self::MyFinalizable finalizable11 = new self::MyFinalizable::•();
|
||||
#L12:
|
||||
#L13:
|
||||
{
|
||||
final self::MyFinalizable finalizable12 = new self::MyFinalizable::•();
|
||||
if(new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 1) {
|
||||
{
|
||||
_in::reachabilityFence(finalizable11);
|
||||
_in::reachabilityFence(finalizable12);
|
||||
break #L11;
|
||||
break #L12;
|
||||
}
|
||||
}
|
||||
if(new core::DateTime::now().{core::DateTime::millisecondsSinceEpoch}{core::int} =={core::num::==}{(core::Object) → core::bool} 3) {
|
||||
{
|
||||
_in::reachabilityFence(finalizable12);
|
||||
break #L12;
|
||||
break #L13;
|
||||
}
|
||||
}
|
||||
_in::reachabilityFence(finalizable12);
|
||||
|
|
Loading…
Reference in a new issue