blob: 1d82bfcc74074cd18e957370b025d41ef9439880 [file] [log] [blame] [edit]
// 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 'package:kernel/type_environment.dart' as ir;
import 'closure.dart';
import 'scope_visitor.dart';
class ScopeModel {
final ClosureScopeModel? closureScopeModel;
final VariableScopeModel? variableScopeModel;
final EvaluationComplexity initializerComplexity;
const ScopeModel({
this.closureScopeModel,
this.variableScopeModel,
required this.initializerComplexity,
});
/// 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.TypeEnvironment typeEnvironment) {
ScopeModelBuilder builder = ScopeModelBuilder(typeEnvironment);
return builder.computeModel(node);
}
}
abstract class VariableScopeModel {
VariableScope getScopeFor(ir.TreeNode node);
Iterable<ir.VariableDeclaration> get assignedVariables;
}
class VariableScopeModelImpl implements VariableScopeModel {
final Map<ir.TreeNode, VariableScopeImpl> _scopeMap = {};
Set<ir.VariableDeclaration>? _assignedVariables;
VariableScopeImpl createScopeFor(ir.TreeNode node) {
return _scopeMap[node] ??= VariableScopeImpl();
}
void registerAssignedVariable(ir.VariableDeclaration node) {
(_assignedVariables ??= {}).add(node);
}
@override
VariableScope getScopeFor(ir.TreeNode node) {
return _scopeMap[node]!;
}
@override
Iterable<ir.VariableDeclaration> get assignedVariables =>
_assignedVariables ?? <ir.VariableDeclaration>[];
}
/// 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 ??= <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;
}
}
}
}
mixin VariableCollectorMixin {
VariableScopeImpl? currentVariableScope;
VariableScopeModelImpl variableScopeModel = VariableScopeModelImpl();
void visitInVariableScope(ir.TreeNode root, void Function() f) {
VariableScopeImpl? oldScope = currentVariableScope;
final newScope = currentVariableScope = variableScopeModel.createScopeFor(
root,
);
oldScope?.addSubScope(newScope);
f();
currentVariableScope = oldScope;
}
void registerAssignedVariable(ir.VariableDeclaration node) {
currentVariableScope?.registerAssignedVariable(node);
variableScopeModel.registerAssignedVariable(node);
}
void registerContinueSwitch() {
currentVariableScope?.hasContinueSwitch = true;
}
}