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 0bb7ecc8ba9f92ff5dc96b30e8dd30a13980c28d..164663372e22cb8250b1c25be82a45353fa5b459 100644 |
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
@@ -28,6 +28,8 @@ abstract class Node { |
/// that can be obtained without side-effects, divergence, or throwing |
/// exceptions can be built using a [LetPrim]. |
abstract class Expression extends Node { |
+ InteriorNode get parent; // Only InteriorNodes may contain expressions. |
+ |
Expression plug(Expression expr) => throw 'impossible'; |
} |
@@ -357,10 +359,47 @@ class InvokeConstructor extends Expression implements Invoke { |
accept(Visitor visitor) => visitor.visitInvokeConstructor(this); |
} |
-// TODO(asgerf): Make a Primitive for "is" and an Expression for "as". |
+/// An "is" type test. |
+/// |
+/// Returns `true` if [value] not `null` and is an instance of [type]. |
+/// |
+/// [type] must not be the [Object], `dynamic` or [Null] types (though it might |
+/// be a type variable containing one of these types). This design is chosen |
+/// to simplify code generation for type tests. |
+class TypeTest extends Primitive { |
+ Reference<Primitive> value; |
+ final DartType type; |
-/// An "as" cast or an "is" check. |
-class TypeOperator extends Expression { |
+ /// If [type] is an [InterfaceType], this holds the internal representation of |
+ /// the type arguments to [type]. Since these may reference type variables |
+ /// from the enclosing class, they are not constant. |
+ /// |
+ /// If [type] is a [TypeVariableType], this is a singleton list with |
+ /// the internal representation of the type held in that type variable. |
+ /// |
+ /// Otherwise the list is empty. |
+ final List<Reference<Primitive>> typeArguments; |
+ |
+ TypeTest(Primitive value, |
+ this.type, |
+ List<Primitive> typeArguments) |
+ : this.value = new Reference<Primitive>(value), |
+ this.typeArguments = _referenceList(typeArguments); |
+ |
+ accept(Visitor visitor) => visitor.visitTypeTest(this); |
+} |
+ |
+/// An "as" type cast. |
+/// |
+/// If [value] is `null` or is an instance of [type], [continuation] is invoked |
+/// with [value] as argument. Otherwise, a [CastError] is thrown. |
+/// |
+/// Discussion: |
+/// The parameter to [continuation] is redundant since it will always equal |
+/// [value], which is typically in scope in the continuation. However, it might |
+/// simplify type propagation, since a better type can be computed for the |
+/// continuation parameter without needing flow-sensitive analysis. |
+class TypeCast extends Expression { |
Reference<Primitive> value; |
final DartType type; |
@@ -374,22 +413,16 @@ class TypeOperator extends Expression { |
/// Otherwise the list is empty. |
final List<Reference<Primitive>> typeArguments; |
final Reference<Continuation> continuation; |
- final bool isTypeTest; |
- TypeOperator(Primitive value, |
- this.type, |
- List<Primitive> typeArguments, |
- Continuation cont, |
- {bool this.isTypeTest}) |
+ TypeCast(Primitive value, |
+ this.type, |
+ List<Primitive> typeArguments, |
+ Continuation cont) |
: this.value = new Reference<Primitive>(value), |
this.typeArguments = _referenceList(typeArguments), |
- this.continuation = new Reference<Continuation>(cont) { |
- assert(isTypeTest != null); |
- } |
- |
- bool get isTypeCast => !isTypeTest; |
+ this.continuation = new Reference<Continuation>(cont); |
- accept(Visitor visitor) => visitor.visitTypeOperator(this); |
+ accept(Visitor visitor) => visitor.visitTypeCast(this); |
} |
/// Invoke [toString] on each argument and concatenate the results. |
@@ -439,6 +472,14 @@ class NonTailThrow extends Primitive { |
accept(Visitor visitor) => visitor.visitNonTailThrow(this); |
} |
+/// An expression that is known to be unreachable. |
+/// |
+/// This can be placed as the body of a call continuation, when the caller is |
+/// known never to invoke it, e.g. because the calling expression always throws. |
+class Unreachable extends Expression { |
+ accept(Visitor visitor) => visitor.visitUnreachable(this); |
+} |
+ |
/// Gets the value from a [MutableVariable]. |
/// |
/// [MutableVariable]s can be seen as ref cells that are not first-class |
@@ -495,6 +536,14 @@ class InvokeContinuation extends Expression { |
if (isRecursive) cont.isRecursive = true; |
} |
+ /// Build a one-argument InvokeContinuation using existing reference objects. |
+ /// |
+ /// This is useful for converting call continuations to local continuations. |
+ InvokeContinuation.fromCall(this.continuation, |
+ Reference<Primitive> argument) |
+ : arguments = <Reference<Primitive>>[argument], |
+ isRecursive = false; |
+ |
/// A continuation invocation whose target and arguments will be filled |
/// in later. |
/// |
@@ -875,11 +924,12 @@ abstract class Visitor<T> { |
T visitThrow(Throw node); |
T visitRethrow(Rethrow node); |
T visitBranch(Branch node); |
- T visitTypeOperator(TypeOperator node); |
+ T visitTypeCast(TypeCast node); |
T visitSetMutableVariable(SetMutableVariable node); |
T visitSetStatic(SetStatic node); |
T visitGetLazyStatic(GetLazyStatic node); |
T visitSetField(SetField node); |
+ T visitUnreachable(Unreachable node); |
// Definitions. |
T visitLiteralList(LiteralList node); |
@@ -901,6 +951,7 @@ abstract class Visitor<T> { |
T visitReadTypeVariable(ReadTypeVariable node); |
T visitTypeExpression(TypeExpression node); |
T visitCreateInvocationMirror(CreateInvocationMirror node); |
+ T visitTypeTest(TypeTest node); |
// Conditions. |
T visitIsTrue(IsTrue node); |
@@ -1018,14 +1069,21 @@ class RecursiveVisitor implements Visitor { |
visit(node.condition); |
} |
- processTypeOperator(TypeOperator node) {} |
- visitTypeOperator(TypeOperator node) { |
- processTypeOperator(node); |
+ processTypeCast(TypeCast node) {} |
+ visitTypeCast(TypeCast node) { |
+ processTypeCast(node); |
processReference(node.continuation); |
processReference(node.value); |
node.typeArguments.forEach(processReference); |
} |
+ processTypeTest(TypeTest node) {} |
+ visitTypeTest(TypeTest node) { |
+ processTypeTest(node); |
+ processReference(node.value); |
+ node.typeArguments.forEach(processReference); |
+ } |
+ |
processSetMutableVariable(SetMutableVariable node) {} |
visitSetMutableVariable(SetMutableVariable node) { |
processSetMutableVariable(node); |
@@ -1175,4 +1233,22 @@ class RecursiveVisitor implements Visitor { |
processCreateInvocationMirror(node); |
node.arguments.forEach(processReference); |
} |
+ |
+ processUnreachable(Unreachable node) {} |
+ visitUnreachable(Unreachable node) { |
+ processUnreachable(node); |
+ } |
+} |
+ |
+/// Visit a just-deleted subterm and unlink all [Reference]s in it. |
+class RemovalVisitor extends RecursiveVisitor { |
+ const RemovalVisitor(); |
+ |
+ processReference(Reference reference) { |
+ reference.unlink(); |
+ } |
+ |
+ static void remove(Node node) { |
+ (const RemovalVisitor()).visit(node); |
+ } |
} |