// Copyright (c) 2016, 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.

// @dart = 2.10

import 'package:compiler/src/js_model/element_map.dart';

import '../closure.dart';
import '../common.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import '../inferrer/abstract_value_domain.dart';
import '../inferrer/types.dart';
import '../io/source_information.dart';
import '../js_backend/native_data.dart';
import '../js_backend/interceptor_data.dart';
import '../js_model/closure.dart' show JRecordField, JClosureField;
import '../js_model/locals.dart' show GlobalLocalsMap, JLocal;
import '../world.dart' show JClosedWorld;

import 'builder.dart';
import 'nodes.dart';
import 'types.dart';

/// Keeps track of locals (including parameters and phis) when building. The
/// 'this' reference is treated as parameter and hence handled by this class,
/// too.
class LocalsHandler {
  /// The values of locals that can be directly accessed (without redirections
  /// to boxes or closure-fields).
  ///
  /// [directLocals] is iterated, so it is "insertion ordered" to make the
  /// iteration order a function only of insertions and not a function of
  /// e.g. Element hash codes.  I'd prefer to use a SortedMap but some elements
  /// don't have source locations for [Elements.compareByPosition].
  Map<Local, HInstruction> directLocals = {};
  Map<Local, FieldEntity> redirectionMapping = {};
  final KernelSsaGraphBuilder builder;

  MemberEntity _scopeInfoMember;
  ScopeInfo _scopeInfo;
  KernelToLocalsMap _localsMap;

  Map<TypeVariableEntity, TypeVariableLocal> typeVariableLocals = {};
  final Entity executableContext;
  final MemberEntity memberContext;

  /// The type of the current instance. `null` if in a static context.
  ///
  /// This is the type of `this` is the current context, and is often the
  /// 'this type' of the enclosing class of a member.
  ///
  /// If the current instance is concrete, we can handle fixed type argument in
  /// case of inlining. For instance, checking `'foo'` against `String` instead
  /// of `T` in `main`:
  ///
  ///     class Foo<T> {
  ///       T field;
  ///       Foo(this.field);
  ///     }
  ///     main() {
  ///       new Foo<String>('foo');
  ///     }
  ///
  final InterfaceType instanceType;

  final NativeData _nativeData;

  final InterceptorData _interceptorData;

  LocalsHandler(this.builder, this.executableContext, this.memberContext,
      this.instanceType, this._nativeData, this._interceptorData);

  JClosedWorld get _closedWorld => builder.closedWorld;

  AbstractValueDomain get _abstractValueDomain =>
      _closedWorld.abstractValueDomain;

  GlobalTypeInferenceResults get _globalInferenceResults =>
      builder.globalInferenceResults;

  GlobalLocalsMap get _globalLocalsMap =>
      _globalInferenceResults.globalLocalsMap;

  /// Substituted type variables occurring in [type] into the context of
  /// [contextClass].
  DartType substInContext(DartType type) {
    DartType newType = type;
    if (instanceType != null) {
      ClassEntity typeContext = DartTypes.getClassContext(newType);
      if (typeContext != null) {
        newType = _closedWorld.dartTypes.substByContext(
            newType,
            _closedWorld.dartTypes.asInstanceOf(
                _closedWorld.dartTypes.getThisType(instanceType.element),
                typeContext));
      }
      if (!instanceType.containsTypeVariables) {
        newType = _closedWorld.dartTypes.substByContext(newType, instanceType);
      }
    }
    return newType;
  }

  /// Creates a new [LocalsHandler] based on [other]. We only need to
  /// copy the [directLocals], since the other fields can be shared
  /// throughout the AST visit.
  LocalsHandler.from(LocalsHandler other)
      : directLocals = Map<Local, HInstruction>.from(other.directLocals),
        redirectionMapping = other.redirectionMapping,
        executableContext = other.executableContext,
        memberContext = other.memberContext,
        instanceType = other.instanceType,
        builder = other.builder,
        _scopeInfo = other._scopeInfo,
        _scopeInfoMember = other._scopeInfoMember,
        _localsMap = other._localsMap,
        _nativeData = other._nativeData,
        _interceptorData = other._interceptorData,
        activationVariables = other.activationVariables,
        cachedTypeOfThis = other.cachedTypeOfThis,
        cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables;

