| Index: pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
|
| diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
|
| index 8999b560ac409ab9ed3bfebc9346aa88dbe8a664..02b963eb6b3231088104bb2d22cc68af3c6c179b 100644
|
| --- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
|
| +++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
|
| @@ -4,7 +4,6 @@
|
| library dart2js.ir_nodes;
|
|
|
| import 'dart:collection';
|
| -import 'cps_fragment.dart' show CpsFragment;
|
| import '../constants/values.dart' as values;
|
| import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType;
|
| import '../elements/elements.dart';
|
| @@ -204,7 +203,18 @@ class EffectiveUseIterable extends IterableBase<Reference<Primitive>> {
|
| ///
|
| /// All primitives except [Parameter] must be bound by a [LetPrim].
|
| abstract class Primitive extends Variable<Primitive> {
|
| - Primitive() : super(null);
|
| + /// The [VariableElement] or [ParameterElement] from which the primitive
|
| + /// binding originated.
|
| + Entity hint;
|
| +
|
| + /// Use the given element as a hint for naming this primitive.
|
| + ///
|
| + /// Has no effect if this primitive already has a non-null [element].
|
| + void useElementAsHint(Entity hint) {
|
| + if (this.hint == null) {
|
| + this.hint = hint;
|
| + }
|
| + }
|
|
|
| /// True if this primitive has a value that can be used by other expressions.
|
| bool get hasValue;
|
| @@ -285,23 +295,6 @@ abstract class Primitive extends Variable<Primitive> {
|
| newDefinition.parent = let;
|
| newDefinition.useElementAsHint(hint);
|
| }
|
| -
|
| - /// Replaces this definition with a CPS fragment (a term with a hole in it),
|
| - /// given the value to replace the uses of the definition with.
|
| - ///
|
| - /// This can be thought of as substituting:
|
| - ///
|
| - /// let x = OLD in BODY
|
| - /// ==>
|
| - /// FRAGMENT[BODY{newPrimitive/x}]
|
| - void replaceWithFragment(CpsFragment fragment, Primitive newPrimitive) {
|
| - assert(this is! Parameter);
|
| - replaceUsesWith(newPrimitive);
|
| - destroy();
|
| - LetPrim let = parent;
|
| - fragment.insertBelow(let);
|
| - let.remove();
|
| - }
|
| }
|
|
|
| /// A primitive that is generally not safe for elimination, but may be marked
|
| @@ -471,43 +464,6 @@ class LetMutable extends InteriorExpression {
|
| }
|
| }
|
|
|
| -enum CallingConvention {
|
| - /// JS receiver is the Dart receiver, there are no extra arguments.
|
| - ///
|
| - /// This includes cases (e.g., static functions, constructors) where there
|
| - /// is no receiver.
|
| - ///
|
| - /// For example: `foo.bar$1(x)`
|
| - Normal,
|
| -
|
| - /// JS receiver is an interceptor, the first argument is the Dart receiver.
|
| - ///
|
| - /// For example: `getInterceptor(foo).bar$1(foo, x)`
|
| - Intercepted,
|
| -
|
| - /// JS receiver is the Dart receiver, the first argument is a dummy value.
|
| - ///
|
| - /// For example: `foo.bar$1(0, x)`
|
| - DummyIntercepted,
|
| -
|
| - /// JS receiver is the Dart receiver, there are no extra arguments.
|
| - ///
|
| - /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)`
|
| - OneShotIntercepted,
|
| -}
|
| -
|
| -/// Base class of function invocations.
|
| -///
|
| -/// This class defines the common interface of function invocations.
|
| -abstract class InvocationPrimitive extends UnsafePrimitive {
|
| - Reference<Primitive> get receiver => null;
|
| - List<Reference<Primitive>> get arguments;
|
| - SourceInformation get sourceInformation;
|
| -
|
| - Reference<Primitive> get dartReceiverReference => null;
|
| - CallingConvention get callingConvention => CallingConvention.Normal;
|
| -}
|
| -
|
| /// Invoke a static function.
|
| ///
|
| /// All optional arguments declared by [target] are passed in explicitly, and
|
| @@ -516,7 +472,7 @@ abstract class InvocationPrimitive extends UnsafePrimitive {
|
| /// Discussion:
|
| /// All information in the [selector] is technically redundant; it will likely
|
| /// be removed.
|
| -class InvokeStatic extends InvocationPrimitive {
|
| +class InvokeStatic extends UnsafePrimitive {
|
| final FunctionElement target;
|
| final Selector selector;
|
| final List<Reference<Primitive>> arguments;
|
| @@ -542,6 +498,28 @@ class InvokeStatic extends InvocationPrimitive {
|
| }
|
| }
|
|
|
| +enum CallingConvention {
|
| + /// JS receiver is the Dart receiver, there are no extra arguments.
|
| + ///
|
| + /// For example: `foo.bar$1(x)`
|
| + Normal,
|
| +
|
| + /// JS receiver is an interceptor, the first argument is the Dart receiver.
|
| + ///
|
| + /// For example: `getInterceptor(foo).bar$1(foo, x)`
|
| + Intercepted,
|
| +
|
| + /// JS receiver is the Dart receiver, the first argument is a dummy value.
|
| + ///
|
| + /// For example: `foo.bar$1(0, x)`
|
| + DummyIntercepted,
|
| +
|
| + /// JS receiver is the Dart receiver, there are no extra arguments.
|
| + ///
|
| + /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)`
|
| + OneShotIntercepted,
|
| +}
|
| +
|
| /// Invoke a method on an object.
|
| ///
|
| /// This includes getters, setters, operators, and index getter/setters.
|
| @@ -551,7 +529,7 @@ class InvokeStatic extends InvocationPrimitive {
|
| ///
|
| /// The [selector] records the names of named arguments. The value of named
|
| /// arguments occur at the end of the [arguments] list, in normalized order.
|
| -class InvokeMethod extends InvocationPrimitive {
|
| +class InvokeMethod extends UnsafePrimitive {
|
| Reference<Primitive> receiver;
|
| Selector selector;
|
| TypeMask mask;
|
| @@ -628,7 +606,7 @@ class InvokeMethod extends InvocationPrimitive {
|
| ///
|
| /// All optional arguments declared by [target] are passed in explicitly, and
|
| /// occur at the end of [arguments] list, in normalized order.
|
| -class InvokeMethodDirectly extends InvocationPrimitive {
|
| +class InvokeMethodDirectly extends UnsafePrimitive {
|
| Reference<Primitive> receiver;
|
| final FunctionElement target;
|
| final Selector selector;
|
| @@ -686,7 +664,7 @@ class InvokeMethodDirectly extends InvocationPrimitive {
|
| ///
|
| /// Note that [InvokeConstructor] does it itself allocate an object.
|
| /// The invoked constructor will do that using [CreateInstance].
|
| -class InvokeConstructor extends InvocationPrimitive {
|
| +class InvokeConstructor extends UnsafePrimitive {
|
| final DartType dartType;
|
| final ConstructorElement target;
|
| final List<Reference<Primitive>> arguments;
|
| @@ -1710,24 +1688,13 @@ abstract class Variable<T extends Variable<T>> extends Definition<T> {
|
| ///
|
| /// Is `null` until initialized by type propagation.
|
| TypeMask type;
|
| -
|
| - /// The [VariableElement] or [ParameterElement] from which the variable
|
| - /// binding originated.
|
| - Entity hint;
|
| -
|
| - Variable(this.hint);
|
| -
|
| - /// Use the given element as a hint for naming this primitive.
|
| - ///
|
| - /// Has no effect if this primitive already has a non-null [element].
|
| - void useElementAsHint(Entity hint) {
|
| - this.hint ??= hint;
|
| - }
|
| }
|
|
|
| /// Identifies a mutable variable.
|
| class MutableVariable extends Variable<MutableVariable> {
|
| - MutableVariable(Entity hint) : super(hint);
|
| + Entity hint;
|
| +
|
| + MutableVariable(this.hint);
|
|
|
| accept(Visitor v) => v.visitMutableVariable(this);
|
|
|
| @@ -1907,23 +1874,23 @@ abstract class Visitor<T> {
|
| T visitLetHandler(LetHandler node);
|
| T visitLetMutable(LetMutable node);
|
| T visitInvokeContinuation(InvokeContinuation node);
|
| - T visitThrow(Throw node);
|
| - T visitRethrow(Rethrow node);
|
| - T visitBranch(Branch node);
|
| - T visitUnreachable(Unreachable node);
|
| -
|
| - // Definitions.
|
| T visitInvokeStatic(InvokeStatic node);
|
| T visitInvokeMethod(InvokeMethod node);
|
| T visitInvokeMethodDirectly(InvokeMethodDirectly node);
|
| T visitInvokeConstructor(InvokeConstructor node);
|
| + T visitThrow(Throw node);
|
| + T visitRethrow(Rethrow node);
|
| + T visitBranch(Branch node);
|
| T visitTypeCast(TypeCast node);
|
| T visitSetMutable(SetMutable node);
|
| T visitSetStatic(SetStatic node);
|
| - T visitSetField(SetField node);
|
| T visitGetLazyStatic(GetLazyStatic node);
|
| + T visitSetField(SetField node);
|
| + T visitUnreachable(Unreachable node);
|
| T visitAwait(Await node);
|
| T visitYield(Yield node);
|
| +
|
| + // Definitions.
|
| T visitLiteralList(LiteralList node);
|
| T visitLiteralMap(LiteralMap node);
|
| T visitConstant(Constant node);
|
| @@ -2425,373 +2392,3 @@ class RemovalVisitor extends TrampolineRecursiveVisitor {
|
| (new RemovalVisitor()).visit(node);
|
| }
|
| }
|
| -
|
| -/// A visitor to copy instances of [Definition] or its subclasses, except for
|
| -/// instances of [Continuation].
|
| -///
|
| -/// The visitor maintains a map from original definitions to their copies.
|
| -/// When the [copy] method is called for a non-Continuation definition,
|
| -/// a copy is created, added to the map and returned as the result. Copying a
|
| -/// definition assumes that the definitions of all references have already
|
| -/// been copied by the same visitor.
|
| -class DefinitionCopyingVisitor extends Visitor<Definition> {
|
| - Map<Definition, Definition> _copies = <Definition, Definition>{};
|
| -
|
| - /// Put a copy into the map.
|
| - ///
|
| - /// This method should be used instead of directly adding copies to the map.
|
| - Definition putCopy(Definition original, Definition copy) {
|
| - if (copy is Variable) {
|
| - Variable originalVariable = original;
|
| - copy.type = originalVariable.type;
|
| - copy.hint = originalVariable.hint;
|
| - }
|
| - return _copies[original] = copy;
|
| - }
|
| -
|
| - /// Get the copy of a [Reference]'s definition from the map.
|
| - Definition getCopy(Reference reference) => _copies[reference.definition];
|
| -
|
| - /// Map a list of [Reference]s to the list of their definition's copies.
|
| - List<Definition> getList(List<Reference> list) => list.map(getCopy).toList();
|
| -
|
| - /// Copy a non-[Continuation] [Definition].
|
| - Definition copy(Definition node) {
|
| - assert (node is! Continuation);
|
| - return putCopy(node, visit(node));
|
| - }
|
| -
|
| - Definition visit(Node node) => node.accept(this);
|
| -
|
| - Definition visitFunctionDefinition(FunctionDefinition node) {}
|
| - Definition visitLetPrim(LetPrim node) {}
|
| - Definition visitLetCont(LetCont node) {}
|
| - Definition visitLetHandler(LetHandler node) {}
|
| - Definition visitLetMutable(LetMutable node) {}
|
| - Definition visitInvokeContinuation(InvokeContinuation node) {}
|
| - Definition visitThrow(Throw node) {}
|
| - Definition visitRethrow(Rethrow node) {}
|
| - Definition visitBranch(Branch node) {}
|
| - Definition visitUnreachable(Unreachable node) {}
|
| - Definition visitContinuation(Continuation node) {}
|
| -
|
| - Definition visitInvokeStatic(InvokeStatic node) {
|
| - return new InvokeStatic(node.target, node.selector, getList(node.arguments),
|
| - node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitInvokeMethod(InvokeMethod node) {
|
| - return new InvokeMethod(getCopy(node.receiver), node.selector, node.mask,
|
| - getList(node.arguments),
|
| - node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitInvokeMethodDirectly(InvokeMethodDirectly node) {
|
| - return new InvokeMethodDirectly(getCopy(node.receiver), node.target,
|
| - node.selector,
|
| - getList(node.arguments),
|
| - node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitInvokeConstructor(InvokeConstructor node) {
|
| - return new InvokeConstructor(node.dartType, node.target, node.selector,
|
| - getList(node.arguments),
|
| - node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitTypeCast(TypeCast node) {
|
| - return new TypeCast(getCopy(node.value), node.dartType,
|
| - getList(node.typeArguments));
|
| - }
|
| -
|
| - Definition visitSetMutable(SetMutable node) {
|
| - return new SetMutable(getCopy(node.variable), getCopy(node.value));
|
| - }
|
| -
|
| - Definition visitSetStatic(SetStatic node) {
|
| - return new SetStatic(node.element, getCopy(node.value),
|
| - node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitSetField(SetField node) {
|
| - return new SetField(getCopy(node.object), node.field, getCopy(node.value));
|
| - }
|
| -
|
| - Definition visitGetLazyStatic(GetLazyStatic node) {
|
| - return new GetLazyStatic(node.element, node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitAwait(Await node) {
|
| - return new Await(getCopy(node.input));
|
| - }
|
| -
|
| - Definition visitYield(Yield node) {
|
| - return new Yield(getCopy(node.input), node.hasStar);
|
| - }
|
| -
|
| - Definition visitLiteralList(LiteralList node) {
|
| - return new LiteralList(node.dartType, getList(node.values));
|
| - }
|
| -
|
| - Definition visitLiteralMap(LiteralMap node) {
|
| - List<LiteralMapEntry> entries = node.entries.map((LiteralMapEntry entry) {
|
| - return new LiteralMapEntry(getCopy(entry.key), getCopy(entry.value));
|
| - }).toList();
|
| - return new LiteralMap(node.dartType, entries);
|
| - }
|
| -
|
| - Definition visitConstant(Constant node) {
|
| - return new Constant(node.value, sourceInformation: node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitGetMutable(GetMutable node) {
|
| - return new GetMutable(getCopy(node.variable));
|
| - }
|
| -
|
| - Definition visitParameter(Parameter node) {
|
| - return new Parameter(node.hint);
|
| - }
|
| -
|
| - Definition visitMutableVariable(MutableVariable node) {
|
| - return new MutableVariable(node.hint);
|
| - }
|
| -
|
| - Definition visitGetStatic(GetStatic node) {
|
| - return new GetStatic(node.element, node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitInterceptor(Interceptor node) {
|
| - return new Interceptor(getCopy(node.input), node.sourceInformation)
|
| - ..interceptedClasses.addAll(node.interceptedClasses);
|
| - }
|
| -
|
| - Definition visitCreateInstance(CreateInstance node) {
|
| - return new CreateInstance(node.classElement, getList(node.arguments),
|
| - getList(node.typeInformation),
|
| - node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitGetField(GetField node) {
|
| - return new GetField(getCopy(node.object), node.field);
|
| - }
|
| -
|
| - Definition visitCreateBox(CreateBox node) {
|
| - return new CreateBox();
|
| - }
|
| -
|
| - Definition visitReifyRuntimeType(ReifyRuntimeType node) {
|
| - return new ReifyRuntimeType(getCopy(node.value), node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitReadTypeVariable(ReadTypeVariable node) {
|
| - return new ReadTypeVariable(node.variable, getCopy(node.target),
|
| - node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitTypeExpression(TypeExpression node) {
|
| - return new TypeExpression(node.dartType, getList(node.arguments));
|
| - }
|
| -
|
| - Definition visitCreateInvocationMirror(CreateInvocationMirror node) {
|
| - return new CreateInvocationMirror(node.selector, getList(node.arguments));
|
| - }
|
| -
|
| - Definition visitTypeTest(TypeTest node) {
|
| - return new TypeTest(getCopy(node.value), node.dartType,
|
| - getList(node.typeArguments));
|
| - }
|
| -
|
| - Definition visitTypeTestViaFlag(TypeTestViaFlag node) {
|
| - return new TypeTestViaFlag(getCopy(node.interceptor), node.dartType);
|
| - }
|
| -
|
| - Definition visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
|
| - return new ApplyBuiltinOperator(node.operator, getList(node.arguments),
|
| - node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
|
| - return new ApplyBuiltinMethod(node.method, getCopy(node.receiver),
|
| - getList(node.arguments),
|
| - node.sourceInformation,
|
| - receiverIsNotNull: node.receiverIsNotNull);
|
| - }
|
| -
|
| - Definition visitGetLength(GetLength node) {
|
| - return new GetLength(getCopy(node.object));
|
| - }
|
| -
|
| - Definition visitGetIndex(GetIndex node) {
|
| - return new GetIndex(getCopy(node.object), getCopy(node.index));
|
| - }
|
| -
|
| - Definition visitSetIndex(SetIndex node) {
|
| - return new SetIndex(getCopy(node.object), getCopy(node.index),
|
| - getCopy(node.value));
|
| - }
|
| -
|
| - Definition visitRefinement(Refinement node) {
|
| - return new Refinement(getCopy(node.value), node.refineType);
|
| - }
|
| -
|
| - Definition visitBoundsCheck(BoundsCheck node) {
|
| - if (node.hasNoChecks) {
|
| - return new BoundsCheck.noCheck(getCopy(node.object),
|
| - node.sourceInformation);
|
| - } else {
|
| - return new BoundsCheck(getCopy(node.object), getCopy(node.index),
|
| - getCopy(node.length),
|
| - node.checks,
|
| - node.sourceInformation);
|
| - }
|
| - }
|
| -
|
| - Definition visitNullCheck(NullCheck node) {
|
| - return new NullCheck(getCopy(node.value), node.sourceInformation);
|
| - }
|
| -
|
| - Definition visitForeignCode(ForeignCode node) {
|
| - return new ForeignCode(node.codeTemplate, node.type,
|
| - getList(node.arguments),
|
| - node.nativeBehavior,
|
| - dependency: node.dependency);
|
| - }
|
| -}
|
| -
|
| -/// A trampolining visitor to copy [FunctionDefinition]s.
|
| -class CopyingVisitor extends TrampolineRecursiveVisitor {
|
| - // The visitor maintains a map from original continuations to their copies.
|
| - Map<Continuation, Continuation> _copies = <Continuation, Continuation>{};
|
| -
|
| - // The visitor uses an auxiliary visitor to copy definitions.
|
| - DefinitionCopyingVisitor _definitions = new DefinitionCopyingVisitor();
|
| -
|
| - // While copying a block, the state of the visitor is a 'linked list' of
|
| - // the expressions in the block's body, with a pointer to the last element
|
| - // of the list.
|
| - Expression _first = null;
|
| - Expression _current = null;
|
| -
|
| - void plug(Expression body) {
|
| - if (_first == null) {
|
| - _first = body;
|
| - } else {
|
| - assert(_current != null);
|
| - InteriorExpression interior = _current;
|
| - interior.body = body;
|
| - }
|
| - _current = body;
|
| - }
|
| -
|
| - // Continuations are added to the visitor's stack to be visited after copying
|
| - // the current block is finished. The stack action saves the current block,
|
| - // copies the continuation's body, sets the body on the copy of the
|
| - // continuation, and restores the current block.
|
| - //
|
| - // Note that continuations are added to the copy map before the stack action
|
| - // to visit them is performed.
|
| - void push(Continuation cont) {
|
| - assert(!cont.isReturnContinuation);
|
| - _stack.add(() {
|
| - Expression savedFirst = _first;
|
| - _first = _current = null;
|
| - _processBlock(cont.body);
|
| - _copies[cont].body = _first;
|
| - _first = savedFirst;
|
| - _current = null;
|
| - });
|
| - }
|
| -
|
| - FunctionDefinition copy(FunctionDefinition node) {
|
| - assert(_first == null && _current == null);
|
| - _first = _current = null;
|
| - // Definitions are copied where they are bound, before processing
|
| - // expressions in the scope of their binding.
|
| - Parameter thisParameter = node.thisParameter == null
|
| - ? null
|
| - : _definitions.copy(node.thisParameter);
|
| - List<Parameter> parameters =
|
| - node.parameters.map(_definitions.copy).toList();
|
| - // Though the return continuation's parameter does not have any uses,
|
| - // we still make a proper copy to ensure that hints, type, etc. are
|
| - // copied.
|
| - Parameter returnParameter =
|
| - _definitions.copy(node.returnContinuation.parameters.first);
|
| - Continuation returnContinuation = _copies[node.returnContinuation] =
|
| - new Continuation([returnParameter]);
|
| -
|
| - visit(node.body);
|
| - FunctionDefinition copy = new FunctionDefinition(node.element,
|
| - thisParameter,
|
| - parameters,
|
| - returnContinuation,
|
| - _first);
|
| - _first = _current = null;
|
| - return copy;
|
| - }
|
| -
|
| - Node visit(Node node) => node.accept(this);
|
| -
|
| - Expression traverseLetCont(LetCont node) {
|
| - // Continuations are copied where they are bound, before processing
|
| - // expressions in the scope of their binding.
|
| - List<Continuation> continuations = node.continuations.map((Continuation c) {
|
| - push(c);
|
| - return _copies[c] =
|
| - new Continuation(c.parameters.map(_definitions.copy).toList());
|
| - }).toList();
|
| - plug(new LetCont.many(continuations, null));
|
| - return node.body;
|
| - }
|
| -
|
| - Expression traverseLetHandler(LetHandler node) {
|
| - // Continuations are copied where they are bound, before processing
|
| - // expressions in the scope of their binding.
|
| - push(node.handler);
|
| - Continuation handler = _copies[node.handler] =
|
| - new Continuation(node.handler.parameters.map(_definitions.copy)
|
| - .toList());
|
| - plug(new LetHandler(handler, null));
|
| - return node.body;
|
| - }
|
| -
|
| - Expression traverseLetPrim(LetPrim node) {
|
| - plug(new LetPrim(_definitions.copy(node.primitive)));
|
| - return node.body;
|
| - }
|
| -
|
| - Expression traverseLetMutable(LetMutable node) {
|
| - plug(new LetMutable(_definitions.copy(node.variable),
|
| - _definitions.getCopy(node.value)));
|
| - return node.body;
|
| - }
|
| -
|
| - // Tail expressions do not have references, so we do not need to map them
|
| - // to their copies.
|
| - visitInvokeContinuation(InvokeContinuation node) {
|
| - plug(new InvokeContinuation(_copies[node.continuation.definition],
|
| - _definitions.getList(node.arguments),
|
| - isRecursive: node.isRecursive,
|
| - isEscapingTry: node.isEscapingTry,
|
| - sourceInformation: node.sourceInformation));
|
| - }
|
| -
|
| - Node visitThrow(Throw node) {
|
| - plug(new Throw(_definitions.getCopy(node.value)));
|
| - }
|
| -
|
| - Node visitRethrow(Rethrow node) {
|
| - plug(new Rethrow());
|
| - }
|
| -
|
| - Node visitBranch(Branch node) {
|
| - plug(new Branch.loose(_definitions.getCopy(node.condition),
|
| - _copies[node.trueContinuation.definition],
|
| - _copies[node.falseContinuation.definition])
|
| - ..isStrictCheck = node.isStrictCheck);
|
| - }
|
| -
|
| - Node visitUnreachable(Unreachable node) {
|
| - plug(new Unreachable());
|
| - }
|
| -}
|
|
|