[cfe] Add verification of tear-off lowering
This adds verification that tear-off nodes for which the target
requested a lowering, do not occur in the generated AST.
Change-Id: Ic5e58d1cc607778d6239ced2bf9509439ae1e92b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/223080
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/verifier.dart b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
index 7543cd9..ae560e2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/verifier.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
@@ -29,7 +29,10 @@
import '../type_inference/type_schema.dart' show UnknownType;
import 'redirecting_factory_body.dart'
- show RedirectingFactoryBody, isRedirectingFactory;
+ show
+ RedirectingFactoryBody,
+ isRedirectingFactory,
+ isRedirectingFactoryField;
List<LocatedMessage> verifyComponent(Component component, Target target,
{bool? isOutline, bool? afterConst, bool skipPlatform: false}) {
@@ -431,6 +434,89 @@
exitTreeNode(node);
}
+ void _checkConstructorTearOff(Node node, Member tearOffTarget) {
+ if (tearOffTarget.enclosingLibrary.importUri.scheme == 'dart') {
+ // Platform libraries are not compilation with test flags and might
+ // contain tear-offs not expected when testing lowerings.
+ return;
+ }
+ if (currentMember != null && isRedirectingFactoryField(currentMember!)) {
+ // The encoding of the redirecting factory field uses
+ // [ConstructorTearOffConstant] nodes also when lowerings are enabled.
+ return;
+ }
+ if (tearOffTarget is Constructor &&
+ target.isConstructorTearOffLoweringEnabled) {
+ problem(
+ node is TreeNode ? node : getLastSeenTreeNode(),
+ '${node.runtimeType} nodes for generative constructors should be '
+ 'lowered for target "${target.name}".');
+ }
+ if (tearOffTarget is Procedure &&
+ tearOffTarget.isFactory &&
+ target.isFactoryTearOffLoweringEnabled) {
+ problem(
+ node is TreeNode ? node : getLastSeenTreeNode(),
+ '${node.runtimeType} nodes for factory constructors should be '
+ 'lowered for target "${target.name}".');
+ }
+ }
+
+ @override
+ void visitConstructorTearOff(ConstructorTearOff node) {
+ _checkConstructorTearOff(node, node.target);
+ super.visitConstructorTearOff(node);
+ }
+
+ @override
+ void visitConstructorTearOffConstant(ConstructorTearOffConstant node) {
+ _checkConstructorTearOff(node, node.target);
+ super.visitConstructorTearOffConstant(node);
+ }
+
+ void _checkTypedefTearOff(Node node) {
+ if (target.isTypedefTearOffLoweringEnabled) {
+ problem(
+ node is TreeNode ? node : getLastSeenTreeNode(),
+ '${node.runtimeType} nodes for typedefs should be '
+ 'lowered for target "${target.name}".');
+ }
+ }
+
+ @override
+ void visitTypedefTearOff(TypedefTearOff node) {
+ _checkTypedefTearOff(node);
+ super.visitTypedefTearOff(node);
+ }
+
+ @override
+ void visitTypedefTearOffConstant(TypedefTearOffConstant node) {
+ _checkTypedefTearOff(node);
+ super.visitTypedefTearOffConstant(node);
+ }
+
+ void _checkRedirectingFactoryTearOff(Node node) {
+ if (target.isRedirectingFactoryTearOffLoweringEnabled) {
+ problem(
+ node is TreeNode ? node : getLastSeenTreeNode(),
+ 'ConstructorTearOff nodes for redirecting factories should be '
+ 'lowered for target "${target.name}".');
+ }
+ }
+
+ @override
+ void visitRedirectingFactoryTearOff(RedirectingFactoryTearOff node) {
+ _checkRedirectingFactoryTearOff(node);
+ super.visitRedirectingFactoryTearOff(node);
+ }
+
+ @override
+ void visitRedirectingFactoryTearOffConstant(
+ RedirectingFactoryTearOffConstant node) {
+ _checkRedirectingFactoryTearOff(node);
+ super.visitRedirectingFactoryTearOffConstant(node);
+ }
+
@override
void defaultTreeNode(TreeNode node) {
enterTreeNode(node);
diff --git a/pkg/front_end/testcases/dart2js/constructor_tearoff.dart b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart
new file mode 100644
index 0000000..b7234a7
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2021, 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.
+
+typedef Alias<T extends num> = Class<T>;
+
+class Class<T> {
+ Class();
+ factory Class.fact() => Class<T>();
+ factory Class.redirect() = Class<T>;
+}
+
+const a = Class.new;
+const b = Class.fact;
+const c = Class.redirect;
+const d = Alias.new;
+const e = Alias.fact;
+const f = Alias.redirect;
+
+main() {
+ print('$a$b$c$d$e$f');
+}
diff --git a/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.strong.expect b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.strong.expect
new file mode 100644
index 0000000..46e4364
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.strong.expect
@@ -0,0 +1,46 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef Alias<T extends core::num> = self::Class<T>;
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
+ constructor •() → self::Class<self::Class::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#new#tearOff::T%>
+ return new self::Class::•<self::Class::_#new#tearOff::T%>();
+ static factory fact<T extends core::Object? = dynamic>() → self::Class<self::Class::fact::T%>
+ return new self::Class::•<self::Class::fact::T%>();
+ static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#fact#tearOff::T%>
+ return self::Class::fact<self::Class::_#fact#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → self::Class<self::Class::redirect::T%>
+ return new self::Class::•<self::Class::redirect::T%>();
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#redirect#tearOff::T%>
+ return new self::Class::•<self::Class::_#redirect#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> a = #C2;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> b = #C3;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> c = #C4;
+static const field <T extends core::num>() → self::Class<T> d = #C5;
+static const field <T extends core::num>() → self::Class<T> e = #C6;
+static const field <T extends core::num>() → self::Class<T> f = #C7;
+static method main() → dynamic {
+ core::print("${#C2}${#C3}${#C4}${#C5}${#C6}${#C7}");
+}
+static method _#Alias#new#tearOff<T extends core::num>() → self::Class<self::_#Alias#new#tearOff::T>
+ return new self::Class::•<self::_#Alias#new#tearOff::T>();
+static method _#Alias#fact#tearOff<T extends core::num>() → self::Class<self::_#Alias#fact#tearOff::T>
+ return self::Class::fact<self::_#Alias#fact#tearOff::T>();
+static method _#Alias#redirect#tearOff<T extends core::num>() → self::Class<self::_#Alias#redirect#tearOff::T>
+ return self::Class::_#redirect#tearOff<self::_#Alias#redirect#tearOff::T>();
+
+constants {
+ #C1 = constructor-tearoff self::Class::redirect
+ #C2 = static-tearoff self::Class::_#new#tearOff
+ #C3 = static-tearoff self::Class::_#fact#tearOff
+ #C4 = static-tearoff self::Class::_#redirect#tearOff
+ #C5 = static-tearoff self::_#Alias#new#tearOff
+ #C6 = static-tearoff self::_#Alias#fact#tearOff
+ #C7 = static-tearoff self::_#Alias#redirect#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.strong.transformed.expect
new file mode 100644
index 0000000..46e4364
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.strong.transformed.expect
@@ -0,0 +1,46 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef Alias<T extends core::num> = self::Class<T>;
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
+ constructor •() → self::Class<self::Class::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#new#tearOff::T%>
+ return new self::Class::•<self::Class::_#new#tearOff::T%>();
+ static factory fact<T extends core::Object? = dynamic>() → self::Class<self::Class::fact::T%>
+ return new self::Class::•<self::Class::fact::T%>();
+ static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#fact#tearOff::T%>
+ return self::Class::fact<self::Class::_#fact#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → self::Class<self::Class::redirect::T%>
+ return new self::Class::•<self::Class::redirect::T%>();
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#redirect#tearOff::T%>
+ return new self::Class::•<self::Class::_#redirect#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> a = #C2;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> b = #C3;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> c = #C4;
+static const field <T extends core::num>() → self::Class<T> d = #C5;
+static const field <T extends core::num>() → self::Class<T> e = #C6;
+static const field <T extends core::num>() → self::Class<T> f = #C7;
+static method main() → dynamic {
+ core::print("${#C2}${#C3}${#C4}${#C5}${#C6}${#C7}");
+}
+static method _#Alias#new#tearOff<T extends core::num>() → self::Class<self::_#Alias#new#tearOff::T>
+ return new self::Class::•<self::_#Alias#new#tearOff::T>();
+static method _#Alias#fact#tearOff<T extends core::num>() → self::Class<self::_#Alias#fact#tearOff::T>
+ return self::Class::fact<self::_#Alias#fact#tearOff::T>();
+static method _#Alias#redirect#tearOff<T extends core::num>() → self::Class<self::_#Alias#redirect#tearOff::T>
+ return self::Class::_#redirect#tearOff<self::_#Alias#redirect#tearOff::T>();
+
+constants {
+ #C1 = constructor-tearoff self::Class::redirect
+ #C2 = static-tearoff self::Class::_#new#tearOff
+ #C3 = static-tearoff self::Class::_#fact#tearOff
+ #C4 = static-tearoff self::Class::_#redirect#tearOff
+ #C5 = static-tearoff self::_#Alias#new#tearOff
+ #C6 = static-tearoff self::_#Alias#fact#tearOff
+ #C7 = static-tearoff self::_#Alias#redirect#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.textual_outline.expect
new file mode 100644
index 0000000..89d865d
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.textual_outline.expect
@@ -0,0 +1,15 @@
+typedef Alias<T extends num> = Class<T>;
+
+class Class<T> {
+ Class();
+ factory Class.fact() => Class<T>();
+ factory Class.redirect() = Class<T>;
+}
+
+const a = Class.new;
+const b = Class.fact;
+const c = Class.redirect;
+const d = Alias.new;
+const e = Alias.fact;
+const f = Alias.redirect;
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3f714c9
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.textual_outline_modelled.expect
@@ -0,0 +1,14 @@
+class Class<T> {
+ Class();
+ factory Class.fact() => Class<T>();
+ factory Class.redirect() = Class<T>;
+}
+
+const a = Class.new;
+const b = Class.fact;
+const c = Class.redirect;
+const d = Alias.new;
+const e = Alias.fact;
+const f = Alias.redirect;
+main() {}
+typedef Alias<T extends num> = Class<T>;
diff --git a/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.expect b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.expect
new file mode 100644
index 0000000..46e4364
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.expect
@@ -0,0 +1,46 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef Alias<T extends core::num> = self::Class<T>;
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
+ constructor •() → self::Class<self::Class::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#new#tearOff::T%>
+ return new self::Class::•<self::Class::_#new#tearOff::T%>();
+ static factory fact<T extends core::Object? = dynamic>() → self::Class<self::Class::fact::T%>
+ return new self::Class::•<self::Class::fact::T%>();
+ static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#fact#tearOff::T%>
+ return self::Class::fact<self::Class::_#fact#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → self::Class<self::Class::redirect::T%>
+ return new self::Class::•<self::Class::redirect::T%>();
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#redirect#tearOff::T%>
+ return new self::Class::•<self::Class::_#redirect#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> a = #C2;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> b = #C3;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> c = #C4;
+static const field <T extends core::num>() → self::Class<T> d = #C5;
+static const field <T extends core::num>() → self::Class<T> e = #C6;
+static const field <T extends core::num>() → self::Class<T> f = #C7;
+static method main() → dynamic {
+ core::print("${#C2}${#C3}${#C4}${#C5}${#C6}${#C7}");
+}
+static method _#Alias#new#tearOff<T extends core::num>() → self::Class<self::_#Alias#new#tearOff::T>
+ return new self::Class::•<self::_#Alias#new#tearOff::T>();
+static method _#Alias#fact#tearOff<T extends core::num>() → self::Class<self::_#Alias#fact#tearOff::T>
+ return self::Class::fact<self::_#Alias#fact#tearOff::T>();
+static method _#Alias#redirect#tearOff<T extends core::num>() → self::Class<self::_#Alias#redirect#tearOff::T>
+ return self::Class::_#redirect#tearOff<self::_#Alias#redirect#tearOff::T>();
+
+constants {
+ #C1 = constructor-tearoff self::Class::redirect
+ #C2 = static-tearoff self::Class::_#new#tearOff
+ #C3 = static-tearoff self::Class::_#fact#tearOff
+ #C4 = static-tearoff self::Class::_#redirect#tearOff
+ #C5 = static-tearoff self::_#Alias#new#tearOff
+ #C6 = static-tearoff self::_#Alias#fact#tearOff
+ #C7 = static-tearoff self::_#Alias#redirect#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.outline.expect
new file mode 100644
index 0000000..48c9e36
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.outline.expect
@@ -0,0 +1,45 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef Alias<T extends core::num> = self::Class<T>;
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class::redirect]/*isLegacy*/;
+ constructor •() → self::Class<self::Class::T%>
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#new#tearOff::T%>
+ return new self::Class::•<self::Class::_#new#tearOff::T%>();
+ static factory fact<T extends core::Object? = dynamic>() → self::Class<self::Class::fact::T%>
+ ;
+ static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#fact#tearOff::T%>
+ return self::Class::fact<self::Class::_#fact#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → self::Class<self::Class::redirect::T%>
+ return new self::Class::•<self::Class::redirect::T%>();
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#redirect#tearOff::T%>
+ return new self::Class::•<self::Class::_#redirect#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> a = self::Class::_#new#tearOff;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> b = self::Class::_#fact#tearOff;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> c = self::Class::_#redirect#tearOff;
+static const field <T extends core::num>() → self::Class<T> d = self::_#Alias#new#tearOff;
+static const field <T extends core::num>() → self::Class<T> e = self::_#Alias#fact#tearOff;
+static const field <T extends core::num>() → self::Class<T> f = self::_#Alias#redirect#tearOff;
+static method main() → dynamic
+ ;
+static method _#Alias#new#tearOff<T extends core::num>() → self::Class<self::_#Alias#new#tearOff::T>
+ return new self::Class::•<self::_#Alias#new#tearOff::T>();
+static method _#Alias#fact#tearOff<T extends core::num>() → self::Class<self::_#Alias#fact#tearOff::T>
+ return self::Class::fact<self::_#Alias#fact#tearOff::T>();
+static method _#Alias#redirect#tearOff<T extends core::num>() → self::Class<self::_#Alias#redirect#tearOff::T>
+ return self::Class::_#redirect#tearOff<self::_#Alias#redirect#tearOff::T>();
+
+
+Extra constant evaluation status:
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///constructor_tearoff.dart:7:7 -> ConstructorTearOffConstant(Class.redirect)
+Evaluated: StaticTearOff @ org-dartlang-testcase:///constructor_tearoff.dart:13:11 -> StaticTearOffConstant(Class._#new#tearOff)
+Evaluated: StaticTearOff @ org-dartlang-testcase:///constructor_tearoff.dart:14:11 -> StaticTearOffConstant(Class._#fact#tearOff)
+Evaluated: StaticTearOff @ org-dartlang-testcase:///constructor_tearoff.dart:15:11 -> StaticTearOffConstant(Class._#redirect#tearOff)
+Evaluated: StaticTearOff @ org-dartlang-testcase:///constructor_tearoff.dart:16:11 -> StaticTearOffConstant(_#Alias#new#tearOff)
+Evaluated: StaticTearOff @ org-dartlang-testcase:///constructor_tearoff.dart:17:11 -> StaticTearOffConstant(_#Alias#fact#tearOff)
+Evaluated: StaticTearOff @ org-dartlang-testcase:///constructor_tearoff.dart:18:11 -> StaticTearOffConstant(_#Alias#redirect#tearOff)
+Extra constant evaluation: evaluated: 15, effectively constant: 7
diff --git a/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.transformed.expect
new file mode 100644
index 0000000..46e4364
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.transformed.expect
@@ -0,0 +1,46 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef Alias<T extends core::num> = self::Class<T>;
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
+ constructor •() → self::Class<self::Class::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#new#tearOff::T%>
+ return new self::Class::•<self::Class::_#new#tearOff::T%>();
+ static factory fact<T extends core::Object? = dynamic>() → self::Class<self::Class::fact::T%>
+ return new self::Class::•<self::Class::fact::T%>();
+ static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#fact#tearOff::T%>
+ return self::Class::fact<self::Class::_#fact#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → self::Class<self::Class::redirect::T%>
+ return new self::Class::•<self::Class::redirect::T%>();
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#redirect#tearOff::T%>
+ return new self::Class::•<self::Class::_#redirect#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> a = #C2;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> b = #C3;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> c = #C4;
+static const field <T extends core::num>() → self::Class<T> d = #C5;
+static const field <T extends core::num>() → self::Class<T> e = #C6;
+static const field <T extends core::num>() → self::Class<T> f = #C7;
+static method main() → dynamic {
+ core::print("${#C2}${#C3}${#C4}${#C5}${#C6}${#C7}");
+}
+static method _#Alias#new#tearOff<T extends core::num>() → self::Class<self::_#Alias#new#tearOff::T>
+ return new self::Class::•<self::_#Alias#new#tearOff::T>();
+static method _#Alias#fact#tearOff<T extends core::num>() → self::Class<self::_#Alias#fact#tearOff::T>
+ return self::Class::fact<self::_#Alias#fact#tearOff::T>();
+static method _#Alias#redirect#tearOff<T extends core::num>() → self::Class<self::_#Alias#redirect#tearOff::T>
+ return self::Class::_#redirect#tearOff<self::_#Alias#redirect#tearOff::T>();
+
+constants {
+ #C1 = constructor-tearoff self::Class::redirect
+ #C2 = static-tearoff self::Class::_#new#tearOff
+ #C3 = static-tearoff self::Class::_#fact#tearOff
+ #C4 = static-tearoff self::Class::_#redirect#tearOff
+ #C5 = static-tearoff self::_#Alias#new#tearOff
+ #C6 = static-tearoff self::_#Alias#fact#tearOff
+ #C7 = static-tearoff self::_#Alias#redirect#tearOff
+}