  /// Sets up the scope to use the scope and locals from [member].
  void setupScope(MemberEntity member) {
    _scopeInfoMember = member;
    if (member != null) {
      _scopeInfo = _closedWorld.closureDataLookup.getScopeInfo(member);
      _localsMap = _globalLocalsMap.getLocalsMap(member);
    } else {
      _scopeInfo = null;
      _localsMap = null;
    }
  }

  /// Returns the member that currently defines the scope as setup in
  /// [setupScope].
  MemberEntity get scopeMember => _scopeInfoMember;

  Local get thisLocal => _scopeInfo.thisLocal;

  /// Redirects accesses from element [from] to element [to]. The [to] element
  /// must be a boxed variable or a variable that is stored in a closure-field.
  void redirectElement(Local from, FieldEntity to) {
    assert(redirectionMapping[from] == null);
    redirectionMapping[from] = to;
    assert(isStoredInClosureField(from) || isBoxed(from));
  }

  HInstruction createBox(SourceInformation sourceInformation) {
    HInstruction box = HCreateBox(_abstractValueDomain.nonNullType)
      ..sourceInformation = sourceInformation;
    builder.add(box);
    return box;
  }

  /// If the scope (function or loop) [node] has captured variables then this
  /// method creates a box and sets up the redirections.
  void enterScope(
      CapturedScope closureInfo, SourceInformation sourceInformation,
      {bool forGenerativeConstructorBody = false, HInstruction inlinedBox}) {
    // See if any variable in the top-scope of the function is captured. If yes
    // we need to create a box-object.
    if (!closureInfo.requiresContextBox) return;
    HInstruction box;
    // The scope has captured variables.
    if (forGenerativeConstructorBody) {
      // The box is passed as a parameter to a generative constructor body.
      box = inlinedBox ??
          builder.addParameter(
              closureInfo.contextBox, _abstractValueDomain.nonNullType);
    } else {
      box = createBox(sourceInformation);
    }
    // Add the box to the known locals.
    directLocals[closureInfo.contextBox] = box;
    // Make sure that accesses to the boxed locals go into the box. We also
    // need to make sure that parameters are copied into the box if necessary.
    closureInfo.forEachBoxedVariable(_localsMap, (Local from, FieldEntity to) {
      // The [from] can only be a parameter for function-scopes and not
      // loop scopes.
      JLocal jFrom = from;
      bool isParameter = jFrom.isRegularParameter;
      assert(isParameter != null);
      if (isParameter && !forGenerativeConstructorBody) {
        // Now that the redirection is set up, the update to the local will
        // write the parameter value into the box.
        // Store the captured parameter in the box. Get the current value
        // before we put the redirection in place.
        // We don't need to update the local for a generative
        // constructor body, because it receives a box that already
        // contains the updates as the last parameter.
        HInstruction instruction = readLocal(from);
        redirectElement(from, to);
        updateLocal(from, instruction);
      } else {
        redirectElement(from, to);
      }
    });
  }

  /// Replaces the current box with a new box and copies over the given list
  /// of elements from the old box into the new box.
  void updateCaptureBox(Local currentBox, List<Local> toBeCopiedElements,
      SourceInformation sourceInformation) {
    // Create a new box and copy over the values from the old box into the
    // new one.
    HInstruction oldBox = readLocal(currentBox);
    HInstruction newBox = createBox(sourceInformation);
    for (Local boxedVariable in toBeCopiedElements) {
      // [readLocal] uses the [currentBox] to find its box. By replacing it
      // behind its back we can still get to the old values.
      updateLocal(currentBox, oldBox);
      HInstruction oldValue = readLocal(boxedVariable);
      updateLocal(currentBox, newBox);
      updateLocal(boxedVariable, oldValue);
    }
    updateLocal(currentBox, newBox);
  }

