blob: 2a9cee643862886b1824f7779cfbf83f8aa663be [file] [log] [blame]
// Copyright (c) 2018, 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.
import 'package:kernel/ast.dart' as ir;
import 'closure.dart';
import 'scope_visitor.dart';
import 'package:front_end/src/api_prototype/constant_evaluator.dart' as ir;
class ScopeModel {
final ClosureScopeModel closureScopeModel;
final VariableScopeModel variableScopeModel;
final InitializerComplexity initializerComplexity;
const ScopeModel(
{this.closureScopeModel,
this.variableScopeModel,
this.initializerComplexity})
: assert(initializerComplexity != null);
/// Inspect members and mark if those members capture any state that needs to
/// be marked as free variables.
factory ScopeModel.from(
ir.Member node, ir.ConstantEvaluator constantEvaluator) {
ScopeModelBuilder builder = new ScopeModelBuilder(constantEvaluator);
return builder.computeModel(node);
}
}
abstract class VariableScopeModel {
VariableScope getScopeFor(ir.TreeNode node);
Iterable<ir.VariableDeclaration> get assignedVariables;
bool isEffectivelyFinal(ir.VariableDeclaration node);
}
class VariableScopeModelImpl implements VariableScopeModel {
Map<ir.TreeNode, VariableScope> _scopeMap = {};
Set<ir.VariableDeclaration> _assignedVariables;
VariableScope createScopeFor(ir.TreeNode node) {
return _scopeMap[node] ??= new VariableScopeImpl();
}
void registerAssignedVariable(ir.VariableDeclaration node) {
_assignedVariables ??= new Set<ir.VariableDeclaration>();
_assignedVariables.add(node);
}
@override
VariableScope getScopeFor(ir.TreeNode node) {
return _scopeMap[node];
}
@override
Iterable<ir.VariableDeclaration> get assignedVariables =>
_assignedVariables ?? <ir.VariableDeclaration>[];
@override
bool isEffectivelyFinal(ir.VariableDeclaration node) {
return _assignedVariables == null || !_assignedVariables.contains(node);
}
}
/// Variable information for a scope.
abstract class VariableScope {
/// Returns the set of [ir.VariableDeclaration]s that have been assigned to in
/// this scope.
Iterable<ir.VariableDeclaration> get assignedVariables;
/// Returns `true` if this scope has a [ir.ContinueSwitchStatement].
bool get hasContinueSwitch;
}
class VariableScopeImpl implements VariableScope {
List<VariableScope> _subScopes;
Set<ir.VariableDeclaration> _assignedVariables;
@override
bool hasContinueSwitch = false;
void addSubScope(VariableScope scope) {
_subScopes ??= <VariableScope>[];
_subScopes.add(scope);
}
void registerAssignedVariable(ir.VariableDeclaration variable) {
_assignedVariables ??= new Set<ir.VariableDeclaration>();
_assignedVariables.add(variable);
}
@override
Iterable<ir.VariableDeclaration> get assignedVariables sync* {
if (_assignedVariables != null) {
yield* _assignedVariables;
}
if (_subScopes != null) {
for (VariableScope subScope in _subScopes) {
yield* subScope.assignedVariables;
}
}
}
}
abstract class VariableCollectorMixin {
VariableScopeImpl currentVariableScope;
VariableScopeModelImpl variableScopeModel = new VariableScopeModelImpl();
void visitInVariableScope(ir.TreeNode root, void f()) {
VariableScopeImpl oldScope = currentVariableScope;
currentVariableScope = variableScopeModel.createScopeFor(root);
oldScope?.addSubScope(currentVariableScope);
f();
currentVariableScope = oldScope;
}
void registerAssignedVariable(ir.VariableDeclaration node) {
currentVariableScope?.registerAssignedVariable(node);
variableScopeModel.registerAssignedVariable(node);
}
void registerContinueSwitch() {
currentVariableScope?.hasContinueSwitch = true;
}
}