Version 2.18.0-57.0.dev
Merge commit '76387a9c5b3d89035be13a84b5303e2780e94e6e' into 'dev'
diff --git a/OWNERS b/OWNERS
index 911f0bb..b179edd 100644
--- a/OWNERS
+++ b/OWNERS
@@ -17,7 +17,7 @@
per-file CONTRIBUTING.md,LICENSE,PATENT_GRANT,README.*,SECURITY.md=file:/tools/OWNERS_PRODUCT
# Top level build files
-per-file .clang-format,BUILD.gn,sdk_args.gni=file:/tools/OWNERS_VM
+per-file .clang-format,BUILD.gn,sdk_args.gni=file:/tools/OWNERS_BUILD
# Generated file
per-file .packages=*
diff --git a/benchmarks/Startup/dart/Startup.dart b/benchmarks/Startup/dart/Startup.dart
index 7beaede..03bd22e 100644
--- a/benchmarks/Startup/dart/Startup.dart
+++ b/benchmarks/Startup/dart/Startup.dart
@@ -76,7 +76,7 @@
print(ends.toList());
throw '$name is missing or ambiguous';
}
- print('Startup.$name(RunTimeRaw): $micros us.');
+ print('Startup.$name(StartupTime): $micros us.');
}
report('CreateIsolateGroupAndSetupHelper', null);
diff --git a/benchmarks/Startup/dart2/Startup.dart b/benchmarks/Startup/dart2/Startup.dart
index 3220928..b79e3a3 100644
--- a/benchmarks/Startup/dart2/Startup.dart
+++ b/benchmarks/Startup/dart2/Startup.dart
@@ -78,7 +78,7 @@
print(ends.toList());
throw '$name is missing or ambiguous';
}
- print('Startup.$name(RunTimeRaw): $micros us.');
+ print('Startup.$name(StartupTime): $micros us.');
}
report('CreateIsolateGroupAndSetupHelper', null);
diff --git a/build/OWNERS b/build/OWNERS
index 2b67506..24995df 100644
--- a/build/OWNERS
+++ b/build/OWNERS
@@ -1 +1 @@
-file:/tools/OWNERS_ENG
+file:/tools/OWNERS_BUILD
diff --git a/pkg/analyzer/lib/src/summary2/kernel_compilation_service.dart b/pkg/analyzer/lib/src/summary2/kernel_compilation_service.dart
index e7ed68c..36caada 100644
--- a/pkg/analyzer/lib/src/summary2/kernel_compilation_service.dart
+++ b/pkg/analyzer/lib/src/summary2/kernel_compilation_service.dart
@@ -36,11 +36,7 @@
}
final executablePath = io.Platform.resolvedExecutable;
- final binPath = package_path.dirname(executablePath);
- final sdkPath = package_path.dirname(binPath);
-
- final frontEndSnapshotPath = package_path.join(
- binPath, 'snapshots', 'frontend_server.dart.snapshot');
+ final sdkPaths = _computeSdkPaths();
final socketCompleter = Completer<io.Socket>();
final serverSocket = await _loopbackServerSocket();
@@ -52,7 +48,7 @@
final addressStr = '$host:${serverSocket.port}';
final process = await io.Process.start(executablePath, [
- frontEndSnapshotPath,
+ sdkPaths.frontEndSnapshot,
'--binary-protocol-address=$addressStr',
]);
@@ -66,8 +62,7 @@
final requestChannel = RequestChannel(socket);
// Put the platform dill.
- final platformDillPath = package_path.join(
- sdkPath, 'lib', '_internal', 'vm_platform_strong.dill');
+ final platformDillPath = sdkPaths.platformDill;
final platformDillBytes = io.File(platformDillPath).readAsBytesSync();
await requestChannel.sendRequest<void>('dill.put', {
'uri': 'dill:vm',
@@ -149,6 +144,30 @@
});
}
+ static _SdkPaths _computeSdkPaths() {
+ // Check for google3.
+ final runFiles = io.Platform.environment['RUNFILES'];
+ if (runFiles != null) {
+ final frontServerPath = io.Platform.environment['FRONTEND_SERVER_PATH']!;
+ final platformDillPath = io.Platform.environment['PLATFORM_DILL_PATH']!;
+ return _SdkPaths(
+ frontEndSnapshot: package_path.join(runFiles, frontServerPath),
+ platformDill: package_path.join(runFiles, platformDillPath),
+ );
+ }
+
+ final executablePath = io.Platform.resolvedExecutable;
+ final binPath = package_path.dirname(executablePath);
+ final sdkPath = package_path.dirname(binPath);
+
+ return _SdkPaths(
+ frontEndSnapshot: package_path.join(
+ binPath, 'snapshots', 'frontend_server.dart.snapshot'),
+ platformDill: package_path.join(
+ sdkPath, 'lib', '_internal', 'vm_platform_strong.dill'),
+ );
+ }
+
static Future<io.ServerSocket> _loopbackServerSocket() async {
try {
return await io.ServerSocket.bind(io.InternetAddress.loopbackIPv6, 0);
@@ -199,3 +218,13 @@
}
}
}
+
+class _SdkPaths {
+ final String frontEndSnapshot;
+ final String platformDill;
+
+ _SdkPaths({
+ required this.frontEndSnapshot,
+ required this.platformDill,
+ });
+}
diff --git a/pkg/analyzer_utilities/lib/package_root.dart b/pkg/analyzer_utilities/lib/package_root.dart
index aa3d27c..61a3c96 100644
--- a/pkg/analyzer_utilities/lib/package_root.dart
+++ b/pkg/analyzer_utilities/lib/package_root.dart
@@ -25,5 +25,13 @@
if (pkgIndex != -1) {
return pathos.joinAll(parts.sublist(0, pkgIndex + 1)) + pathos.separator;
}
+ // Try google3 environment. We expect that all packages that will be
+ // accessed via this root are configured in the BUILD file, and located
+ // inside this single root.
+ final runFiles = Platform.environment['RUNFILES'];
+ final analyzerPackagesRoot = Platform.environment['ANALYZER_PACKAGES_ROOT'];
+ if (runFiles != null && analyzerPackagesRoot != null) {
+ return pathos.join(runFiles, analyzerPackagesRoot);
+ }
throw StateError('Unable to find sdk/pkg/ in $scriptPath');
}
diff --git a/pkg/compiler/lib/src/ir/impact_data.dart b/pkg/compiler/lib/src/ir/impact_data.dart
index 1d9aefd..462b6c3 100644
--- a/pkg/compiler/lib/src/ir/impact_data.dart
+++ b/pkg/compiler/lib/src/ir/impact_data.dart
@@ -575,6 +575,12 @@
@override
void handleConstantExpression(ir.ConstantExpression node) {
+ // Evaluate any [ir.UnevaluatedConstant]s to ensure they are processed for
+ // impacts correctly.
+ // TODO(joshualitt): Remove this when we have CFE constants.
+ if (node.constant is ir.UnevaluatedConstant) {
+ _elementMap.constantEvaluator.evaluate(staticTypeContext, node);
+ }
ir.LibraryDependency import = getDeferredImport(node);
ConstantImpactVisitor(this, import, node, staticTypeContext)
.visitConstant(node.constant);
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index 6a45f08..cb44cf3 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -67,6 +67,8 @@
path: ../meta
dart2js_info:
path: ../dart2js_info
+ smith:
+ path: ../smith
# Packages brought in via DEPS
args:
diff --git a/pkg/compiler/test/impact/data/issue230108748.dart b/pkg/compiler/test/impact/data/issue230108748.dart
new file mode 100644
index 0000000..ea16c2f
--- /dev/null
+++ b/pkg/compiler/test/impact/data/issue230108748.dart
@@ -0,0 +1,75 @@
+class B {
+ /*member: B.x:
+ static=[
+ Rti._bind(1),
+ Rti._eval(1),
+ _arrayInstanceType(1),
+ _asBool(1),
+ _asBoolQ(1),
+ _asBoolS(1),
+ _asDouble(1),
+ _asDoubleQ(1),
+ _asDoubleS(1),
+ _asInt(1),
+ _asIntQ(1),
+ _asIntS(1),
+ _asNum(1),
+ _asNumQ(1),
+ _asNumS(1),
+ _asObject(1),
+ _asString(1),
+ _asStringQ(1),
+ _asStringS(1),
+ _asTop(1),
+ _generalAsCheckImplementation(1),
+ _generalIsTestImplementation(1),
+ _generalNullableAsCheckImplementation(1),
+ _generalNullableIsTestImplementation(1),
+ _installSpecializedAsCheck(1),
+ _installSpecializedIsTest(1),
+ _instanceType(1),
+ _isBool(1),
+ _isInt(1),
+ _isNum(1),
+ _isObject(1),
+ _isString(1),
+ _isTop(1),
+ findType(1),
+ instanceType(1)],
+ type=[
+ inst:Closure,
+ inst:JSBool,
+ inst:JSNull,
+ param:int]
+ */
+ final int x;
+ const B(this.x);
+}
+
+/*member: case3:
+ static=[B.x=IntConstant(1)],
+ type=[
+ const:B,
+ inst:JSInt,
+ inst:JSNull,
+ inst:JSNumNotInt,
+ inst:JSNumber,
+ inst:JSPositiveInt,
+ inst:JSUInt31,
+ inst:JSUInt32]
+*/
+int case3() {
+ switch (null as dynamic) {
+ case B(const bool.fromEnvironment('x') ? 0 : 1):
+ return 1;
+ default:
+ return 2;
+ }
+}
+
+/*member: main:static=[
+ case3(0),
+ print(1)]*/
+void main() {
+ print(case3());
+}
diff --git a/pkg/dart2wasm/lib/class_info.dart b/pkg/dart2wasm/lib/class_info.dart
index c94c023..27986fc 100644
--- a/pkg/dart2wasm/lib/class_info.dart
+++ b/pkg/dart2wasm/lib/class_info.dart
@@ -25,6 +25,7 @@
static const hashBaseData = 4;
static const closureContext = 2;
static const closureFunction = 3;
+ static const typeTypeArguments = 3;
static const typedListBaseLength = 2;
static const typedListArray = 3;
static const typedListViewTypedData = 3;
@@ -50,6 +51,7 @@
check(translator.hashFieldBaseClass, "_index", FieldIndex.hashBaseIndex);
check(translator.hashFieldBaseClass, "_data", FieldIndex.hashBaseData);
check(translator.functionClass, "context", FieldIndex.closureContext);
+ check(translator.typeClass, "typeArguments", FieldIndex.typeTypeArguments);
}
}
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index d12efbd..2489dfb 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -9,6 +9,7 @@
import 'package:dart2wasm/param_info.dart';
import 'package:dart2wasm/reference_extensions.dart';
import 'package:dart2wasm/translator.dart';
+import 'package:dart2wasm/types.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/type_environment.dart';
@@ -77,6 +78,8 @@
w.ValueType get voidMarker => translator.voidMarker;
+ Types get types => translator.types;
+
w.ValueType translateType(DartType type) => translator.translateType(type);
w.Local addLocal(w.ValueType type) {
@@ -87,7 +90,7 @@
return exp.getStaticType(typeContext);
}
- void _unimplemented(
+ void unimplemented(
TreeNode node, Object message, List<w.ValueType> expectedTypes) {
final text = "Not implemented: $message at ${node.location}";
print(text);
@@ -99,18 +102,18 @@
@override
void defaultInitializer(Initializer node) {
- _unimplemented(node, node.runtimeType, const []);
+ unimplemented(node, node.runtimeType, const []);
}
@override
w.ValueType defaultExpression(Expression node, w.ValueType expectedType) {
- _unimplemented(node, node.runtimeType, [expectedType]);
+ unimplemented(node, node.runtimeType, [expectedType]);
return expectedType;
}
@override
void defaultStatement(Statement node) {
- _unimplemented(node, node.runtimeType, const []);
+ unimplemented(node, node.runtimeType, const []);
}
/// Generate code for the body of the member.
@@ -460,7 +463,8 @@
b.ref_as_non_null();
}
for (TypeParameter typeParam in cls.typeParameters) {
- _makeType(TypeParameterType(typeParam, Nullability.nonNullable), node);
+ types.makeType(
+ this, TypeParameterType(typeParam, Nullability.nonNullable), node);
}
_visitArguments(node.arguments, node.targetReference, 1);
_call(node.targetReference);
@@ -478,7 +482,7 @@
b.ref_as_non_null();
}
for (DartType typeArg in supertype!.typeArguments) {
- _makeType(typeArg, node);
+ types.makeType(this, typeArg, node);
}
_visitArguments(node.arguments, node.targetReference,
1 + supertype.typeArguments.length);
@@ -594,8 +598,8 @@
// Only emit the type test if the guard is not [Object].
if (guard != translator.coreTypes.objectNonNullableRawType) {
b.local_get(thrownException);
- emitTypeTest(
- guard, translator.coreTypes.objectNonNullableRawType, node);
+ types.emitTypeTest(
+ this, guard, translator.coreTypes.objectNonNullableRawType, node);
b.i32_eqz();
b.br_if(catchBlock);
}
@@ -982,10 +986,10 @@
@override
w.ValueType visitThisExpression(
ThisExpression node, w.ValueType expectedType) {
- return _visitThis(expectedType);
+ return visitThis(expectedType);
}
- w.ValueType _visitThis(w.ValueType expectedType) {
+ w.ValueType visitThis(w.ValueType expectedType) {
w.ValueType thisType = thisLocal!.type.withNullability(false);
w.ValueType preciseThisType = preciseThisLocal!.type.withNullability(false);
if (!thisType.isSubtypeOf(expectedType) &&
@@ -1049,7 +1053,7 @@
_lookupSuperTarget(node.interfaceTarget!, setter: false).reference;
w.BaseFunction targetFunction = translator.functions.getFunction(target);
w.ValueType receiverType = targetFunction.type.inputs.first;
- w.ValueType thisType = _visitThis(receiverType);
+ w.ValueType thisType = visitThis(receiverType);
translator.convertType(function, thisType, receiverType);
_visitArguments(node.arguments, target, 1);
return _call(target);
@@ -1080,7 +1084,7 @@
b.end();
return resultType;
default:
- _unimplemented(node, "Nullable invocation of ${target.name.text}",
+ unimplemented(node, "Nullable invocation of ${target.name.text}",
[if (expectedType != voidMarker) expectedType]);
return expectedType;
}
@@ -1103,7 +1107,7 @@
w.ValueType visitDynamicInvocation(
DynamicInvocation node, w.ValueType expectedType) {
if (node.name.text != "call") {
- _unimplemented(node, "Dynamic invocation of ${node.name.text}",
+ unimplemented(node, "Dynamic invocation of ${node.name.text}",
[if (expectedType != voidMarker) expectedType]);
return expectedType;
}
@@ -1460,7 +1464,7 @@
wrap(ConstantExpression(TypeLiteralConstant(NullType())), resultType);
break;
default:
- _unimplemented(
+ unimplemented(
node, "Nullable get of ${target.name.text}", [resultType]);
break;
}
@@ -1773,7 +1777,7 @@
final w.FunctionType signature = translator.signatureFor(target);
final ParameterInfo paramInfo = translator.paramInfoFor(target);
for (int i = 0; i < node.types.length; i++) {
- _makeType(node.types[i], node);
+ types.makeType(this, node.types[i], node);
}
signatureOffset += node.types.length;
for (int i = 0; i < node.positional.length; i++) {
@@ -1812,7 +1816,7 @@
@override
w.ValueType visitStringConcatenation(
StringConcatenation node, w.ValueType expectedType) {
- _makeList(
+ makeList(
node.expressions,
translator.fixedLengthListClass,
InterfaceType(translator.stringBaseClass, Nullability.nonNullable),
@@ -1884,11 +1888,11 @@
@override
w.ValueType visitListLiteral(ListLiteral node, w.ValueType expectedType) {
- return _makeList(node.expressions, translator.growableListClass,
+ return makeList(node.expressions, translator.growableListClass,
node.typeArgument, node);
}
- w.ValueType _makeList(List<Expression> expressions, Class cls,
+ w.ValueType makeList(List<Expression> expressions, Class cls,
DartType typeArg, TreeNode node) {
ClassInfo info = translator.classInfo[cls]!;
translator.functions.allocateClass(info.classId);
@@ -1899,7 +1903,7 @@
b.i32_const(info.classId);
b.i32_const(initialIdentityHash);
- _makeType(typeArg, node);
+ types.makeType(this, typeArg, node);
b.i64_const(length);
if (options.lazyConstants) {
// Avoid array.init instruction in lazy constants mode
@@ -1935,8 +1939,8 @@
w.BaseFunction mapFactory =
translator.functions.getFunction(translator.mapFactory.reference);
w.ValueType factoryReturnType = mapFactory.type.outputs.single;
- _makeType(node.keyType, node);
- _makeType(node.valueType, node);
+ types.makeType(this, node.keyType, node);
+ types.makeType(this, node.valueType, node);
b.call(mapFactory);
if (node.entries.isEmpty) {
return factoryReturnType;
@@ -1962,167 +1966,16 @@
@override
w.ValueType visitTypeLiteral(TypeLiteral node, w.ValueType expectedType) {
- return _makeType(node.type, node);
- }
-
- w.ValueType _makeType(DartType type, TreeNode node) {
- w.ValueType typeType =
- translator.classInfo[translator.typeClass]!.nullableType;
- if (_isTypeConstant(type)) {
- return wrap(ConstantExpression(TypeLiteralConstant(type)), typeType);
- }
- if (type is TypeParameterType) {
- if (type.parameter.parent is FunctionNode) {
- // Type argument to function
- w.Local? local = typeLocals[type.parameter];
- if (local != null) {
- b.local_get(local);
- return local.type;
- } else {
- _unimplemented(
- node, "Type parameter access inside lambda", [typeType]);
- return typeType;
- }
- }
- // Type argument of class
- Class cls = type.parameter.parent as Class;
- ClassInfo info = translator.classInfo[cls]!;
- int fieldIndex = translator.typeParameterIndex[type.parameter]!;
- w.ValueType thisType = _visitThis(info.nullableType);
- translator.convertType(function, thisType, info.nullableType);
- b.struct_get(info.struct, fieldIndex);
- return typeType;
- }
- ClassInfo info = translator.classInfo[translator.typeClass]!;
- translator.functions.allocateClass(info.classId);
- if (type is FutureOrType) {
- // TODO(askesc): Have an actual representation of FutureOr types
- b.ref_null(info.nullableType.heapType);
- return info.nullableType;
- }
- if (type is! InterfaceType) {
- _unimplemented(node, type, [info.nullableType]);
- return info.nullableType;
- }
- ClassInfo typeInfo = translator.classInfo[type.classNode]!;
- w.ValueType typeListExpectedType = info.struct.fields[3].type.unpacked;
- b.i32_const(info.classId);
- b.i32_const(initialIdentityHash);
- b.i64_const(typeInfo.classId);
- if (type.typeArguments.isEmpty) {
- b.global_get(translator.constants.emptyTypeList);
- translator.convertType(function,
- translator.constants.emptyTypeList.type.type, typeListExpectedType);
- } else if (type.typeArguments.every(_isTypeConstant)) {
- ListConstant typeArgs = ListConstant(
- InterfaceType(translator.typeClass, Nullability.nonNullable),
- type.typeArguments.map((t) => TypeLiteralConstant(t)).toList());
- translator.constants
- .instantiateConstant(function, b, typeArgs, typeListExpectedType);
- } else {
- w.ValueType listType = _makeList(
- type.typeArguments.map((t) => TypeLiteral(t)).toList(),
- translator.fixedLengthListClass,
- InterfaceType(translator.typeClass, Nullability.nonNullable),
- node);
- translator.convertType(function, listType, typeListExpectedType);
- }
- translator.struct_new(b, info);
- return info.nullableType;
- }
-
- bool _isTypeConstant(DartType type) {
- return type is DynamicType ||
- type is VoidType ||
- type is NeverType ||
- type is NullType ||
- type is FunctionType ||
- type is InterfaceType && type.typeArguments.every(_isTypeConstant);
+ return types.makeType(this, node.type, node);
}
@override
w.ValueType visitIsExpression(IsExpression node, w.ValueType expectedType) {
wrap(node.operand, translator.topInfo.nullableType);
- emitTypeTest(node.type, dartTypeOf(node.operand), node);
+ types.emitTypeTest(this, node.type, dartTypeOf(node.operand), node);
return w.NumType.i32;
}
- /// Test value against a Dart type. Expects the value on the stack as a
- /// (ref null #Top) and leaves the result on the stack as an i32.
- void emitTypeTest(DartType type, DartType operandType, TreeNode node) {
- if (type is! InterfaceType) {
- // TODO(askesc): Implement type test for remaining types
- print("Not implemented: Type test with non-interface type $type"
- " at ${node.location}");
- b.drop();
- b.i32_const(1);
- return;
- }
- bool isNullable = operandType.isPotentiallyNullable;
- w.Label? resultLabel;
- if (isNullable) {
- // Store operand in a temporary variable, since Binaryen does not support
- // block inputs.
- w.Local operand = addLocal(translator.topInfo.nullableType);
- b.local_set(operand);
- resultLabel = b.block(const [], const [w.NumType.i32]);
- w.Label nullLabel = b.block(const [], const []);
- b.local_get(operand);
- b.br_on_null(nullLabel);
- }
- if (type.typeArguments.any((t) => t is! DynamicType)) {
- // If the tested-against type as an instance of the static operand type
- // has the same type arguments as the static operand type, it is not
- // necessary to test the type arguments.
- Class cls = translator.classForType(operandType);
- InterfaceType? base = translator.hierarchy
- .getTypeAsInstanceOf(type, cls, member.enclosingLibrary)
- ?.withDeclaredNullability(operandType.declaredNullability);
- if (base != operandType) {
- print("Not implemented: Type test with type arguments"
- " at ${node.location}");
- }
- }
- List<Class> concrete = translator.subtypes
- .getSubtypesOf(type.classNode)
- .where((c) => !c.isAbstract)
- .toList();
- if (type.classNode == translator.coreTypes.functionClass) {
- ClassInfo functionInfo = translator.classInfo[translator.functionClass]!;
- translator.ref_test(b, functionInfo);
- } else if (concrete.isEmpty) {
- b.drop();
- b.i32_const(0);
- } else if (concrete.length == 1) {
- ClassInfo info = translator.classInfo[concrete.single]!;
- b.struct_get(translator.topInfo.struct, FieldIndex.classId);
- b.i32_const(info.classId);
- b.i32_eq();
- } else {
- w.Local idLocal = addLocal(w.NumType.i32);
- b.struct_get(translator.topInfo.struct, FieldIndex.classId);
- b.local_set(idLocal);
- w.Label done = b.block(const [], const [w.NumType.i32]);
- b.i32_const(1);
- for (Class cls in concrete) {
- ClassInfo info = translator.classInfo[cls]!;
- b.i32_const(info.classId);
- b.local_get(idLocal);
- b.i32_eq();
- b.br_if(done);
- }
- b.drop();
- b.i32_const(0);
- b.end(); // done
- }
- if (isNullable) {
- b.br(resultLabel!);
- b.end(); // nullLabel
- b.i32_const(type.declaredNullability == Nullability.nullable ? 1 : 0);
- b.end(); // resultLabel
- }
- }
-
@override
w.ValueType visitAsExpression(AsExpression node, w.ValueType expectedType) {
w.Label asCheckBlock = b.block();
@@ -2132,10 +1985,10 @@
// We lower an `as` expression to a type test, throwing a [TypeError] if
// the type test fails.
- emitTypeTest(node.type, dartTypeOf(node.operand), node);
+ types.emitTypeTest(this, node.type, dartTypeOf(node.operand), node);
b.br_if(asCheckBlock);
b.local_get(operand);
- _makeType(node.type, node);
+ types.makeType(this, node.type, node);
_call(translator.stackTraceCurrent.reference);
_call(translator.throwAsCheckError.reference);
b.unreachable();
diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart
index 2744ea7..7a1a84a 100644
--- a/pkg/dart2wasm/lib/constants.dart
+++ b/pkg/dart2wasm/lib/constants.dart
@@ -670,7 +670,8 @@
translator.functions.allocateClass(info.classId);
return createConstant(constant, info.nonNullableType, (function, b) {
ClassInfo typeInfo = translator.classInfo[type.classNode]!;
- w.ValueType typeListExpectedType = info.struct.fields[3].type.unpacked;
+ w.ValueType typeListExpectedType =
+ info.struct.fields[FieldIndex.typeTypeArguments].type.unpacked;
b.i32_const(info.classId);
b.i32_const(initialIdentityHash);
diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart
index 7fb0cf5..bb31c61 100644
--- a/pkg/dart2wasm/lib/intrinsics.dart
+++ b/pkg/dart2wasm/lib/intrinsics.dart
@@ -976,7 +976,8 @@
w.Local receiver = paramLocals[0];
ClassInfo info = translator.classInfo[translator.typeClass]!;
translator.functions.allocateClass(info.classId);
- w.ValueType typeListExpectedType = info.struct.fields[3].type.unpacked;
+ w.ValueType typeListExpectedType =
+ info.struct.fields[FieldIndex.typeTypeArguments].type.unpacked;
b.i32_const(info.classId);
b.i32_const(initialIdentityHash);
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index ecb5a41..d6711a2 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -13,6 +13,7 @@
import 'package:dart2wasm/globals.dart';
import 'package:dart2wasm/param_info.dart';
import 'package:dart2wasm/reference_extensions.dart';
+import 'package:dart2wasm/types.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart'
@@ -113,6 +114,7 @@
late final DispatchTable dispatchTable;
late final Globals globals;
late final Constants constants;
+ late final Types types;
late final FunctionCollector functions;
// Information about the program used and updated by the various phases.
@@ -259,6 +261,7 @@
globals = Globals(this);
constants = Constants(this);
+ types = Types(this);
dispatchTable.build();
diff --git a/pkg/dart2wasm/lib/types.dart b/pkg/dart2wasm/lib/types.dart
new file mode 100644
index 0000000..f9ee6a4
--- /dev/null
+++ b/pkg/dart2wasm/lib/types.dart
@@ -0,0 +1,179 @@
+// Copyright (c) 2022, 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.
+
+import 'package:dart2wasm/class_info.dart';
+import 'package:dart2wasm/code_generator.dart';
+import 'package:dart2wasm/translator.dart';
+
+import 'package:kernel/ast.dart';
+
+import 'package:wasm_builder/wasm_builder.dart' as w;
+
+/// Helper class for building runtime types.
+class Types {
+ final Translator translator;
+
+ Types(this.translator);
+
+ List<Class> _getConcreteSubtypes(Class cls) => translator.subtypes
+ .getSubtypesOf(cls)
+ .where((c) => !c.isAbstract)
+ .toList();
+
+ bool _isTypeConstant(DartType type) {
+ return type is DynamicType ||
+ type is VoidType ||
+ type is NeverType ||
+ type is NullType ||
+ type is FunctionType ||
+ type is InterfaceType && type.typeArguments.every(_isTypeConstant);
+ }
+
+ /// Makes a `_Type` object on the stack.
+ w.ValueType makeType(CodeGenerator codeGen, DartType type, TreeNode node) {
+ w.ValueType typeType =
+ translator.classInfo[translator.typeClass]!.nullableType;
+ w.Instructions b = codeGen.b;
+ if (_isTypeConstant(type)) {
+ translator.constants.instantiateConstant(
+ codeGen.function, b, TypeLiteralConstant(type), typeType);
+ return typeType;
+ }
+ if (type is TypeParameterType) {
+ if (type.parameter.parent is FunctionNode) {
+ // Type argument to function
+ w.Local? local = codeGen.typeLocals[type.parameter];
+ if (local != null) {
+ b.local_get(local);
+ return local.type;
+ } else {
+ codeGen.unimplemented(
+ node, "Type parameter access inside lambda", [typeType]);
+ return typeType;
+ }
+ }
+ // Type argument of class
+ Class cls = type.parameter.parent as Class;
+ ClassInfo info = translator.classInfo[cls]!;
+ int fieldIndex = translator.typeParameterIndex[type.parameter]!;
+ w.ValueType thisType = codeGen.visitThis(info.nullableType);
+ translator.convertType(codeGen.function, thisType, info.nullableType);
+ b.struct_get(info.struct, fieldIndex);
+ return typeType;
+ }
+ ClassInfo info = translator.classInfo[translator.typeClass]!;
+ translator.functions.allocateClass(info.classId);
+ if (type is FutureOrType) {
+ // TODO(askesc): Have an actual representation of FutureOr types
+ b.ref_null(info.nullableType.heapType);
+ return info.nullableType;
+ }
+ if (type is! InterfaceType) {
+ codeGen.unimplemented(node, type, [info.nullableType]);
+ return info.nullableType;
+ }
+ ClassInfo typeInfo = translator.classInfo[type.classNode]!;
+ w.ValueType typeListExpectedType =
+ info.struct.fields[FieldIndex.typeTypeArguments].type.unpacked;
+ b.i32_const(info.classId);
+ b.i32_const(initialIdentityHash);
+ b.i64_const(typeInfo.classId);
+ w.DefinedFunction function = codeGen.function;
+ if (type.typeArguments.isEmpty) {
+ b.global_get(translator.constants.emptyTypeList);
+ translator.convertType(function,
+ translator.constants.emptyTypeList.type.type, typeListExpectedType);
+ } else if (type.typeArguments.every(_isTypeConstant)) {
+ ListConstant typeArgs = ListConstant(
+ InterfaceType(translator.typeClass, Nullability.nonNullable),
+ type.typeArguments.map((t) => TypeLiteralConstant(t)).toList());
+ translator.constants
+ .instantiateConstant(function, b, typeArgs, typeListExpectedType);
+ } else {
+ w.ValueType listType = codeGen.makeList(
+ type.typeArguments.map((t) => TypeLiteral(t)).toList(),
+ translator.fixedLengthListClass,
+ InterfaceType(translator.typeClass, Nullability.nonNullable),
+ node);
+ translator.convertType(function, listType, typeListExpectedType);
+ }
+ translator.struct_new(b, info);
+ return info.nullableType;
+ }
+
+ /// Test value against a Dart type. Expects the value on the stack as a
+ /// (ref null #Top) and leaves the result on the stack as an i32.
+ void emitTypeTest(CodeGenerator codeGen, DartType type, DartType operandType,
+ TreeNode node) {
+ w.Instructions b = codeGen.b;
+ if (type is! InterfaceType) {
+ // TODO(askesc): Implement type test for remaining types
+ print("Not implemented: Type test with non-interface type $type"
+ " at ${node.location}");
+ b.drop();
+ b.i32_const(1);
+ return;
+ }
+ bool isNullable = operandType.isPotentiallyNullable;
+ w.Label? resultLabel;
+ if (isNullable) {
+ // Store operand in a temporary variable, since Binaryen does not support
+ // block inputs.
+ w.Local operand = codeGen.addLocal(translator.topInfo.nullableType);
+ b.local_set(operand);
+ resultLabel = b.block(const [], const [w.NumType.i32]);
+ w.Label nullLabel = b.block(const [], const []);
+ b.local_get(operand);
+ b.br_on_null(nullLabel);
+ }
+ if (type.typeArguments.any((t) => t is! DynamicType)) {
+ // If the tested-against type as an instance of the static operand type
+ // has the same type arguments as the static operand type, it is not
+ // necessary to test the type arguments.
+ Class cls = translator.classForType(operandType);
+ InterfaceType? base = translator.hierarchy
+ .getTypeAsInstanceOf(type, cls, codeGen.member.enclosingLibrary)
+ ?.withDeclaredNullability(operandType.declaredNullability);
+ if (base != operandType) {
+ print("Not implemented: Type test with type arguments"
+ " at ${node.location}");
+ }
+ }
+ List<Class> concrete = _getConcreteSubtypes(type.classNode);
+ if (type.classNode == translator.coreTypes.functionClass) {
+ ClassInfo functionInfo = translator.classInfo[translator.functionClass]!;
+ translator.ref_test(b, functionInfo);
+ } else if (concrete.isEmpty) {
+ b.drop();
+ b.i32_const(0);
+ } else if (concrete.length == 1) {
+ ClassInfo info = translator.classInfo[concrete.single]!;
+ b.struct_get(translator.topInfo.struct, FieldIndex.classId);
+ b.i32_const(info.classId);
+ b.i32_eq();
+ } else {
+ w.Local idLocal = codeGen.addLocal(w.NumType.i32);
+ b.struct_get(translator.topInfo.struct, FieldIndex.classId);
+ b.local_set(idLocal);
+ w.Label done = b.block(const [], const [w.NumType.i32]);
+ b.i32_const(1);
+ for (Class cls in concrete) {
+ ClassInfo info = translator.classInfo[cls]!;
+ b.i32_const(info.classId);
+ b.local_get(idLocal);
+ b.i32_eq();
+ b.br_if(done);
+ }
+ b.drop();
+ b.i32_const(0);
+ b.end(); // done
+ }
+ if (isNullable) {
+ b.br(resultLabel!);
+ b.end(); // nullLabel
+ b.i32_const(type.declaredNullability == Nullability.nullable ? 1 : 0);
+ b.end(); // resultLabel
+ }
+ }
+}
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 9b497f6..3645c43 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -349,9 +349,9 @@
abbr: 'p',
valueHelp: 'path',
help:
- '''Get package locations from the specified file instead of .packages.
+ '''Get package locations from the specified file instead of .dart_tool/package_config.json.
<path> can be relative or absolute.
-For example: dart compile $name --packages=/tmp/pkgs main.dart'''),
+For example: dart compile $name --packages=/tmp/pkgs.json main.dart'''),
super(name, description, verbose, hidden: hidden);
}
diff --git a/pkg/dds/lib/src/devtools/handler.dart b/pkg/dds/lib/src/devtools/handler.dart
index d323f9d..817ff17 100644
--- a/pkg/dds/lib/src/devtools/handler.dart
+++ b/pkg/dds/lib/src/devtools/handler.dart
@@ -3,8 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
import 'package:devtools_shared/devtools_server.dart';
+import 'package:path/path.dart' as path;
import 'package:shelf/shelf.dart';
import 'package:shelf_static/shelf_static.dart';
import 'package:sse/server/sse_handler.dart';
@@ -29,21 +32,51 @@
ClientManager? clientManager,
Handler? notFoundHandler,
}) {
- // Serves the web assets for DevTools.
- final devtoolsAssetHandler = createStaticHandler(
+ // When served through DDS, the app root is /devtools/.
+ // This variable is used in base href and must start and end with `/`.
+ var appRoot = dds != null ? '/devtools/' : '/';
+ if (dds?.authCodesEnabled ?? false) {
+ appRoot = '/${dds!.authCode}$appRoot';
+ }
+
+ const defaultDocument = 'index.html';
+ final indexFile = File(path.join(buildDir, defaultDocument));
+
+ // Serves the static web assets for DevTools.
+ final devtoolsStaticAssetHandler = createStaticHandler(
buildDir,
- defaultDocument: 'index.html',
+ defaultDocument: defaultDocument,
);
+ /// A wrapper around [devtoolsStaticAssetHandler] that handles serving
+ /// index.html up for / and non-file requests like /memory, /inspector, etc.
+ /// with the correct base href for the DevTools root.
+ final devtoolsAssetHandler = (Request request) {
+ // To avoid hard-coding a set of page names here (or needing access to one
+ // from DevTools, assume any single-segment path with no extension is a
+ // DevTools page that needs to serve up index.html).
+ final pathSegments = request.url.pathSegments;
+ final isValidRootPage = pathSegments.isEmpty ||
+ (pathSegments.length == 1 && !pathSegments[0].contains('.'));
+ if (isValidRootPage) {
+ return _serveStaticFile(
+ request,
+ indexFile,
+ 'text/html',
+ baseHref: appRoot,
+ );
+ }
+
+ return devtoolsStaticAssetHandler(request);
+ };
+
// Support DevTools client-server interface via SSE.
// Note: the handler path needs to match the full *original* path, not the
// current request URL (we remove '/devtools' in the initial router but we
// need to include it here).
- final devToolsSseHandlerPath = dds != null ? '/devtools/api/sse' : '/api/sse';
+ final devToolsSseHandlerPath = '${appRoot}api/sse';
final devToolsApiHandler = SseHandler(
- (dds?.authCodesEnabled ?? false)
- ? Uri.parse('/${dds!.authCode}$devToolsSseHandlerPath')
- : Uri.parse(devToolsSseHandlerPath),
+ Uri.parse(devToolsSseHandlerPath),
keepAlive: sseKeepAlive,
);
@@ -78,7 +111,7 @@
return ServerApi.handle(request);
};
- return (request) {
+ return (Request request) {
if (notFoundHandler != null) {
final pathSegments = request.url.pathSegments;
if (pathSegments.isEmpty || pathSegments.first != 'devtools') {
@@ -90,3 +123,30 @@
return devtoolsHandler(request);
};
}
+
+/// Serves [file] for all requests.
+///
+/// If [baseHref] is provided, any existing `<base href="">` tag will be
+/// rewritten with this path.
+Future<Response> _serveStaticFile(
+ Request request,
+ File file,
+ String contentType, {
+ String? baseHref,
+}) async {
+ final headers = {HttpHeaders.contentTypeHeader: contentType};
+ var contents = file.readAsStringSync();
+
+ if (baseHref != null) {
+ assert(baseHref.startsWith('/'));
+ assert(baseHref.endsWith('/'));
+ // Replace the base href to match where the app is being served from.
+ final baseHrefPattern = RegExp(r'<base href="\/"\s?\/?>');
+ contents = contents.replaceFirst(
+ baseHrefPattern,
+ '<base href="${htmlEscape.convert(baseHref)}">',
+ );
+ }
+
+ return Response.ok(contents, headers: headers);
+}
diff --git a/pkg/dds/test/devtools_server/devtools_server_path_strategy_dds_test.dart b/pkg/dds/test/devtools_server/devtools_server_path_strategy_dds_test.dart
new file mode 100644
index 0000000..78baa0c
--- /dev/null
+++ b/pkg/dds/test/devtools_server/devtools_server_path_strategy_dds_test.dart
@@ -0,0 +1,77 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+import 'utils/server_driver.dart';
+
+late final DevToolsServerTestController testController;
+
+void main() {
+ const testScriptContents =
+ 'Future<void> main() => Future.delayed(const Duration(minutes: 10));';
+ final tempDir = Directory.systemTemp.createTempSync('devtools_server.');
+ final devToolsBannerRegex =
+ RegExp(r'DevTools[\w\s]+at: (https?:.*\/devtools\/)');
+
+ test('serves index.html contents for /token/devtools/inspector', () async {
+ final testFile = File(path.join(tempDir.path, 'foo.dart'));
+ testFile.writeAsStringSync(testScriptContents);
+
+ final proc = await Process.start(
+ Platform.resolvedExecutable, ['--observe=0', testFile.path]);
+ try {
+ final completer = Completer<String>();
+ proc.stderr
+ .transform(utf8.decoder)
+ .transform(LineSplitter())
+ .listen(print);
+ proc.stdout.transform(utf8.decoder).transform(LineSplitter()).listen(
+ (String line) {
+ print(line);
+ final match = devToolsBannerRegex.firstMatch(line);
+ if (match != null) {
+ completer.complete(match.group(1));
+ }
+ },
+ onDone: () {
+ if (!completer.isCompleted) {
+ completer.completeError(
+ 'Process ended without emitting DevTools banner');
+ }
+ },
+ onError: (e) {
+ if (!completer.isCompleted) {
+ completer.completeError(e);
+ }
+ },
+ );
+
+ final devToolsUrl = Uri.parse(await completer.future);
+ final httpClient = HttpClient();
+ late HttpClientResponse resp;
+ try {
+ final req = await httpClient.get(
+ devToolsUrl.host, devToolsUrl.port, '${devToolsUrl.path}inspector');
+ resp = await req.close();
+ expect(resp.statusCode, 200);
+ final bodyContent = await resp.transform(utf8.decoder).join();
+ expect(bodyContent, contains('Dart DevTools'));
+ final expectedBaseHref = htmlEscape.convert(devToolsUrl.path);
+ expect(bodyContent, contains('<base href="$expectedBaseHref">'));
+ } finally {
+ httpClient.close();
+ }
+ } finally {
+ proc.kill();
+ }
+ // TODO(dantup): Unskip this test once DevTools has rolled into
+ // the SDK so that contains the (newly-added) base href tag.
+ }, timeout: const Timeout.factor(10), skip: true);
+}
diff --git a/pkg/dds/test/devtools_server/devtools_server_path_strategy_test.dart b/pkg/dds/test/devtools_server/devtools_server_path_strategy_test.dart
new file mode 100644
index 0000000..9185c15
--- /dev/null
+++ b/pkg/dds/test/devtools_server/devtools_server_path_strategy_test.dart
@@ -0,0 +1,72 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:test/test.dart';
+
+import 'utils/server_driver.dart';
+
+late final DevToolsServerTestController testController;
+
+void main() {
+ testController = DevToolsServerTestController();
+
+ setUp(() async {
+ await testController.setUp();
+ });
+
+ tearDown(() async {
+ await testController.tearDown();
+ });
+
+ test('serves index.html contents for /inspector', () async {
+ final server = await DevToolsServerDriver.create();
+ final httpClient = HttpClient();
+ late HttpClientResponse resp;
+ try {
+ final startedEvent = (await server.stdout.firstWhere(
+ (map) => map!['event'] == 'server.started',
+ ))!;
+ final host = startedEvent['params']['host'];
+ final port = startedEvent['params']['port'];
+
+ final req = await httpClient.get(host, port, '/inspector');
+ resp = await req.close();
+ expect(resp.statusCode, 200);
+ final bodyContent = await resp.transform(utf8.decoder).join();
+ expect(bodyContent, contains('Dart DevTools'));
+ final expectedBaseHref = htmlEscape.convert('/');
+ expect(bodyContent, contains('<base href="$expectedBaseHref">'));
+ } finally {
+ httpClient.close();
+ server.kill();
+ }
+ // TODO(dantup): Unskip this test once DevTools has rolled into
+ // the SDK so that contains the (newly-added) base href tag.
+ }, timeout: const Timeout.factor(10), skip: true);
+
+ test('serves 404 contents for requests that are not pages', () async {
+ final server = await DevToolsServerDriver.create();
+ final httpClient = HttpClient();
+ late HttpClientResponse resp;
+ try {
+ final startedEvent = (await server.stdout.firstWhere(
+ (map) => map!['event'] == 'server.started',
+ ))!;
+ final host = startedEvent['params']['host'];
+ final port = startedEvent['params']['port'];
+
+ // The index page is only served up for extension-less requests.
+ final req = await httpClient.get(host, port, '/inspector.html');
+ resp = await req.close();
+ expect(resp.statusCode, 404);
+ } finally {
+ httpClient.close();
+ await resp.drain();
+ server.kill();
+ }
+ }, timeout: const Timeout.factor(10));
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
index 1edef57..77159ce 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
@@ -159,22 +159,41 @@
reference);
}
-/// Creates the parameters and body for [tearOff] based on [constructor] in
-/// [enclosingClass].
-void buildConstructorTearOffProcedure(Procedure tearOff, Member constructor,
- Class enclosingClass, SourceLibraryBuilder libraryBuilder) {
+/// Creates the parameters and body for [tearOff] based on
+/// [declarationConstructor] in [enclosingClass].
+///
+/// The [declarationConstructor] is the origin constructor and
+/// [implementationConstructor] is the patch constructor, if patched, otherwise
+/// it is the [declarationConstructor].
+void buildConstructorTearOffProcedure(
+ {required Procedure tearOff,
+ required Member declarationConstructor,
+ required Member implementationConstructor,
+ required Class enclosingClass,
+ required SourceLibraryBuilder libraryBuilder}) {
assert(
- constructor is Constructor ||
- (constructor is Procedure && constructor.isFactory) ||
- (constructor is Procedure && constructor.isStatic),
- "Unexpected constructor tear off target $constructor "
- "(${constructor.runtimeType}).");
+ declarationConstructor is Constructor ||
+ (declarationConstructor is Procedure &&
+ declarationConstructor.isFactory) ||
+ (declarationConstructor is Procedure &&
+ declarationConstructor.isStatic),
+ "Unexpected constructor tear off target $declarationConstructor "
+ "(${declarationConstructor.runtimeType}).");
+ assert(
+ declarationConstructor is Constructor ||
+ (declarationConstructor is Procedure &&
+ declarationConstructor.isFactory) ||
+ (declarationConstructor is Procedure &&
+ declarationConstructor.isStatic),
+ "Unexpected constructor tear off target $declarationConstructor "
+ "(${declarationConstructor.runtimeType}).");
+
+ FunctionNode function = implementationConstructor.function!;
int fileOffset = tearOff.fileOffset;
- FunctionNode function = constructor.function!;
List<TypeParameter> classTypeParameters;
- if (constructor is Constructor) {
+ if (declarationConstructor is Constructor) {
// Generative constructors implicitly have the type parameters of the
// enclosing class.
classTypeParameters = enclosingClass.typeParameters;
@@ -189,37 +208,54 @@
List<DartType> typeArguments = freshTypeParameters.freshTypeArguments;
Substitution substitution = freshTypeParameters.substitution;
- _createParameters(tearOff, constructor, substitution, libraryBuilder);
+ _createParameters(tearOff, implementationConstructor, function, substitution,
+ libraryBuilder);
Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
- _createTearOffBody(tearOff, constructor, arguments);
+ _createTearOffBody(tearOff, declarationConstructor, arguments);
tearOff.function.fileOffset = tearOff.fileOffset;
tearOff.function.fileEndOffset = tearOff.fileOffset;
updatePrivateMemberName(tearOff, libraryBuilder);
}
/// Creates the parameters and body for [tearOff] for a typedef tearoff of
-/// [constructor] in [enclosingClass] with [typeParameters] as the typedef
-/// parameters and [typeArguments] as the arguments passed to the
+/// [declarationConstructor] in [enclosingClass] with [typeParameters] as the
+/// typedef parameters and [typeArguments] as the arguments passed to the
/// [enclosingClass].
+///
+/// The [declarationConstructor] is the origin constructor and
+/// [implementationConstructor] is the patch constructor, if patched, otherwise
+/// it is the [declarationConstructor].
void buildTypedefTearOffProcedure(
- Procedure tearOff,
- Member constructor,
- Class enclosingClass,
- List<TypeParameter> typeParameters,
- List<DartType> typeArguments,
- SourceLibraryBuilder libraryBuilder) {
+ {required Procedure tearOff,
+ required Member declarationConstructor,
+ required Member implementationConstructor,
+ required Class enclosingClass,
+ required List<TypeParameter> typeParameters,
+ required List<DartType> typeArguments,
+ required SourceLibraryBuilder libraryBuilder}) {
assert(
- constructor is Constructor ||
- (constructor is Procedure && constructor.isFactory) ||
- (constructor is Procedure && constructor.isStatic),
- "Unexpected constructor tear off target $constructor "
- "(${constructor.runtimeType}).");
+ declarationConstructor is Constructor ||
+ (declarationConstructor is Procedure &&
+ declarationConstructor.isFactory) ||
+ (declarationConstructor is Procedure &&
+ declarationConstructor.isStatic),
+ "Unexpected constructor tear off target $declarationConstructor "
+ "(${declarationConstructor.runtimeType}).");
+ assert(
+ implementationConstructor is Constructor ||
+ (implementationConstructor is Procedure &&
+ implementationConstructor.isFactory) ||
+ (implementationConstructor is Procedure &&
+ implementationConstructor.isStatic),
+ "Unexpected constructor tear off target $implementationConstructor "
+ "(${declarationConstructor.runtimeType}).");
+
+ FunctionNode function = implementationConstructor.function!;
int fileOffset = tearOff.fileOffset;
- FunctionNode function = constructor.function!;
List<TypeParameter> classTypeParameters;
- if (constructor is Constructor) {
+ if (declarationConstructor is Constructor) {
// Generative constructors implicitly have the type parameters of the
// enclosing class.
classTypeParameters = enclosingClass.typeParameters;
@@ -242,37 +278,43 @@
}
_createParameters(
tearOff,
- constructor,
+ implementationConstructor,
+ function,
Substitution.fromPairs(classTypeParameters, typeArguments),
libraryBuilder);
Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
- _createTearOffBody(tearOff, constructor, arguments);
+ _createTearOffBody(tearOff, declarationConstructor, arguments);
tearOff.function.fileOffset = tearOff.fileOffset;
tearOff.function.fileEndOffset = tearOff.fileOffset;
updatePrivateMemberName(tearOff, libraryBuilder);
}
/// Creates the parameters for the redirecting factory [tearOff] based on the
-/// [redirectingConstructor] declaration.
+/// [declarationConstructor] declaration.
+///
+/// The [declarationConstructor] is the [Procedure] for the origin constructor
+/// and [implementationConstructorFunctionNode] is the [FunctionNode] for the
+/// implementation constructor. If the constructor is patched, these are not
+/// connected until [Builder.finishPatch].
FreshTypeParameters buildRedirectingFactoryTearOffProcedureParameters(
- Procedure tearOff,
- Procedure redirectingConstructor,
- SourceLibraryBuilder libraryBuilder) {
- assert(redirectingConstructor.isRedirectingFactory);
- FunctionNode function = redirectingConstructor.function;
+ {required Procedure tearOff,
+ required Procedure implementationConstructor,
+ required SourceLibraryBuilder libraryBuilder}) {
+ assert(implementationConstructor.isRedirectingFactory);
+ FunctionNode function = implementationConstructor.function;
FreshTypeParameters freshTypeParameters =
_createFreshTypeParameters(function.typeParameters, tearOff.function);
Substitution substitution = freshTypeParameters.substitution;
- _createParameters(
- tearOff, redirectingConstructor, substitution, libraryBuilder);
+ _createParameters(tearOff, implementationConstructor, function, substitution,
+ libraryBuilder);
tearOff.function.fileOffset = tearOff.fileOffset;
tearOff.function.fileEndOffset = tearOff.fileOffset;
updatePrivateMemberName(tearOff, libraryBuilder);
return freshTypeParameters;
}
-/// Creates the body for the redirecting factory [tearOff] with the target
-/// [constructor] and [typeArguments].
+/// Creates the body for the redirecting factory [tearOff] with the [target]
+/// constructor and [typeArguments].
///
/// Returns the [DelayedDefaultValueCloner] object need to perform default value
/// computation.
@@ -355,9 +397,12 @@
/// Creates the parameters for the [tearOff] lowering based of the parameters
/// in [constructor] and using the [substitution] to compute the parameter and
/// return types.
-void _createParameters(Procedure tearOff, Member constructor,
- Substitution substitution, SourceLibraryBuilder libraryBuilder) {
- FunctionNode function = constructor.function!;
+void _createParameters(
+ Procedure tearOff,
+ Member constructor,
+ FunctionNode function,
+ Substitution substitution,
+ SourceLibraryBuilder libraryBuilder) {
for (VariableDeclaration constructorParameter
in function.positionalParameters) {
VariableDeclaration tearOffParameter = new VariableDeclaration(
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
index 75a94cf..ffbbab7 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
@@ -300,3 +300,39 @@
_hasBeenInferred = true;
}
}
+
+/// Copies properties, function parameters and body from the [patch] constructor
+/// to its [origin].
+void finishConstructorPatch(Constructor origin, Constructor patch) {
+ // TODO(ahe): restore file-offset once we track both origin and patch file
+ // URIs. See https://github.com/dart-lang/sdk/issues/31579
+ origin.fileUri = patch.fileUri;
+ origin.startFileOffset = patch.startFileOffset;
+ origin.fileOffset = patch.fileOffset;
+ origin.fileEndOffset = patch.fileEndOffset;
+ origin.annotations.forEach((m) => m.fileOffset = patch.fileOffset);
+
+ origin.isExternal = patch.isExternal;
+ origin.function = patch.function;
+ origin.function.parent = origin;
+ origin.initializers = patch.initializers;
+ setParents(origin.initializers, origin);
+}
+
+/// Copies properties, function parameters and body from the [patch] procedure
+/// to its [origin].
+void finishProcedurePatch(Procedure origin, Procedure patch) {
+ // TODO(ahe): restore file-offset once we track both origin and patch file
+ // URIs. See https://github.com/dart-lang/sdk/issues/31579
+ origin.fileUri = patch.fileUri;
+ origin.startFileOffset = patch.startFileOffset;
+ origin.fileOffset = patch.fileOffset;
+ origin.fileEndOffset = patch.fileEndOffset;
+ origin.annotations.forEach((m) => m.fileOffset = patch.fileOffset);
+
+ origin.isAbstract = patch.isAbstract;
+ origin.isExternal = patch.isExternal;
+ origin.function = patch.function;
+ origin.function.parent = origin;
+ origin.isRedirectingFactory = patch.isRedirectingFactory;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 5794d25..c80faa19 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -1092,8 +1092,12 @@
forAbstractClassOrEnum: classBuilder.isAbstract);
if (constructorTearOff != null) {
- buildConstructorTearOffProcedure(constructorTearOff, constructor,
- classBuilder.cls, classBuilder.libraryBuilder);
+ buildConstructorTearOffProcedure(
+ tearOff: constructorTearOff,
+ declarationConstructor: constructor,
+ implementationConstructor: constructor,
+ enclosingClass: classBuilder.cls,
+ libraryBuilder: classBuilder.libraryBuilder);
}
SyntheticSourceConstructorBuilder constructorBuilder =
new SyntheticSourceConstructorBuilder(
@@ -1170,8 +1174,12 @@
forAbstractClassOrEnum:
enclosingClass.isAbstract || enclosingClass.isEnum);
if (constructorTearOff != null) {
- buildConstructorTearOffProcedure(constructorTearOff, constructor,
- classBuilder.cls, classBuilder.libraryBuilder);
+ buildConstructorTearOffProcedure(
+ tearOff: constructorTearOff,
+ declarationConstructor: constructor,
+ implementationConstructor: constructor,
+ enclosingClass: classBuilder.cls,
+ libraryBuilder: classBuilder.libraryBuilder);
}
return new SyntheticSourceConstructorBuilder(
classBuilder, constructor, constructorTearOff);
diff --git a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
index 3aa7702..c0dadf6 100644
--- a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
@@ -27,7 +27,11 @@
import '../kernel/expression_generator_helper.dart';
import '../kernel/hierarchy/class_member.dart' show ClassMember;
import '../kernel/kernel_helper.dart'
- show DelayedDefaultValueCloner, TypeDependency;
+ show
+ DelayedDefaultValueCloner,
+ TypeDependency,
+ finishConstructorPatch,
+ finishProcedurePatch;
import '../kernel/utils.dart'
show isRedirectingGenerativeConstructorImplementation;
import '../messages.dart'
@@ -202,8 +206,12 @@
updatePrivateMemberName(_constructor, libraryBuilder);
if (_constructorTearOff != null) {
- buildConstructorTearOffProcedure(_constructorTearOff!, _constructor,
- classBuilder.cls, libraryBuilder);
+ buildConstructorTearOffProcedure(
+ tearOff: _constructorTearOff!,
+ declarationConstructor: constructor,
+ implementationConstructor: _constructor,
+ enclosingClass: classBuilder.cls,
+ libraryBuilder: libraryBuilder);
}
_hasBeenBuilt = true;
@@ -660,20 +668,11 @@
}
void _finishPatch() {
- // TODO(ahe): restore file-offset once we track both origin and patch file
- // URIs. See https://github.com/dart-lang/sdk/issues/31579
- origin.constructor.fileUri = fileUri;
- origin.constructor.startFileOffset = _constructor.startFileOffset;
- origin.constructor.fileOffset = _constructor.fileOffset;
- origin.constructor.fileEndOffset = _constructor.fileEndOffset;
- origin.constructor.annotations
- .forEach((m) => m.fileOffset = _constructor.fileOffset);
+ finishConstructorPatch(origin.constructor, _constructor);
- origin.constructor.isExternal = _constructor.isExternal;
- origin.constructor.function = _constructor.function;
- origin.constructor.function.parent = origin.constructor;
- origin.constructor.initializers = _constructor.initializers;
- setParents(origin.constructor.initializers, origin.constructor);
+ if (_constructorTearOff != null) {
+ finishProcedurePatch(origin._constructorTearOff!, _constructorTearOff!);
+ }
}
@override
diff --git a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
index cef67f3..09523b6 100644
--- a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
@@ -151,8 +151,12 @@
_procedureInternal.isStatic = isStatic;
if (_factoryTearOff != null) {
- buildConstructorTearOffProcedure(_factoryTearOff!, _procedureInternal,
- classBuilder!.cls, libraryBuilder);
+ buildConstructorTearOffProcedure(
+ tearOff: _factoryTearOff!,
+ declarationConstructor: _procedure,
+ implementationConstructor: _procedureInternal,
+ enclosingClass: classBuilder!.cls,
+ libraryBuilder: libraryBuilder);
}
return _procedureInternal;
}
@@ -224,21 +228,11 @@
}
void _finishPatch() {
- // TODO(ahe): restore file-offset once we track both origin and patch file
- // URIs. See https://github.com/dart-lang/sdk/issues/31579
- origin._procedure.fileUri = fileUri;
- origin._procedure.startFileOffset = _procedureInternal.startFileOffset;
- origin._procedure.fileOffset = _procedureInternal.fileOffset;
- origin._procedure.fileEndOffset = _procedureInternal.fileEndOffset;
- origin._procedure.annotations
- .forEach((m) => m.fileOffset = _procedureInternal.fileOffset);
+ finishProcedurePatch(origin._procedure, _procedureInternal);
- origin._procedure.isAbstract = _procedureInternal.isAbstract;
- origin._procedure.isExternal = _procedureInternal.isExternal;
- origin._procedure.function = _procedureInternal.function;
- origin._procedure.function.parent = origin._procedure;
- origin._procedure.isRedirectingFactory =
- _procedureInternal.isRedirectingFactory;
+ if (_factoryTearOff != null) {
+ finishProcedurePatch(origin._factoryTearOff!, _factoryTearOff!);
+ }
}
@override
@@ -373,7 +367,9 @@
if (_factoryTearOff != null) {
_tearOffTypeParameters =
buildRedirectingFactoryTearOffProcedureParameters(
- _factoryTearOff!, _procedureInternal, libraryBuilder);
+ tearOff: _factoryTearOff!,
+ implementationConstructor: _procedureInternal,
+ libraryBuilder: libraryBuilder);
}
return _procedureInternal;
}
diff --git a/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart b/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
index 89731b6..1a7fe1f 100644
--- a/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
@@ -16,6 +16,7 @@
import '../builder/type_variable_builder.dart';
import '../kernel/hierarchy/class_member.dart';
import '../kernel/hierarchy/members_builder.dart';
+import '../kernel/kernel_helper.dart';
import '../kernel/member_covariance.dart';
import '../source/name_scheme.dart';
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
@@ -470,20 +471,7 @@
int finishPatch() {
if (!isPatch) return 0;
- // TODO(ahe): restore file-offset once we track both origin and patch file
- // URIs. See https://github.com/dart-lang/sdk/issues/31579
- origin.procedure.fileUri = fileUri;
- origin.procedure.startFileOffset = _procedure.startFileOffset;
- origin.procedure.fileOffset = _procedure.fileOffset;
- origin.procedure.fileEndOffset = _procedure.fileEndOffset;
- origin.procedure.annotations
- .forEach((m) => m.fileOffset = _procedure.fileOffset);
-
- origin.procedure.isAbstract = _procedure.isAbstract;
- origin.procedure.isExternal = _procedure.isExternal;
- origin.procedure.function = _procedure.function;
- origin.procedure.function.parent = origin.procedure;
- origin.procedure.isRedirectingFactory = _procedure.isRedirectingFactory;
+ finishProcedurePatch(origin.procedure, _procedure);
return 1;
}
diff --git a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
index 720a1b4..c24455e 100644
--- a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
@@ -4,7 +4,6 @@
library fasta.source_type_alias_builder;
-import 'package:front_end/src/fasta/kernel/expression_generator_helper.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/type_environment.dart';
@@ -24,6 +23,7 @@
import '../fasta_codes.dart'
show noLength, templateCyclicTypedef, templateTypeArgumentMismatch;
import '../kernel/constructor_tearoff_lowering.dart';
+import '../kernel/expression_generator_helper.dart';
import '../kernel/kernel_helper.dart';
import '../problems.dart' show unhandled;
import '../scope.dart';
@@ -275,14 +275,14 @@
Map<Procedure, Member>? _tearOffDependencies;
void buildTypedefTearOffs(
- SourceLibraryBuilder library, void Function(Procedure) f) {
+ SourceLibraryBuilder libraryBuilder, void Function(Procedure) f) {
TypeDeclarationBuilder? declaration = unaliasDeclaration(null);
DartType? targetType = typedef.type;
if (declaration is ClassBuilder &&
targetType is InterfaceType &&
typedef.typeParameters.isNotEmpty &&
- !isProperRenameForClass(
- library.loader.typeEnvironment, typedef, library.library)) {
+ !isProperRenameForClass(libraryBuilder.loader.typeEnvironment, typedef,
+ libraryBuilder.library)) {
tearOffs = {};
_tearOffDependencies = {};
declaration
@@ -295,19 +295,31 @@
Name targetName =
new Name(constructorName, declaration.libraryBuilder.library);
Reference? tearOffReference;
- if (library.referencesFromIndexed != null) {
- tearOffReference = library.referencesFromIndexed!
+ if (libraryBuilder.referencesFromIndexed != null) {
+ tearOffReference = libraryBuilder.referencesFromIndexed!
.lookupGetterReference(typedefTearOffName(name, constructorName,
- library.referencesFromIndexed!.library));
+ libraryBuilder.referencesFromIndexed!.library));
}
Procedure tearOff = tearOffs![targetName] =
- createTypedefTearOffProcedure(name, constructorName, library,
- target.fileUri, target.fileOffset, tearOffReference);
+ createTypedefTearOffProcedure(
+ name,
+ constructorName,
+ libraryBuilder,
+ target.fileUri,
+ target.fileOffset,
+ tearOffReference);
_tearOffDependencies![tearOff] = target;
- buildTypedefTearOffProcedure(tearOff, target, declaration.cls,
- typedef.typeParameters, targetType.typeArguments, library);
+ buildTypedefTearOffProcedure(
+ tearOff: tearOff,
+ declarationConstructor: target,
+ // TODO(johnniwinther): Handle patched constructors.
+ implementationConstructor: target,
+ enclosingClass: declaration.cls,
+ typeParameters: typedef.typeParameters,
+ typeArguments: targetType.typeArguments,
+ libraryBuilder: libraryBuilder);
f(tearOff);
}
});
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart b/pkg/front_end/testcases/dart2js/issue48776.dart
new file mode 100644
index 0000000..5bad3b1
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, 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.
+
+main() {
+ BigInt.from;
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.strong.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.strong.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.strong.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+ #C1;
+}
+
+constants {
+ #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.strong.transformed.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.strong.transformed.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+ #C1;
+}
+
+constants {
+ #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline.expect
new file mode 100644
index 0000000..bae895a
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline.expect
@@ -0,0 +1 @@
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..bae895a
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.textual_outline_modelled.expect
@@ -0,0 +1 @@
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.weak.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+ #C1;
+}
+
+constants {
+ #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.modular.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.modular.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+ #C1;
+}
+
+constants {
+ #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.outline.expect
new file mode 100644
index 0000000..e2cba6b
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.outline.expect
@@ -0,0 +1,5 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/dart2js/issue48776.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.transformed.expect
new file mode 100644
index 0000000..7fd42484
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/issue48776.dart.weak.transformed.expect
@@ -0,0 +1,11 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+ #C1;
+}
+
+constants {
+ #C1 = static-tearoff core::BigInt::_#from#tearOff
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/libraries.json b/pkg/front_end/testcases/dart2js/tear_off_patch/libraries.json
new file mode 100644
index 0000000..154c73c
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/libraries.json
@@ -0,0 +1,12 @@
+{
+ "none": {
+ "libraries": {
+ "test": {
+ "patches": [
+ "patch_lib.dart"
+ ],
+ "uri": "origin_lib.dart"
+ }
+ }
+ }
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart
new file mode 100644
index 0000000..676f68a
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, 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.
+
+import 'dart:test';
+
+main() {
+ Class.new;
+ Class.fact;
+ Class.redirect;
+ Class.redirect2;
+ ClassImpl.new;
+ ClassImpl.patched;
+ Alias.new;
+ Alias.fact;
+ Alias.redirect;
+ Alias.redirect2;
+ AliasImpl.new;
+ AliasImpl.patched;
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+ return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+ return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+ return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+ return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+ static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+ return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+ return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = static-tearoff test::Class::_#new#tearOff
+ #C2 = static-tearoff test::Class::_#fact#tearOff
+ #C3 = static-tearoff test::Class::_#redirect#tearOff
+ #C4 = static-tearoff test::Class::_#redirect2#tearOff
+ #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+ #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _js::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.strong.transformed.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+ return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+ return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+ return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+ return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+ static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+ return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+ return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = static-tearoff test::Class::_#new#tearOff
+ #C2 = static-tearoff test::Class::_#fact#tearOff
+ #C3 = static-tearoff test::Class::_#redirect#tearOff
+ #C4 = static-tearoff test::Class::_#redirect2#tearOff
+ #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+ #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _js::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+ return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+ return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+ return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+ return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+ static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+ return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+ return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = static-tearoff test::Class::_#new#tearOff
+ #C2 = static-tearoff test::Class::_#fact#tearOff
+ #C3 = static-tearoff test::Class::_#redirect#tearOff
+ #C4 = static-tearoff test::Class::_#redirect2#tearOff
+ #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+ #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _js::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.modular.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.modular.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+ return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+ return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+ return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+ return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+ static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+ return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+ return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = static-tearoff test::Class::_#new#tearOff
+ #C2 = static-tearoff test::Class::_#fact#tearOff
+ #C3 = static-tearoff test::Class::_#redirect#tearOff
+ #C4 = static-tearoff test::Class::_#redirect2#tearOff
+ #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+ #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _js::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.outline.expect
new file mode 100644
index 0000000..49786e9
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.outline.expect
@@ -0,0 +1,77 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic
+ ;
+
+library /*isNonNullableByDefault*/;
+import self as self2;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = self2::Class<T>;
+typedef AliasImpl<T extends core::num> = self2::ClassImpl<T>;
+@_js::patch
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self2::Class::redirect, self2::Class::redirect2]/*isLegacy*/;
+ @_js::patch
+ external constructor •({core::bool defaultValue = true, required self2::Class::T% value = null}) → self2::Class<self2::Class::T%>
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::Class::_#new#tearOff::T% value}) → self2::Class<self2::Class::_#new#tearOff::T%>
+ return new self2::Class::•<self2::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @_js::patch
+ external static factory fact<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::Class::fact::T% value}) → self2::Class<self2::Class::fact::T%>;
+ static method _#fact#tearOff<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::Class::_#fact#tearOff::T% value}) → self2::Class<self2::Class::_#fact#tearOff::T%>
+ return self2::Class::fact<self2::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @_js::patch
+ external static factory redirect<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::redirect::T% value}) → self2::Class<self2::Class::redirect::T%>
+ return new self2::ClassImpl::•<self2::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::_#redirect#tearOff::T% value}) → self2::Class<self2::Class::_#redirect#tearOff::T%>
+ return self2::Class::redirect<self2::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @_js::patch
+ external static factory redirect2<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::redirect2::T% value}) → self2::Class<self2::Class::redirect2::T%>
+ return new self2::ClassImpl::patched<self2::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+ static method _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::_#redirect2#tearOff::T% value}) → self2::Class<self2::Class::_#redirect2#tearOff::T%>
+ return self2::Class::redirect2<self2::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@_js::patch
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements self2::Class<self2::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = true, required self2::ClassImpl::T% value = null}) → self2::ClassImpl<self2::ClassImpl::T%>
+ ;
+ @_js::patch
+ external constructor patched({core::bool defaultValue = true, required self2::ClassImpl::T% value = null}) → self2::ClassImpl<self2::ClassImpl::T%>
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::ClassImpl::_#new#tearOff::T% value}) → self2::ClassImpl<self2::ClassImpl::_#new#tearOff::T%>
+ return new self2::ClassImpl::•<self2::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ static method _#patched#tearOff<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::ClassImpl::_#patched#tearOff::T% value}) → self2::ClassImpl<self2::ClassImpl::_#patched#tearOff::T%>
+ return new self2::ClassImpl::patched<self2::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#Alias#new#tearOff::T value}) → self2::Class<self2::_#Alias#new#tearOff::T>
+ return new self2::Class::•<self2::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#Alias#fact#tearOff::T value}) → self2::Class<self2::_#Alias#fact#tearOff::T>
+ return self2::Class::fact<self2::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue, required self2::_#Alias#redirect#tearOff::T value}) → self2::Class<self2::_#Alias#redirect#tearOff::T>
+ return self2::Class::_#redirect#tearOff<self2::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue, required self2::_#Alias#redirect2#tearOff::T value}) → self2::Class<self2::_#Alias#redirect2#tearOff::T>
+ return self2::Class::_#redirect2#tearOff<self2::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#AliasImpl#new#tearOff::T value}) → self2::ClassImpl<self2::_#AliasImpl#new#tearOff::T>
+ return new self2::ClassImpl::•<self2::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#AliasImpl#patched#tearOff::T value}) → self2::ClassImpl<self2::_#AliasImpl#patched#tearOff::T>
+ return new self2::ClassImpl::patched<self2::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+
+Extra constant evaluation status:
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:6:47 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:7:10 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:8:29 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:12:22 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:15:12 -> InstanceConstant(const _Patch{})
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///origin_lib.dart:5:7 -> ConstructorTearOffConstant(Class.redirect)
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///origin_lib.dart:5:7 -> ConstructorTearOffConstant(Class.redirect2)
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:18:39 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:19:48 -> InstanceConstant(const _Patch{})
+Extra constant evaluation: evaluated: 52, effectively constant: 9
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.transformed.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/main.dart.weak.transformed.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+ return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+ return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+ return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+ return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+ static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+ return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+ return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = static-tearoff test::Class::_#new#tearOff
+ #C2 = static-tearoff test::Class::_#fact#tearOff
+ #C3 = static-tearoff test::Class::_#redirect#tearOff
+ #C4 = static-tearoff test::Class::_#redirect2#tearOff
+ #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+ #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _js::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/origin_lib.dart b/pkg/front_end/testcases/dart2js/tear_off_patch/origin_lib.dart
new file mode 100644
index 0000000..c29cf6f
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/origin_lib.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2022, 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.
+
+class Class<T> {
+ external Class({bool defaultValue: true, required T value});
+ external factory Class.fact({bool defaultValue: true, required T value});
+ external factory Class.redirect({bool defaultValue, required T value});
+ external factory Class.redirect2({bool defaultValue, required T value});
+}
+
+class ClassImpl<T> implements Class<T> {
+ ClassImpl({bool defaultValue: true, required T value});
+
+ external ClassImpl.patched({bool defaultValue: true, required T value});
+}
+
+typedef Alias<T extends num> = Class<T>;
+typedef AliasImpl<T extends num> = ClassImpl<T>;
diff --git a/pkg/front_end/testcases/dart2js/tear_off_patch/patch_lib.dart b/pkg/front_end/testcases/dart2js/tear_off_patch/patch_lib.dart
new file mode 100644
index 0000000..77fdfb0
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/tear_off_patch/patch_lib.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2022, 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.
+
+// ignore: import_internal_library
+import 'dart:_js_helper';
+
+@patch
+class Class<T> {
+ @patch
+ Class({bool defaultValue: true, required T value}) {
+ print('patch Class');
+ }
+
+ @patch
+ factory Class.fact({bool defaultValue: true, required T value}) =>
+ new ClassImpl<T>(defaultValue: defaultValue, value: value);
+
+ @patch
+ factory Class.redirect({bool defaultValue, required T value}) = ClassImpl<T>;
+
+ @patch
+ factory Class.redirect2({bool defaultValue, required T value}) =
+ ClassImpl<T>.patched;
+}
+
+@patch
+class ClassImpl<T> implements Class<T> {
+ @patch
+ ClassImpl.patched({bool defaultValue: true, required T value}) {
+ print('patch ClassImpl');
+ }
+}
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect
index 3eaf932..af74037 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect
@@ -24,12 +24,12 @@
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact({core::bool defaultValue = #C3}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
- static method _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::fact(defaultValue: defaultValue);
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ constFact({core::bool defaultValue = #C3}) → test::Class
return throw "unsupported";
- static method _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::constFact(defaultValue: defaultValue);
static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue = #C2}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect
index 3eaf932..af74037 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect
@@ -24,12 +24,12 @@
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact({core::bool defaultValue = #C3}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
- static method _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::fact(defaultValue: defaultValue);
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ constFact({core::bool defaultValue = #C3}) → test::Class
return throw "unsupported";
- static method _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::constFact(defaultValue: defaultValue);
static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue = #C2}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.expect
index 3eaf932..af74037 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.expect
@@ -24,12 +24,12 @@
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact({core::bool defaultValue = #C3}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
- static method _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::fact(defaultValue: defaultValue);
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ constFact({core::bool defaultValue = #C3}) → test::Class
return throw "unsupported";
- static method _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::constFact(defaultValue: defaultValue);
static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue = #C2}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.modular.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.modular.expect
index 3eaf932..af74037 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.modular.expect
@@ -24,12 +24,12 @@
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact({core::bool defaultValue = #C3}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
- static method _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::fact(defaultValue: defaultValue);
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ constFact({core::bool defaultValue = #C3}) → test::Class
return throw "unsupported";
- static method _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::constFact(defaultValue: defaultValue);
static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue = #C2}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.transformed.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.transformed.expect
index 3eaf932..af74037 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.weak.transformed.expect
@@ -24,12 +24,12 @@
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact({core::bool defaultValue = #C3}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
- static method _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::fact(defaultValue: defaultValue);
@#C1
static factory /* from org-dartlang-testcase:///patch_lib.dart */ constFact({core::bool defaultValue = #C3}) → test::Class
return throw "unsupported";
- static method _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#constFact#tearOff({core::bool defaultValue = #C3}) → test::Class
return test::Class::constFact(defaultValue: defaultValue);
static method /* from org-dartlang-testcase:///patch_lib.dart */ _#_internal#tearOff({core::bool defaultValue = #C2}) → test::Class
return new test::Class::_internal(defaultValue: defaultValue);
diff --git a/pkg/front_end/testcases/general/tear_off_patch/libraries.json b/pkg/front_end/testcases/general/tear_off_patch/libraries.json
new file mode 100644
index 0000000..154c73c
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/libraries.json
@@ -0,0 +1,12 @@
+{
+ "none": {
+ "libraries": {
+ "test": {
+ "patches": [
+ "patch_lib.dart"
+ ],
+ "uri": "origin_lib.dart"
+ }
+ }
+ }
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart b/pkg/front_end/testcases/general/tear_off_patch/main.dart
new file mode 100644
index 0000000..676f68a
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, 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.
+
+import 'dart:test';
+
+main() {
+ Class.new;
+ Class.fact;
+ Class.redirect;
+ Class.redirect2;
+ ClassImpl.new;
+ ClassImpl.patched;
+ Alias.new;
+ Alias.fact;
+ Alias.redirect;
+ Alias.redirect2;
+ AliasImpl.new;
+ AliasImpl.patched;
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+ return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+ return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+ return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+ return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+ static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+ return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+ return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = static-tearoff test::Class::_#new#tearOff
+ #C2 = static-tearoff test::Class::_#fact#tearOff
+ #C3 = static-tearoff test::Class::_#redirect#tearOff
+ #C4 = static-tearoff test::Class::_#redirect2#tearOff
+ #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+ #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _js::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..3ba9f86
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.strong.transformed.expect
@@ -0,0 +1,104 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_js_helper" as _js;
+
+import "dart:_js_helper";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#new#tearOff::T% value = #C17}) → test::Class<test::Class::_#new#tearOff::T%>
+ return new test::Class::•<test::Class::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#fact#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#fact#tearOff::T% value = #C17}) → test::Class<test::Class::_#fact#tearOff::T%>
+ return test::Class::fact<test::Class::_#fact#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect#tearOff::T%>
+ return new test::ClassImpl::•<test::Class::_#redirect#tearOff::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#redirect2#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::_#redirect2#tearOff::T% value = #C17}) → test::Class<test::Class::_#redirect2#tearOff::T%>
+ return new test::ClassImpl::patched<test::Class::_#redirect2#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+ static method _#new#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#new#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#new#tearOff::T%>
+ return new test::ClassImpl::•<test::ClassImpl::_#new#tearOff::T%>(defaultValue: defaultValue, value: value);
+ static method /* from org-dartlang-testcase:///patch_lib.dart */ _#patched#tearOff<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::ClassImpl::_#patched#tearOff::T% value = #C17}) → test::ClassImpl<test::ClassImpl::_#patched#tearOff::T%>
+ return new test::ClassImpl::patched<test::ClassImpl::_#patched#tearOff::T%>(defaultValue: defaultValue, value: value);
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::_#redirect#tearOff<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C17, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::_#redirect2#tearOff<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = static-tearoff test::Class::_#new#tearOff
+ #C2 = static-tearoff test::Class::_#fact#tearOff
+ #C3 = static-tearoff test::Class::_#redirect#tearOff
+ #C4 = static-tearoff test::Class::_#redirect2#tearOff
+ #C5 = static-tearoff test::ClassImpl::_#new#tearOff
+ #C6 = static-tearoff test::ClassImpl::_#patched#tearOff
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _js::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.expect
new file mode 100644
index 0000000..7663f6b
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.expect
@@ -0,0 +1,92 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::redirect<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::redirect2<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = constructor-tearoff test::Class::•
+ #C2 = constructor-tearoff test::Class::fact
+ #C3 = redirecting-factory-tearoff test::Class::redirect
+ #C4 = redirecting-factory-tearoff test::Class::redirect2
+ #C5 = constructor-tearoff test::ClassImpl::•
+ #C6 = constructor-tearoff test::ClassImpl::patched
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _in::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.modular.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.modular.expect
new file mode 100644
index 0000000..7663f6b
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.modular.expect
@@ -0,0 +1,92 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::redirect<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::redirect2<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = constructor-tearoff test::Class::•
+ #C2 = constructor-tearoff test::Class::fact
+ #C3 = redirecting-factory-tearoff test::Class::redirect
+ #C4 = redirecting-factory-tearoff test::Class::redirect2
+ #C5 = constructor-tearoff test::ClassImpl::•
+ #C6 = constructor-tearoff test::ClassImpl::patched
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _in::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.outline.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.outline.expect
new file mode 100644
index 0000000..40d29d3
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.outline.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic
+ ;
+
+library /*isNonNullableByDefault*/;
+import self as self2;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+typedef Alias<T extends core::num> = self2::Class<T>;
+typedef AliasImpl<T extends core::num> = self2::ClassImpl<T>;
+@_in::patch
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self2::Class::redirect, self2::Class::redirect2]/*isLegacy*/;
+ @_in::patch
+ external constructor •({core::bool defaultValue = true, required self2::Class::T% value = null}) → self2::Class<self2::Class::T%>
+ ;
+ @_in::patch
+ external static factory fact<T extends core::Object? = dynamic>({has-declared-initializer core::bool defaultValue, required self2::Class::fact::T% value}) → self2::Class<self2::Class::fact::T%>;
+ @_in::patch
+ external static factory redirect<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::redirect::T% value}) → self2::Class<self2::Class::redirect::T%>
+ return new self2::ClassImpl::•<self2::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ @_in::patch
+ external static factory redirect2<T extends core::Object? = dynamic>({core::bool defaultValue, required self2::Class::redirect2::T% value}) → self2::Class<self2::Class::redirect2::T%>
+ return new self2::ClassImpl::patched<self2::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+}
+@_in::patch
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements self2::Class<self2::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = true, required self2::ClassImpl::T% value = null}) → self2::ClassImpl<self2::ClassImpl::T%>
+ ;
+ @_in::patch
+ external constructor patched({core::bool defaultValue = true, required self2::ClassImpl::T% value = null}) → self2::ClassImpl<self2::ClassImpl::T%>
+ ;
+}
+static method _#Alias#new#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#Alias#new#tearOff::T value}) → self2::Class<self2::_#Alias#new#tearOff::T>
+ return new self2::Class::•<self2::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#Alias#fact#tearOff::T value}) → self2::Class<self2::_#Alias#fact#tearOff::T>
+ return self2::Class::fact<self2::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue, required self2::_#Alias#redirect#tearOff::T value}) → self2::Class<self2::_#Alias#redirect#tearOff::T>
+ return self2::Class::redirect<self2::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue, required self2::_#Alias#redirect2#tearOff::T value}) → self2::Class<self2::_#Alias#redirect2#tearOff::T>
+ return self2::Class::redirect2<self2::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#AliasImpl#new#tearOff::T value}) → self2::ClassImpl<self2::_#AliasImpl#new#tearOff::T>
+ return new self2::ClassImpl::•<self2::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({has-declared-initializer core::bool defaultValue, required self2::_#AliasImpl#patched#tearOff::T value}) → self2::ClassImpl<self2::_#AliasImpl#patched#tearOff::T>
+ return new self2::ClassImpl::patched<self2::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+
+Extra constant evaluation status:
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:6:46 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:7:9 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:8:28 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:12:21 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:15:11 -> InstanceConstant(const _Patch{})
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///origin_lib.dart:5:7 -> ConstructorTearOffConstant(Class.redirect)
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///origin_lib.dart:5:7 -> ConstructorTearOffConstant(Class.redirect2)
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:18:38 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:19:47 -> InstanceConstant(const _Patch{})
+Extra constant evaluation: evaluated: 34, effectively constant: 9
diff --git a/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.transformed.expect b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.transformed.expect
new file mode 100644
index 0000000..7663f6b
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/main.dart.weak.transformed.expect
@@ -0,0 +1,92 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:test" as test;
+
+import "dart:test";
+
+static method main() → dynamic {
+ #C1;
+ #C2;
+ #C3;
+ #C4;
+ #C5;
+ #C6;
+ #C7;
+ #C8;
+ #C9;
+ #C10;
+ #C11;
+ #C12;
+}
+
+library /*isNonNullableByDefault*/;
+import self as test;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+typedef Alias<T extends core::num> = test::Class<T>;
+typedef AliasImpl<T extends core::num> = test::ClassImpl<T>;
+@#C13
+class Class<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C14, #C15]/*isLegacy*/;
+ @#C13
+ constructor •({core::bool defaultValue = #C16, required test::Class::T% value = #C17}) → test::Class<test::Class::T%>
+ : super core::Object::•() {
+ core::print("patch Class");
+ }
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ fact<T extends core::Object? = dynamic>({core::bool defaultValue = #C16, required test::Class::fact::T% value = #C17}) → test::Class<test::Class::fact::T%>
+ return new test::ClassImpl::•<test::Class::fact::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect::T% value = #C17}) → test::Class<test::Class::redirect::T%>
+ return new test::ClassImpl::•<test::Class::redirect::T%>(defaultValue: defaultValue, value: value);
+ @#C13
+ static factory /* from org-dartlang-testcase:///patch_lib.dart */ redirect2<T extends core::Object? = dynamic>({core::bool defaultValue = #C17, required test::Class::redirect2::T% value = #C17}) → test::Class<test::Class::redirect2::T%>
+ return new test::ClassImpl::patched<test::Class::redirect2::T%>(defaultValue: defaultValue, value: value);
+}
+@#C13
+class ClassImpl<T extends core::Object? = dynamic> extends core::Object implements test::Class<test::ClassImpl::T%> {
+ constructor •({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•()
+ ;
+ @#C13
+ constructor patched({core::bool defaultValue = #C16, required test::ClassImpl::T% value = #C17}) → test::ClassImpl<test::ClassImpl::T%>
+ : super core::Object::•() {
+ core::print("patch ClassImpl");
+ }
+}
+static method _#Alias#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#new#tearOff::T value = #C17}) → test::Class<test::_#Alias#new#tearOff::T>
+ return new test::Class::•<test::_#Alias#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#fact#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#fact#tearOff::T value = #C17}) → test::Class<test::_#Alias#fact#tearOff::T>
+ return test::Class::fact<test::_#Alias#fact#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect#tearOff::T>
+ return test::Class::redirect<test::_#Alias#redirect#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#Alias#redirect2#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#Alias#redirect2#tearOff::T value = #C17}) → test::Class<test::_#Alias#redirect2#tearOff::T>
+ return test::Class::redirect2<test::_#Alias#redirect2#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#new#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#new#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#new#tearOff::T>
+ return new test::ClassImpl::•<test::_#AliasImpl#new#tearOff::T>(defaultValue: defaultValue, value: value);
+static method _#AliasImpl#patched#tearOff<T extends core::num>({core::bool defaultValue = #C16, required test::_#AliasImpl#patched#tearOff::T value = #C17}) → test::ClassImpl<test::_#AliasImpl#patched#tearOff::T>
+ return new test::ClassImpl::patched<test::_#AliasImpl#patched#tearOff::T>(defaultValue: defaultValue, value: value);
+
+constants {
+ #C1 = constructor-tearoff test::Class::•
+ #C2 = constructor-tearoff test::Class::fact
+ #C3 = redirecting-factory-tearoff test::Class::redirect
+ #C4 = redirecting-factory-tearoff test::Class::redirect2
+ #C5 = constructor-tearoff test::ClassImpl::•
+ #C6 = constructor-tearoff test::ClassImpl::patched
+ #C7 = static-tearoff test::_#Alias#new#tearOff
+ #C8 = static-tearoff test::_#Alias#fact#tearOff
+ #C9 = static-tearoff test::_#Alias#redirect#tearOff
+ #C10 = static-tearoff test::_#Alias#redirect2#tearOff
+ #C11 = static-tearoff test::_#AliasImpl#new#tearOff
+ #C12 = static-tearoff test::_#AliasImpl#patched#tearOff
+ #C13 = _in::_Patch {}
+ #C14 = constructor-tearoff test::Class::redirect
+ #C15 = constructor-tearoff test::Class::redirect2
+ #C16 = true
+ #C17 = null
+}
diff --git a/pkg/front_end/testcases/general/tear_off_patch/origin_lib.dart b/pkg/front_end/testcases/general/tear_off_patch/origin_lib.dart
new file mode 100644
index 0000000..c29cf6f
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/origin_lib.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2022, 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.
+
+class Class<T> {
+ external Class({bool defaultValue: true, required T value});
+ external factory Class.fact({bool defaultValue: true, required T value});
+ external factory Class.redirect({bool defaultValue, required T value});
+ external factory Class.redirect2({bool defaultValue, required T value});
+}
+
+class ClassImpl<T> implements Class<T> {
+ ClassImpl({bool defaultValue: true, required T value});
+
+ external ClassImpl.patched({bool defaultValue: true, required T value});
+}
+
+typedef Alias<T extends num> = Class<T>;
+typedef AliasImpl<T extends num> = ClassImpl<T>;
diff --git a/pkg/front_end/testcases/general/tear_off_patch/patch_lib.dart b/pkg/front_end/testcases/general/tear_off_patch/patch_lib.dart
new file mode 100644
index 0000000..7265272
--- /dev/null
+++ b/pkg/front_end/testcases/general/tear_off_patch/patch_lib.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2022, 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.
+
+// ignore: import_internal_library
+import 'dart:_internal';
+
+@patch
+class Class<T> {
+ @patch
+ Class({bool defaultValue: true, required T value}) {
+ print('patch Class');
+ }
+
+ @patch
+ factory Class.fact({bool defaultValue: true, required T value}) =>
+ new ClassImpl<T>(defaultValue: defaultValue, value: value);
+
+ @patch
+ factory Class.redirect({bool defaultValue, required T value}) = ClassImpl<T>;
+
+ @patch
+ factory Class.redirect2({bool defaultValue, required T value}) =
+ ClassImpl<T>.patched;
+}
+
+@patch
+class ClassImpl<T> implements Class<T> {
+ @patch
+ ClassImpl.patched({bool defaultValue: true, required T value}) {
+ print('patch ClassImpl');
+ }
+}
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index 11fc5c8..bd73e56 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.dart
@@ -331,6 +331,7 @@
/// ```
String toString() {
var microseconds = inMicroseconds;
+ var sign = (microseconds < 0) ? "-" : "";
var hours = microseconds ~/ microsecondsPerHour;
microseconds = microseconds.remainder(microsecondsPerHour);
@@ -348,7 +349,7 @@
var secondsPadding = seconds < 10 ? "0" : "";
var paddedMicroseconds = microseconds.toString().padLeft(6, "0");
- return "$hours:"
+ return "$sign${hours.abs()}:"
"$minutesPadding$minutes:"
"$secondsPadding$seconds.$paddedMicroseconds";
}
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index 9dccd22..a9990a3 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -4,6 +4,9 @@
part of dart.developer;
+// Examples can assume:
+// void doSomething() {}
+
const bool _hasTimeline =
const bool.fromEnvironment("dart.developer.timeline", defaultValue: true);
diff --git a/sdk/lib/ffi/dynamic_library.dart b/sdk/lib/ffi/dynamic_library.dart
index 3f740d5..5106021 100644
--- a/sdk/lib/ffi/dynamic_library.dart
+++ b/sdk/lib/ffi/dynamic_library.dart
@@ -9,7 +9,7 @@
/// A dynamically loaded library is a mapping from symbols to memory addresses.
/// These memory addresses can be accessed through [lookup].
class DynamicLibrary {
- /// Creates a dynamic library holding all global symbols.
+ /// Creates a [DynamicLibrary] holding all global symbols.
///
/// Any symbol in a library currently loaded with global visibility
/// (including the executable itself) may be resolved through this library.
@@ -17,8 +17,10 @@
/// This feature is not available on Windows.
external factory DynamicLibrary.process();
- /// Creates a dynamic library containing all the symbols of the running
+ /// Creates a [DynamicLibrary] containing all the symbols of the running
/// executable.
+ ///
+ /// This is useful for using dart:ffi with static libraries.
external factory DynamicLibrary.executable();
/// Loads a library file and provides access to its symbols.
diff --git a/sdk/lib/js_util/js_util.dart b/sdk/lib/js_util/js_util.dart
index d0db609..081bcb8 100644
--- a/sdk/lib/js_util/js_util.dart
+++ b/sdk/lib/js_util/js_util.dart
@@ -17,6 +17,10 @@
import 'dart:_js_helper'
show convertDartClosureToJS, assertInterop, assertInteropArgs;
+// Examples can assume:
+// class JS { const JS(); }
+// class Promise<T> {}
+
/// Recursively converts a JSON-like collection to JavaScript compatible
/// representation.
///
@@ -305,9 +309,11 @@
/// @JS()
/// external Promise<num> get threePromise; // Resolves to 3
///
-/// final Future<num> threeFuture = promiseToFuture(threePromise);
+/// void main() async {
+/// final Future<num> threeFuture = promiseToFuture(threePromise);
///
-/// final three = await threeFuture; // == 3
+/// final three = await threeFuture; // == 3
+/// }
/// ```
Future<T> promiseToFuture<T>(Object jsPromise) {
final completer = Completer<T>();
diff --git a/tests/corelib/duration_test.dart b/tests/corelib/duration_test.dart
index 7080723..e60efb8 100644
--- a/tests/corelib/duration_test.dart
+++ b/tests/corelib/duration_test.dart
@@ -298,4 +298,21 @@
Expect.equals(d2, -d1);
Expect.equals(d1, -d2);
+
+ // Regression test for http://dartbug.com/48841
+ d = const Duration(minutes: -1);
+ Expect.equals("-0:01:00.000000", d.toString());
+ d = const Duration(seconds: -1);
+ Expect.equals("-0:00:01.000000", d.toString());
+ d = const Duration(milliseconds: -1);
+ Expect.equals("-0:00:00.001000", d.toString());
+ d = const Duration(microseconds: -1);
+ Expect.equals("-0:00:00.000001", d.toString());
+ d = const Duration(microseconds: -9223372036854775808); // Min 64-bit int.
+ // Not checking precise values, because they will be off on the web.
+ Expect.equals("-2562047788:00:54.775808", d.toString());
+ Expect.isTrue(d.toString().startsWith("-"));
+ Expect.isFalse(d.toString().startsWith("--"));
+ d = const Duration(minutes: -0); // is -0.0 on web.
+ Expect.equals("0:00:00.000000", d.toString());
}
diff --git a/tests/corelib_2/duration_test.dart b/tests/corelib_2/duration_test.dart
index fb80464..33ebf1f 100644
--- a/tests/corelib_2/duration_test.dart
+++ b/tests/corelib_2/duration_test.dart
@@ -300,4 +300,21 @@
Expect.equals(d2, -d1);
Expect.equals(d1, -d2);
+
+ // Regression test for http://dartbug.com/48841
+ d = const Duration(minutes: -1);
+ Expect.equals("-0:01:00.000000", d.toString());
+ d = const Duration(seconds: -1);
+ Expect.equals("-0:00:01.000000", d.toString());
+ d = const Duration(milliseconds: -1);
+ Expect.equals("-0:00:00.001000", d.toString());
+ d = const Duration(microseconds: -1);
+ Expect.equals("-0:00:00.000001", d.toString());
+ d = const Duration(microseconds: -9223372036854775808); // Min 64-bit int.
+ // Not checking precise values, because they will be off on the web.
+ Expect.equals("-2562047788:00:54.775808", d.toString());
+ Expect.isTrue(d.toString().startsWith("-"));
+ Expect.isFalse(d.toString().startsWith("--"));
+ d = const Duration(minutes: -0); // is -0.0 on web.
+ Expect.equals("0:00:00.000000", d.toString());
}
diff --git a/tests/language/constructor/patch_tear_off_test.dart b/tests/language/constructor/patch_tear_off_test.dart
new file mode 100644
index 0000000..632a208
--- /dev/null
+++ b/tests/language/constructor/patch_tear_off_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2022, 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.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/48776
+
+main() {
+ /// BigInt.from is a patched constructor.
+ BigInt.from;
+}
diff --git a/tests/web/regress/issue/230108748_test.dart b/tests/web/regress/issue/230108748_test.dart
new file mode 100644
index 0000000..c90c6b6
--- /dev/null
+++ b/tests/web/regress/issue/230108748_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2022, 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.
+// SharedOptions=-Da=true -Db=false
+
+import 'package:expect/expect.dart';
+
+class Base {
+ final int x;
+ const Base(this.x);
+}
+
+class Child extends Base {
+ static const Child A = Child._(const bool.fromEnvironment('a') ? 0 : 1);
+ static const Child B = Child._(const bool.fromEnvironment('b') ? 0 : 2);
+
+ const Child._(int x) : super(x);
+}
+
+int case1() {
+ switch (null as dynamic) {
+ case Child.A:
+ return 1;
+ default:
+ return 2;
+ }
+}
+
+class A {
+ final int x;
+ const A(this.x);
+
+ static const A a1 = A(const bool.fromEnvironment('x') ? 0 : 1);
+ static const A a2 = A(const bool.fromEnvironment('x') ? 0 : 2);
+}
+
+int case2() {
+ switch (null as dynamic) {
+ case A.a1:
+ return 1;
+ default:
+ return 2;
+ }
+}
+
+class B {
+ final int x;
+ const B(this.x);
+}
+
+int case3() {
+ switch (null as dynamic) {
+ case B(const bool.fromEnvironment('x') ? 0 : 1):
+ return 1;
+ default:
+ return 2;
+ }
+}
+
+void main() {
+ Expect.equals(case1(), 2);
+ Expect.equals(case2(), 2);
+ Expect.equals(case3(), 2);
+}
diff --git a/tools/OWNERS b/tools/OWNERS
index 8d66888..fa2dc56 100644
--- a/tools/OWNERS
+++ b/tools/OWNERS
@@ -2,6 +2,7 @@
# Groups administrate themselves.
per-file OWNERS_ANALYZER=file:OWNERS_ANALYZER
+per-file OWNERS_BUILD=file:OWNERS_BUILD
per-file OWNERS_CFE=file:OWNERS_CFE
per-file OWNERS_ECOSYSTEM=file:OWNERS_ECOSYSTEM
per-file OWNERS_FOUNDATION=file:OWNERS_FOUNDATION
@@ -11,3 +12,6 @@
per-file OWNERS_PUB=file:OWNERS_PUB
per-file OWNERS_VM=file:OWNERS_VM
per-file OWNERS_WEB=file:OWNERS_WEB
+
+# Changed along with build files
+per-file *.py=file:OWNERS_BUILD
diff --git a/tools/OWNERS_BUILD b/tools/OWNERS_BUILD
new file mode 100644
index 0000000..2d5cb00
--- /dev/null
+++ b/tools/OWNERS_BUILD
@@ -0,0 +1,2 @@
+file:OWNERS_INFRA
+file:OWNERS_VM
diff --git a/tools/VERSION b/tools/VERSION
index 2648abd..a15f79a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 56
+PRERELEASE 57
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 459362c..7bab851 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -3682,14 +3682,17 @@
"script": "out/ReleaseX64/dart-sdk/bin/dart",
"arguments": [
"tools/verify_docs/bin/verify_docs.dart",
- "sdk/lib/_http",
- "sdk/lib/_internal",
- "sdk/lib/cli",
- "sdk/lib/convert",
- "sdk/lib/ffi",
- "sdk/lib/js",
- "sdk/lib/math",
- "sdk/lib/mirrors"
+ "dart:_http",
+ "dart:_internal",
+ "dart:cli",
+ "dart:convert",
+ "dart:developer",
+ "dart:ffi",
+ "dart:js",
+ "dart:js_util",
+ "dart:math",
+ "dart:mirrors",
+ "dart:wasm"
]
},
{