  /// Documentation wanted -- johnniwinther
  ///
  /// Invariant: [function] must be an implementation element.
  void startFunction(MemberEntity element, Map<Local, AbstractValue> parameters,
      Set<Local> elidedParameters, SourceInformation sourceInformation,
      {bool isGenerativeConstructorBody}) {
    setupScope(element);

    CapturedScope scopeData =
        _closedWorld.closureDataLookup.getCapturedScope(element);

    parameters.forEach((Local local, AbstractValue typeMask) {
      if (isGenerativeConstructorBody) {
        if (scopeData.isBoxedVariable(_localsMap, local)) {
          // The parameter will be a field in the box passed as the
          // last parameter. So no need to have it.
          return;
        }
      }
      HInstruction parameter = builder.addParameter(local, typeMask,
          isElided: elidedParameters.contains(local));
      builder.parameters[local] = parameter;
      directLocals[local] = parameter;
    });
    builder.elidedParameters = elidedParameters;

    enterScope(scopeData, sourceInformation,
        forGenerativeConstructorBody: isGenerativeConstructorBody);

    // When we remove the element model, we can just use the first check
    // (because the underlying elements won't all be *both* ScopeInfos and
    // ClosureRepresentationInfos).
    ScopeInfo scopeInfo = _scopeInfo;
    if (scopeInfo is ClosureRepresentationInfo && scopeInfo.isClosure) {
      ClosureRepresentationInfo closureData = scopeInfo;
      // If the freeVariableMapping is not empty, then this function was a
      // nested closure that captures variables. Redirect the captured
      // variables to fields in the closure.
      closureData.forEachFreeVariable(_localsMap, (Local from, FieldEntity to) {
        redirectElement(from, to);
      });
      // Inside closure redirect references to itself to [:this:].
      HThis thisInstruction =
          HThis(closureData.thisLocal, _abstractValueDomain.nonNullType);
      builder.graph.thisInstruction = thisInstruction;
      builder.graph.entry.addAtEntry(thisInstruction);
      updateLocal(closureData.getClosureEntity(_localsMap), thisInstruction);
    } else if (element.isInstanceMember) {
      // Once closures have been mapped to classes their instance members might
      // not have any thisElement if the closure was created inside a static
      // context.
      HThis thisInstruction = HThis(scopeInfo.thisLocal, getTypeOfThis());
      builder.graph.thisInstruction = thisInstruction;
      builder.graph.entry.addAtEntry(thisInstruction);
      directLocals[scopeInfo.thisLocal] = thisInstruction;
    }

    // If this method is an intercepted method, add the extra
    // parameter to it, that is the actual receiver for intercepted
    // classes, or the same as [:this:] for non-intercepted classes.
    ClassEntity cls = element.enclosingClass;

    // When the class extends a native class, the instance is pre-constructed
    // and passed to the generative constructor factory function as a parameter.
    // Instead of allocating and initializing the object, the constructor
    // 'upgrades' the native subclass object by initializing the Dart fields.
    bool isNativeUpgradeFactory = element is ConstructorEntity &&
        element.isGenerativeConstructor &&
        _nativeData.isNativeOrExtendsNative(cls);
    if (_interceptorData.isInterceptedMethod(element)) {
      SyntheticLocal parameter = createLocal('receiver');
      HParameterValue value = HParameterValue(parameter, getTypeOfThis());
      builder.graph.explicitReceiverParameter = value;
      builder.graph.entry.addAfter(directLocals[scopeInfo.thisLocal], value);
      if (builder.lastAddedParameter == null) {
        // If this is the first parameter inserted, make sure it stays first.
        builder.lastAddedParameter = value;
      }
      directLocals[scopeInfo.thisLocal] = value;
    } else if (isNativeUpgradeFactory) {
      SyntheticLocal parameter = createLocal('receiver');
      // Unlike `this`, receiver is nullable since direct calls to generative
      // constructor call the constructor with `null`.
      HParameterValue value = HParameterValue(
          parameter, _closedWorld.abstractValueDomain.createNullableExact(cls));
      builder.graph.explicitReceiverParameter = value;
      builder.graph.entry.addAtEntry(value);
      if (builder.lastAddedParameter == null) {
        // If this is the first parameter inserted, make sure it stays first.
        builder.lastAddedParameter = value;
      }
    }
  }

