[fasta] Fix inference for const redirecting factories invocations

Fixes #33813.

Bug: http://dartbug.com/33813
Change-Id: I53708666f6c5d55760a8bc23f042565ba073812f
Reviewed-on: https://dart-review.googlesource.com/64841
Reviewed-by: Jens Johansen <jensj@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index 143ea69..bee205f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -996,7 +996,8 @@
         fileOffset,
         target.function.functionType,
         computeConstructorReturnType(target),
-        argumentJudgments);
+        argumentJudgments,
+        isConst: isConst);
     var inferredType = inferenceResult.type;
     this.inferredType = inferredType;
     inferrer.listener.constructorInvocation(
diff --git a/pkg/front_end/testcases/compile.status b/pkg/front_end/testcases/compile.status
index f34d98f..cd8199e 100644
--- a/pkg/front_end/testcases/compile.status
+++ b/pkg/front_end/testcases/compile.status
@@ -117,6 +117,8 @@
 runtime_checks_new/mixin_forwarding_stub_getter: RuntimeError # Test exercises strong mode semantics
 runtime_checks_new/mixin_forwarding_stub_setter: RuntimeError # Test exercises strong mode semantics
 runtime_checks_new/stub_checked_via_target: RuntimeError # Test exercises strong mode semantics
+constructor_const_inference: RuntimeError # Test exercises strong mode semantics.  See also Issue #33813.
+redirecting_factory_const_inference: RuntimeError # Test exercises strong mode semantics.  See also Issue #33813.
 
 ambiguous_exports: RuntimeError # Expected, this file exports two main methods.
 rasta/duplicated_mixin: RuntimeError # Expected, this file has no main method.
diff --git a/pkg/front_end/testcases/constructor_const_inference.dart b/pkg/front_end/testcases/constructor_const_inference.dart
new file mode 100644
index 0000000..824e517
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_const_inference.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2018, 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.
+
+// This test checks that the type inference implementation correctly uses least
+// closure of the inferred type arguments in invocations of 'const' constructors
+// in case there are type variables in them.
+
+class _Y<T> {
+  const _Y();
+}
+
+class A<T> {
+  _Y<T> x;
+  A(this.x);
+}
+
+class B<T> extends A<T> {
+  B() : super(const _Y());
+}
+
+main() {
+  dynamic x = new B().x;
+  if (x is! _Y<Null>) {
+    throw "Unexpected run-time type: `new B().x` is ${x.runtimeType}, "
+        "but `_Y<Null>` expected";
+  }
+}
diff --git a/pkg/front_end/testcases/constructor_const_inference.dart.direct.expect b/pkg/front_end/testcases/constructor_const_inference.dart.direct.expect
new file mode 100644
index 0000000..00cffbc
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_const_inference.dart.direct.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _Y<T extends core::Object = dynamic> extends core::Object {
+  const constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  field self::_Y<self::A::T> x;
+  constructor •(self::_Y<self::A::T> x) → void
+    : self::A::x = x, super core::Object::•()
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    : super self::A::•(const self::_Y::•<dynamic>())
+    ;
+}
+static method main() → dynamic {
+  dynamic x = new self::B::•<dynamic>().x;
+  if(!(x is self::_Y<core::Null>)) {
+    throw "Unexpected run-time type: `new B().x` is ${x.runtimeType}, but `_Y<Null>` expected";
+  }
+}
diff --git a/pkg/front_end/testcases/constructor_const_inference.dart.direct.transformed.expect b/pkg/front_end/testcases/constructor_const_inference.dart.direct.transformed.expect
new file mode 100644
index 0000000..00cffbc
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_const_inference.dart.direct.transformed.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _Y<T extends core::Object = dynamic> extends core::Object {
+  const constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  field self::_Y<self::A::T> x;
+  constructor •(self::_Y<self::A::T> x) → void
+    : self::A::x = x, super core::Object::•()
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    : super self::A::•(const self::_Y::•<dynamic>())
+    ;
+}
+static method main() → dynamic {
+  dynamic x = new self::B::•<dynamic>().x;
+  if(!(x is self::_Y<core::Null>)) {
+    throw "Unexpected run-time type: `new B().x` is ${x.runtimeType}, but `_Y<Null>` expected";
+  }
+}
diff --git a/pkg/front_end/testcases/constructor_const_inference.dart.outline.expect b/pkg/front_end/testcases/constructor_const_inference.dart.outline.expect
new file mode 100644
index 0000000..0e89f88
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_const_inference.dart.outline.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _Y<T extends core::Object = dynamic> extends core::Object {
+  const constructor •() → void
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  field self::_Y<self::A::T> x;
+  constructor •(self::_Y<self::A::T> x) → void
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_const_inference.dart.strong.expect b/pkg/front_end/testcases/constructor_const_inference.dart.strong.expect
new file mode 100644
index 0000000..0ec23a5
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_const_inference.dart.strong.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _Y<T extends core::Object = dynamic> extends core::Object {
+  const constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  generic-covariant-impl field self::_Y<self::A::T> x;
+  constructor •(self::_Y<self::A::T> x) → void
+    : self::A::x = x, super core::Object::•()
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    : super self::A::•(const self::_Y::•<core::Null>())
+    ;
+}
+static method main() → dynamic {
+  dynamic x = new self::B::•<dynamic>().{self::A::x};
+  if(!(x is self::_Y<core::Null>)) {
+    throw "Unexpected run-time type: `new B().x` is ${x.{core::Object::runtimeType}}, but `_Y<Null>` expected";
+  }
+}
diff --git a/pkg/front_end/testcases/constructor_const_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_const_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..0ec23a5
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_const_inference.dart.strong.transformed.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _Y<T extends core::Object = dynamic> extends core::Object {
+  const constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  generic-covariant-impl field self::_Y<self::A::T> x;
+  constructor •(self::_Y<self::A::T> x) → void
+    : self::A::x = x, super core::Object::•()
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    : super self::A::•(const self::_Y::•<core::Null>())
+    ;
+}
+static method main() → dynamic {
+  dynamic x = new self::B::•<dynamic>().{self::A::x};
+  if(!(x is self::_Y<core::Null>)) {
+    throw "Unexpected run-time type: `new B().x` is ${x.{core::Object::runtimeType}}, but `_Y<Null>` expected";
+  }
+}
diff --git a/pkg/front_end/testcases/redirecting_factory_const_inference.dart b/pkg/front_end/testcases/redirecting_factory_const_inference.dart
new file mode 100644
index 0000000..8d904fd
--- /dev/null
+++ b/pkg/front_end/testcases/redirecting_factory_const_inference.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2018, 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.
+
+// This test checks that the type inference implementation correctly uses least
+// closure of the inferred type arguments in invocations of 'const' redirecting
+// factory constructors in case there are type variables in them.
+
+class _X<T> {
+  const factory _X() = _Y<T>;
+}
+
+class _Y<T> implements _X<T> {
+  const _Y();
+}
+
+class A<T> {
+  _X<T> x;
+  A(this.x);
+}
+
+class B<T> extends A<T> {
+  B() : super(const _X());
+}
+
+main() {
+  dynamic x = new B().x;
+  if (x is! _Y<Null>) {
+    throw "Unexpected run-time type: `new B().x` is ${x.runtimeType}, "
+        "but `_Y<Null>` expected";
+  }
+}
diff --git a/pkg/front_end/testcases/redirecting_factory_const_inference.dart.direct.expect b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.direct.expect
new file mode 100644
index 0000000..5e1d683
--- /dev/null
+++ b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.direct.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _X<T extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::_X::•];
+  static factory •<T extends core::Object = dynamic>() → self::_X<self::_X::•::T>
+    let dynamic #redirecting_factory = self::_Y::• in let self::_X::•::T #typeArg0 = null in invalid-expression;
+}
+class _Y<T extends core::Object = dynamic> extends core::Object implements self::_X<self::_Y::T> {
+  const constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  field self::_X<self::A::T> x;
+  constructor •(self::_X<self::A::T> x) → void
+    : self::A::x = x, super core::Object::•()
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    : super self::A::•(const self::_Y::•<dynamic>())
+    ;
+}
+static method main() → dynamic {
+  dynamic x = new self::B::•<dynamic>().x;
+  if(!(x is self::_Y<core::Null>)) {
+    throw "Unexpected run-time type: `new B().x` is ${x.runtimeType}, but `_Y<Null>` expected";
+  }
+}
diff --git a/pkg/front_end/testcases/redirecting_factory_const_inference.dart.direct.transformed.expect b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.direct.transformed.expect
new file mode 100644
index 0000000..5e1d683
--- /dev/null
+++ b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.direct.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _X<T extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::_X::•];
+  static factory •<T extends core::Object = dynamic>() → self::_X<self::_X::•::T>
+    let dynamic #redirecting_factory = self::_Y::• in let self::_X::•::T #typeArg0 = null in invalid-expression;
+}
+class _Y<T extends core::Object = dynamic> extends core::Object implements self::_X<self::_Y::T> {
+  const constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  field self::_X<self::A::T> x;
+  constructor •(self::_X<self::A::T> x) → void
+    : self::A::x = x, super core::Object::•()
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    : super self::A::•(const self::_Y::•<dynamic>())
+    ;
+}
+static method main() → dynamic {
+  dynamic x = new self::B::•<dynamic>().x;
+  if(!(x is self::_Y<core::Null>)) {
+    throw "Unexpected run-time type: `new B().x` is ${x.runtimeType}, but `_Y<Null>` expected";
+  }
+}
diff --git a/pkg/front_end/testcases/redirecting_factory_const_inference.dart.outline.expect b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.outline.expect
new file mode 100644
index 0000000..1b16077
--- /dev/null
+++ b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _X<T extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::_X::•];
+  static factory •<T extends core::Object = dynamic>() → self::_X<self::_X::•::T>
+    let dynamic #redirecting_factory = self::_Y::• in let self::_X::•::T #typeArg0 = null in invalid-expression;
+}
+class _Y<T extends core::Object = dynamic> extends core::Object implements self::_X<self::_Y::T> {
+  const constructor •() → void
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  field self::_X<self::A::T> x;
+  constructor •(self::_X<self::A::T> x) → void
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/redirecting_factory_const_inference.dart.strong.expect b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.strong.expect
new file mode 100644
index 0000000..3e7197c
--- /dev/null
+++ b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.strong.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _X<T extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::_X::•];
+  static factory •<T extends core::Object = dynamic>() → self::_X<self::_X::•::T>
+    let dynamic #redirecting_factory = self::_Y::• in let self::_X::•::T #typeArg0 = null in invalid-expression;
+}
+class _Y<T extends core::Object = dynamic> extends core::Object implements self::_X<self::_Y::T> {
+  const constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  generic-covariant-impl field self::_X<self::A::T> x;
+  constructor •(self::_X<self::A::T> x) → void
+    : self::A::x = x, super core::Object::•()
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    : super self::A::•(const self::_Y::•<core::Null>())
+    ;
+}
+static method main() → dynamic {
+  dynamic x = new self::B::•<dynamic>().{self::A::x};
+  if(!(x is self::_Y<core::Null>)) {
+    throw "Unexpected run-time type: `new B().x` is ${x.{core::Object::runtimeType}}, but `_Y<Null>` expected";
+  }
+}
diff --git a/pkg/front_end/testcases/redirecting_factory_const_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..c825208
--- /dev/null
+++ b/pkg/front_end/testcases/redirecting_factory_const_inference.dart.strong.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class _X<T extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::_X::•];
+  static factory •<T extends core::Object = dynamic>() → self::_X<self::_X::•::T>
+    let<BottomType> #redirecting_factory = self::_Y::• in let self::_X::•::T #typeArg0 = null in invalid-expression;
+}
+class _Y<T extends core::Object = dynamic> extends core::Object implements self::_X<self::_Y::T> {
+  const constructor •() → void
+    : super core::Object::•()
+    ;
+}
+class A<T extends core::Object = dynamic> extends core::Object {
+  generic-covariant-impl field self::_X<self::A::T> x;
+  constructor •(self::_X<self::A::T> x) → void
+    : self::A::x = x, super core::Object::•()
+    ;
+}
+class B<T extends core::Object = dynamic> extends self::A<self::B::T> {
+  constructor •() → void
+    : super self::A::•(const self::_Y::•<core::Null>())
+    ;
+}
+static method main() → dynamic {
+  dynamic x = new self::B::•<dynamic>().{self::A::x};
+  if(!(x is self::_Y<core::Null>)) {
+    throw "Unexpected run-time type: `new B().x` is ${x.{core::Object::runtimeType}}, but `_Y<Null>` expected";
+  }
+}