Handle ir constants in noSuchMethod handling and deferred load

Change-Id: Ic57e44bd3f03d88119962c235fb6f136785d9ac1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97118
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 39c73a8..8598e78 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -221,7 +221,8 @@
         measurer.startWallClock();
 
         return new Future.sync(() => runInternal(uri))
-            .catchError((error) => _reporter.onError(uri, error))
+            .catchError((error, StackTrace stackTrace) =>
+                _reporter.onError(uri, error, stackTrace))
             .whenComplete(() {
           measurer.stopWallClock();
         }).then((_) {
@@ -911,7 +912,7 @@
     }
   }
 
-  onError(Uri uri, error) {
+  onError(Uri uri, error, StackTrace stackTrace) {
     try {
       if (!hasCrashed) {
         hasCrashed = true;
@@ -929,7 +930,7 @@
     } catch (doubleFault) {
       // Ignoring exceptions in exception handling.
     }
-    throw error;
+    return new Future.error(error, stackTrace);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/ir/visitors.dart b/pkg/compiler/lib/src/ir/visitors.dart
index 0b7e8e4..5935303 100644
--- a/pkg/compiler/lib/src/ir/visitors.dart
+++ b/pkg/compiler/lib/src/ir/visitors.dart
@@ -690,7 +690,7 @@
     for (ir.DartType type in node.types) {
       typeArguments.add(elementMap.getDartType(type));
     }
-    FunctionConstantValue function = node.accept(this);
+    FunctionConstantValue function = node.tearOffConstant.accept(this);
     return new InstantiationConstantValue(typeArguments, function);
   }
 
diff --git a/pkg/compiler/lib/src/kernel/deferred_load.dart b/pkg/compiler/lib/src/kernel/deferred_load.dart
index 24b64b6..7980e62 100644
--- a/pkg/compiler/lib/src/kernel/deferred_load.dart
+++ b/pkg/compiler/lib/src/kernel/deferred_load.dart
@@ -212,4 +212,9 @@
     // constant.
     add(node, required: false);
   }
+
+  @override
+  void visitConstantExpression(ir.ConstantExpression node) {
+    add(node);
+  }
 }
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 6a206cd..265dbea 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -312,6 +312,9 @@
       });
     });
   }
+
+  @override
+  String toString() => 'KernelWorkItem($element)';
 }
 
 /// If `true` kernel impacts are computed as [ImpactData] directly on kernel
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 8047624..55b3a9c 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -3811,7 +3811,8 @@
 
     ir.ListLiteral positionalArgumentsLiteral =
         invocation.arguments.positional[2];
-    ir.MapLiteral namedArgumentsLiteral = invocation.arguments.positional[3];
+    ir.Expression namedArgumentsLiteral = invocation.arguments.positional[3];
+    Map<String, ir.Expression> namedArguments = {};
     ir.IntLiteral kindLiteral = invocation.arguments.positional[4];
 
     Name memberName = new Name(name, _currentFrame.member.library);