  /// Returns true if the local can be accessed directly. Boxed variables or
  /// captured variables that are stored in the closure-field return [:false:].
  bool isAccessedDirectly(Local local) {
    assert(local != null);
    return !redirectionMapping.containsKey(local) &&
        !_scopeInfo.localIsUsedInTryOrSync(_localsMap, local);
  }

  bool isStoredInClosureField(Local local) {
    assert(local != null);
    if (isAccessedDirectly(local)) return false;
    if (_scopeInfo is! ClosureRepresentationInfo) return false;
    FieldEntity redirectTarget = redirectionMapping[local];
    if (redirectTarget == null) return false;
    return redirectTarget is JClosureField;
  }

  bool isBoxed(Local local) {
    if (isAccessedDirectly(local)) return false;
    if (isStoredInClosureField(local)) return false;
    return redirectionMapping.containsKey(local);
  }

  bool _isUsedInTryOrGenerator(Local local) {
    return _scopeInfo.localIsUsedInTryOrSync(_localsMap, local);
  }

  /// Returns an [HInstruction] for the given element. If the element is
  /// boxed or stored in a closure then the method generates code to retrieve
  /// the value.
  HInstruction readLocal(Local local, {SourceInformation sourceInformation}) {
    if (isAccessedDirectly(local)) {
      if (directLocals[local] == null) {
        if (local is TypeVariableLocal) {
          failedAt(
              CURRENT_ELEMENT_SPANNABLE,
              "Runtime type information not available for $local "
              "in ${directLocals.keys} for $executableContext.");
        } else {
          failedAt(
              local,
              "Cannot find value $local in ${directLocals.keys} for "
              "$executableContext.");
        }
      }
      HInstruction value = directLocals[local];
      if (sourceInformation != null) {
        value = HRef(value, sourceInformation);
        builder.add(value);
      }
      return value;
    } else if (isStoredInClosureField(local)) {
      ClosureRepresentationInfo closureData = _scopeInfo;
      FieldEntity redirect = redirectionMapping[local];
      HInstruction receiver =
          readLocal(closureData.getClosureEntity(_localsMap));
      AbstractValue type = local is BoxLocal
          ? _abstractValueDomain.nonNullType
          : getTypeOfCapturedVariable(redirect);
      HInstruction fieldGet =
          HFieldGet(redirect, receiver, type, sourceInformation);
      builder.add(fieldGet);
      return fieldGet;
    } else if (isBoxed(local)) {
      FieldEntity redirect = redirectionMapping[local];
      BoxLocal localBox;
      // In the function that declares the captured variable the box is
      // accessed as direct local. Inside the nested closure the box is
      // accessed through a closure-field.
      // Calling [readLocal] makes sure we generate the correct code to get
      // the box.
      if (redirect is JRecordField) {
        localBox = redirect.box;
      }
      assert(localBox != null);

      HInstruction box = readLocal(localBox);
      HInstruction lookup = HFieldGet(redirect, box,
          getTypeOfCapturedVariable(redirect), sourceInformation);
      builder.add(lookup);
      return lookup;
    } else {
      assert(_isUsedInTryOrGenerator(local));
      HLocalValue localValue = getLocal(local);
      HInstruction instruction = HLocalGet(local, localValue,
          _abstractValueDomain.dynamicType, sourceInformation);
      builder.add(instruction);
      return instruction;
    }
  }

