| // 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 'constants.dart' show Dart2jsConstantEvaluator; | 
 | 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 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.ConstantEvaluator constantEvaluator) { | 
 |     ScopeModelBuilder builder = | 
 |         ScopeModelBuilder(constantEvaluator as Dart2jsConstantEvaluator); | 
 |     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 { | 
 |   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>[]; | 
 |  | 
 |   @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 ??= 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 = VariableScopeModelImpl(); | 
 |  | 
 |   void visitInVariableScope(ir.TreeNode root, void 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; | 
 |   } | 
 | } |