@@ -3829,12 +3830,28 @@
         } else if (memberName == Names.INDEX_SET_NAME) {
           selector = new Selector.indexSet();
         } else {
+          if (namedArgumentsLiteral is ir.MapLiteral) {
+            namedArgumentsLiteral.entries.forEach((ir.MapEntry entry) {
+              ir.StringLiteral key = entry.key;
+              namedArguments[key.value] = entry.value;
+            });
+          } else if (namedArgumentsLiteral is ir.ConstantExpression &&
+              namedArgumentsLiteral.constant is ir.MapConstant) {
+            ir.MapConstant constant = namedArgumentsLiteral.constant;
+            for (ir.ConstantMapEntry entry in constant.entries) {
+              ir.StringConstant key = entry.key;
+              namedArguments[key.value] =
+                  new ir.ConstantExpression(entry.value);
+            }
+          } else {
+            reporter.internalError(
+                computeSourceSpanFromTreeNode(invocation),
+                "Unexpected named arguments value in createInvocationMirrror: "
+                "${namedArgumentsLiteral}.");
+          }
           CallStructure callStructure = new CallStructure(
               positionalArgumentsLiteral.expressions.length,
-              namedArgumentsLiteral.entries.map<String>((ir.MapEntry entry) {
-                ir.StringLiteral key = entry.key;
-                return key.value;
-              }).toList(),
+              namedArguments.keys.toList(),
               typeArguments.length);
           if (Selector.isOperatorName(name)) {
             selector =
@@ -3855,14 +3872,12 @@
       argument.accept(this);
       arguments.add(pop());
     }
-    if (namedArgumentsLiteral.entries.isNotEmpty) {
+    if (namedArguments.isNotEmpty) {
       Map<String, HInstruction> namedValues = <String, HInstruction>{};
-      for (ir.MapEntry entry in namedArgumentsLiteral.entries) {
-        ir.StringLiteral key = entry.key;
-        String name = key.value;
-        entry.value.accept(this);
+      namedArguments.forEach((String name, ir.Expression value) {
+        value.accept(this);
         namedValues[name] = pop();
-      }
+      });
       for (String name in selector.callStructure.getOrderedNamedArguments()) {
         arguments.add(namedValues[name]);
       }
diff --git a/tests/compiler/dart2js/model/no_such_method_enabled_test.dart b/tests/compiler/dart2js/model/no_such_method_enabled_test.dart
index 6410edf..58d85b9 100644
--- a/tests/compiler/dart2js/model/no_such_method_enabled_test.dart
+++ b/tests/compiler/dart2js/model/no_such_method_enabled_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/common_elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
@@ -234,12 +235,15 @@
 ];
 
 main() {
-  runTests() async {
+  runTests({bool useCFEConstants: false}) async {
     for (NoSuchMethodTest test in TESTS) {
       print('---- testing -------------------------------------------------');
       print(test.code);
-      CompilationResult result =
-          await runCompiler(memorySourceFiles: {'main.dart': test.code});
+      CompilationResult result = await runCompiler(
+          memorySourceFiles: {'main.dart': test.code},
+          options: useCFEConstants
+              ? ['${Flags.enableLanguageExperiments}=constant-update-2018']
+              : []);
       Expect.isTrue(result.isSuccess);
       Compiler compiler = result.compiler;
       checkTest(compiler, test);
@@ -249,6 +253,8 @@
   asyncTest(() async {
     print('--test from kernel------------------------------------------------');
     await runTests();
+    print('--test from kernel with CFE constants-----------------------------');
+    await runTests(useCFEConstants: true);
   });
 }
 
diff --git a/tests/compiler/dart2js/serialization/serialization_test.dart b/tests/compiler/dart2js/serialization/serialization_test.dart
index 6c5a1cb..496787d 100644
--- a/tests/compiler/dart2js/serialization/serialization_test.dart
+++ b/tests/compiler/dart2js/serialization/serialization_test.dart
@@ -13,12 +13,16 @@
   asyncTest(() async {
     Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
     Directory libDir = new Directory.fromUri(Platform.script.resolve('libs'));
+    print('--testing without CFE constants-----------------------------------');
     await checkTests(dataDir, options: [], args: args, libDirectory: libDir);
+    print('--testing with CFE constants--------------------------------------');
+    await checkTests(dataDir,
+        options: [], args: args, libDirectory: libDir, testCFEConstants: true);
   });
 }
 
 Future checkTests(Directory dataDir,
-    {bool testStrongMode: true,
+    {bool testCFEConstants: false,
     List<String> options: const <String>[],
     List<String> args: const <String>[],
     Directory libDirectory: null,
@@ -50,6 +54,10 @@
     if (shouldContinue) continued = true;
     testCount++;
     List<String> testOptions = options.toList();
+    if (testCFEConstants) {
+      testOptions
+          .add('${Flags.enableLanguageExperiments}=constant-update-2018');
+    }
     testOptions.add(Flags.dumpInfo);
     testOptions.add('--out=out.js');
     if (onTest != null) {