[dart2js] Generate new-rti SSA instructions for checks

There is no codegen yet so almost all code compiled with
--experiment-new-rti will crash the compiler.

Change-Id: Idf542646ac3629cb02a50d44c2a98abd156047ed
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106001
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 3d8a473..c3bbed6 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -4373,7 +4373,8 @@
 
   HAsCheck(HInstruction checked, HInstruction rti, this.isTypeError,
       AbstractValue type)
-      : super([rti, checked], type) {}
+      : assert(isTypeError != null),
+        super([rti, checked], type);
 
   // The type input is first to facilitate the `type.as(value)` codegen pattern.
   HInstruction get typeInput => inputs[0];
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 249121e..1a27e5b 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -1322,6 +1322,11 @@
     // convention, but is not a call on an interceptor.
     HInstruction value = node.inputs.last;
     if (_options.parameterCheckPolicy.isEmitted) {
+      if (_options.experimentNewRti) {
+        // TODO(sra): Implement inlining of setters with checks for new rti.
+        node.needsCheck = true;
+        return node;
+      }
       DartType type = _closedWorld.elementEnvironment.getFieldType(field);
       if (!type.treatAsRaw ||
           type.isTypeVariable ||
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index 95bfbb5..539261d 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -696,13 +696,13 @@
   @override
   visitLoadType(HLoadType node) {
     var inputs = node.inputs.map(temporaryId).join(', ');
-    return "LoadType: $inputs";
+    return "LoadType: ${node.typeExpression}  $inputs";
   }
 
   @override
   visitTypeEval(HTypeEval node) {
     var inputs = node.inputs.map(temporaryId).join(', ');
-    return "TypeEval: $inputs";
+    return "TypeEval: ${node.typeExpression}  $inputs";
   }
 
   @override
diff --git a/pkg/compiler/lib/src/ssa/type_builder.dart b/pkg/compiler/lib/src/ssa/type_builder.dart
index 0a5d8fe..d546cfe 100644
--- a/pkg/compiler/lib/src/ssa/type_builder.dart
+++ b/pkg/compiler/lib/src/ssa/type_builder.dart
@@ -69,10 +69,11 @@
 
   /// Produces code that checks the runtime type is actually the type specified
   /// by attempting a type conversion.
-  HInstruction _checkType(HInstruction original, DartType type, int kind) {
+  HInstruction _checkType(HInstruction original, DartType type) {
     assert(type != null);
     type = builder.localsHandler.substInContext(type);
-    HInstruction other = buildTypeConversion(original, type, kind);
+    HInstruction other =
+        buildTypeConversion(original, type, HTypeConversion.TYPE_CHECK);
     // TODO(johnniwinther): This operation on `registry` may be inconsistent.
     // If it is needed then it seems likely that similar invocations of
     // `buildTypeConversion` in `SsaBuilder.visitAs` should also be followed by
@@ -116,7 +117,7 @@
     if (builder.options.parameterCheckPolicy.isTrusted) {
       checkedOrTrusted = _trustType(original, type);
     } else if (builder.options.parameterCheckPolicy.isEmitted) {
-      checkedOrTrusted = _checkType(original, type, HTypeConversion.TYPE_CHECK);
+      checkedOrTrusted = _checkType(original, type);
     }
     if (checkedOrTrusted == original) return original;
     builder.add(checkedOrTrusted);
@@ -127,14 +128,13 @@
   /// instruction that checks the type is what we expect or automatically
   /// trusts the written type.
   HInstruction potentiallyCheckOrTrustTypeOfAssignment(
-      HInstruction original, DartType type,
-      {int kind: HTypeConversion.TYPE_CHECK}) {
+      HInstruction original, DartType type) {
     if (type == null) return original;
     HInstruction checkedOrTrusted = original;
     if (builder.options.assignmentCheckPolicy.isTrusted) {
       checkedOrTrusted = _trustType(original, type);
     } else if (builder.options.assignmentCheckPolicy.isEmitted) {
-      checkedOrTrusted = _checkType(original, type, kind);
+      checkedOrTrusted = _checkType(original, type);
     }
     if (checkedOrTrusted == original) return original;
     builder.add(checkedOrTrusted);
@@ -273,6 +273,28 @@
     return result;
   }
 
+  HInstruction analyzeTypeArgumentNewRti(
+      DartType argument, MemberEntity sourceElement,
+      {SourceInformation sourceInformation}) {
+    argument = argument.unaliased;
+
+    if (argument.containsFreeTypeVariables) {
+      // TODO(sra): Locate type environment.
+      HInstruction environment =
+          builder.graph.addConstantString("env", _closedWorld);
+      HInstruction rti =
+          HTypeEval(environment, argument, _abstractValueDomain.dynamicType)
+            ..sourceInformation = sourceInformation;
+      builder.add(rti);
+      return rti;
+    }
+
+    HInstruction rti = HLoadType(argument, _abstractValueDomain.dynamicType)
+      ..sourceInformation = sourceInformation;
+    builder.add(rti);
+    return rti;
+  }
+
   /// Build a [HTypeConversion] for converting [original] to type [type].
   ///
   /// Invariant: [type] must be valid in the context.
@@ -280,6 +302,12 @@
   HInstruction buildTypeConversion(
       HInstruction original, DartType type, int kind,
       {SourceInformation sourceInformation}) {
+    if (builder.options.experimentNewRti) {
+      return buildAsCheck(original, type,
+          isTypeError: kind == HTypeConversion.TYPE_CHECK,
+          sourceInformation: sourceInformation);
+    }
+
     if (type == null) return original;
     type = type.unaliased;
     if (type.isInterfaceType && !type.treatAsRaw) {
@@ -312,4 +340,30 @@
         ..sourceInformation = sourceInformation;
     }
   }
+
+  /// Build a [HAsCheck] for converting [original] to type [type].
+  ///
+  /// Invariant: [type] must be valid in the context.
+  /// See [LocalsHandler.substInContext].
+  HInstruction buildAsCheck(HInstruction original, DartType type,
+      {bool isTypeError, SourceInformation sourceInformation}) {
+    if (type == null) return original;
+    type = type.unaliased;
+
+    HInstruction reifiedType =
+        analyzeTypeArgumentNewRti(type, builder.sourceElement);
+    if (type is InterfaceType) {
+      // TODO(sra): Under NNDB opt-in, this will be NonNullable.
+      AbstractValue subtype =
+          _abstractValueDomain.createNullableSubtype(type.element);
+      return HAsCheck(original, reifiedType, isTypeError, subtype)
+        ..sourceInformation = sourceInformation;
+    } else {
+      // TypeMasks don't encode function types or FutureOr types or type
+      // variable types.
+      AbstractValue abstractValue = original.instructionType;
+      return HAsCheck(original, reifiedType, isTypeError, abstractValue)
+        ..sourceInformation = sourceInformation;
+    }
+  }
 }