  HInstruction readThis({SourceInformation sourceInformation}) {
    HInstruction res =
        readLocal(_scopeInfo.thisLocal, sourceInformation: sourceInformation);
    if (res.instructionType == null) {
      res.instructionType = getTypeOfThis();
    }
    return res;
  }

  HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) {
    // If the element is a parameter, we already have a
    // HParameterValue for it. We cannot create another one because
    // it could then have another name than the real parameter. And
    // the other one would not know it is just a copy of the real
    // parameter.
    if (builder.parameters.containsKey(local)) {
      return builder.parameters[local];
    }

    return activationVariables.putIfAbsent(local, () {
      HLocalValue localValue =
          HLocalValue(local, _abstractValueDomain.nonNullType)
            ..sourceInformation = sourceInformation;
      builder.graph.entry.addAtExit(localValue);
      return localValue;
    });
  }

  Local getTypeVariableAsLocal(TypeVariableType type) {
    return typeVariableLocals[type.element] ??= TypeVariableLocal(type.element);
  }

  /// Sets the [element] to [value]. If the element is boxed or stored in a
  /// closure then the method generates code to set the value.
  void updateLocal(Local local, HInstruction value,
      {SourceInformation sourceInformation}) {
    if (value is HRef) {
      HRef ref = value;
      value = ref.value;
    }
    assert(!isStoredInClosureField(local),
        "Local $local is stored in a closure field.");
    if (isAccessedDirectly(local)) {
      directLocals[local] = value;
    } else if (isBoxed(local)) {
      FieldEntity redirect = redirectionMapping[local];
      assert(redirect != null);
      BoxLocal localBox;
      if (redirect is JRecordField) {
        localBox = redirect.box;
      }
      assert(localBox != null);

      // The box itself could be captured, or be local. A local variable that
      // is captured will be boxed, but the box itself will be a local.
      // Inside the closure the box is stored in a closure-field and cannot
      // be accessed directly.
      HInstruction box = readLocal(localBox);
      builder.add(HFieldSet(_abstractValueDomain, redirect, box, value)
        ..sourceInformation = sourceInformation);
    } else {
      assert(_isUsedInTryOrGenerator(local));
      HLocalValue localValue = getLocal(local);
      builder.add(HLocalSet(_abstractValueDomain, local, localValue, value)
        ..sourceInformation = sourceInformation);
    }
  }

  /// This function, startLoop, must be called before visiting any children of
  /// the loop. In particular it needs to be called before executing the
  /// initializers.
  ///
  /// The [LocalsHandler] will make the boxes and updates at the right moment.
  /// The builder just needs to call [enterLoopBody] and [enterLoopUpdates]
  /// (for [ast.For] loops) at the correct places. For phi-handling
  /// [beginLoopHeader] and [endLoop] must also be called.
  ///
  /// The correct place for the box depends on the given loop. In most cases
  /// the box will be created when entering the loop-body: while, do-while, and
  /// for-in (assuming the call to [:next:] is inside the body) can always be
  /// constructed this way.
  ///
  /// Things are slightly more complicated for [ast.For] loops. If no declared
  /// loop variable is boxed then the loop-body approach works here too. If a
  /// loop-variable is boxed we need to introduce a new box for the
  /// loop-variable before we enter the initializer so that the initializer
  /// writes the values into the box. In any case we need to create the box
  /// before the condition since the condition could box the variable.
  /// Since the first box is created outside the actual loop we have a second
  /// location where a box is created: just before the updates. This is
  /// necessary since updates are considered to be part of the next iteration
  /// (and can again capture variables).
  ///
  /// For example the following Dart code prints 1 3 -- 3 4.
  ///
  ///     var fs = [];
  ///     for (var i = 0; i < 3; (f() { fs.add(f); print(i); i++; })()) {
  ///       i++;
  ///     }
  ///     print("--");
  ///     for (var i = 0; i < 2; i++) fs[i]();
  ///
  /// We solve this by emitting the following code (only for [ast.For] loops):
  ///  <Create box>    <== move the first box creation outside the loop.
  ///  <initializer>;
  ///  loop-entry:
  ///    if (!<condition>) goto loop-exit;
  ///    <body>
  ///    <update box>  // create a new box and copy the captured loop-variables.
  ///    <updates>
  ///    goto loop-entry;
  ///  loop-exit:
  void startLoop(
      CapturedLoopScope loopInfo, SourceInformation sourceInformation) {
    if (loopInfo.hasBoxedLoopVariables) {
      // If there are boxed loop variables then we set up the box and
      // redirections already now. This way the initializer can write its
      // values into the box.
      // For other loops the box will be created when entering the body.
      enterScope(loopInfo, sourceInformation);
    }
  }

  /// Create phis at the loop entry for local variables (ready for the values
  /// from the back edge).  Populate the phis with the current values.
  void beginLoopHeader(HBasicBlock loopEntry) {
    // Create a copy because we modify the map while iterating over it.
    Map<Local, HInstruction> savedDirectLocals =
        Map<Local, HInstruction>.from(directLocals);

    // Create phis for all elements in the definitions environment.
    savedDirectLocals.forEach((Local local, HInstruction instruction) {
      if (isAccessedDirectly(local)) {
        // We know 'this' cannot be modified.
        if (local != _scopeInfo.thisLocal) {
          HPhi phi = HPhi.singleInput(
              local, instruction, _abstractValueDomain.dynamicType);
          loopEntry.addPhi(phi);
          directLocals[local] = phi;
        } else {
          directLocals[local] = instruction;
        }
      }
    });
  }

  void enterLoopBody(
      CapturedLoopScope loopInfo, SourceInformation sourceInformation) {
    // If there are no declared boxed loop variables then we did not create the
    // box before the initializer and we have to create the box now.
    if (!loopInfo.hasBoxedLoopVariables) {
      enterScope(loopInfo, sourceInformation);
    }
  }

  void enterLoopUpdates(
      CapturedLoopScope loopInfo, SourceInformation sourceInformation) {
    // If there are declared boxed loop variables then the updates might have
    // access to the box and we must switch to a new box before executing the
    // updates.
    // In all other cases a new box will be created when entering the body of
    // the next iteration.
    if (loopInfo.hasBoxedLoopVariables) {
      updateCaptureBox(loopInfo.contextBox,
          loopInfo.getBoxedLoopVariables(_localsMap), sourceInformation);
    }
  }

  /// Goes through the phis created in beginLoopHeader entry and adds the
  /// input from the back edge (from the current value of directLocals) to them.
  void endLoop(HBasicBlock loopEntry) {
    // If the loop has an aborting body, we don't update the loop
    // phis.
    if (loopEntry.predecessors.length == 1) return;
    loopEntry.forEachPhi((HPhi phi) {
      Local element = phi.sourceElement;
      HInstruction postLoopDefinition = directLocals[element];
      phi.addInput(postLoopDefinition);
    });
  }

  /// Merge [otherLocals] into this locals handler, creating phi-nodes when
  /// there is a conflict.
  /// If a phi node is necessary, it will use this handler's instruction as the
  /// first input, and the otherLocals instruction as the second.
  void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) {
    // If an element is in one map but not the other we can safely
    // ignore it. It means that a variable was declared in the
    // block. Since variable declarations are scoped the declared
    // variable cannot be alive outside the block. Note: this is only
    // true for nodes where we do joins.
    Map<Local, HInstruction> joinedLocals = {};
    otherLocals.directLocals.forEach((Local local, HInstruction instruction) {
      // We know 'this' cannot be modified.
      if (local == _scopeInfo.thisLocal) {
        assert(directLocals[local] == instruction);
        joinedLocals[local] = instruction;
      } else {
        HInstruction mine = directLocals[local];
        if (mine == null) return;
        if (identical(instruction, mine)) {
          joinedLocals[local] = instruction;
        } else {
          HInstruction phi = HPhi.manyInputs(
              local,
              <HInstruction>[mine, instruction],
              _abstractValueDomain.dynamicType);
          joinBlock.addPhi(phi);
          joinedLocals[local] = phi;
        }
      }
    });
    directLocals = joinedLocals;
  }

  /// When control flow merges, this method can be used to merge several
  /// localsHandlers into a new one using phis.  The new localsHandler is
  /// returned.  Unless it is also in the list, the current localsHandler is not
  /// used for its values, only for its declared variables. This is a way to
  /// exclude local values from the result when they are no longer in scope.
  LocalsHandler mergeMultiple(
      List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) {
    assert(localsHandlers.length > 0);
    if (localsHandlers.length == 1) return localsHandlers.single;
    Map<Local, HInstruction> joinedLocals = {};
    HInstruction thisValue = null;
    directLocals.forEach((Local local, HInstruction instruction) {
      if (local != _scopeInfo.thisLocal) {
        HPhi phi = HPhi.noInputs(local, _abstractValueDomain.dynamicType);
        joinedLocals[local] = phi;
        joinBlock.addPhi(phi);
      } else {
        // We know that "this" never changes, if it's there.
        // Save it for later. While merging, there is no phi for "this",
        // so we don't have to special case it in the merge loop.
        thisValue = instruction;
      }
    });
    for (LocalsHandler handler in localsHandlers) {
      handler.directLocals.forEach((Local local, HInstruction instruction) {
        HPhi phi = joinedLocals[local];
        if (phi != null) {
          phi.addInput(instruction);
        }
      });
    }
    if (thisValue != null) {
      // If there was a "this" for the scope, add it to the new locals.
      joinedLocals[_scopeInfo.thisLocal] = thisValue;
    }

    // Remove locals that are not in all handlers.
    directLocals = {};
    joinedLocals.forEach((Local local, HInstruction instruction) {
      if (local != _scopeInfo.thisLocal &&
          instruction.inputs.length != localsHandlers.length) {
        joinBlock.removePhi(instruction);
      } else {
        directLocals[local] = instruction;
      }
    });
    return this;
  }

  AbstractValue cachedTypeOfThis;

  AbstractValue getTypeOfThis() {
    AbstractValue result = cachedTypeOfThis;
    if (result == null) {
      ThisLocal local = _scopeInfo.thisLocal;
      ClassEntity cls = local.enclosingClass;
      if (_closedWorld.isUsedAsMixin(cls)) {
        // If the enclosing class is used as a mixin, [:this:] can be
        // of the class that mixins the enclosing class. These two
        // classes do not have a subclass relationship, so, for
        // simplicity, we mark the type as an interface type.
        result = _abstractValueDomain.createNonNullSubtype(cls);
      } else {
        result = _abstractValueDomain.createNonNullSubclass(cls);
      }
      cachedTypeOfThis = result;
    }
    return result;
  }

  Map<FieldEntity, AbstractValue> cachedTypesOfCapturedVariables = {};

  AbstractValue getTypeOfCapturedVariable(FieldEntity element) {
    return cachedTypesOfCapturedVariables.putIfAbsent(element, () {
      return AbstractValueFactory.inferredTypeForMember(
          element, _globalInferenceResults);
    });
  }

  /// Variables stored in the current activation. These variables are
  /// being updated in try/catch blocks, and should be
  /// accessed indirectly through [HLocalGet] and [HLocalSet].
  Map<Local, HLocalValue> activationVariables = {};

  SyntheticLocal createLocal(String name) {
    return SyntheticLocal(name, executableContext, memberContext);
  }
}

/// A synthetic local variable only used with the SSA graph.
///
/// For instance used for holding return value of function or the exception of a
/// try-catch statement.
class SyntheticLocal extends Local {
  @override
  final String name;
  final Entity executableContext;
  final MemberEntity memberContext;

  // Avoid slow Object.hashCode.
  @override
  final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30);
  static int _nextHashCode = 0;

  SyntheticLocal(this.name, this.executableContext, this.memberContext);

  @override
  toString() => 'SyntheticLocal($name)';
}
