Version 2.14.0-340.0.dev
Merge commit 'f258c7fe62cdce70ef3c0a8d52505167cf433d76' into 'dev'
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
index ed17c2a..20c4d27 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
@@ -14,6 +14,8 @@
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
final _manager = _RefactorManager();
@@ -173,6 +175,32 @@
InlineMethodRefactoring(server.searchEngine, result, offset);
return success(refactor);
+ case RefactoringKind.CONVERT_GETTER_TO_METHOD:
+ final node = NodeLocator(offset).searchWithin(result.unit);
+ final element = server.getElementOfNode(node);
+ if (element != null) {
+ if (element is PropertyAccessorElement) {
+ final refactor = ConvertGetterToMethodRefactoring(
+ server.searchEngine, result.session, element);
+ return success(refactor);
+ }
+ }
+ return error(ServerErrorCodes.InvalidCommandArguments,
+ 'Location supplied to $commandName $kind is not longer valid');
+
+ case RefactoringKind.CONVERT_METHOD_TO_GETTER:
+ final node = NodeLocator(offset).searchWithin(result.unit);
+ final element = server.getElementOfNode(node);
+ if (element != null) {
+ if (element is ExecutableElement) {
+ final refactor = ConvertMethodToGetterRefactoring(
+ server.searchEngine, result.session, element);
+ return success(refactor);
+ }
+ }
+ return error(ServerErrorCodes.InvalidCommandArguments,
+ 'Location supplied to $commandName $kind is not longer valid');
+
default:
return error(ServerErrorCodes.InvalidCommandArguments,
'Unknown RefactoringKind $kind was supplied to $commandName');
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 0fb95ee..8ccb4bf 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -21,7 +21,9 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart'
show InconsistentAnalysisException;
+import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:collection/collection.dart' show groupBy;
@@ -428,6 +430,28 @@
}
}
+ // Converts/Rewrites
+ if (shouldIncludeKind(CodeActionKind.RefactorRewrite)) {
+ final node = NodeLocator(offset).searchWithin(unit.unit);
+ final element = server.getElementOfNode(node);
+ // Getter to Method
+ if (element is PropertyAccessorElement) {
+ refactorActions.add(createRefactor(
+ CodeActionKind.RefactorRewrite,
+ 'Convert Getter to Method',
+ RefactoringKind.CONVERT_GETTER_TO_METHOD));
+ }
+
+ // Method to Getter
+ if (element is ExecutableElement &&
+ element is! PropertyAccessorElement) {
+ refactorActions.add(createRefactor(
+ CodeActionKind.RefactorRewrite,
+ 'Convert Method to Getter',
+ RefactoringKind.CONVERT_METHOD_TO_GETTER));
+ }
+ }
+
return refactorActions;
} on InconsistentAnalysisException {
// If an InconsistentAnalysisException occurs, it's likely the user modified
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart
index 1ccaff4..8a6b2c8 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart
@@ -17,8 +17,9 @@
var body = getEnclosingFunctionBody();
if (body == null ||
body is EmptyFunctionBody ||
- body.isAsynchronous ||
- body.isGenerator) {
+ // Do not offer a correction if there is an `async`, `async*`, `sync*`,
+ // or the fictional `sync` keyword.
+ body.keyword != null) {
return;
}
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
index 5ebc918..e8921f7 100644
--- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -20,10 +20,76 @@
defineReflectiveTests(ExtractVariableRefactorCodeActionsTest);
defineReflectiveTests(InlineLocalVariableRefactorCodeActionsTest);
defineReflectiveTests(InlineMethodRefactorCodeActionsTest);
+ defineReflectiveTests(ConvertGetterToMethodCodeActionsTest);
+ defineReflectiveTests(ConvertMethodToGetterCodeActionsTest);
});
}
@reflectiveTest
+class ConvertGetterToMethodCodeActionsTest extends AbstractCodeActionsTest {
+ final refactorTitle = 'Convert Getter to Method';
+
+ Future<void> test_refactor() async {
+ const content = '''
+int get ^test => 42;
+main() {
+ var a = test;
+ var b = test;
+}
+''';
+ const expectedContent = '''
+int test() => 42;
+main() {
+ var a = test();
+ var b = test();
+}
+''';
+ newFile(mainFilePath, content: withoutMarkers(content));
+ await initialize();
+
+ final codeActions = await getCodeActions(mainFileUri.toString(),
+ position: positionFromMarker(content));
+ final codeAction =
+ findCommand(codeActions, Commands.performRefactor, refactorTitle)!;
+
+ await verifyCodeActionEdits(
+ codeAction, withoutMarkers(content), expectedContent);
+ }
+}
+
+@reflectiveTest
+class ConvertMethodToGetterCodeActionsTest extends AbstractCodeActionsTest {
+ final refactorTitle = 'Convert Method to Getter';
+
+ Future<void> test_refactor() async {
+ const content = '''
+int ^test() => 42;
+main() {
+ var a = test();
+ var b = test();
+}
+''';
+ const expectedContent = '''
+int get test => 42;
+main() {
+ var a = test;
+ var b = test;
+}
+''';
+ newFile(mainFilePath, content: withoutMarkers(content));
+ await initialize();
+
+ final codeActions = await getCodeActions(mainFileUri.toString(),
+ position: positionFromMarker(content));
+ final codeAction =
+ findCommand(codeActions, Commands.performRefactor, refactorTitle)!;
+
+ await verifyCodeActionEdits(
+ codeAction, withoutMarkers(content), expectedContent);
+ }
+}
+
+@reflectiveTest
class ExtractMethodRefactorCodeActionsTest extends AbstractCodeActionsTest {
final extractMethodTitle = 'Extract Method';
@@ -176,7 +242,12 @@
}
''';
newFile(mainFilePath, content: withoutMarkers(content));
- await initialize();
+ await initialize(
+ textDocumentCapabilities: withCodeActionKinds(
+ emptyTextDocumentClientCapabilities,
+ [CodeActionKind.Empty], // Support everything (empty prefix matches all)
+ ),
+ );
final ofKind = (CodeActionKind kind) => getCodeActions(
mainFileUri.toString(),
@@ -184,13 +255,31 @@
kinds: [kind],
);
- // The code above will return a RefactorExtract that should be included
- // by both Refactor and RefactorExtract, but not RefactorExtractFoo or
- // RefactorRewrite
- expect(await ofKind(CodeActionKind.Refactor), isNotEmpty);
- expect(await ofKind(CodeActionKind.RefactorExtract), isNotEmpty);
- expect(await ofKind(CodeActionKind('refactor.extract.foo')), isEmpty);
- expect(await ofKind(CodeActionKind.RefactorRewrite), isEmpty);
+ // Helper that requests CodeActions for [kind] and ensures all results
+ // returned have either an equal kind, or a kind that is prefixed with the
+ // requested kind followed by a dot.
+ Future<void> checkResults(CodeActionKind kind) async {
+ final results = await ofKind(kind);
+ for (final result in results) {
+ final resultKind = result.map(
+ (cmd) => throw 'Expected CodeAction, got Command: ${cmd.title}',
+ (action) => action.kind,
+ );
+ expect(
+ '$resultKind',
+ anyOf([
+ equals('$kind'),
+ startsWith('$kind.'),
+ ]),
+ );
+ }
+ }
+
+ // Check a few of each that will produces multiple matches and no matches.
+ await checkResults(CodeActionKind.Refactor);
+ await checkResults(CodeActionKind.RefactorExtract);
+ await checkResults(CodeActionKind('refactor.extract.foo'));
+ await checkResults(CodeActionKind.RefactorRewrite);
}
Future<void> test_generatesNames() async {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_into_async_body_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_into_async_body_test.dart
index 0120636..fc933c1 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_into_async_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_into_async_body_test.dart
@@ -136,6 +136,17 @@
''');
}
+ Future<void> test_sync() async {
+ // This code is erroneous; the test ensures there is no error thrown when
+ // computing assists.
+ verifyNoTestUnitErrors = false;
+ await resolveTestCode('''
+Iterable<String> f() sync {}
+''');
+ await assertNoAssistAt('{}');
+ }
+
+
Future<void> test_syncStar() async {
await resolveTestCode('''
Iterable<String> f() sync* {}
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index ab82e26..6c1563b 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -1061,7 +1061,7 @@
/// [PostfixExpression] when the operator is an increment operator.
///
/// Clients may not extend, implement or mix-in this class.
-abstract class CompoundAssignmentExpression {
+abstract class CompoundAssignmentExpression implements Expression {
/// The element that is used to read the value.
///
/// If this node is not a compound assignment, this element is `null`.
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 874c8f5..9256fa8 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -5892,8 +5892,7 @@
final parent = this.parent;
if (parent is CompoundAssignmentExpression) {
- var assignment = parent as CompoundAssignmentExpression;
- element = assignment.writeElement ?? assignment.readElement;
+ element = parent.writeElement ?? parent.readElement;
}
if (element is ExecutableElement) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
index 5dd33ec..80022ea 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -25,13 +26,17 @@
/// The resolver driving this participant.
final ResolverVisitor _resolver;
+ /// Helper for extension method resolution.
+ final ExtensionMemberResolver _extensionResolver;
+
final bool _isNonNullableByDefault;
/// The type representing the type 'type'.
final InterfaceType _typeType;
FunctionReferenceResolver(this._resolver, this._isNonNullableByDefault)
- : _typeType = _resolver.typeProvider.typeType;
+ : _extensionResolver = _resolver.extensionResolver,
+ _typeType = _resolver.typeProvider.typeType;
ErrorReporter get _errorReporter => _resolver.errorReporter;
@@ -43,242 +48,16 @@
node.typeArguments?.accept(_resolver);
if (function is SimpleIdentifierImpl) {
- var element = _resolver.nameScope.lookup(function.name).getter;
-
- if (element == null) {
- DartType receiverType;
- var enclosingClass = _resolver.enclosingClass;
- if (enclosingClass != null) {
- receiverType = enclosingClass.thisType;
- } else {
- // TODO(srawlins): Check `_resolver.enclosingExtension`.
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
- function,
- [function.name],
- );
- node.staticType = DynamicTypeImpl.instance;
- return;
- }
-
- var result = _resolver.typePropertyResolver.resolve(
- receiver: null,
- receiverType: receiverType,
- name: function.name,
- propertyErrorEntity: function,
- nameErrorEntity: function,
- );
-
- var method = result.getter;
- if (method != null) {
- function.staticElement = method;
- _resolve(node: node, rawType: method.type, name: function.name);
- return;
- } else {
- // TODO(srawlins): Report CompileTimeErrorCode.UNDEFINED_METHOD.
- return;
- }
-
- // TODO(srawlins): If `target.isStatic`, report an error, something like
- // [MethodInvocationResolver._reportInstanceAccessToStaticMember].
-
- // TODO(srawlins): if `(target is PropertyAccessorElement)`, report an
- // error.
- }
-
- // Classes and type aliases are checked first so as to include a
- // PropertyAccess parent check, which does not need to be done for
- // functions.
- if (element is ClassElement || element is TypeAliasElement) {
- // A type-instantiated constructor tearoff like `C<int>.name` or
- // `prefix.C<int>.name` is initially represented as a [PropertyAccess]
- // with a [FunctionReference] target.
- if (node.parent is PropertyAccess) {
- _resolveConstructorReference(node);
- return;
- } else if (element is ClassElement) {
- function.staticElement = element;
- _resolveDirectTypeLiteral(node, function, element);
- return;
- } else if (element is TypeAliasElement) {
- function.staticElement = element;
- _resolveTypeAlias(node: node, element: element, typeAlias: function);
- return;
- }
- } else if (element is ExecutableElement) {
- function.staticElement = element;
- function.staticType = element.type;
- _resolve(node: node, rawType: element.type, name: element.name);
- return;
- } else if (element is VariableElement) {
- function.staticElement = element;
- function.staticType = element.type;
- _resolveDisallowedExpression(node, element.type);
- return;
- }
-
- node.staticType = DynamicTypeImpl.instance;
- return;
+ _resolveSimpleIdentifierFunction(node, function);
} else if (function is PrefixedIdentifierImpl) {
- var prefixElement =
- _resolver.nameScope.lookup(function.prefix.name).getter;
-
- if (prefixElement == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
- function.prefix,
- [function.name],
- );
- node.staticType = DynamicTypeImpl.instance;
- return;
- }
-
- function.prefix.staticElement = prefixElement;
- if (prefixElement is PrefixElement) {
- var functionName = function.identifier.name;
- var functionElement = prefixElement.scope.lookup(functionName).getter;
- if (functionElement == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
- function.identifier,
- [function.identifier.name, function.prefix.name],
- );
- function.staticType = DynamicTypeImpl.instance;
- node.staticType = DynamicTypeImpl.instance;
- return;
- } else {
- functionElement = _resolver.toLegacyElement(functionElement);
- _resolveReceiverPrefix(
- node, prefixElement, function, functionElement);
- return;
- }
- }
-
- DartType? prefixType;
- if (prefixElement is VariableElement) {
- prefixType = prefixElement.type;
- } else if (prefixElement is PropertyAccessorElement) {
- prefixType = prefixElement.returnType;
- }
-
- function.prefix.staticType = prefixType;
- if (prefixType != null && prefixType.isDynamic) {
- // TODO(srawlins): Report error. See spec text: "We do not allow dynamic
- // explicit instantiation."
- node.staticType = DynamicTypeImpl.instance;
- return;
- }
-
- var methodElement = _resolveTypeProperty(
- receiver: function.prefix,
- receiverElement: prefixElement,
- name: function.identifier,
- nameErrorEntity: function,
- );
-
- if (methodElement is MethodElement) {
- function.identifier.staticElement = methodElement;
- function.staticType = methodElement.type;
- _resolve(
- node: node,
- rawType: methodElement.type,
- name: function.identifier.name,
- );
- return;
- }
-
- // TODO(srawlins): Need to report cases where [methodElement] is not
- // generic. The 'test_instanceGetter_explicitReceiver' test case needs to
- // be updated to handle this.
-
- function.accept(_resolver);
- node.staticType = DynamicTypeImpl.instance;
- return;
+ _resolvePrefixedIdentifierFunction(node, function);
} else if (function is PropertyAccessImpl) {
- function.accept(_resolver);
- var target = function.target;
- if (target == null) {
- // TODO(srawlins): Can we get here? Perhaps as part of a cascade, but
- // there is currently a parsing error with cascades.
- // https://github.com/dart-lang/sdk/issues/46635
- node.staticType = DynamicTypeImpl.instance;
- return;
- }
-
- DartType targetType;
- if (target is SuperExpressionImpl) {
- targetType = target.typeOrThrow;
- } else if (target is ThisExpressionImpl) {
- targetType = target.typeOrThrow;
- } else if (target is SimpleIdentifierImpl) {
- var targetElement = _resolver.nameScope.lookup(target.name).getter;
- if (targetElement is VariableElement) {
- targetType = targetElement.type;
- } else if (targetElement is PropertyAccessorElement) {
- targetType = targetElement.returnType;
- } else {
- // TODO(srawlins): Can we get here?
- node.staticType = DynamicTypeImpl.instance;
- return;
- }
- } else if (target is PrefixedIdentifierImpl) {
- var prefixElement =
- _resolver.nameScope.lookup(target.prefix.name).getter;
- if (prefixElement is PrefixElement) {
- var prefixName = target.identifier.name;
- var targetElement = prefixElement.scope.lookup(prefixName).getter;
-
- var methodElement = _resolveTypeProperty(
- receiver: target,
- receiverElement: targetElement,
- name: function.propertyName,
- nameErrorEntity: function,
- );
-
- if (methodElement == null) {
- // TODO(srawlins): Can we get here?
- node.staticType = DynamicTypeImpl.instance;
- return;
- } else {
- _resolveReceiverPrefix(node, prefixElement, target, methodElement);
- return;
- }
- } else {
- // TODO(srawlins): Can we get here?
- node.staticType = DynamicTypeImpl.instance;
- return;
- }
- } else {
- targetType = target.typeOrThrow;
- }
-
- var propertyElement = _resolver.typePropertyResolver
- .resolve(
- receiver: function.realTarget,
- receiverType: targetType,
- name: function.propertyName.name,
- propertyErrorEntity: function.propertyName,
- nameErrorEntity: function,
- )
- .getter;
-
- if (propertyElement is TypeParameterElement) {
- _resolveDisallowedExpression(node, propertyElement!.type);
- return;
- }
-
- _resolve(
- node: node,
- rawType: function.staticType,
- name: propertyElement?.name,
- );
- return;
+ _resolvePropertyAccessFunction(node, function);
} else {
// TODO(srawlins): Handle `function` being a [SuperExpression].
function.accept(_resolver);
_resolveDisallowedExpression(node, node.function.staticType);
- return;
}
}
@@ -315,6 +94,37 @@
}
}
+ void _reportInvalidAccessToStaticMember(
+ SimpleIdentifier nameNode,
+ ExecutableElement element, {
+ required bool implicitReceiver,
+ }) {
+ if (_resolver.enclosingExtension != null) {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode
+ .UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
+ nameNode,
+ [element.enclosingElement.displayName],
+ );
+ } else if (implicitReceiver) {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
+ nameNode,
+ [element.enclosingElement.displayName],
+ );
+ } else {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
+ nameNode,
+ [
+ nameNode.name,
+ element.kind.displayName,
+ element.enclosingElement.displayName,
+ ],
+ );
+ }
+ }
+
/// Resolves [node]'s static type, as an instantiated function type, and type
/// argument types, using [rawType] as the uninstantiated function type.
void _resolve({
@@ -384,6 +194,194 @@
_resolve(node: node, rawType: rawType);
}
+ void _resolveExtensionOverride(
+ FunctionReferenceImpl node,
+ PropertyAccessImpl function,
+ ExtensionOverride override,
+ ) {
+ var propertyName = function.propertyName;
+ var result =
+ _extensionResolver.getOverrideMember(override, propertyName.name);
+ var member = _resolver.toLegacyElement(result.getter);
+
+ if (member == null) {
+ node.staticType = DynamicTypeImpl.instance;
+ return;
+ }
+
+ if (member.isStatic) {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
+ function.propertyName,
+ );
+ // Continue to resolve type.
+ }
+
+ if (function.isCascaded) {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.EXTENSION_OVERRIDE_WITH_CASCADE,
+ override.extensionName,
+ );
+ // Continue to resolve type.
+ }
+
+ // TODO(srawlins): If PropertyAccessorElement, report error.
+
+ _resolve(node: node, rawType: member.type, name: propertyName.name);
+ }
+
+ void _resolvePrefixedIdentifierFunction(
+ FunctionReferenceImpl node, PrefixedIdentifierImpl function) {
+ var prefixElement = _resolver.nameScope.lookup(function.prefix.name).getter;
+
+ if (prefixElement == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
+ function.prefix,
+ [function.name],
+ );
+ function.staticType = DynamicTypeImpl.instance;
+ node.staticType = DynamicTypeImpl.instance;
+ return;
+ }
+
+ function.prefix.staticElement = prefixElement;
+ if (prefixElement is PrefixElement) {
+ var functionName = function.identifier.name;
+ var functionElement = prefixElement.scope.lookup(functionName).getter;
+ if (functionElement == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
+ function.identifier,
+ [function.identifier.name, function.prefix.name],
+ );
+ function.staticType = DynamicTypeImpl.instance;
+ node.staticType = DynamicTypeImpl.instance;
+ return;
+ } else {
+ functionElement = _resolver.toLegacyElement(functionElement);
+ _resolveReceiverPrefix(node, prefixElement, function, functionElement);
+ return;
+ }
+ }
+
+ DartType? prefixType;
+ if (prefixElement is VariableElement) {
+ prefixType = prefixElement.type;
+ } else if (prefixElement is PropertyAccessorElement) {
+ prefixType = prefixElement.returnType;
+ }
+
+ function.prefix.staticType = prefixType;
+ if (prefixType != null && prefixType.isDynamic) {
+ // TODO(srawlins): Report error. See spec text: "We do not allow dynamic
+ // explicit instantiation."
+ node.staticType = DynamicTypeImpl.instance;
+ return;
+ }
+
+ var methodElement = _resolveTypeProperty(
+ receiver: function.prefix,
+ receiverElement: prefixElement,
+ name: function.identifier,
+ nameErrorEntity: function,
+ );
+
+ if (methodElement is MethodElement) {
+ function.identifier.staticElement = methodElement;
+ function.staticType = methodElement.type;
+ _resolve(
+ node: node,
+ rawType: methodElement.type,
+ name: function.identifier.name,
+ );
+ return;
+ }
+
+ // TODO(srawlins): Need to report cases where [methodElement] is not
+ // generic. The 'test_instanceGetter_explicitReceiver' test case needs to
+ // be updated to handle this.
+
+ function.accept(_resolver);
+ node.staticType = DynamicTypeImpl.instance;
+ }
+
+ void _resolvePropertyAccessFunction(
+ FunctionReferenceImpl node, PropertyAccessImpl function) {
+ function.accept(_resolver);
+ var target = function.realTarget;
+
+ DartType targetType;
+ if (target is SuperExpressionImpl) {
+ targetType = target.typeOrThrow;
+ } else if (target is ThisExpressionImpl) {
+ targetType = target.typeOrThrow;
+ } else if (target is SimpleIdentifierImpl) {
+ var targetElement = _resolver.nameScope.lookup(target.name).getter;
+ if (targetElement is VariableElement) {
+ targetType = targetElement.type;
+ } else if (targetElement is PropertyAccessorElement) {
+ targetType = targetElement.returnType;
+ } else {
+ // TODO(srawlins): Can we get here?
+ node.staticType = DynamicTypeImpl.instance;
+ return;
+ }
+ } else if (target is PrefixedIdentifierImpl) {
+ var prefixElement = _resolver.nameScope.lookup(target.prefix.name).getter;
+ if (prefixElement is PrefixElement) {
+ var prefixName = target.identifier.name;
+ var targetElement = prefixElement.scope.lookup(prefixName).getter;
+
+ var methodElement = _resolveTypeProperty(
+ receiver: target,
+ receiverElement: targetElement,
+ name: function.propertyName,
+ nameErrorEntity: function,
+ );
+
+ if (methodElement == null) {
+ // TODO(srawlins): Can we get here?
+ node.staticType = DynamicTypeImpl.instance;
+ return;
+ } else {
+ _resolveReceiverPrefix(node, prefixElement, target, methodElement);
+ return;
+ }
+ } else {
+ // TODO(srawlins): Can we get here?
+ node.staticType = DynamicTypeImpl.instance;
+ return;
+ }
+ } else if (target is ExtensionOverrideImpl) {
+ _resolveExtensionOverride(node, function, target);
+ return;
+ } else {
+ targetType = target.typeOrThrow;
+ }
+
+ var propertyElement = _resolver.typePropertyResolver
+ .resolve(
+ receiver: function.realTarget,
+ receiverType: targetType,
+ name: function.propertyName.name,
+ propertyErrorEntity: function.propertyName,
+ nameErrorEntity: function,
+ )
+ .getter;
+
+ if (propertyElement is TypeParameterElement) {
+ _resolveDisallowedExpression(node, propertyElement!.type);
+ return;
+ }
+
+ _resolve(
+ node: node,
+ rawType: function.staticType,
+ name: propertyElement?.name,
+ );
+ }
+
void _resolveReceiverPrefix(
FunctionReferenceImpl node,
PrefixElement prefixElement,
@@ -433,6 +431,94 @@
node.staticType = DynamicTypeImpl.instance;
}
+ void _resolveSimpleIdentifierFunction(
+ FunctionReferenceImpl node, SimpleIdentifierImpl function) {
+ var element = _resolver.nameScope.lookup(function.name).getter;
+
+ if (element == null) {
+ DartType receiverType;
+ var enclosingClass = _resolver.enclosingClass;
+ if (enclosingClass != null) {
+ receiverType = enclosingClass.thisType;
+ } else {
+ var enclosingExtension = _resolver.enclosingExtension;
+ if (enclosingExtension != null) {
+ receiverType = enclosingExtension.extendedType;
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
+ function,
+ [function.name],
+ );
+ function.staticType = DynamicTypeImpl.instance;
+ node.staticType = DynamicTypeImpl.instance;
+ return;
+ }
+ }
+
+ var result = _resolver.typePropertyResolver.resolve(
+ receiver: null,
+ receiverType: receiverType,
+ name: function.name,
+ propertyErrorEntity: function,
+ nameErrorEntity: function,
+ );
+
+ var method = result.getter;
+ if (method != null) {
+ if (method.isStatic) {
+ _reportInvalidAccessToStaticMember(function, method,
+ implicitReceiver: true);
+ // Continue to assign types.
+ }
+
+ function.staticElement = method;
+ function.staticType = method.type;
+ _resolve(node: node, rawType: method.type, name: function.name);
+ return;
+ } else {
+ // TODO(srawlins): Report CompileTimeErrorCode.UNDEFINED_METHOD.
+ return;
+ }
+
+ // TODO(srawlins): if `(target is PropertyAccessorElement)`, report an
+ // error.
+ }
+
+ // Classes and type aliases are checked first so as to include a
+ // PropertyAccess parent check, which does not need to be done for
+ // functions.
+ if (element is ClassElement || element is TypeAliasElement) {
+ // A type-instantiated constructor tearoff like `C<int>.name` or
+ // `prefix.C<int>.name` is initially represented as a [PropertyAccess]
+ // with a [FunctionReference] target.
+ if (node.parent is PropertyAccess) {
+ _resolveConstructorReference(node);
+ return;
+ } else if (element is ClassElement) {
+ function.staticElement = element;
+ _resolveDirectTypeLiteral(node, function, element);
+ return;
+ } else if (element is TypeAliasElement) {
+ function.staticElement = element;
+ _resolveTypeAlias(node: node, element: element, typeAlias: function);
+ return;
+ }
+ } else if (element is ExecutableElement) {
+ function.staticElement = element;
+ function.staticType = element.type;
+ _resolve(node: node, rawType: element.type, name: element.name);
+ return;
+ } else if (element is VariableElement) {
+ function.staticElement = element;
+ function.staticType = element.type;
+ _resolveDisallowedExpression(node, element.type);
+ return;
+ } else {
+ node.staticType = DynamicTypeImpl.instance;
+ }
+ }
+
/// Returns the element that represents the property named [propertyName] on
/// [classElement].
ExecutableElement? _resolveStaticElement(
@@ -517,7 +603,7 @@
'Unexpected receiverElement type: ${receiverElement.runtimeType}');
return null;
}
- return _resolver.typePropertyResolver
+ var methodElement = _resolver.typePropertyResolver
.resolve(
receiver: receiver,
receiverType: receiverType,
@@ -526,5 +612,10 @@
nameErrorEntity: nameErrorEntity,
)
.getter;
+ if (methodElement != null && methodElement.isStatic) {
+ _reportInvalidAccessToStaticMember(name, methodElement,
+ implicitReceiver: false);
+ }
+ return methodElement;
}
}
diff --git a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
index b53a4a1..21ffd13 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
@@ -41,6 +41,140 @@
assertType(reference, 'dynamic');
}
+ test_extensionMethod() async {
+ await assertNoErrorsInCode('''
+class A {}
+
+extension E on A {
+ void foo<T>(T a) {}
+
+ bar() {
+ foo<int>;
+ }
+}
+''');
+
+ var reference = findNode.functionReference('foo<int>;');
+ assertFunctionReference(
+ reference, findElement.method('foo'), 'void Function(int)');
+ }
+
+ test_extensionMethod_explicitReceiver_this() async {
+ await assertNoErrorsInCode('''
+class A {}
+
+extension E on A {
+ void foo<T>(T a) {}
+
+ bar() {
+ this.foo<int>;
+ }
+}
+''');
+
+ var reference = findNode.functionReference('foo<int>;');
+ assertFunctionReference(
+ reference, findElement.method('foo'), 'void Function(int)');
+ }
+
+ test_extensionMethod_extensionOverride() async {
+ await assertNoErrorsInCode('''
+class A {
+ int foo = 0;
+}
+
+extension E on A {
+ void foo<T>(T a) {}
+}
+
+bar(A a) {
+ E(a).foo<int>;
+}
+''');
+
+ var reference = findNode.functionReference('foo<int>;');
+ assertFunctionReference(
+ reference, findElement.method('foo'), 'void Function(int)');
+ }
+
+ test_extensionMethod_extensionOverride_cascade() async {
+ await assertErrorsInCode('''
+class A {
+ int foo = 0;
+}
+
+extension E on A {
+ void foo<T>(T a) {}
+}
+
+bar(A a) {
+ E(a)..foo<int>;
+}
+''', [
+ error(CompileTimeErrorCode.EXTENSION_OVERRIDE_WITH_CASCADE, 85, 1),
+ ]);
+
+ var reference = findNode.functionReference('foo<int>;');
+ assertFunctionReference(
+ reference, findElement.method('foo'), 'void Function(int)');
+ }
+
+ test_extensionMethod_extensionOverride_static() async {
+ await assertErrorsInCode('''
+class A {}
+
+extension E on A {
+ static void foo<T>(T a) {}
+}
+
+bar(A a) {
+ E(a).foo<int>;
+}
+''', [
+ error(CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER, 81,
+ 3),
+ ]);
+
+ var reference = findNode.functionReference('foo<int>;');
+ assertFunctionReference(
+ reference, findElement.method('foo'), 'void Function(int)');
+ }
+
+ test_extensionMethod_extensionOverride_unknown() async {
+ await assertErrorsInCode('''
+class A {}
+
+extension E on A {}
+
+bar(A a) {
+ E(a).foo<int>;
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER, 51, 3),
+ ]);
+
+ var reference = findNode.functionReference('foo<int>;');
+ assertType(reference, 'dynamic');
+ }
+
+ test_extensionMethod_fromClassDeclaration() async {
+ await assertNoErrorsInCode('''
+class A {
+ bar() {
+ foo<int>;
+ }
+}
+
+extension E on A {
+ void foo<T>(T a) {}
+}
+''');
+
+ var reference = findNode.functionReference('foo<int>;');
+ assertFunctionReference(
+ reference, findElement.method('foo'), 'void Function(int)');
+ }
+
test_instanceGetter_explicitReceiver() async {
// This test is here to assert that the resolver does not throw, but in the
// future, an error should be reported here as well.
@@ -212,6 +346,27 @@
'void Function(int)');
}
+ test_instanceMethod_explicitReceiver_topLevelVariable_prefix_unknown() async {
+ newFile('$testPackageLibPath/a.dart', content: '''
+class A {}
+var a = A();
+''');
+ await assertErrorsInCode('''
+import 'a.dart' as prefix;
+
+bar() {
+ prefix.a.foo<int>;
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_GETTER, 47, 3),
+ ]);
+
+ assertImportPrefix(
+ findNode.simple('prefix.'), findElement.prefix('prefix'));
+ var reference = findNode.functionReference('foo<int>;');
+ assertType(reference, 'dynamic');
+ }
+
test_instanceMethod_explicitReceiver_typeParameter() async {
await assertErrorsInCode('''
bar<T>() {
@@ -241,7 +396,6 @@
reference, findElement.method('foo'), 'void Function(int)');
}
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/46635')
test_instanceMethod_explicitReceiver_variable_cascade() async {
await assertNoErrorsInCode('''
class A {
@@ -568,6 +722,24 @@
);
}
+ test_topLevelVariable_prefix_unknown() async {
+ newFile('$testPackageLibPath/a.dart', content: '');
+ await assertErrorsInCode('''
+import 'a.dart' as prefix;
+
+bar() {
+ prefix.a.foo<int>;
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME, 45, 1),
+ ]);
+
+ assertImportPrefix(
+ findNode.simple('prefix.'), findElement.prefix('prefix'));
+ var reference = findNode.functionReference('foo<int>;');
+ assertType(reference, 'dynamic');
+ }
+
test_typeAlias_function_unknownProperty() async {
await assertErrorsInCode('''
typedef Cb = void Function();
diff --git a/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart b/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
index aeaec55..ee423c8 100644
--- a/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
@@ -102,6 +102,19 @@
]);
}
+ test_method_reference_typeInstantiation() async {
+ await assertErrorsInCode(r'''
+class A {
+ static m<T>() {}
+}
+f(A a) {
+ a.m<int>;
+}
+''', [
+ error(CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, 44, 1),
+ ]);
+ }
+
test_propertyAccess_field() async {
await assertErrorsInCode(r'''
class A {
diff --git a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
index 9627043..79ab24a 100644
--- a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
@@ -692,4 +692,32 @@
A get foo => throw 0;
''');
}
+
+ test_typeLiteral_class() async {
+ await assertErrorsInCode('''
+class C<T extends int> {}
+var t = C<String>;
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 36, 6),
+ ]);
+ }
+
+ test_typeLiteral_functionTypeAlias() async {
+ await assertErrorsInCode('''
+typedef Cb<T extends int> = void Function();
+var t = Cb<String>;
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 56, 6),
+ ]);
+ }
+
+ test_typeLiteral_typeAlias() async {
+ await assertErrorsInCode('''
+class C {}
+typedef D<T extends int> = C;
+var t = D<String>;
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 51, 6),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_non_local_static_member_test.dart b/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_non_local_static_member_test.dart
index 6551ffe..8e24064 100644
--- a/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_non_local_static_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_non_local_static_member_test.dart
@@ -50,6 +50,21 @@
]);
}
+ test_methodTearoff() async {
+ await assertErrorsInCode('''
+class A {
+ static void a<T>() {}
+}
+class B extends A {
+ void b() {
+ a<int>;
+ }
+}
+''', [
+ error(_errorCode, 73, 1),
+ ]);
+ }
+
test_readWrite() async {
await assertErrorsInCode(r'''
class A {
diff --git a/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_static_member_of_extended_type_test.dart b/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_static_member_of_extended_type_test.dart
index 8525aa2..1cf7168 100644
--- a/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_static_member_of_extended_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_static_member_of_extended_type_test.dart
@@ -51,6 +51,21 @@
]);
}
+ test_methodTearoff() async {
+ await assertErrorsInCode('''
+class MyClass {
+ static void sm<T>() {}
+}
+extension MyExtension on MyClass {
+ void m() {
+ sm<int>;
+ }
+}
+''', [
+ error(_errorCode, 95, 2),
+ ]);
+ }
+
test_readWrite() async {
await assertErrorsInCode('''
class MyClass {
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index a3b5448..28e3590 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -382,7 +382,7 @@
Iterable<io.File> _collectFiles(String filePath, AnalysisOptions options) {
var files = <io.File>[];
var file = io.File(filePath);
- if (file.existsSync() && !pathFilter.ignored(filePath)) {
+ if (file.existsSync()) {
files.add(file);
} else {
var directory = io.Directory(filePath);
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index 419aceb..19d778d 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -73,7 +73,9 @@
path.join(testDirectory, options),
];
}
- cmd..addAll(sources.map(_adjustFileSpec))..addAll(args);
+ cmd
+ ..addAll(sources.map(_adjustFileSpec))
+ ..addAll(args);
await driver.start(cmd);
}
@@ -390,6 +392,20 @@
ErrorProcessor processorFor(AnalysisError error) =>
processors.firstWhere((p) => p.appliesTo(error));
+ /// If a file is specified explicitly, it should be analyzed, even if
+ /// it is excluded. Excludes work when an including directory is specified.
+ Future<void> test_analysisOptions_excluded_requested() async {
+ await drive(
+ 'data/exclude_test_project/lib/excluded_error.dart',
+ options: 'data/exclude_test_project/$analysisOptionsYaml',
+ );
+ expect(
+ bulletToDash(outSink),
+ contains("error - Undefined class 'ExcludedUndefinedClass'"),
+ );
+ expect(outSink.toString(), contains('1 error found.'));
+ }
+
Future<void> test_analysisOptions_excludes() async {
await drive('data/exclude_test_project',
options: 'data/exclude_test_project/$analysisOptionsYaml');
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 5c4515c..acf8fb5 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -42,6 +42,8 @@
import '../fasta_codes.dart';
+import '../kernel/kernel_target.dart';
+
import '../loader.dart';
import '../modifier.dart';
@@ -121,7 +123,8 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers);
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes);
/// Registers a constructor redirection for this class and returns true if
/// this redirection gives rise to a cycle that has not been reported before.
@@ -341,11 +344,13 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
void build(String ignore, Builder declaration) {
MemberBuilder member = declaration as MemberBuilder;
member.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers);
+ library, coreTypes, delayedActionPerformers,
+ clonedFunctionNodes);
}
MetadataBuilder.buildAnnotations(
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
index 505f29b..b0a984c 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -251,8 +251,10 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
- super.buildOutlineExpressions(library, coreTypes, delayedActionPerformers);
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
+ super.buildOutlineExpressions(
+ library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
// For modular compilation purposes we need to include initializers
// for const constructors into the outline.
@@ -482,15 +484,16 @@
void buildOutlineExpressions(
SourceLibraryBuilder libraryBuilder,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
if (_origin != null) {
// Ensure that default value expressions have been created for [_origin].
LibraryBuilder originLibraryBuilder = _origin!.library;
if (originLibraryBuilder is SourceLibraryBuilder) {
// If [_origin] is from a source library, we need to build the default
// values and initializers first.
- _origin!.buildOutlineExpressions(
- originLibraryBuilder, coreTypes, delayedActionPerformers);
+ _origin!.buildOutlineExpressions(originLibraryBuilder, coreTypes,
+ delayedActionPerformers, clonedFunctionNodes);
}
_clonedFunctionNode!.cloneDefaultValues();
_clonedFunctionNode = null;
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
index 8947531..6c173ef 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -42,6 +42,8 @@
templateDuplicatedDeclarationSyntheticCause,
templateEnumConstantSameNameAsEnclosing;
+import '../kernel/kernel_target.dart';
+
import '../util/helpers.dart';
import '../modifier.dart'
@@ -520,7 +522,8 @@
void buildOutlineExpressions(
SourceLibraryBuilder libraryBuilder,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
List<Expression> values = <Expression>[];
if (enumConstantInfos != null) {
for (EnumConstantInfo? enumConstantInfo in enumConstantInfos!) {
@@ -564,7 +567,8 @@
}
}
}
- super.buildOutlineExpressions(library, coreTypes, delayedActionPerformers);
+ super.buildOutlineExpressions(
+ library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
}
@override
diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
index 0ca4e45..d52ae6f 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -7,6 +7,7 @@
import '../fasta_codes.dart'
show templateInternalProblemNotFoundIn, templateTypeArgumentMismatch;
+import '../kernel/kernel_target.dart';
import '../scope.dart';
import '../source/source_library_builder.dart';
import '../problems.dart';
@@ -36,7 +37,8 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers);
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes);
/// Looks up extension member by [name] taking privacy into account.
///
diff --git a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
index e79afa3..4ca72bb 100644
--- a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:kernel/ast.dart';
+import 'package:kernel/type_algebra.dart';
import '../dill/dill_member_builder.dart';
@@ -11,6 +12,7 @@
import '../kernel/forest.dart';
import '../kernel/internal_ast.dart';
import '../kernel/kernel_api.dart';
+import '../kernel/kernel_target.dart';
import '../kernel/redirecting_factory_body.dart'
show getRedirectingFactoryBody, RedirectingFactoryBody;
@@ -34,7 +36,6 @@
import 'function_builder.dart';
import 'member_builder.dart';
import 'metadata_builder.dart';
-import 'library_builder.dart';
import 'procedure_builder.dart';
import 'type_builder.dart';
import 'type_variable_builder.dart';
@@ -161,6 +162,21 @@
}
@override
+ VariableDeclaration? getTearOffParameter(int index) {
+ if (_factoryTearOff != null) {
+ if (index < _factoryTearOff!.function.positionalParameters.length) {
+ return _factoryTearOff!.function.positionalParameters[index];
+ } else {
+ index -= _factoryTearOff!.function.positionalParameters.length;
+ if (index < _factoryTearOff!.function.namedParameters.length) {
+ return _factoryTearOff!.function.namedParameters[index];
+ }
+ }
+ }
+ return null;
+ }
+
+ @override
List<ClassMember> get localMembers =>
throw new UnsupportedError('${runtimeType}.localMembers');
@@ -225,6 +241,8 @@
final ConstructorReferenceBuilder redirectionTarget;
List<DartType>? typeArguments;
+ FreshTypeParameters? _tearOffTypeParameters;
+
RedirectingFactoryBuilder(
List<MetadataBuilder>? metadata,
int modifiers,
@@ -299,6 +317,9 @@
SourceLibraryBuilder library, void Function(Member, BuiltMemberKind) f) {
Member member = build(library);
f(member, BuiltMemberKind.RedirectingFactory);
+ if (_factoryTearOff != null) {
+ f(_factoryTearOff!, BuiltMemberKind.Method);
+ }
}
@override
@@ -319,6 +340,12 @@
growable: false);
}
updatePrivateMemberName(_procedureInternal, libraryBuilder);
+ if (_factoryTearOff != null) {
+ _tearOffTypeParameters = buildRedirectingFactoryTearOffProcedure(
+ _factoryTearOff!,
+ _procedure,
+ library as SourceLibraryBuilder);
+ }
return _procedureInternal;
}
@@ -326,72 +353,77 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
- super.buildOutlineExpressions(library, coreTypes, delayedActionPerformers);
- LibraryBuilder thisLibrary = this.library;
- if (thisLibrary is SourceLibraryBuilder) {
- RedirectingFactoryBody redirectingFactoryBody =
- _procedure.function.body as RedirectingFactoryBody;
- if (redirectingFactoryBody.typeArguments != null &&
- redirectingFactoryBody.typeArguments!.any((t) => t is UnknownType)) {
- TypeInferrerImpl inferrer = thisLibrary.loader.typeInferenceEngine
- .createLocalTypeInferrer(
- fileUri, classBuilder!.thisType, thisLibrary, null)
- as TypeInferrerImpl;
- inferrer.helper = thisLibrary.loader
- .createBodyBuilderForOutlineExpression(
- thisLibrary, classBuilder, this, classBuilder!.scope, fileUri);
- Builder? targetBuilder = redirectionTarget.target;
- Member target;
- if (targetBuilder is FunctionBuilder) {
- target = targetBuilder.member;
- } else if (targetBuilder is DillMemberBuilder) {
- target = targetBuilder.member;
- } else {
- unhandled("${targetBuilder.runtimeType}", "buildOutlineExpressions",
- charOffset, fileUri);
- }
- Arguments targetInvocationArguments;
- {
- List<Expression> positionalArguments = <Expression>[];
- for (VariableDeclaration parameter
- in _procedure.function.positionalParameters) {
- inferrer.flowAnalysis.declare(parameter, true);
- positionalArguments.add(
- new VariableGetImpl(parameter, forNullGuardedAccess: false));
- }
- List<NamedExpression> namedArguments = <NamedExpression>[];
- for (VariableDeclaration parameter
- in _procedure.function.namedParameters) {
- inferrer.flowAnalysis.declare(parameter, true);
- namedArguments.add(new NamedExpression(parameter.name!,
- new VariableGetImpl(parameter, forNullGuardedAccess: false)));
- }
- // If arguments are created using [Forest.createArguments], and the
- // type arguments are omitted, they are to be inferred.
- targetInvocationArguments = const Forest().createArguments(
- _procedure.fileOffset, positionalArguments,
- named: namedArguments);
- }
- InvocationInferenceResult result = inferrer.inferInvocation(
- function.returnType,
- charOffset,
- target.function!.computeFunctionType(Nullability.nonNullable),
- targetInvocationArguments,
- staticTarget: target);
- List<DartType> typeArguments;
- if (result.inferredType is InterfaceType) {
- typeArguments = (result.inferredType as InterfaceType).typeArguments;
- } else {
- // Assume that the error is reported elsewhere, use 'dynamic' for
- // recovery.
- typeArguments = new List<DartType>.filled(
- target.enclosingClass!.typeParameters.length, const DynamicType(),
- growable: true);
- }
- member.function!.body =
- new RedirectingFactoryBody(target, typeArguments);
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
+ super.buildOutlineExpressions(
+ library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
+ RedirectingFactoryBody redirectingFactoryBody =
+ _procedure.function.body as RedirectingFactoryBody;
+ List<DartType>? typeArguments = redirectingFactoryBody.typeArguments;
+ Member? target = redirectingFactoryBody.target;
+ if (typeArguments != null && typeArguments.any((t) => t is UnknownType)) {
+ TypeInferrerImpl inferrer = library.loader.typeInferenceEngine
+ .createLocalTypeInferrer(
+ fileUri, classBuilder!.thisType, library, null)
+ as TypeInferrerImpl;
+ inferrer.helper = library.loader.createBodyBuilderForOutlineExpression(
+ library, classBuilder, this, classBuilder!.scope, fileUri);
+ Builder? targetBuilder = redirectionTarget.target;
+ if (targetBuilder is FunctionBuilder) {
+ target = targetBuilder.member;
+ } else if (targetBuilder is DillMemberBuilder) {
+ target = targetBuilder.member;
+ } else {
+ unhandled("${targetBuilder.runtimeType}", "buildOutlineExpressions",
+ charOffset, fileUri);
}
+ Arguments targetInvocationArguments;
+ {
+ List<Expression> positionalArguments = <Expression>[];
+ for (VariableDeclaration parameter
+ in _procedure.function.positionalParameters) {
+ inferrer.flowAnalysis.declare(parameter, true);
+ positionalArguments
+ .add(new VariableGetImpl(parameter, forNullGuardedAccess: false));
+ }
+ List<NamedExpression> namedArguments = <NamedExpression>[];
+ for (VariableDeclaration parameter
+ in _procedure.function.namedParameters) {
+ inferrer.flowAnalysis.declare(parameter, true);
+ namedArguments.add(new NamedExpression(parameter.name!,
+ new VariableGetImpl(parameter, forNullGuardedAccess: false)));
+ }
+ // If arguments are created using [Forest.createArguments], and the
+ // type arguments are omitted, they are to be inferred.
+ targetInvocationArguments = const Forest().createArguments(
+ _procedure.fileOffset, positionalArguments,
+ named: namedArguments);
+ }
+ InvocationInferenceResult result = inferrer.inferInvocation(
+ function.returnType,
+ charOffset,
+ target.function!.computeFunctionType(Nullability.nonNullable),
+ targetInvocationArguments,
+ staticTarget: target);
+ if (result.inferredType is InterfaceType) {
+ typeArguments = (result.inferredType as InterfaceType).typeArguments;
+ } else {
+ // Assume that the error is reported elsewhere, use 'dynamic' for
+ // recovery.
+ typeArguments = new List<DartType>.filled(
+ target.enclosingClass!.typeParameters.length, const DynamicType(),
+ growable: true);
+ }
+ member.function!.body = new RedirectingFactoryBody(target, typeArguments);
+ }
+ if (_factoryTearOff != null) {
+ clonedFunctionNodes.add(buildRedirectingFactoryTearOffBody(
+ _factoryTearOff!,
+ target as Constructor,
+ typeArguments ?? [],
+ _tearOffTypeParameters!));
+ delayedActionPerformers.add(new _CopyDefaultValues(
+ _factoryTearOff!, redirectingFactoryBody.target!.function!));
}
}
@@ -413,3 +445,18 @@
return getRedirectingFactoryBody(_procedure)!.typeArguments;
}
}
+
+class _CopyDefaultValues implements DelayedActionPerformer {
+ final Procedure _tearOff;
+ final FunctionNode _function;
+
+ _CopyDefaultValues(this._tearOff, this._function);
+
+ @override
+ bool get hasDelayedActions => true;
+
+ @override
+ void performDelayedActions() {
+ copyTearOffDefaultValues(_tearOff, _function);
+ }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 12b9103..b1ae35f 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -17,6 +17,7 @@
import '../kernel/body_builder.dart' show BodyBuilder;
import '../kernel/class_hierarchy_builder.dart';
import '../kernel/kernel_builder.dart' show ImplicitFieldType;
+import '../kernel/kernel_target.dart';
import '../kernel/late_lowering.dart' as late_lowering;
import '../kernel/member_covariance.dart';
@@ -398,7 +399,8 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
_fieldEncoding.completeSignature(coreTypes);
for (Annotatable annotatable in _fieldEncoding.annotatables) {
diff --git a/pkg/front_end/lib/src/fasta/builder/function_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
index d74aa66..638c80f 100644
--- a/pkg/front_end/lib/src/fasta/builder/function_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
@@ -4,8 +4,8 @@
library fasta.procedure_builder;
-import 'package:front_end/src/fasta/kernel/kernel_api.dart';
import 'package:kernel/ast.dart';
+import 'package:kernel/core_types.dart';
import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
@@ -13,6 +13,7 @@
import '../scope.dart';
import '../kernel/internal_ast.dart' show VariableDeclarationImpl;
+import '../kernel/kernel_target.dart';
import '../loader.dart' show Loader;
@@ -478,7 +479,8 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
if (!_hasBuiltOutlineExpressions) {
DeclarationBuilder? classOrExtensionBuilder =
isClassMember || isExtensionMember
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
index 14ae7c9..c7d1f9d 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -10,6 +10,7 @@
import '../../base/common.dart';
import '../kernel/class_hierarchy_builder.dart';
+import '../kernel/kernel_target.dart';
import '../modifier.dart';
import '../problems.dart' show unsupported;
import '../source/source_library_builder.dart';
@@ -78,7 +79,8 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers);
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes);
/// Returns the [ClassMember]s for the non-setter members created for this
/// member builder.
@@ -184,7 +186,8 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {}
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {}
/// Builds the core AST structures for this member as needed for the outline.
void buildMembers(
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
index 94e7b8c..0c5d28f 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
@@ -11,6 +11,8 @@
import '../builder/type_builder.dart';
import '../builder/type_variable_builder.dart';
+import '../kernel/kernel_target.dart';
+
import '../scope.dart';
import '../util/helpers.dart';
@@ -103,8 +105,11 @@
}
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ void buildOutlineExpressions(
+ LibraryBuilder library,
+ CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
// TODO(johnniwinther): Remove the need for this.
}
}
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 a1f4efa..f7603ef 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
@@ -2,11 +2,12 @@
// 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:front_end/src/fasta/kernel/kernel_api.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart';
import '../builder/member_builder.dart';
import '../source/source_library_builder.dart';
+import 'kernel_api.dart';
+import 'kernel_target.dart';
const String _tearOffNamePrefix = '_#';
const String _tearOffNameSuffix = '#tearOff';
@@ -47,13 +48,11 @@
if (!forAbstractClassOrEnum &&
compilationUnit
.loader.target.backendTarget.isConstructorTearOffLoweringEnabled) {
- return new Procedure(constructorTearOffName(name, compilationUnit.library),
- ProcedureKind.Method, new FunctionNode(null),
- fileUri: fileUri, isStatic: true)
- ..startFileOffset = fileOffset
- ..fileOffset = fileOffset
- ..fileEndOffset = fileOffset
- ..isNonNullableByDefault = compilationUnit.isNonNullableByDefault;
+ return _createTearOffProcedure(
+ compilationUnit,
+ constructorTearOffName(name, compilationUnit.library),
+ fileUri,
+ fileOffset);
}
return null;
}
@@ -78,55 +77,14 @@
classTypeParameters = function.typeParameters;
}
- List<TypeParameter> typeParameters;
- List<DartType> typeArguments;
- Substitution substitution = Substitution.empty;
- if (classTypeParameters.isNotEmpty) {
- FreshTypeParameters freshTypeParameters =
- getFreshTypeParameters(classTypeParameters);
- typeParameters = freshTypeParameters.freshTypeParameters;
- typeArguments = freshTypeParameters.freshTypeArguments;
- substitution = freshTypeParameters.substitution;
- tearOff.function.typeParameters.addAll(typeParameters);
- setParents(typeParameters, tearOff.function);
- } else {
- typeParameters = [];
- typeArguments = [];
- substitution = Substitution.empty;
- }
+ FreshTypeParameters freshTypeParameters =
+ _createFreshTypeParameters(classTypeParameters, tearOff.function);
- List<Expression> positionalArguments = [];
- for (VariableDeclaration constructorParameter
- in function.positionalParameters) {
- VariableDeclaration tearOffParameter = new VariableDeclaration(
- constructorParameter.name,
- type: substitution.substituteType(constructorParameter.type))
- ..fileOffset = constructorParameter.fileOffset;
- tearOff.function.positionalParameters.add(tearOffParameter);
- positionalArguments
- .add(new VariableGet(tearOffParameter)..fileOffset = fileOffset);
- tearOffParameter.parent = tearOff.function;
- }
- List<NamedExpression> namedArguments = [];
- for (VariableDeclaration constructorParameter in function.namedParameters) {
- VariableDeclaration tearOffParameter = new VariableDeclaration(
- constructorParameter.name,
- type: substitution.substituteType(constructorParameter.type),
- isRequired: constructorParameter.isRequired)
- ..fileOffset = constructorParameter.fileOffset;
- tearOff.function.namedParameters.add(tearOffParameter);
- tearOffParameter.parent = tearOff.function;
- namedArguments.add(new NamedExpression(tearOffParameter.name!,
- new VariableGet(tearOffParameter)..fileOffset = fileOffset)
- ..fileOffset = fileOffset);
- }
- tearOff.function.returnType =
- substitution.substituteType(function.returnType);
- tearOff.function.requiredParameterCount = function.requiredParameterCount;
+ List<DartType> typeArguments = freshTypeParameters.freshTypeArguments;
+ Substitution substitution = freshTypeParameters.substitution;
+ _createParameters(tearOff, function, substitution);
+ Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
- Arguments arguments = new Arguments(positionalArguments,
- named: namedArguments, types: typeArguments)
- ..fileOffset = tearOff.fileOffset;
Expression constructorInvocation;
if (constructor is Constructor) {
constructorInvocation = new ConstructorInvocation(constructor, arguments)
@@ -178,28 +136,80 @@
}
}
-void buildConstructorTearOffDefaultValues(
- Procedure tearOff, Constructor constructor, Class enclosingClass) {
+void copyTearOffDefaultValues(Procedure tearOff, FunctionNode function) {
CloneVisitorNotMembers cloner = new CloneVisitorNotMembers();
- for (int i = 0; i < constructor.function.positionalParameters.length; i++) {
+ for (int i = 0; i < function.positionalParameters.length; i++) {
VariableDeclaration tearOffParameter =
tearOff.function.positionalParameters[i];
- VariableDeclaration constructorParameter =
- constructor.function.positionalParameters[i];
+ VariableDeclaration constructorParameter = function.positionalParameters[i];
tearOffParameter.initializer =
cloner.cloneOptional(constructorParameter.initializer);
tearOffParameter.initializer?.parent = tearOffParameter;
}
- for (int i = 0; i < constructor.function.namedParameters.length; i++) {
+ for (int i = 0; i < function.namedParameters.length; i++) {
VariableDeclaration tearOffParameter = tearOff.function.namedParameters[i];
- VariableDeclaration constructorParameter =
- constructor.function.namedParameters[i];
+ VariableDeclaration constructorParameter = function.namedParameters[i];
tearOffParameter.initializer =
cloner.cloneOptional(constructorParameter.initializer);
tearOffParameter.initializer?.parent = tearOffParameter;
}
}
+/// Creates the parameters for the redirecting factory [tearOff] based on the
+/// [redirectingConstructor] declaration.
+FreshTypeParameters buildRedirectingFactoryTearOffProcedure(
+ Procedure tearOff,
+ Procedure redirectingConstructor,
+ SourceLibraryBuilder libraryBuilder) {
+ assert(redirectingConstructor.isRedirectingFactory);
+ FunctionNode function = redirectingConstructor.function;
+ FreshTypeParameters freshTypeParameters =
+ _createFreshTypeParameters(function.typeParameters, tearOff.function);
+ Substitution substitution = freshTypeParameters.substitution;
+ _createParameters(tearOff, function, substitution);
+ 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].
+///
+/// Returns the [ClonedFunctionNode] object need to perform default value
+/// computation.
+ClonedFunctionNode buildRedirectingFactoryTearOffBody(
+ Procedure tearOff,
+ Constructor constructor,
+ List<DartType> typeArguments,
+ FreshTypeParameters freshTypeParameters) {
+ int fileOffset = tearOff.fileOffset;
+
+ if (!freshTypeParameters.substitution.isEmpty) {
+ if (typeArguments.isNotEmpty) {
+ // Translate [typeArgument] into the context of the synthesized procedure.
+ typeArguments = new List<DartType>.generate(
+ typeArguments.length,
+ (int index) => freshTypeParameters.substitution
+ .substituteType(typeArguments[index]));
+ }
+ }
+
+ Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
+ Expression constructorInvocation =
+ new ConstructorInvocation(constructor, arguments)
+ ..fileOffset = tearOff.fileOffset;
+ tearOff.function.body = new ReturnStatement(constructorInvocation)
+ ..fileOffset = tearOff.fileOffset
+ ..parent = tearOff.function;
+
+ return new ClonedFunctionNode(
+ new Map<TypeParameter, DartType>.fromIterables(
+ constructor.enclosingClass.typeParameters, typeArguments),
+ constructor.function,
+ tearOff.function);
+}
+
/// Creates the synthesized name to use for the lowering of the tear off of a
/// typedef in [library] using [index] for a unique name within the library.
Name typedefTearOffName(int index, Library library) {
@@ -218,54 +228,35 @@
Procedure createTypedefTearOffLowering(SourceLibraryBuilder libraryBuilder,
TypedefTearOff node, FunctionType targetType, Uri fileUri, int index) {
int fileOffset = node.fileOffset;
- Procedure tearOff = new Procedure(
+ Procedure tearOff = _createTearOffProcedure(
+ libraryBuilder,
typedefTearOffName(index, libraryBuilder.library),
- ProcedureKind.Method,
- new FunctionNode(null),
- fileUri: fileUri,
- isStatic: true)
- ..startFileOffset = fileOffset
- ..fileOffset = fileOffset
- ..fileEndOffset = fileOffset
- ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault;
- List<TypeParameter> typedefTypeParameters = node.typeParameters;
- List<TypeParameter> typeParameters;
+ fileUri,
+ node.fileOffset);
+ FreshTypeParameters freshTypeParameters =
+ _createFreshTypeParameters(node.typeParameters, tearOff.function);
+ Substitution substitution = freshTypeParameters.substitution;
+
List<DartType> typeArguments = node.typeArguments;
- Substitution substitution = Substitution.empty;
- if (typedefTypeParameters.isNotEmpty) {
- FreshTypeParameters freshTypeParameters =
- getFreshTypeParameters(typedefTypeParameters);
- typeParameters = freshTypeParameters.freshTypeParameters;
- substitution = freshTypeParameters.substitution;
- tearOff.function.typeParameters.addAll(typeParameters);
- setParents(typeParameters, tearOff.function);
- if (typeArguments.isNotEmpty) {
+ if (typeArguments.isNotEmpty) {
+ if (!substitution.isEmpty) {
// Translate [typeArgument] into the context of the synthesized procedure.
typeArguments = new List<DartType>.generate(typeArguments.length,
(int index) => substitution.substituteType(typeArguments[index]));
}
- } else {
- typeParameters = [];
- substitution = Substitution.empty;
- }
- if (typeArguments.isNotEmpty) {
// Instantiate [targetType] with [typeArguments].
targetType =
Substitution.fromPairs(targetType.typeParameters, typeArguments)
.substituteType(targetType.withoutTypeParameters) as FunctionType;
}
- List<Expression> positionalArguments = [];
for (DartType constructorParameter in targetType.positionalParameters) {
VariableDeclaration tearOffParameter = new VariableDeclaration(null,
type: substitution.substituteType(constructorParameter))
..fileOffset = fileOffset;
tearOff.function.positionalParameters.add(tearOffParameter);
- positionalArguments
- .add(new VariableGet(tearOffParameter)..fileOffset = fileOffset);
tearOffParameter.parent = tearOff.function;
}
- List<NamedExpression> namedArguments = [];
for (NamedType constructorParameter in targetType.namedParameters) {
VariableDeclaration tearOffParameter = new VariableDeclaration(
constructorParameter.name,
@@ -274,17 +265,12 @@
..fileOffset = fileOffset;
tearOff.function.namedParameters.add(tearOffParameter);
tearOffParameter.parent = tearOff.function;
- namedArguments.add(new NamedExpression(tearOffParameter.name!,
- new VariableGet(tearOffParameter)..fileOffset = fileOffset)
- ..fileOffset = fileOffset);
}
tearOff.function.returnType =
substitution.substituteType(targetType.returnType);
tearOff.function.requiredParameterCount = targetType.requiredParameterCount;
- Arguments arguments = new Arguments(positionalArguments,
- named: namedArguments, types: typeArguments)
- ..fileOffset = tearOff.fileOffset;
+ Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
Expression constructorInvocation = new FunctionInvocation(
FunctionAccessKind.FunctionType, node.expression, arguments,
functionType: targetType)
@@ -296,3 +282,84 @@
tearOff.function.fileEndOffset = tearOff.fileOffset;
return tearOff;
}
+
+/// Creates the synthesized [Procedure] node for a tear off lowering by the
+/// given [name].
+Procedure _createTearOffProcedure(SourceLibraryBuilder libraryBuilder,
+ Name name, Uri fileUri, int fileOffset) {
+ return new Procedure(name, ProcedureKind.Method, new FunctionNode(null),
+ fileUri: fileUri, isStatic: true)
+ ..startFileOffset = fileOffset
+ ..fileOffset = fileOffset
+ ..fileEndOffset = fileOffset
+ ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault;
+}
+
+/// Creates the synthesized type parameters for a tear off lowering. The type
+/// parameters are based [originalTypeParameters] and are inserted into
+/// [newFunctionNode]. The created [FreshTypeParameters] is returned.
+FreshTypeParameters _createFreshTypeParameters(
+ List<TypeParameter> originalTypeParameters, FunctionNode newFunctionNode) {
+ FreshTypeParameters freshTypeParameters;
+ if (originalTypeParameters.isNotEmpty) {
+ freshTypeParameters = getFreshTypeParameters(originalTypeParameters);
+ List<TypeParameter> typeParameters =
+ freshTypeParameters.freshTypeParameters;
+ newFunctionNode.typeParameters.addAll(typeParameters);
+ setParents(typeParameters, newFunctionNode);
+ } else {
+ freshTypeParameters = new FreshTypeParameters([], [], Substitution.empty);
+ }
+ return freshTypeParameters;
+}
+
+/// Creates the parameters for the [tearOff] lowering based of the parameters
+/// in [function] and using the [substitution] to compute the parameter and
+/// return types.
+void _createParameters(
+ Procedure tearOff, FunctionNode function, Substitution substitution) {
+ for (VariableDeclaration constructorParameter
+ in function.positionalParameters) {
+ VariableDeclaration tearOffParameter = new VariableDeclaration(
+ constructorParameter.name,
+ type: substitution.substituteType(constructorParameter.type))
+ ..fileOffset = constructorParameter.fileOffset;
+ tearOff.function.positionalParameters.add(tearOffParameter);
+ tearOffParameter.parent = tearOff.function;
+ }
+ for (VariableDeclaration constructorParameter in function.namedParameters) {
+ VariableDeclaration tearOffParameter = new VariableDeclaration(
+ constructorParameter.name,
+ type: substitution.substituteType(constructorParameter.type),
+ isRequired: constructorParameter.isRequired)
+ ..fileOffset = constructorParameter.fileOffset;
+ tearOff.function.namedParameters.add(tearOffParameter);
+ tearOffParameter.parent = tearOff.function;
+ }
+ tearOff.function.returnType =
+ substitution.substituteType(function.returnType);
+ tearOff.function.requiredParameterCount = function.requiredParameterCount;
+}
+
+/// Creates the [Arguments] for passing the parameters from [tearOff] to its
+/// target, using [typeArguments] as the passed type arguments.
+Arguments _createArguments(
+ Procedure tearOff, List<DartType> typeArguments, int fileOffset) {
+ List<Expression> positionalArguments = [];
+ for (VariableDeclaration tearOffParameter
+ in tearOff.function.positionalParameters) {
+ positionalArguments
+ .add(new VariableGet(tearOffParameter)..fileOffset = fileOffset);
+ }
+ List<NamedExpression> namedArguments = [];
+ for (VariableDeclaration tearOffParameter
+ in tearOff.function.namedParameters) {
+ namedArguments.add(new NamedExpression(tearOffParameter.name!,
+ new VariableGet(tearOffParameter)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset);
+ }
+ Arguments arguments = new Arguments(positionalArguments,
+ named: namedArguments, types: typeArguments)
+ ..fileOffset = tearOff.fileOffset;
+ return arguments;
+}
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 c3a5e4e..a49ae77 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -336,7 +336,7 @@
loader.checkAbstractMembers(myClasses);
loader.addNoSuchMethodForwarders(myClasses);
loader.checkMixins(myClasses);
- loader.buildOutlineExpressions(loader.coreTypes);
+ loader.buildOutlineExpressions(loader.coreTypes, clonedFunctionNodes);
loader.checkTypes();
loader.checkRedirectingFactories(myClasses);
loader.checkMainMethods();
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 76daac6..9427c99 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -15,6 +15,7 @@
import 'builder/type_variable_builder.dart';
import 'kernel/body_builder.dart' show JumpTarget;
import 'kernel/class_hierarchy_builder.dart' show ClassMember;
+import 'kernel/kernel_target.dart';
import 'util/helpers.dart' show DelayedActionPerformer;
import 'fasta_codes.dart'
@@ -806,8 +807,11 @@
ProcedureKind? get kind => null;
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ void buildOutlineExpressions(
+ LibraryBuilder library,
+ CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
throw new UnsupportedError(
'AmbiguousMemberBuilder.buildOutlineExpressions');
}
diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
index a6774b6..30f4fff 100644
--- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
@@ -26,6 +26,8 @@
noLength,
templateExtensionMemberConflictsWithObjectMember;
+import '../kernel/kernel_target.dart';
+
import '../problems.dart';
import '../scope.dart';
@@ -273,7 +275,8 @@
void buildOutlineExpressions(
SourceLibraryBuilder library,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ List<DelayedActionPerformer> delayedActionPerformers,
+ List<ClonedFunctionNode> clonedFunctionNodes) {
MetadataBuilder.buildAnnotations(isPatch ? origin.extension : extension,
metadata, library, this, null, fileUri);
if (typeParameters != null) {
@@ -286,7 +289,7 @@
void build(String ignore, Builder declaration) {
MemberBuilder member = declaration as MemberBuilder;
member.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers);
+ library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
}
scope.forEach(build);
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 51b2dd8..843754e 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -92,7 +92,7 @@
import '../kernel/kernel_builder.dart'
show ClassHierarchyBuilder, ClassMember, DelayedCheck;
-import '../kernel/kernel_target.dart' show KernelTarget;
+import '../kernel/kernel_target.dart' show ClonedFunctionNode, KernelTarget;
import '../kernel/body_builder.dart' show BodyBuilder;
@@ -1182,7 +1182,8 @@
ticker.logMs("Checked mixin declaration applications");
}
- void buildOutlineExpressions(CoreTypes coreTypes) {
+ void buildOutlineExpressions(
+ CoreTypes coreTypes, List<ClonedFunctionNode> clonedFunctionNodes) {
List<DelayedActionPerformer> delayedActionPerformers =
<DelayedActionPerformer>[];
for (LibraryBuilder library in builders.values) {
@@ -1192,14 +1193,14 @@
while (iterator.moveNext()) {
Builder declaration = iterator.current;
if (declaration is ClassBuilder) {
- declaration.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers);
+ declaration.buildOutlineExpressions(library, coreTypes,
+ delayedActionPerformers, clonedFunctionNodes);
} else if (declaration is ExtensionBuilder) {
- declaration.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers);
+ declaration.buildOutlineExpressions(library, coreTypes,
+ delayedActionPerformers, clonedFunctionNodes);
} else if (declaration is MemberBuilder) {
- declaration.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers);
+ declaration.buildOutlineExpressions(library, coreTypes,
+ delayedActionPerformers, clonedFunctionNodes);
} else if (declaration is TypeAliasBuilder) {
declaration.buildOutlineExpressions(
library, coreTypes, delayedActionPerformers);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart
index 80b72e45..dda860c 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart
@@ -15,6 +15,12 @@
Class1([this.field = 42]);
}
+class Class2 {
+ final int field;
+
+ Class2({this.field: 42});
+}
+
void testDefaultValues() {
var f1a = Class1.new;
var c1a = f1a();
@@ -31,6 +37,22 @@
var c1d = f1b(87);
expect(87, c1d.field);
throws(() => f1b(42, 87));
+
+ var f2a = Class2.new;
+ var c2a = f2a();
+ expect(42, c2a.field);
+ var c2b = f2a(field: 87);
+ expect(87, c2b.field);
+ () {
+ f2a(87); // error
+ };
+
+ dynamic f2b = Class2.new;
+ var c2c = f2b();
+ expect(42, c2c.field);
+ var c2d = f2b(field: 87);
+ expect(87, c2d.field);
+ throws(() => f2b(87));
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.expect
index b41e8e2..066aa724 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.expect
@@ -2,11 +2,16 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f1a(42, 87); // error
// ^
//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -18,6 +23,14 @@
static method _#new#tearOff([core::int field = #C1]) → self::Class1
return new self::Class1::•(field);
}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor •({core::int field = #C1}) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::•(field: field);
+}
static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -30,7 +43,7 @@
self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
self::expect(87, c1b.{self::Class1::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f1a(42, 87); // error
^" in f1a{<inapplicable>}.(42, 87);
@@ -41,12 +54,29 @@
dynamic c1d = f1b{dynamic}.call(87);
self::expect(87, c1d{dynamic}.field);
self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C3;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C3}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
try {
f(){() → dynamic};
}
@@ -63,5 +93,6 @@
constants {
#C1 = 42
#C2 = static-tearoff self::Class1::_#new#tearOff
- #C3 = false
+ #C3 = static-tearoff self::Class2::_#new#tearOff
+ #C4 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.transformed.expect
index ac558cd..c76d239 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.transformed.expect
@@ -2,11 +2,16 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f1a(42, 87); // error
// ^
//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -18,6 +23,14 @@
static method _#new#tearOff([core::int field = #C1]) → self::Class1
return new self::Class1::•(field);
}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor •({core::int field = #C1}) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::•(field: field);
+}
static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -30,7 +43,7 @@
self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
self::expect(87, c1b.{self::Class1::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f1a(42, 87); // error
^" in f1a{<inapplicable>}.(42, 87);
@@ -41,12 +54,29 @@
dynamic c1d = f1b{dynamic}.call(87);
self::expect(87, c1d{dynamic}.field);
self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C3;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C3}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
try {
f(){() → dynamic};
}
@@ -63,5 +93,6 @@
constants {
#C1 = 42
#C2 = static-tearoff self::Class1::_#new#tearOff
- #C3 = false
+ #C3 = static-tearoff self::Class2::_#new#tearOff
+ #C4 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline.expect
index cd95744..8aff8da 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline.expect
@@ -6,6 +6,11 @@
Class1([this.field = 42]);
}
+class Class2 {
+ final int field;
+ Class2({this.field: 42});
+}
+
void testDefaultValues() {}
expect(expected, actual) {}
throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline_modelled.expect
index 0426153..ecb692c 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline_modelled.expect
@@ -3,6 +3,11 @@
final int field;
}
+class Class2 {
+ Class2({this.field: 42});
+ final int field;
+}
+
expect(expected, actual) {}
final bool inSoundMode = <int?>[] is! List<int>;
main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.expect
index b41e8e2..066aa724 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.expect
@@ -2,11 +2,16 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f1a(42, 87); // error
// ^
//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -18,6 +23,14 @@
static method _#new#tearOff([core::int field = #C1]) → self::Class1
return new self::Class1::•(field);
}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor •({core::int field = #C1}) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::•(field: field);
+}
static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -30,7 +43,7 @@
self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
self::expect(87, c1b.{self::Class1::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f1a(42, 87); // error
^" in f1a{<inapplicable>}.(42, 87);
@@ -41,12 +54,29 @@
dynamic c1d = f1b{dynamic}.call(87);
self::expect(87, c1d{dynamic}.field);
self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C3;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C3}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
try {
f(){() → dynamic};
}
@@ -63,5 +93,6 @@
constants {
#C1 = 42
#C2 = static-tearoff self::Class1::_#new#tearOff
- #C3 = false
+ #C3 = static-tearoff self::Class2::_#new#tearOff
+ #C4 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.outline.expect
index 7554ec1..128018d 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.outline.expect
@@ -9,6 +9,13 @@
static method _#new#tearOff([core::int field]) → self::Class1
return new self::Class1::•(field);
}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor •({core::int field}) → self::Class2
+ ;
+ static method _#new#tearOff({core::int field}) → self::Class2
+ return new self::Class2::•(field: field);
+}
static final field core::bool inSoundMode;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.transformed.expect
index ac558cd..c76d239 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.transformed.expect
@@ -2,11 +2,16 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f1a(42, 87); // error
// ^
//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -18,6 +23,14 @@
static method _#new#tearOff([core::int field = #C1]) → self::Class1
return new self::Class1::•(field);
}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor •({core::int field = #C1}) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::•(field: field);
+}
static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -30,7 +43,7 @@
self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
self::expect(87, c1b.{self::Class1::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f1a(42, 87); // error
^" in f1a{<inapplicable>}.(42, 87);
@@ -41,12 +54,29 @@
dynamic c1d = f1b{dynamic}.call(87);
self::expect(87, c1d{dynamic}.field);
self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C3;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C3}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
try {
f(){() → dynamic};
}
@@ -63,5 +93,6 @@
constants {
#C1 = 42
#C2 = static-tearoff self::Class1::_#new#tearOff
- #C3 = false
+ #C3 = static-tearoff self::Class2::_#new#tearOff
+ #C4 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
index 1411efa..7c14634 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
@@ -88,7 +88,7 @@
return new self::Class4::_(field);
static factory •([core::int? field = #C1]) → self::Class4
return new self::Class4::_(field);
- static method _#new#tearOff([core::int? field]) → self::Class4
+ static method _#new#tearOff([core::int? field = #C1]) → self::Class4
return self::Class4::•(field);
}
class Class5 extends core::Object {
@@ -101,7 +101,7 @@
return new self::Class5::_(field1, field2);
static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
return new self::Class5::_(field1, field2);
- static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
return self::Class5::•(field1, field2);
}
class Class6 extends core::Object {
@@ -115,7 +115,7 @@
return new self::Class6::_(field1, field2: field2, field3: field3);
static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return new self::Class6::_(field1, field2: field2, field3: field3);
- static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+ static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return self::Class6::•(field1, field2: field2, field3: field3);
}
static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect
index afcbd72..ebe5432 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect
@@ -88,7 +88,7 @@
return new self::Class4::_(field);
static factory •([core::int? field = #C1]) → self::Class4
return new self::Class4::_(field);
- static method _#new#tearOff([core::int? field]) → self::Class4
+ static method _#new#tearOff([core::int? field = #C1]) → self::Class4
return self::Class4::•(field);
}
class Class5 extends core::Object {
@@ -101,7 +101,7 @@
return new self::Class5::_(field1, field2);
static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
return new self::Class5::_(field1, field2);
- static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
return self::Class5::•(field1, field2);
}
class Class6 extends core::Object {
@@ -115,7 +115,7 @@
return new self::Class6::_(field1, field2: field2, field3: field3);
static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return new self::Class6::_(field1, field2: field2, field3: field3);
- static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+ static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return self::Class6::•(field1, field2: field2, field3: field3);
}
static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
index 1411efa..7c14634 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
@@ -88,7 +88,7 @@
return new self::Class4::_(field);
static factory •([core::int? field = #C1]) → self::Class4
return new self::Class4::_(field);
- static method _#new#tearOff([core::int? field]) → self::Class4
+ static method _#new#tearOff([core::int? field = #C1]) → self::Class4
return self::Class4::•(field);
}
class Class5 extends core::Object {
@@ -101,7 +101,7 @@
return new self::Class5::_(field1, field2);
static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
return new self::Class5::_(field1, field2);
- static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
return self::Class5::•(field1, field2);
}
class Class6 extends core::Object {
@@ -115,7 +115,7 @@
return new self::Class6::_(field1, field2: field2, field3: field3);
static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return new self::Class6::_(field1, field2: field2, field3: field3);
- static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+ static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return self::Class6::•(field1, field2: field2, field3: field3);
}
static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
index afcbd72..ebe5432 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
@@ -88,7 +88,7 @@
return new self::Class4::_(field);
static factory •([core::int? field = #C1]) → self::Class4
return new self::Class4::_(field);
- static method _#new#tearOff([core::int? field]) → self::Class4
+ static method _#new#tearOff([core::int? field = #C1]) → self::Class4
return self::Class4::•(field);
}
class Class5 extends core::Object {
@@ -101,7 +101,7 @@
return new self::Class5::_(field1, field2);
static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
return new self::Class5::_(field1, field2);
- static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
return self::Class5::•(field1, field2);
}
class Class6 extends core::Object {
@@ -115,7 +115,7 @@
return new self::Class6::_(field1, field2: field2, field3: field3);
static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return new self::Class6::_(field1, field2: field2, field3: field3);
- static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+ static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return self::Class6::•(field1, field2: field2, field3: field3);
}
static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart
new file mode 100644
index 0000000..f966b5b
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+ print('inSoundMode: $inSoundMode');
+ testDefaultValues();
+}
+
+class Class1 {
+ final int field;
+
+ Class1._(this.field);
+ factory Class1([int field = 42]) => new Class1._(field);
+}
+
+class Class2 {
+ final int field;
+
+ Class2._(this.field);
+ factory Class2({int field: 42}) => new Class2._(field);
+}
+
+void testDefaultValues() {
+ var f1a = Class1.new;
+ var c1a = f1a();
+ expect(42, c1a.field);
+ var c1b = f1a(87);
+ expect(87, c1b.field);
+ () {
+ f1a(42, 87); // error
+ };
+
+ dynamic f1b = Class1.new;
+ var c1c = f1b();
+ expect(42, c1c.field);
+ var c1d = f1b(87);
+ expect(87, c1d.field);
+ throws(() => f1b(42, 87));
+
+ var f2a = Class2.new;
+ var c2a = f2a();
+ expect(42, c2a.field);
+ var c2b = f2a(field: 87);
+ expect(87, c2b.field);
+ () {
+ f2a(87); // error
+ };
+
+ dynamic f2b = Class2.new;
+ var c2c = f2b();
+ expect(42, c2c.field);
+ var c2d = f2b(field: 87);
+ expect(87, c2d.field);
+ throws(() => f2b(87));
+}
+
+expect(expected, actual) {
+ if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+ try {
+ f();
+ } catch (e) {
+ print('Thrown: $e');
+ return;
+ }
+ if (!inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw 'Expected exception';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.expect
new file mode 100644
index 0000000..bcc5942
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.expect
@@ -0,0 +1,106 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+ static method _#new#tearOff([core::int field = #C1]) → self::Class1
+ return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class2
+ return new self::Class2::_(field);
+ static factory •({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field);
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+ ([core::int]) → self::Class1 f1a = #C2;
+ self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+ self::expect(42, c1a.{self::Class1::field}{core::int});
+ self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+ self::expect(87, c1b.{self::Class1::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1a(42, 87); // error
+ ^" in f1a{<inapplicable>}.(42, 87);
+ };
+ dynamic f1b = #C2;
+ dynamic c1c = f1b{dynamic}.call();
+ self::expect(42, c1c{dynamic}.field);
+ dynamic c1d = f1b{dynamic}.call(87);
+ self::expect(87, c1d{dynamic}.field);
+ self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C3;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 42
+ #C2 = static-tearoff self::Class1::_#new#tearOff
+ #C3 = static-tearoff self::Class2::_#new#tearOff
+ #C4 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.transformed.expect
new file mode 100644
index 0000000..db9b0fa
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.transformed.expect
@@ -0,0 +1,106 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+ static method _#new#tearOff([core::int field = #C1]) → self::Class1
+ return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class2
+ return new self::Class2::_(field);
+ static factory •({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field);
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+ ([core::int]) → self::Class1 f1a = #C2;
+ self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+ self::expect(42, c1a.{self::Class1::field}{core::int});
+ self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+ self::expect(87, c1b.{self::Class1::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1a(42, 87); // error
+ ^" in f1a{<inapplicable>}.(42, 87);
+ };
+ dynamic f1b = #C2;
+ dynamic c1c = f1b{dynamic}.call();
+ self::expect(42, c1c{dynamic}.field);
+ dynamic c1d = f1b{dynamic}.call(87);
+ self::expect(87, c1d{dynamic}.field);
+ self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C3;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 42
+ #C2 = static-tearoff self::Class1::_#new#tearOff
+ #C3 = static-tearoff self::Class2::_#new#tearOff
+ #C4 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline.expect
new file mode 100644
index 0000000..99a80f2
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline.expect
@@ -0,0 +1,18 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+ final int field;
+ Class1._(this.field);
+ factory Class1([int field = 42]) => new Class1._(field);
+}
+
+class Class2 {
+ final int field;
+ Class2._(this.field);
+ factory Class2({int field: 42}) => new Class2._(field);
+}
+
+void testDefaultValues() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..4f18568
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline_modelled.expect
@@ -0,0 +1,17 @@
+class Class1 {
+ Class1._(this.field);
+ factory Class1([int field = 42]) => new Class1._(field);
+ final int field;
+}
+
+class Class2 {
+ Class2._(this.field);
+ factory Class2({int field: 42}) => new Class2._(field);
+ final int field;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
+void testDefaultValues() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.expect
new file mode 100644
index 0000000..bcc5942
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.expect
@@ -0,0 +1,106 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+ static method _#new#tearOff([core::int field = #C1]) → self::Class1
+ return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class2
+ return new self::Class2::_(field);
+ static factory •({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field);
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+ ([core::int]) → self::Class1 f1a = #C2;
+ self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+ self::expect(42, c1a.{self::Class1::field}{core::int});
+ self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+ self::expect(87, c1b.{self::Class1::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1a(42, 87); // error
+ ^" in f1a{<inapplicable>}.(42, 87);
+ };
+ dynamic f1b = #C2;
+ dynamic c1c = f1b{dynamic}.call();
+ self::expect(42, c1c{dynamic}.field);
+ dynamic c1d = f1b{dynamic}.call(87);
+ self::expect(87, c1d{dynamic}.field);
+ self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C3;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 42
+ #C2 = static-tearoff self::Class1::_#new#tearOff
+ #C3 = static-tearoff self::Class2::_#new#tearOff
+ #C4 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.outline.expect
new file mode 100644
index 0000000..da300f3
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.outline.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class1
+ ;
+ static method _#_#tearOff(core::int field) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field]) → self::Class1
+ ;
+ static method _#new#tearOff([core::int field]) → self::Class1
+ return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class2
+ ;
+ static method _#_#tearOff(core::int field) → self::Class2
+ return new self::Class2::_(field);
+ static factory •({core::int field}) → self::Class2
+ ;
+ static method _#new#tearOff({core::int field}) → self::Class2
+ return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+ ;
+static method testDefaultValues() → void
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.transformed.expect
new file mode 100644
index 0000000..db9b0fa
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.transformed.expect
@@ -0,0 +1,106 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+ static method _#new#tearOff([core::int field = #C1]) → self::Class1
+ return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ constructor _(core::int field) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class2
+ return new self::Class2::_(field);
+ static factory •({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field);
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+ ([core::int]) → self::Class1 f1a = #C2;
+ self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+ self::expect(42, c1a.{self::Class1::field}{core::int});
+ self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+ self::expect(87, c1b.{self::Class1::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1a(42, 87); // error
+ ^" in f1a{<inapplicable>}.(42, 87);
+ };
+ dynamic f1b = #C2;
+ dynamic c1c = f1b{dynamic}.call();
+ self::expect(42, c1c{dynamic}.field);
+ dynamic c1d = f1b{dynamic}.call(87);
+ self::expect(87, c1d{dynamic}.field);
+ self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C3;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 42
+ #C2 = static-tearoff self::Class1::_#new#tearOff
+ #C3 = static-tearoff self::Class2::_#new#tearOff
+ #C4 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart
new file mode 100644
index 0000000..302f380
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart
@@ -0,0 +1,134 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+ print('inSoundMode: $inSoundMode');
+ testGeneric();
+ testBounded();
+}
+
+class Class1<T> {
+ Class1._();
+ factory Class1() = Class1<T>._;
+}
+
+testGeneric() {
+ var f1a = Class1.new;
+ var c1a = f1a();
+ expect(true, c1a is Class1<dynamic>);
+ expect(false, c1a is Class1<int>);
+ var c1b = f1a<int>();
+ expect(true, c1b is Class1<int>);
+ expect(false, c1b is Class1<String>);
+ () {
+ f1a<int, String>(); // error
+ };
+
+ var f1b = f1a<int>;
+ var c1c = f1b();
+ expect(true, c1c is Class1<int>);
+ expect(false, c1c is Class1<String>);
+ () {
+ f1b<int>(); // error
+ };
+
+ dynamic f1c = Class1.new;
+ var c1d = f1c();
+ expect(true, c1a is Class1<dynamic>);
+ expect(false, c1a is Class1<int>);
+ throws(() => f1c<int, String>());
+}
+
+class Class2<T extends num> {
+ Class2._();
+ factory Class2() = Class2<T>._;
+}
+
+class Class3<T extends S, S> {
+ Class3._();
+ factory Class3() = Class3<T, S>._;
+}
+
+class Class4<T extends Class4<T>> {
+ Class4._();
+ factory Class4() = Class4<T>._;
+}
+
+class Class4int extends Class4<Class4int> {
+ Class4int._() : super._();
+ factory Class4int() = Class4int._;
+}
+
+testBounded() {
+ var f2a = Class2.new;
+ var c2a = f2a();
+ expect(true, c2a is Class2<num>);
+ expect(false, c2a is Class2<int>);
+ var c2b = f2a<int>();
+ expect(true, c2b is Class2<int>);
+ expect(false, c2b is Class2<double>);
+ () {
+ f2a<String>(); // error
+ f2a<int, String>(); // error
+ };
+
+ dynamic f2b = Class2.new;
+ var c2c = f2b();
+ expect(true, c2c is Class2<num>);
+ expect(false, c2c is Class2<int>);
+ var c2d = f2b<int>();
+ expect(true, c2d is Class2<int>);
+ expect(false, c2d is Class2<double>);
+ throws(() => f2b<String>());
+ throws(() => f2b<int, String>());
+
+ var f3a = Class3.new;
+ var c3a = f3a();
+ expect(true, c3a is Class3<dynamic, dynamic>);
+ expect(false, c3a is Class3<int, num>);
+ var c3b = f3a<int, num>();
+ expect(true, c3b is Class3<int, num>);
+ expect(false, c3b is Class3<double, num>);
+ () {
+ f3a<num, int>(); // error
+ };
+
+ dynamic f3b = Class3.new;
+ var c3c = f3b();
+ expect(true, c3c is Class3<dynamic, dynamic>);
+ expect(false, c3c is Class3<int, num>);
+ var c3d = f3b<int, num>();
+ expect(true, c3d is Class3<int, num>);
+ expect(false, c3d is Class3<double, num>);
+ throws(() => f3b<num, int>());
+
+ var f4a = Class4.new;
+ () {
+ var c4a = f4a(); // error
+ };
+
+ dynamic f4b = Class4.new;
+ throws(() => f4b());
+ var c4b = f4b<Class4int>();
+ expect(true, c4b is Class4<Class4int>);
+}
+
+expect(expected, actual) {
+ if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+ try {
+ f();
+ } catch (e) {
+ print('Thrown: $e');
+ return;
+ }
+ if (!inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw 'Expected exception';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.expect
new file mode 100644
index 0000000..14303b7
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.expect
@@ -0,0 +1,205 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+// f1a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+// f1b<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:74:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+// f2a<String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+// f2a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:96:8: Error: Type argument 'num' doesn't conform to the bound 'S' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+// f3a<num, int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:110:18: Error: Inferred type argument 'Class4<Object?>' doesn't conform to the bound 'Class4<T>' of the type variable 'T' on 'call'.
+// - 'Class4' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// var c4a = f4a(); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1<self::Class1::T%>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+ static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+ let dynamic #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _() → self::Class2<self::Class2::T>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+ return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+ static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+ let dynamic #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+ static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+ let dynamic #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _() → self::Class4<self::Class4::T>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+ return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+ static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+ let dynamic #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+ constructor _() → self::Class4int
+ : super self::Class4::_()
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ let dynamic #redirecting_factory = self::Class4int::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class4int
+ return new self::Class4int::_();
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testGeneric();
+ self::testBounded();
+}
+static method testGeneric() → dynamic {
+ <T extends core::Object? = dynamic>() → self::Class1<T%> f1a = #C1;
+ self::Class1<dynamic> c1a = f1a<dynamic>(){() → self::Class1<dynamic>};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+ self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::Class1<core::int> c1b = f1a<core::int>(){() → self::Class1<core::int>};
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::expect(false, c1b is{ForNonNullableByDefault} self::Class1<core::String>);
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+ f1a<int, String>(); // error
+ ^" in f1a{<inapplicable>}.<core::int, core::String>();
+ };
+ () → self::Class1<core::int> f1b = f1a<core::int>;
+ self::Class1<core::int> c1c = f1b(){() → self::Class1<core::int>};
+ self::expect(true, c1c is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::expect(false, c1c is{ForNonNullableByDefault} self::Class1<core::String>);
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+ f1b<int>(); // error
+ ^" in f1b{<inapplicable>}.<core::int>();
+ };
+ dynamic f1c = #C1;
+ dynamic c1d = f1c{dynamic}.call();
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+ self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::throws(() → dynamic => f1c{dynamic}.call<core::int, core::String>());
+}
+static method testBounded() → dynamic {
+ <T extends core::num>() → self::Class2<T> f2a = #C2;
+ self::Class2<core::num> c2a = f2a<core::num>(){() → self::Class2<core::num>};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2<core::num>);
+ self::expect(false, c2a is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::Class2<core::int> c2b = f2a<core::int>(){() → self::Class2<core::int>};
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::expect(false, c2b is{ForNonNullableByDefault} self::Class2<core::double>);
+ () → Null {
+ f2a<core::String>(){() → self::Class2<core::String>};
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+ f2a<int, String>(); // error
+ ^" in f2a{<inapplicable>}.<core::int, core::String>();
+ };
+ dynamic f2b = #C2;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(true, c2c is{ForNonNullableByDefault} self::Class2<core::num>);
+ self::expect(false, c2c is{ForNonNullableByDefault} self::Class2<core::int>);
+ dynamic c2d = f2b{dynamic}.call<core::int>();
+ self::expect(true, c2d is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::expect(false, c2d is{ForNonNullableByDefault} self::Class2<core::double>);
+ self::throws(() → dynamic => f2b{dynamic}.call<core::String>());
+ self::throws(() → dynamic => f2b{dynamic}.call<core::int, core::String>());
+ <T extends S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<T%, S%> f3a = #C3;
+ self::Class3<dynamic, dynamic> c3a = f3a<dynamic, dynamic>(){() → self::Class3<dynamic, dynamic>};
+ self::expect(true, c3a is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+ self::expect(false, c3a is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::Class3<core::int, core::num> c3b = f3a<core::int, core::num>(){() → self::Class3<core::int, core::num>};
+ self::expect(true, c3b is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::expect(false, c3b is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+ () → Null {
+ f3a<core::num, core::int>(){() → self::Class3<core::num, core::int>};
+ };
+ dynamic f3b = #C3;
+ dynamic c3c = f3b{dynamic}.call();
+ self::expect(true, c3c is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+ self::expect(false, c3c is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ dynamic c3d = f3b{dynamic}.call<core::int, core::num>();
+ self::expect(true, c3d is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::expect(false, c3d is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+ self::throws(() → dynamic => f3b{dynamic}.call<core::num, core::int>());
+ <T extends self::Class4<T> = self::Class4<dynamic>>() → self::Class4<T> f4a = #C4;
+ () → Null {
+ self::Class4<self::Class4<core::Object?>> c4a = f4a<self::Class4<core::Object?>>(){() → self::Class4<self::Class4<core::Object?>>};
+ };
+ dynamic f4b = #C4;
+ self::throws(() → dynamic => f4b{dynamic}.call());
+ dynamic c4b = f4b{dynamic}.call<self::Class4int>();
+ self::expect(true, c4b is{ForNonNullableByDefault} self::Class4<self::Class4int>);
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C5}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = static-tearoff self::Class1::_#new#tearOff
+ #C2 = static-tearoff self::Class2::_#new#tearOff
+ #C3 = static-tearoff self::Class3::_#new#tearOff
+ #C4 = static-tearoff self::Class4::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.transformed.expect
new file mode 100644
index 0000000..2ede93c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,205 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+// f1a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+// f1b<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:74:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+// f2a<String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+// f2a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:96:8: Error: Type argument 'num' doesn't conform to the bound 'S' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+// f3a<num, int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:110:18: Error: Inferred type argument 'Class4<Object?>' doesn't conform to the bound 'Class4<T>' of the type variable 'T' on 'call'.
+// - 'Class4' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// var c4a = f4a(); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1<self::Class1::T%>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+ static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+ let Never #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _() → self::Class2<self::Class2::T>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+ return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+ static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+ let Never #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+ static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+ let Never #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _() → self::Class4<self::Class4::T>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+ return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+ static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+ let Never #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+ constructor _() → self::Class4int
+ : super self::Class4::_()
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ let Never #redirecting_factory = self::Class4int::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class4int
+ return new self::Class4int::_();
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testGeneric();
+ self::testBounded();
+}
+static method testGeneric() → dynamic {
+ <T extends core::Object? = dynamic>() → self::Class1<T%> f1a = #C1;
+ self::Class1<dynamic> c1a = f1a<dynamic>(){() → self::Class1<dynamic>};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+ self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::Class1<core::int> c1b = f1a<core::int>(){() → self::Class1<core::int>};
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::expect(false, c1b is{ForNonNullableByDefault} self::Class1<core::String>);
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+ f1a<int, String>(); // error
+ ^" in f1a{<inapplicable>}.<core::int, core::String>();
+ };
+ () → self::Class1<core::int> f1b = f1a<core::int>;
+ self::Class1<core::int> c1c = f1b(){() → self::Class1<core::int>};
+ self::expect(true, c1c is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::expect(false, c1c is{ForNonNullableByDefault} self::Class1<core::String>);
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+ f1b<int>(); // error
+ ^" in f1b{<inapplicable>}.<core::int>();
+ };
+ dynamic f1c = #C1;
+ dynamic c1d = f1c{dynamic}.call();
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+ self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::throws(() → dynamic => f1c{dynamic}.call<core::int, core::String>());
+}
+static method testBounded() → dynamic {
+ <T extends core::num>() → self::Class2<T> f2a = #C2;
+ self::Class2<core::num> c2a = f2a<core::num>(){() → self::Class2<core::num>};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2<core::num>);
+ self::expect(false, c2a is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::Class2<core::int> c2b = f2a<core::int>(){() → self::Class2<core::int>};
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::expect(false, c2b is{ForNonNullableByDefault} self::Class2<core::double>);
+ () → Null {
+ f2a<core::String>(){() → self::Class2<core::String>};
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+ f2a<int, String>(); // error
+ ^" in f2a{<inapplicable>}.<core::int, core::String>();
+ };
+ dynamic f2b = #C2;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(true, c2c is{ForNonNullableByDefault} self::Class2<core::num>);
+ self::expect(false, c2c is{ForNonNullableByDefault} self::Class2<core::int>);
+ dynamic c2d = f2b{dynamic}.call<core::int>();
+ self::expect(true, c2d is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::expect(false, c2d is{ForNonNullableByDefault} self::Class2<core::double>);
+ self::throws(() → dynamic => f2b{dynamic}.call<core::String>());
+ self::throws(() → dynamic => f2b{dynamic}.call<core::int, core::String>());
+ <T extends S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<T%, S%> f3a = #C3;
+ self::Class3<dynamic, dynamic> c3a = f3a<dynamic, dynamic>(){() → self::Class3<dynamic, dynamic>};
+ self::expect(true, c3a is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+ self::expect(false, c3a is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::Class3<core::int, core::num> c3b = f3a<core::int, core::num>(){() → self::Class3<core::int, core::num>};
+ self::expect(true, c3b is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::expect(false, c3b is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+ () → Null {
+ f3a<core::num, core::int>(){() → self::Class3<core::num, core::int>};
+ };
+ dynamic f3b = #C3;
+ dynamic c3c = f3b{dynamic}.call();
+ self::expect(true, c3c is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+ self::expect(false, c3c is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ dynamic c3d = f3b{dynamic}.call<core::int, core::num>();
+ self::expect(true, c3d is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::expect(false, c3d is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+ self::throws(() → dynamic => f3b{dynamic}.call<core::num, core::int>());
+ <T extends self::Class4<T> = self::Class4<dynamic>>() → self::Class4<T> f4a = #C4;
+ () → Null {
+ self::Class4<self::Class4<core::Object?>> c4a = f4a<self::Class4<core::Object?>>(){() → self::Class4<self::Class4<core::Object?>>};
+ };
+ dynamic f4b = #C4;
+ self::throws(() → dynamic => f4b{dynamic}.call());
+ dynamic c4b = f4b{dynamic}.call<self::Class4int>();
+ self::expect(true, c4b is{ForNonNullableByDefault} self::Class4<self::Class4int>);
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C5}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = static-tearoff self::Class1::_#new#tearOff
+ #C2 = static-tearoff self::Class2::_#new#tearOff
+ #C3 = static-tearoff self::Class3::_#new#tearOff
+ #C4 = static-tearoff self::Class4::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..ad86735
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline.expect
@@ -0,0 +1,33 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1<T> {
+ Class1._();
+ factory Class1() = Class1<T>._;
+}
+
+testGeneric() {}
+
+class Class2<T extends num> {
+ Class2._();
+ factory Class2() = Class2<T>._;
+}
+
+class Class3<T extends S, S> {
+ Class3._();
+ factory Class3() = Class3<T, S>._;
+}
+
+class Class4<T extends Class4<T>> {
+ Class4._();
+ factory Class4() = Class4<T>._;
+}
+
+class Class4int extends Class4<Class4int> {
+ Class4int._() : super._();
+ factory Class4int() = Class4int._;
+}
+
+testBounded() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..24223f7
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,31 @@
+class Class1<T> {
+ Class1._();
+ factory Class1() = Class1<T>._;
+}
+
+class Class2<T extends num> {
+ Class2._();
+ factory Class2() = Class2<T>._;
+}
+
+class Class3<T extends S, S> {
+ Class3._();
+ factory Class3() = Class3<T, S>._;
+}
+
+class Class4<T extends Class4<T>> {
+ Class4._();
+ factory Class4() = Class4<T>._;
+}
+
+class Class4int extends Class4<Class4int> {
+ Class4int._() : super._();
+ factory Class4int() = Class4int._;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+testBounded() {}
+testGeneric() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.expect
new file mode 100644
index 0000000..14303b7
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.expect
@@ -0,0 +1,205 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+// f1a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+// f1b<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:74:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+// f2a<String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+// f2a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:96:8: Error: Type argument 'num' doesn't conform to the bound 'S' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+// f3a<num, int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:110:18: Error: Inferred type argument 'Class4<Object?>' doesn't conform to the bound 'Class4<T>' of the type variable 'T' on 'call'.
+// - 'Class4' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// var c4a = f4a(); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1<self::Class1::T%>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+ static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+ let dynamic #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _() → self::Class2<self::Class2::T>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+ return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+ static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+ let dynamic #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+ static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+ let dynamic #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _() → self::Class4<self::Class4::T>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+ return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+ static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+ let dynamic #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+ constructor _() → self::Class4int
+ : super self::Class4::_()
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ let dynamic #redirecting_factory = self::Class4int::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class4int
+ return new self::Class4int::_();
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testGeneric();
+ self::testBounded();
+}
+static method testGeneric() → dynamic {
+ <T extends core::Object? = dynamic>() → self::Class1<T%> f1a = #C1;
+ self::Class1<dynamic> c1a = f1a<dynamic>(){() → self::Class1<dynamic>};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+ self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::Class1<core::int> c1b = f1a<core::int>(){() → self::Class1<core::int>};
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::expect(false, c1b is{ForNonNullableByDefault} self::Class1<core::String>);
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+ f1a<int, String>(); // error
+ ^" in f1a{<inapplicable>}.<core::int, core::String>();
+ };
+ () → self::Class1<core::int> f1b = f1a<core::int>;
+ self::Class1<core::int> c1c = f1b(){() → self::Class1<core::int>};
+ self::expect(true, c1c is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::expect(false, c1c is{ForNonNullableByDefault} self::Class1<core::String>);
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+ f1b<int>(); // error
+ ^" in f1b{<inapplicable>}.<core::int>();
+ };
+ dynamic f1c = #C1;
+ dynamic c1d = f1c{dynamic}.call();
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+ self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::throws(() → dynamic => f1c{dynamic}.call<core::int, core::String>());
+}
+static method testBounded() → dynamic {
+ <T extends core::num>() → self::Class2<T> f2a = #C2;
+ self::Class2<core::num> c2a = f2a<core::num>(){() → self::Class2<core::num>};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2<core::num>);
+ self::expect(false, c2a is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::Class2<core::int> c2b = f2a<core::int>(){() → self::Class2<core::int>};
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::expect(false, c2b is{ForNonNullableByDefault} self::Class2<core::double>);
+ () → Null {
+ f2a<core::String>(){() → self::Class2<core::String>};
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+ f2a<int, String>(); // error
+ ^" in f2a{<inapplicable>}.<core::int, core::String>();
+ };
+ dynamic f2b = #C2;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(true, c2c is{ForNonNullableByDefault} self::Class2<core::num>);
+ self::expect(false, c2c is{ForNonNullableByDefault} self::Class2<core::int>);
+ dynamic c2d = f2b{dynamic}.call<core::int>();
+ self::expect(true, c2d is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::expect(false, c2d is{ForNonNullableByDefault} self::Class2<core::double>);
+ self::throws(() → dynamic => f2b{dynamic}.call<core::String>());
+ self::throws(() → dynamic => f2b{dynamic}.call<core::int, core::String>());
+ <T extends S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<T%, S%> f3a = #C3;
+ self::Class3<dynamic, dynamic> c3a = f3a<dynamic, dynamic>(){() → self::Class3<dynamic, dynamic>};
+ self::expect(true, c3a is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+ self::expect(false, c3a is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::Class3<core::int, core::num> c3b = f3a<core::int, core::num>(){() → self::Class3<core::int, core::num>};
+ self::expect(true, c3b is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::expect(false, c3b is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+ () → Null {
+ f3a<core::num, core::int>(){() → self::Class3<core::num, core::int>};
+ };
+ dynamic f3b = #C3;
+ dynamic c3c = f3b{dynamic}.call();
+ self::expect(true, c3c is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+ self::expect(false, c3c is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ dynamic c3d = f3b{dynamic}.call<core::int, core::num>();
+ self::expect(true, c3d is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::expect(false, c3d is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+ self::throws(() → dynamic => f3b{dynamic}.call<core::num, core::int>());
+ <T extends self::Class4<T> = self::Class4<dynamic>>() → self::Class4<T> f4a = #C4;
+ () → Null {
+ self::Class4<self::Class4<core::Object?>> c4a = f4a<self::Class4<core::Object?>>(){() → self::Class4<self::Class4<core::Object?>>};
+ };
+ dynamic f4b = #C4;
+ self::throws(() → dynamic => f4b{dynamic}.call());
+ dynamic c4b = f4b{dynamic}.call<self::Class4int>();
+ self::expect(true, c4b is{ForNonNullableByDefault} self::Class4<self::Class4int>);
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C5}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = static-tearoff self::Class1::_#new#tearOff
+ #C2 = static-tearoff self::Class2::_#new#tearOff
+ #C3 = static-tearoff self::Class3::_#new#tearOff
+ #C4 = static-tearoff self::Class4::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..26553e6
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.outline.expect
@@ -0,0 +1,70 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1<self::Class1::T%>
+ ;
+ static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+ static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+ let dynamic #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _() → self::Class2<self::Class2::T>
+ ;
+ static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+ return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+ static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+ let dynamic #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+ ;
+ static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+ static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+ let dynamic #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _() → self::Class4<self::Class4::T>
+ ;
+ static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+ return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+ static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+ let dynamic #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+ constructor _() → self::Class4int
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ let dynamic #redirecting_factory = self::Class4int::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class4int
+ return new self::Class4int::_();
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+ ;
+static method testGeneric() → dynamic
+ ;
+static method testBounded() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..2ede93c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,205 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+// f1a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+// f1b<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:74:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+// f2a<String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+// f2a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:96:8: Error: Type argument 'num' doesn't conform to the bound 'S' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+// f3a<num, int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:110:18: Error: Inferred type argument 'Class4<Object?>' doesn't conform to the bound 'Class4<T>' of the type variable 'T' on 'call'.
+// - 'Class4' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// var c4a = f4a(); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1<self::Class1::T%>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+ static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+ let Never #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _() → self::Class2<self::Class2::T>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+ return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+ static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+ let Never #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+ static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+ let Never #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+ return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _() → self::Class4<self::Class4::T>
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+ return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+ static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+ let Never #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+ constructor _() → self::Class4int
+ : super self::Class4::_()
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ let Never #redirecting_factory = self::Class4int::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class4int
+ return new self::Class4int::_();
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testGeneric();
+ self::testBounded();
+}
+static method testGeneric() → dynamic {
+ <T extends core::Object? = dynamic>() → self::Class1<T%> f1a = #C1;
+ self::Class1<dynamic> c1a = f1a<dynamic>(){() → self::Class1<dynamic>};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+ self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::Class1<core::int> c1b = f1a<core::int>(){() → self::Class1<core::int>};
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::expect(false, c1b is{ForNonNullableByDefault} self::Class1<core::String>);
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+ f1a<int, String>(); // error
+ ^" in f1a{<inapplicable>}.<core::int, core::String>();
+ };
+ () → self::Class1<core::int> f1b = f1a<core::int>;
+ self::Class1<core::int> c1c = f1b(){() → self::Class1<core::int>};
+ self::expect(true, c1c is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::expect(false, c1c is{ForNonNullableByDefault} self::Class1<core::String>);
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+ f1b<int>(); // error
+ ^" in f1b{<inapplicable>}.<core::int>();
+ };
+ dynamic f1c = #C1;
+ dynamic c1d = f1c{dynamic}.call();
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+ self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+ self::throws(() → dynamic => f1c{dynamic}.call<core::int, core::String>());
+}
+static method testBounded() → dynamic {
+ <T extends core::num>() → self::Class2<T> f2a = #C2;
+ self::Class2<core::num> c2a = f2a<core::num>(){() → self::Class2<core::num>};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2<core::num>);
+ self::expect(false, c2a is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::Class2<core::int> c2b = f2a<core::int>(){() → self::Class2<core::int>};
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::expect(false, c2b is{ForNonNullableByDefault} self::Class2<core::double>);
+ () → Null {
+ f2a<core::String>(){() → self::Class2<core::String>};
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+ f2a<int, String>(); // error
+ ^" in f2a{<inapplicable>}.<core::int, core::String>();
+ };
+ dynamic f2b = #C2;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(true, c2c is{ForNonNullableByDefault} self::Class2<core::num>);
+ self::expect(false, c2c is{ForNonNullableByDefault} self::Class2<core::int>);
+ dynamic c2d = f2b{dynamic}.call<core::int>();
+ self::expect(true, c2d is{ForNonNullableByDefault} self::Class2<core::int>);
+ self::expect(false, c2d is{ForNonNullableByDefault} self::Class2<core::double>);
+ self::throws(() → dynamic => f2b{dynamic}.call<core::String>());
+ self::throws(() → dynamic => f2b{dynamic}.call<core::int, core::String>());
+ <T extends S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<T%, S%> f3a = #C3;
+ self::Class3<dynamic, dynamic> c3a = f3a<dynamic, dynamic>(){() → self::Class3<dynamic, dynamic>};
+ self::expect(true, c3a is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+ self::expect(false, c3a is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::Class3<core::int, core::num> c3b = f3a<core::int, core::num>(){() → self::Class3<core::int, core::num>};
+ self::expect(true, c3b is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::expect(false, c3b is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+ () → Null {
+ f3a<core::num, core::int>(){() → self::Class3<core::num, core::int>};
+ };
+ dynamic f3b = #C3;
+ dynamic c3c = f3b{dynamic}.call();
+ self::expect(true, c3c is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+ self::expect(false, c3c is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ dynamic c3d = f3b{dynamic}.call<core::int, core::num>();
+ self::expect(true, c3d is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+ self::expect(false, c3d is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+ self::throws(() → dynamic => f3b{dynamic}.call<core::num, core::int>());
+ <T extends self::Class4<T> = self::Class4<dynamic>>() → self::Class4<T> f4a = #C4;
+ () → Null {
+ self::Class4<self::Class4<core::Object?>> c4a = f4a<self::Class4<core::Object?>>(){() → self::Class4<self::Class4<core::Object?>>};
+ };
+ dynamic f4b = #C4;
+ self::throws(() → dynamic => f4b{dynamic}.call());
+ dynamic c4b = f4b{dynamic}.call<self::Class4int>();
+ self::expect(true, c4b is{ForNonNullableByDefault} self::Class4<self::Class4int>);
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C5}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = static-tearoff self::Class1::_#new#tearOff
+ #C2 = static-tearoff self::Class2::_#new#tearOff
+ #C3 = static-tearoff self::Class3::_#new#tearOff
+ #C4 = static-tearoff self::Class4::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart
new file mode 100644
index 0000000..75d63fa
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart
@@ -0,0 +1,163 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+ print('inSoundMode: $inSoundMode');
+ testNoArgs();
+ testArgs();
+}
+
+class Class1 {
+ Class1._();
+ factory Class1() = Class1._;
+}
+
+class Class2 {
+ Class2._();
+ factory Class2.named() = Class2._;
+}
+
+testNoArgs() {
+ var f1a = Class1.new;
+ var c1a = f1a();
+ expect(true, c1a is Class1);
+
+ dynamic f1b = Class1.new;
+ var c1b = f1b();
+ expect(true, c1b is Class1);
+
+ expect(true, identical(f1a, f1b));
+
+ var f2a = Class2.named;
+ var c2a = f2a();
+ expect(true, c2a is Class2);
+
+ dynamic f2b = Class2.named;
+ var c2b = f2b();
+ expect(true, c2b is Class2);
+
+ expect(true, identical(f2a, f2b));
+}
+
+class Class3 {
+ final int field;
+
+ Class3._(this.field);
+ factory Class3(int field) = Class3._;
+}
+
+class Class4 {
+ final int? field;
+
+ Class4._([this.field]);
+ factory Class4([int? field]) = Class4._;
+}
+
+class Class5 {
+ final int field1;
+ final int? field2;
+
+ Class5._(this.field1, [this.field2]);
+ factory Class5(int field1, [int? field2]) = Class5._;
+}
+
+class Class6 {
+ final int field1;
+ final int? field2;
+ final int field3;
+
+ Class6._(this.field1, {this.field2, required this.field3});
+ factory Class6(int field1, {int? field2, required int field3}) =
+ Class6._;
+}
+
+testArgs() {
+ var f3a = Class3.new;
+ var c3a = f3a(42);
+ expect(42, c3a.field);
+ () {
+ f3a(); // error
+ f3a(42, 87); // error
+ };
+
+ dynamic f3b = Class3.new;
+ var c3b = f3b(87);
+ expect(87, c3b.field);
+ throws(() => f3b());
+ throws(() => f3b(42, 87));
+
+ var f4a = Class4.new;
+ var c4a = f4a();
+ expect(null, c4a.field);
+ var c4b = f4a(42);
+ expect(42, c4b.field);
+ () {
+ f4a(42, 87); // error
+ };
+ dynamic f4b = Class4.new;
+ throws(() => f4b(42, 87));
+
+
+ var f5a = Class5.new;
+ var c5a = f5a(42);
+ expect(42, c5a.field1);
+ expect(null, c5a.field2);
+ var c5b = f5a(87, 42);
+ expect(87, c5b.field1);
+ expect(42, c5b.field2);
+ () {
+ f5a(); // error
+ f5a(42, 87, 123); // error
+ };
+ dynamic f5b = Class5.new;
+ throws(() => f5b());
+ throws(() => f5b(42, 87, 123));
+
+ var f6a = Class6.new;
+ var c6a = f6a(42, field3: 87);
+ expect(42, c6a.field1);
+ expect(null, c6a.field2);
+ expect(87, c6a.field3);
+ () {
+ f6a(); // error
+ f6a(42); // error
+ f6a(42, 87); // error
+ f6a(field1: 87, field2: 87); // error
+ };
+
+ var c6b = f6a(42, field2: 123, field3: 87);
+ expect(42, c6b.field1);
+ expect(123, c6b.field2);
+ expect(87, c6b.field3);
+
+ var c6c = f6a(87, field3: 42, field2: 123);
+ expect(87, c6c.field1);
+ expect(123, c6c.field2);
+ expect(42, c6c.field3);
+
+ dynamic f6b = Class6.new;
+ throws(() => f6b());
+ throws(() => f6b(42), inSoundModeOnly: true);
+ throws(() => f6b(42, 87), inSoundModeOnly: true);
+ throws(() => f6b(field1: 87, field2: 87));
+}
+
+expect(expected, actual) {
+ if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+ try {
+ f();
+ } catch (e) {
+ print('Thrown: $e');
+ return;
+ }
+ if (!inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw 'Expected exception';
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect
new file mode 100644
index 0000000..f5b0f3e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect
@@ -0,0 +1,260 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// f3a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f3a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f4a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// f5a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+// f5a(42, 87, 123); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// f6a(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f6a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(field1: 87, field2: 87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class1
+ return new self::Class1::_();
+}
+class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+ constructor _() → self::Class2
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#named#tearOff() → self::Class2
+ return new self::Class2::_();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _(core::int field) → self::Class3
+ : self::Class3::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+ static factory •(core::int field) → self::Class3
+ let dynamic #redirecting_factory = self::Class3::_ in invalid-expression;
+ static method _#new#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _([core::int? field = #C1]) → self::Class4
+ : self::Class4::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff([core::int? field = #C1]) → self::Class4
+ return new self::Class4::_(field);
+ static factory •([core::int? field = #C1]) → self::Class4
+ let dynamic #redirecting_factory = self::Class4::_ in invalid-expression;
+ static method _#new#tearOff([core::int? field = #C1]) → self::Class4
+ return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+ constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ return new self::Class5::_(field1, field2);
+ static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ let dynamic #redirecting_factory = self::Class5::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+ constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+ static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testNoArgs();
+ self::testArgs();
+}
+static method testNoArgs() → dynamic {
+ () → self::Class1 f1a = #C2;
+ self::Class1 c1a = f1a(){() → self::Class1};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+ dynamic f1b = #C2;
+ dynamic c1b = f1b{dynamic}.call();
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+ self::expect(true, core::identical(f1a, f1b));
+ () → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){() → self::Class2};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+ dynamic f2b = #C3;
+ dynamic c2b = f2b{dynamic}.call();
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+ self::expect(true, core::identical(f2a, f2b));
+}
+static method testArgs() → dynamic {
+ (core::int) → self::Class3 f3a = #C4;
+ self::Class3 c3a = f3a(42){(core::int) → self::Class3};
+ self::expect(42, c3a.{self::Class3::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ f3a(); // error
+ ^" in f3a{<inapplicable>}.();
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f3a(42, 87); // error
+ ^" in f3a{<inapplicable>}.(42, 87);
+ };
+ dynamic f3b = #C4;
+ dynamic c3b = f3b{dynamic}.call(87);
+ self::expect(87, c3b{dynamic}.field);
+ self::throws(() → dynamic => f3b{dynamic}.call());
+ self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+ ([core::int?]) → self::Class4 f4a = #C5;
+ self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+ self::expect(null, c4a.{self::Class4::field}{core::int?});
+ self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+ self::expect(42, c4b.{self::Class4::field}{core::int?});
+ () → Null {
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f4a(42, 87); // error
+ ^" in f4a{<inapplicable>}.(42, 87);
+ };
+ dynamic f4b = #C5;
+ self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+ (core::int, [core::int?]) → self::Class5 f5a = #C6;
+ self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+ self::expect(42, c5a.{self::Class5::field1}{core::int});
+ self::expect(null, c5a.{self::Class5::field2}{core::int?});
+ self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+ self::expect(87, c5b.{self::Class5::field1}{core::int});
+ self::expect(42, c5b.{self::Class5::field2}{core::int?});
+ () → Null {
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ f5a(); // error
+ ^" in f5a{<inapplicable>}.();
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+ f5a(42, 87, 123); // error
+ ^" in f5a{<inapplicable>}.(42, 87, 123);
+ };
+ dynamic f5b = #C6;
+ self::throws(() → dynamic => f5b{dynamic}.call());
+ self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+ (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+ self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(42, c6a.{self::Class6::field1}{core::int});
+ self::expect(null, c6a.{self::Class6::field2}{core::int?});
+ self::expect(87, c6a.{self::Class6::field3}{core::int});
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ f6a(); // error
+ ^" in f6a{<inapplicable>}.();
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ f6a(42); // error
+ ^" in f6a{<inapplicable>}.(42);
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f6a(42, 87); // error
+ ^" in f6a{<inapplicable>}.(42, 87);
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ f6a(field1: 87, field2: 87); // error
+ ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+ };
+ self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(42, c6b.{self::Class6::field1}{core::int});
+ self::expect(123, c6b.{self::Class6::field2}{core::int?});
+ self::expect(87, c6b.{self::Class6::field3}{core::int});
+ self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(87, c6c.{self::Class6::field1}{core::int});
+ self::expect(123, c6c.{self::Class6::field2}{core::int?});
+ self::expect(42, c6c.{self::Class6::field3}{core::int});
+ dynamic f6b = #C7;
+ self::throws(() → dynamic => f6b{dynamic}.call());
+ self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+ self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+ self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = null
+ #C2 = static-tearoff self::Class1::_#new#tearOff
+ #C3 = static-tearoff self::Class2::_#named#tearOff
+ #C4 = static-tearoff self::Class3::_#new#tearOff
+ #C5 = static-tearoff self::Class4::_#new#tearOff
+ #C6 = static-tearoff self::Class5::_#new#tearOff
+ #C7 = static-tearoff self::Class6::_#new#tearOff
+ #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect
new file mode 100644
index 0000000..59fb725
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,260 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// f3a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f3a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f4a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// f5a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+// f5a(42, 87, 123); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// f6a(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f6a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(field1: 87, field2: 87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class1
+ return new self::Class1::_();
+}
+class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+ constructor _() → self::Class2
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#named#tearOff() → self::Class2
+ return new self::Class2::_();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _(core::int field) → self::Class3
+ : self::Class3::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+ static factory •(core::int field) → self::Class3
+ let Never #redirecting_factory = self::Class3::_ in invalid-expression;
+ static method _#new#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _([core::int? field = #C1]) → self::Class4
+ : self::Class4::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff([core::int? field = #C1]) → self::Class4
+ return new self::Class4::_(field);
+ static factory •([core::int? field = #C1]) → self::Class4
+ let Never #redirecting_factory = self::Class4::_ in invalid-expression;
+ static method _#new#tearOff([core::int? field = #C1]) → self::Class4
+ return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+ constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ return new self::Class5::_(field1, field2);
+ static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ let Never #redirecting_factory = self::Class5::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+ constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+ static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ let Never #redirecting_factory = self::Class6::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testNoArgs();
+ self::testArgs();
+}
+static method testNoArgs() → dynamic {
+ () → self::Class1 f1a = #C2;
+ self::Class1 c1a = f1a(){() → self::Class1};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+ dynamic f1b = #C2;
+ dynamic c1b = f1b{dynamic}.call();
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+ self::expect(true, core::identical(f1a, f1b));
+ () → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){() → self::Class2};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+ dynamic f2b = #C3;
+ dynamic c2b = f2b{dynamic}.call();
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+ self::expect(true, core::identical(f2a, f2b));
+}
+static method testArgs() → dynamic {
+ (core::int) → self::Class3 f3a = #C4;
+ self::Class3 c3a = f3a(42){(core::int) → self::Class3};
+ self::expect(42, c3a.{self::Class3::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ f3a(); // error
+ ^" in f3a{<inapplicable>}.();
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f3a(42, 87); // error
+ ^" in f3a{<inapplicable>}.(42, 87);
+ };
+ dynamic f3b = #C4;
+ dynamic c3b = f3b{dynamic}.call(87);
+ self::expect(87, c3b{dynamic}.field);
+ self::throws(() → dynamic => f3b{dynamic}.call());
+ self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+ ([core::int?]) → self::Class4 f4a = #C5;
+ self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+ self::expect(null, c4a.{self::Class4::field}{core::int?});
+ self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+ self::expect(42, c4b.{self::Class4::field}{core::int?});
+ () → Null {
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f4a(42, 87); // error
+ ^" in f4a{<inapplicable>}.(42, 87);
+ };
+ dynamic f4b = #C5;
+ self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+ (core::int, [core::int?]) → self::Class5 f5a = #C6;
+ self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+ self::expect(42, c5a.{self::Class5::field1}{core::int});
+ self::expect(null, c5a.{self::Class5::field2}{core::int?});
+ self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+ self::expect(87, c5b.{self::Class5::field1}{core::int});
+ self::expect(42, c5b.{self::Class5::field2}{core::int?});
+ () → Null {
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ f5a(); // error
+ ^" in f5a{<inapplicable>}.();
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+ f5a(42, 87, 123); // error
+ ^" in f5a{<inapplicable>}.(42, 87, 123);
+ };
+ dynamic f5b = #C6;
+ self::throws(() → dynamic => f5b{dynamic}.call());
+ self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+ (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+ self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(42, c6a.{self::Class6::field1}{core::int});
+ self::expect(null, c6a.{self::Class6::field2}{core::int?});
+ self::expect(87, c6a.{self::Class6::field3}{core::int});
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ f6a(); // error
+ ^" in f6a{<inapplicable>}.();
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ f6a(42); // error
+ ^" in f6a{<inapplicable>}.(42);
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f6a(42, 87); // error
+ ^" in f6a{<inapplicable>}.(42, 87);
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ f6a(field1: 87, field2: 87); // error
+ ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+ };
+ self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(42, c6b.{self::Class6::field1}{core::int});
+ self::expect(123, c6b.{self::Class6::field2}{core::int?});
+ self::expect(87, c6b.{self::Class6::field3}{core::int});
+ self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(87, c6c.{self::Class6::field1}{core::int});
+ self::expect(123, c6c.{self::Class6::field2}{core::int?});
+ self::expect(42, c6c.{self::Class6::field3}{core::int});
+ dynamic f6b = #C7;
+ self::throws(() → dynamic => f6b{dynamic}.call());
+ self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+ self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+ self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = null
+ #C2 = static-tearoff self::Class1::_#new#tearOff
+ #C3 = static-tearoff self::Class2::_#named#tearOff
+ #C4 = static-tearoff self::Class3::_#new#tearOff
+ #C5 = static-tearoff self::Class4::_#new#tearOff
+ #C6 = static-tearoff self::Class5::_#new#tearOff
+ #C7 = static-tearoff self::Class6::_#new#tearOff
+ #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..999b5d2
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect
@@ -0,0 +1,45 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+ Class1._();
+ factory Class1() = Class1._;
+}
+
+class Class2 {
+ Class2._();
+ factory Class2.named() = Class2._;
+}
+
+testNoArgs() {}
+
+class Class3 {
+ final int field;
+ Class3._(this.field);
+ factory Class3(int field) = Class3._;
+}
+
+class Class4 {
+ final int? field;
+ Class4._([this.field]);
+ factory Class4([int? field]) = Class4._;
+}
+
+class Class5 {
+ final int field1;
+ final int? field2;
+ Class5._(this.field1, [this.field2]);
+ factory Class5(int field1, [int? field2]) = Class5._;
+}
+
+class Class6 {
+ final int field1;
+ final int? field2;
+ final int field3;
+ Class6._(this.field1, {this.field2, required this.field3});
+ factory Class6(int field1, {int? field2, required int field3}) = Class6._;
+}
+
+testArgs() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..edb4f68
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,43 @@
+class Class1 {
+ Class1._();
+ factory Class1() = Class1._;
+}
+
+class Class2 {
+ Class2._();
+ factory Class2.named() = Class2._;
+}
+
+class Class3 {
+ Class3._(this.field);
+ factory Class3(int field) = Class3._;
+ final int field;
+}
+
+class Class4 {
+ Class4._([this.field]);
+ factory Class4([int? field]) = Class4._;
+ final int? field;
+}
+
+class Class5 {
+ Class5._(this.field1, [this.field2]);
+ factory Class5(int field1, [int? field2]) = Class5._;
+ final int? field2;
+ final int field1;
+}
+
+class Class6 {
+ Class6._(this.field1, {this.field2, required this.field3});
+ factory Class6(int field1, {int? field2, required int field3}) = Class6._;
+ final int? field2;
+ final int field1;
+ final int field3;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+testArgs() {}
+testNoArgs() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect
new file mode 100644
index 0000000..f5b0f3e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect
@@ -0,0 +1,260 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// f3a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f3a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f4a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// f5a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+// f5a(42, 87, 123); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// f6a(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f6a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(field1: 87, field2: 87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class1
+ return new self::Class1::_();
+}
+class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+ constructor _() → self::Class2
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#named#tearOff() → self::Class2
+ return new self::Class2::_();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _(core::int field) → self::Class3
+ : self::Class3::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+ static factory •(core::int field) → self::Class3
+ let dynamic #redirecting_factory = self::Class3::_ in invalid-expression;
+ static method _#new#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _([core::int? field = #C1]) → self::Class4
+ : self::Class4::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff([core::int? field = #C1]) → self::Class4
+ return new self::Class4::_(field);
+ static factory •([core::int? field = #C1]) → self::Class4
+ let dynamic #redirecting_factory = self::Class4::_ in invalid-expression;
+ static method _#new#tearOff([core::int? field = #C1]) → self::Class4
+ return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+ constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ return new self::Class5::_(field1, field2);
+ static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ let dynamic #redirecting_factory = self::Class5::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+ constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+ static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testNoArgs();
+ self::testArgs();
+}
+static method testNoArgs() → dynamic {
+ () → self::Class1 f1a = #C2;
+ self::Class1 c1a = f1a(){() → self::Class1};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+ dynamic f1b = #C2;
+ dynamic c1b = f1b{dynamic}.call();
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+ self::expect(true, core::identical(f1a, f1b));
+ () → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){() → self::Class2};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+ dynamic f2b = #C3;
+ dynamic c2b = f2b{dynamic}.call();
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+ self::expect(true, core::identical(f2a, f2b));
+}
+static method testArgs() → dynamic {
+ (core::int) → self::Class3 f3a = #C4;
+ self::Class3 c3a = f3a(42){(core::int) → self::Class3};
+ self::expect(42, c3a.{self::Class3::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ f3a(); // error
+ ^" in f3a{<inapplicable>}.();
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f3a(42, 87); // error
+ ^" in f3a{<inapplicable>}.(42, 87);
+ };
+ dynamic f3b = #C4;
+ dynamic c3b = f3b{dynamic}.call(87);
+ self::expect(87, c3b{dynamic}.field);
+ self::throws(() → dynamic => f3b{dynamic}.call());
+ self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+ ([core::int?]) → self::Class4 f4a = #C5;
+ self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+ self::expect(null, c4a.{self::Class4::field}{core::int?});
+ self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+ self::expect(42, c4b.{self::Class4::field}{core::int?});
+ () → Null {
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f4a(42, 87); // error
+ ^" in f4a{<inapplicable>}.(42, 87);
+ };
+ dynamic f4b = #C5;
+ self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+ (core::int, [core::int?]) → self::Class5 f5a = #C6;
+ self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+ self::expect(42, c5a.{self::Class5::field1}{core::int});
+ self::expect(null, c5a.{self::Class5::field2}{core::int?});
+ self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+ self::expect(87, c5b.{self::Class5::field1}{core::int});
+ self::expect(42, c5b.{self::Class5::field2}{core::int?});
+ () → Null {
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ f5a(); // error
+ ^" in f5a{<inapplicable>}.();
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+ f5a(42, 87, 123); // error
+ ^" in f5a{<inapplicable>}.(42, 87, 123);
+ };
+ dynamic f5b = #C6;
+ self::throws(() → dynamic => f5b{dynamic}.call());
+ self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+ (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+ self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(42, c6a.{self::Class6::field1}{core::int});
+ self::expect(null, c6a.{self::Class6::field2}{core::int?});
+ self::expect(87, c6a.{self::Class6::field3}{core::int});
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ f6a(); // error
+ ^" in f6a{<inapplicable>}.();
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ f6a(42); // error
+ ^" in f6a{<inapplicable>}.(42);
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f6a(42, 87); // error
+ ^" in f6a{<inapplicable>}.(42, 87);
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ f6a(field1: 87, field2: 87); // error
+ ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+ };
+ self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(42, c6b.{self::Class6::field1}{core::int});
+ self::expect(123, c6b.{self::Class6::field2}{core::int?});
+ self::expect(87, c6b.{self::Class6::field3}{core::int});
+ self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(87, c6c.{self::Class6::field1}{core::int});
+ self::expect(123, c6c.{self::Class6::field2}{core::int?});
+ self::expect(42, c6c.{self::Class6::field3}{core::int});
+ dynamic f6b = #C7;
+ self::throws(() → dynamic => f6b{dynamic}.call());
+ self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+ self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+ self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = null
+ #C2 = static-tearoff self::Class1::_#new#tearOff
+ #C3 = static-tearoff self::Class2::_#named#tearOff
+ #C4 = static-tearoff self::Class3::_#new#tearOff
+ #C5 = static-tearoff self::Class4::_#new#tearOff
+ #C6 = static-tearoff self::Class5::_#new#tearOff
+ #C7 = static-tearoff self::Class6::_#new#tearOff
+ #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..f5e4544
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect
@@ -0,0 +1,88 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class1
+ return new self::Class1::_();
+}
+class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+ constructor _() → self::Class2
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#named#tearOff() → self::Class2
+ return new self::Class2::_();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _(core::int field) → self::Class3
+ ;
+ static method _#_#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+ static factory •(core::int field) → self::Class3
+ let dynamic #redirecting_factory = self::Class3::_ in invalid-expression;
+ static method _#new#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _([core::int? field]) → self::Class4
+ ;
+ static method _#_#tearOff([core::int? field]) → self::Class4
+ return new self::Class4::_(field);
+ static factory •([core::int? field]) → self::Class4
+ let dynamic #redirecting_factory = self::Class4::_ in invalid-expression;
+ static method _#new#tearOff([core::int? field]) → self::Class4
+ return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+ constructor _(core::int field1, [core::int? field2]) → self::Class5
+ ;
+ static method _#_#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ return new self::Class5::_(field1, field2);
+ static factory •(core::int field1, [core::int? field2]) → self::Class5
+ let dynamic #redirecting_factory = self::Class5::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+ constructor _(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+ ;
+ static method _#_#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+ static factory •(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+ let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+ ;
+static method testNoArgs() → dynamic
+ ;
+static method testArgs() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..59fb725
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,260 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// f3a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f3a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f4a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// f5a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+// f5a(42, 87, 123); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// f6a(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f6a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(field1: 87, field2: 87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff() → self::Class1
+ return new self::Class1::_();
+}
+class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+ constructor _() → self::Class2
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#named#tearOff() → self::Class2
+ return new self::Class2::_();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+ constructor _(core::int field) → self::Class3
+ : self::Class3::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+ static factory •(core::int field) → self::Class3
+ let Never #redirecting_factory = self::Class3::_ in invalid-expression;
+ static method _#new#tearOff(core::int field) → self::Class3
+ return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+ constructor _([core::int? field = #C1]) → self::Class4
+ : self::Class4::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff([core::int? field = #C1]) → self::Class4
+ return new self::Class4::_(field);
+ static factory •([core::int? field = #C1]) → self::Class4
+ let Never #redirecting_factory = self::Class4::_ in invalid-expression;
+ static method _#new#tearOff([core::int? field = #C1]) → self::Class4
+ return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+ constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ return new self::Class5::_(field1, field2);
+ static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ let Never #redirecting_factory = self::Class5::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+ return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+ constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+ ;
+ static method _#_#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+ static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ let Never #redirecting_factory = self::Class6::_ in invalid-expression;
+ static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+ return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testNoArgs();
+ self::testArgs();
+}
+static method testNoArgs() → dynamic {
+ () → self::Class1 f1a = #C2;
+ self::Class1 c1a = f1a(){() → self::Class1};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+ dynamic f1b = #C2;
+ dynamic c1b = f1b{dynamic}.call();
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+ self::expect(true, core::identical(f1a, f1b));
+ () → self::Class2 f2a = #C3;
+ self::Class2 c2a = f2a(){() → self::Class2};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+ dynamic f2b = #C3;
+ dynamic c2b = f2b{dynamic}.call();
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+ self::expect(true, core::identical(f2a, f2b));
+}
+static method testArgs() → dynamic {
+ (core::int) → self::Class3 f3a = #C4;
+ self::Class3 c3a = f3a(42){(core::int) → self::Class3};
+ self::expect(42, c3a.{self::Class3::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ f3a(); // error
+ ^" in f3a{<inapplicable>}.();
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f3a(42, 87); // error
+ ^" in f3a{<inapplicable>}.(42, 87);
+ };
+ dynamic f3b = #C4;
+ dynamic c3b = f3b{dynamic}.call(87);
+ self::expect(87, c3b{dynamic}.field);
+ self::throws(() → dynamic => f3b{dynamic}.call());
+ self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+ ([core::int?]) → self::Class4 f4a = #C5;
+ self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+ self::expect(null, c4a.{self::Class4::field}{core::int?});
+ self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+ self::expect(42, c4b.{self::Class4::field}{core::int?});
+ () → Null {
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f4a(42, 87); // error
+ ^" in f4a{<inapplicable>}.(42, 87);
+ };
+ dynamic f4b = #C5;
+ self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+ (core::int, [core::int?]) → self::Class5 f5a = #C6;
+ self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+ self::expect(42, c5a.{self::Class5::field1}{core::int});
+ self::expect(null, c5a.{self::Class5::field2}{core::int?});
+ self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+ self::expect(87, c5b.{self::Class5::field1}{core::int});
+ self::expect(42, c5b.{self::Class5::field2}{core::int?});
+ () → Null {
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ f5a(); // error
+ ^" in f5a{<inapplicable>}.();
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+ f5a(42, 87, 123); // error
+ ^" in f5a{<inapplicable>}.(42, 87, 123);
+ };
+ dynamic f5b = #C6;
+ self::throws(() → dynamic => f5b{dynamic}.call());
+ self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+ (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+ self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(42, c6a.{self::Class6::field1}{core::int});
+ self::expect(null, c6a.{self::Class6::field2}{core::int?});
+ self::expect(87, c6a.{self::Class6::field3}{core::int});
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ f6a(); // error
+ ^" in f6a{<inapplicable>}.();
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ f6a(42); // error
+ ^" in f6a{<inapplicable>}.(42);
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f6a(42, 87); // error
+ ^" in f6a{<inapplicable>}.(42, 87);
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ f6a(field1: 87, field2: 87); // error
+ ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+ };
+ self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(42, c6b.{self::Class6::field1}{core::int});
+ self::expect(123, c6b.{self::Class6::field2}{core::int?});
+ self::expect(87, c6b.{self::Class6::field3}{core::int});
+ self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+ self::expect(87, c6c.{self::Class6::field1}{core::int});
+ self::expect(123, c6c.{self::Class6::field2}{core::int?});
+ self::expect(42, c6c.{self::Class6::field3}{core::int});
+ dynamic f6b = #C7;
+ self::throws(() → dynamic => f6b{dynamic}.call());
+ self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+ self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+ self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = null
+ #C2 = static-tearoff self::Class1::_#new#tearOff
+ #C3 = static-tearoff self::Class2::_#named#tearOff
+ #C4 = static-tearoff self::Class3::_#new#tearOff
+ #C5 = static-tearoff self::Class4::_#new#tearOff
+ #C6 = static-tearoff self::Class5::_#new#tearOff
+ #C7 = static-tearoff self::Class6::_#new#tearOff
+ #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart
new file mode 100644
index 0000000..ef380c5
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+ print('inSoundMode: $inSoundMode');
+ testDefaultValues();
+}
+
+class Class1 {
+ final int field;
+
+ Class1._([this.field = 42]);
+ factory Class1([int field]) = Class1._;
+}
+
+class Class2 {
+ final int field;
+
+ Class2._({this.field: 42});
+ factory Class2({int field}) = Class2._;
+}
+
+void testDefaultValues() {
+ var f1a = Class1.new;
+ var c1a = f1a();
+ expect(42, c1a.field);
+ var c1b = f1a(87);
+ expect(87, c1b.field);
+ () {
+ f1a(42, 87); // error
+ };
+
+ dynamic f1b = Class1.new;
+ var c1c = f1b();
+ expect(42, c1c.field);
+ var c1d = f1b(87);
+ expect(87, c1d.field);
+ throws(() => f1b(42, 87));
+
+ var f2a = Class2.new;
+ var c2a = f2a();
+ expect(42, c2a.field);
+ var c2b = f2a(field: 87);
+ expect(87, c2b.field);
+ () {
+ f2a(87); // error
+ };
+
+ dynamic f2b = Class2.new;
+ var c2c = f2b();
+ expect(42, c2c.field);
+ var c2d = f2b(field: 87);
+ expect(87, c2d.field);
+ throws(() => f2b(87));
+}
+
+expect(expected, actual) {
+ if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+ try {
+ f();
+ } catch (e) {
+ print('Thrown: $e');
+ return;
+ }
+ if (!inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw 'Expected exception';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.expect
new file mode 100644
index 0000000..873e7a9
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.expect
@@ -0,0 +1,109 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _([core::int field = #C1]) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field = #C2]) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _({core::int field = #C1}) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field: field);
+ static factory •({core::int field = #C2}) → self::Class2
+ let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+ ([core::int]) → self::Class1 f1a = #C3;
+ self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+ self::expect(42, c1a.{self::Class1::field}{core::int});
+ self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+ self::expect(87, c1b.{self::Class1::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1a(42, 87); // error
+ ^" in f1a{<inapplicable>}.(42, 87);
+ };
+ dynamic f1b = #C3;
+ dynamic c1c = f1b{dynamic}.call();
+ self::expect(42, c1c{dynamic}.field);
+ dynamic c1d = f1b{dynamic}.call(87);
+ self::expect(87, c1d{dynamic}.field);
+ self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C4;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C4;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C5}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 42
+ #C2 = null
+ #C3 = static-tearoff self::Class1::_#new#tearOff
+ #C4 = static-tearoff self::Class2::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.transformed.expect
new file mode 100644
index 0000000..fe92fac
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.transformed.expect
@@ -0,0 +1,109 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _([core::int field = #C1]) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field = #C2]) → self::Class1
+ let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _({core::int field = #C1}) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field: field);
+ static factory •({core::int field = #C2}) → self::Class2
+ let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+ ([core::int]) → self::Class1 f1a = #C3;
+ self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+ self::expect(42, c1a.{self::Class1::field}{core::int});
+ self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+ self::expect(87, c1b.{self::Class1::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1a(42, 87); // error
+ ^" in f1a{<inapplicable>}.(42, 87);
+ };
+ dynamic f1b = #C3;
+ dynamic c1c = f1b{dynamic}.call();
+ self::expect(42, c1c{dynamic}.field);
+ dynamic c1d = f1b{dynamic}.call(87);
+ self::expect(87, c1d{dynamic}.field);
+ self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C4;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C4;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C5}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 42
+ #C2 = null
+ #C3 = static-tearoff self::Class1::_#new#tearOff
+ #C4 = static-tearoff self::Class2::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline.expect
new file mode 100644
index 0000000..1194776
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline.expect
@@ -0,0 +1,18 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+ final int field;
+ Class1._([this.field = 42]);
+ factory Class1([int field]) = Class1._;
+}
+
+class Class2 {
+ final int field;
+ Class2._({this.field: 42});
+ factory Class2({int field}) = Class2._;
+}
+
+void testDefaultValues() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..c51e203
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline_modelled.expect
@@ -0,0 +1,17 @@
+class Class1 {
+ Class1._([this.field = 42]);
+ factory Class1([int field]) = Class1._;
+ final int field;
+}
+
+class Class2 {
+ Class2._({this.field: 42});
+ factory Class2({int field}) = Class2._;
+ final int field;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
+void testDefaultValues() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.expect
new file mode 100644
index 0000000..873e7a9
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.expect
@@ -0,0 +1,109 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _([core::int field = #C1]) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field = #C2]) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _({core::int field = #C1}) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field: field);
+ static factory •({core::int field = #C2}) → self::Class2
+ let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+ ([core::int]) → self::Class1 f1a = #C3;
+ self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+ self::expect(42, c1a.{self::Class1::field}{core::int});
+ self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+ self::expect(87, c1b.{self::Class1::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1a(42, 87); // error
+ ^" in f1a{<inapplicable>}.(42, 87);
+ };
+ dynamic f1b = #C3;
+ dynamic c1c = f1b{dynamic}.call();
+ self::expect(42, c1c{dynamic}.field);
+ dynamic c1d = f1b{dynamic}.call(87);
+ self::expect(87, c1d{dynamic}.field);
+ self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C4;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C4;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C5}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 42
+ #C2 = null
+ #C3 = static-tearoff self::Class1::_#new#tearOff
+ #C4 = static-tearoff self::Class2::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.outline.expect
new file mode 100644
index 0000000..e6fbbd5
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.outline.expect
@@ -0,0 +1,37 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _([core::int field]) → self::Class1
+ ;
+ static method _#_#tearOff([core::int field]) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field]) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff([core::int field]) → self::Class1
+ return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _({core::int field}) → self::Class2
+ ;
+ static method _#_#tearOff({core::int field}) → self::Class2
+ return new self::Class2::_(field: field);
+ static factory •({core::int field}) → self::Class2
+ let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#new#tearOff({core::int field}) → self::Class2
+ return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+ ;
+static method testDefaultValues() → void
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.transformed.expect
new file mode 100644
index 0000000..fe92fac
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.transformed.expect
@@ -0,0 +1,109 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1a(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f2a(87); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _([core::int field = #C1]) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+ static factory •([core::int field = #C2]) → self::Class1
+ let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+ static method _#new#tearOff([core::int field = #C1]) → self::Class1
+ return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+ constructor _({core::int field = #C1}) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#_#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field: field);
+ static factory •({core::int field = #C2}) → self::Class2
+ let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+ static method _#new#tearOff({core::int field = #C1}) → self::Class2
+ return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+ ([core::int]) → self::Class1 f1a = #C3;
+ self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+ self::expect(42, c1a.{self::Class1::field}{core::int});
+ self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+ self::expect(87, c1b.{self::Class1::field}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1a(42, 87); // error
+ ^" in f1a{<inapplicable>}.(42, 87);
+ };
+ dynamic f1b = #C3;
+ dynamic c1c = f1b{dynamic}.call();
+ self::expect(42, c1c{dynamic}.field);
+ dynamic c1d = f1b{dynamic}.call(87);
+ self::expect(87, c1d{dynamic}.field);
+ self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+ ({field: core::int}) → self::Class2 f2a = #C4;
+ self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+ self::expect(42, c2a.{self::Class2::field}{core::int});
+ self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+ self::expect(87, c2b.{self::Class2::field}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f2a(87); // error
+ ^" in f2a{<inapplicable>}.(87);
+ };
+ dynamic f2b = #C4;
+ dynamic c2c = f2b{dynamic}.call();
+ self::expect(42, c2c{dynamic}.field);
+ dynamic c2d = f2b{dynamic}.call(field: 87);
+ self::expect(87, c2d{dynamic}.field);
+ self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C5}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 42
+ #C2 = null
+ #C3 = static-tearoff self::Class1::_#new#tearOff
+ #C4 = static-tearoff self::Class2::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart
new file mode 100644
index 0000000..9a68b87
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+ final int field;
+
+ A([this.field = 42]);
+
+ factory A.redirect([int field = 87]) = A;
+}
+
+main() {
+ expect(42, new A().field);
+ expect(123, new A(123).field);
+ expect(42, new A.redirect().field);
+ expect(123, new A.redirect(123).field);
+}
+
+expect(expected, actual) {
+ if (expected != actual) throw 'Expected $expected, actual $actual';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline.expect
new file mode 100644
index 0000000..6351dd7
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+class A {
+ final int field;
+ A([this.field = 42]);
+ factory A.redirect([int field = 87]) = A;
+}
+
+main() {}
+expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..23adf6f
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline_modelled.expect
@@ -0,0 +1,8 @@
+class A {
+ A([this.field = 42]);
+ factory A.redirect([int field = 87]) = A;
+ final int field;
+}
+
+expect(expected, actual) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.expect
new file mode 100644
index 0000000..1e7a7cc4
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/redirecting_factory_default_value.dart:10:35: Error: Can't have a default value here because any default values of 'A' would be used instead.
+// Try removing the default value.
+// factory A.redirect([int field = 87]) = A;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::A::redirect]/*isLegacy*/;
+ constructor •([core::int field = #C1]) → self::A
+ : self::A::field = field, super core::Object::•()
+ ;
+ static factory redirect([core::int field]) → self::A
+ let dynamic #redirecting_factory = self::A::• in invalid-expression;
+}
+static method main() → dynamic {
+ self::expect(42, new self::A::•().{self::A::field}{core::int});
+ self::expect(123, new self::A::•(123).{self::A::field}{core::int});
+ self::expect(42, new self::A::•().{self::A::field}{core::int});
+ self::expect(123, new self::A::•(123).{self::A::field}{core::int});
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+
+constants {
+ #C1 = 42
+}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.outline.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.outline.expect
new file mode 100644
index 0000000..352e5d1
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.outline.expect
@@ -0,0 +1,16 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::A::redirect]/*isLegacy*/;
+ constructor •([core::int field]) → self::A
+ ;
+ static factory redirect([core::int field]) → self::A
+ let dynamic #redirecting_factory = self::A::• in invalid-expression;
+}
+static method main() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.transformed.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.transformed.expect
new file mode 100644
index 0000000..6b1dd68
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.transformed.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/redirecting_factory_default_value.dart:10:35: Error: Can't have a default value here because any default values of 'A' would be used instead.
+// Try removing the default value.
+// factory A.redirect([int field = 87]) = A;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::A::redirect]/*isLegacy*/;
+ constructor •([core::int field = #C1]) → self::A
+ : self::A::field = field, super core::Object::•()
+ ;
+ static factory redirect([core::int field]) → self::A
+ let Never #redirecting_factory = self::A::• in invalid-expression;
+}
+static method main() → dynamic {
+ self::expect(42, new self::A::•().{self::A::field}{core::int});
+ self::expect(123, new self::A::•(123).{self::A::field}{core::int});
+ self::expect(42, new self::A::•().{self::A::field}{core::int});
+ self::expect(123, new self::A::•(123).{self::A::field}{core::int});
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+
+constants {
+ #C1 = 42
+}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart
index da569e7..d25c571 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart
+++ b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart
@@ -1,7 +1,9 @@
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+
// @dart=2.9
+
// This test checks that annotations on redirecting factories and their formals
// aren't skipped by the compiler and are observable in its output.
diff --git a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.weak.outline.expect b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.weak.outline.expect
index 31008cf..a83d25d 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.weak.outline.expect
@@ -28,5 +28,5 @@
Extra constant evaluation status:
-Evaluated: StaticGet @ org-dartlang-testcase:///redirecting_factory_metadata.dart:13:4 -> IntConstant(2)
+Evaluated: StaticGet @ org-dartlang-testcase:///redirecting_factory_metadata.dart:15:4 -> IntConstant(2)
Extra constant evaluation: evaluated: 5, effectively constant: 1
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 81314ea..2fdf4fb 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -6,16 +6,8 @@
# the round trip for Kernel textual serialization where the initial binary
# Kernel files are produced by compiling Dart code via Fasta.
-constructor_tearoffs/abstract_class_constructor_tear_off: TextSerializationFailure
-constructor_tearoffs/generic_tearoff_with_context: TextSerializationFailure
-constructor_tearoffs/generic_tearoff_without_context: TextSerializationFailure
-constructor_tearoffs/instantiation: TextSerializationFailure
-constructor_tearoffs/nongeneric_tearoff_with_context: TextSerializationFailure
-constructor_tearoffs/nongeneric_tearoff_without_context: TextSerializationFailure
-constructor_tearoffs/redirecting_constructors: TextSerializationFailure
-constructor_tearoffs/redirecting_factory_tear_off: TextSerializationFailure
-constructor_tearoffs/typedef_tearoffs: TextSerializationFailure
-constructor_tearoffs/unnamed_constructor: TextSerializationFailure
+constructor_tearoffs/redirecting_constructors: RuntimeError
+constructor_tearoffs/redirecting_factory_tear_off: RuntimeError
extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
extension_types/simple: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index 7b2c1ef..0232a67 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -97,6 +97,10 @@
String visitStaticGet(StaticGet _) => "get-static";
String visitStaticSet(StaticSet _) => "set-static";
String visitStaticTearOff(StaticTearOff _) => "tearoff-static";
+ String visitConstructorTearOff(ConstructorTearOff _) => "tearoff-constructor";
+ String visitRedirectingFactoryTearOff(RedirectingFactoryTearOff _) =>
+ "tearoff-redirecting-factory";
+ String visitTypedefTearOff(TypedefTearOff _) => "tearoff-typedef";
String visitStaticInvocation(StaticInvocation expression) {
return expression.isConst ? "invoke-const-static" : "invoke-static";
}
@@ -931,6 +935,55 @@
return new StaticTearOff.byReference(name.reference);
}
+const TextSerializer<ConstructorTearOff> constructorTearOffSerializer =
+ const Wrapped(unwrapConstructorTearOff, wrapConstructorTearOff,
+ canonicalNameSerializer);
+
+CanonicalName unwrapConstructorTearOff(ConstructorTearOff expression) {
+ return expression.targetReference.canonicalName!;
+}
+
+ConstructorTearOff wrapConstructorTearOff(CanonicalName name) {
+ return new ConstructorTearOff.byReference(name.reference);
+}
+
+const TextSerializer<RedirectingFactoryTearOff>
+ redirectingFactoryTearOffSerializer = const Wrapped(
+ unwrapRedirectingFactoryTearOff,
+ wrapRedirectingFactoryTearOff,
+ canonicalNameSerializer);
+
+CanonicalName unwrapRedirectingFactoryTearOff(
+ RedirectingFactoryTearOff expression) {
+ return expression.targetReference.canonicalName!;
+}
+
+RedirectingFactoryTearOff wrapRedirectingFactoryTearOff(CanonicalName name) {
+ return new RedirectingFactoryTearOff.byReference(name.reference);
+}
+
+final TextSerializer<TypedefTearOff> typedefTearOffSerializer = new Wrapped<
+ Tuple2<List<TypeParameter>, Tuple2<Expression, List<DartType>>>,
+ TypedefTearOff>(
+ unwrapTypedefTearOff,
+ wrapTypedefTearOff,
+ Bind(
+ typeParametersSerializer,
+ Tuple2Serializer(
+ expressionSerializer, ListSerializer(dartTypeSerializer))));
+
+Tuple2<List<TypeParameter>, Tuple2<Expression, List<DartType>>>
+ unwrapTypedefTearOff(TypedefTearOff node) {
+ return new Tuple2(
+ node.typeParameters, new Tuple2(node.expression, node.typeArguments));
+}
+
+TypedefTearOff wrapTypedefTearOff(
+ Tuple2<List<TypeParameter>, Tuple2<Expression, List<DartType>>> tuple) {
+ return new TypedefTearOff(
+ tuple.first, tuple.second.first, tuple.second.second);
+}
+
TextSerializer<StaticSet> staticSetSerializer = new Wrapped(
unwrapStaticSet,
wrapStaticSet,
@@ -2175,7 +2228,14 @@
String visitStringConstant(StringConstant node) => "const-string";
String visitSymbolConstant(SymbolConstant node) => "const-symbol";
String visitStaticTearOffConstant(StaticTearOffConstant node) =>
- "const-tearoff";
+ "const-tearoff-static";
+ String visitConstructorTearOffConstant(ConstructorTearOffConstant node) =>
+ "const-tearoff-constructor";
+ String visitRedirectingFactoryTearOffConstant(
+ RedirectingFactoryTearOffConstant node) =>
+ "const-tearoff-redirecting-factory";
+ String visitTypedefTearOffConstant(TypedefTearOffConstant node) =>
+ "const-tearoff-typedef";
String visitTypeLiteralConstant(TypeLiteralConstant node) => "const-type";
String visitUnevaluatedConstant(UnevaluatedConstant node) => "const-expr";
@@ -2221,11 +2281,11 @@
Wrapped<void, NullConstant>((w) => null, (u) => NullConstant(), Nothing());
TextSerializer<InstantiationConstant> instantiationConstantSerializer =
- Wrapped<Tuple2<TearOffConstant, List<DartType>>, InstantiationConstant>(
+ Wrapped<Tuple2<Constant, List<DartType>>, InstantiationConstant>(
(w) => Tuple2(w.tearOffConstant, w.types),
- (u) => InstantiationConstant(u.first, u.second),
+ (u) => InstantiationConstant(u.first as TearOffConstant, u.second),
Tuple2Serializer(
- tearOffConstantSerializer, ListSerializer(dartTypeSerializer)));
+ constantSerializer, ListSerializer(dartTypeSerializer)));
TextSerializer<SetConstant> setConstantSerializer =
Wrapped<Tuple2<DartType, List<Constant>>, SetConstant>(
@@ -2244,12 +2304,48 @@
(u) => SymbolConstant(u.first, u.second?.reference),
Tuple2Serializer(DartString(), Optional(CanonicalNameSerializer())));
-TextSerializer<StaticTearOffConstant> tearOffConstantSerializer =
+TextSerializer<StaticTearOffConstant> staticTearOffConstantSerializer =
Wrapped<CanonicalName, StaticTearOffConstant>(
(w) => w.targetReference.canonicalName!,
(u) => StaticTearOffConstant.byReference(u.reference),
CanonicalNameSerializer());
+TextSerializer<ConstructorTearOffConstant>
+ constructorTearOffConstantSerializer =
+ Wrapped<CanonicalName, ConstructorTearOffConstant>(
+ (w) => w.targetReference.canonicalName!,
+ (u) => ConstructorTearOffConstant.byReference(u.reference),
+ CanonicalNameSerializer());
+
+TextSerializer<RedirectingFactoryTearOffConstant>
+ redirectingFactoryTearOffConstantSerializer =
+ Wrapped<CanonicalName, RedirectingFactoryTearOffConstant>(
+ (w) => w.targetReference.canonicalName!,
+ (u) => RedirectingFactoryTearOffConstant.byReference(u.reference),
+ CanonicalNameSerializer());
+
+final TextSerializer<TypedefTearOffConstant> typedefTearOffConstantSerializer =
+ new Wrapped<Tuple2<List<TypeParameter>, Tuple2<Constant, List<DartType>>>,
+ TypedefTearOffConstant>(
+ unwrapTypedefTearOffConstant,
+ wrapTypedefTearOffConstant,
+ Bind(
+ typeParametersSerializer,
+ Tuple2Serializer(
+ constantSerializer, ListSerializer(dartTypeSerializer))));
+
+Tuple2<List<TypeParameter>, Tuple2<Constant, List<DartType>>>
+ unwrapTypedefTearOffConstant(TypedefTearOffConstant node) {
+ return new Tuple2(
+ node.parameters, new Tuple2(node.tearOffConstant, node.types));
+}
+
+TypedefTearOffConstant wrapTypedefTearOffConstant(
+ Tuple2<List<TypeParameter>, Tuple2<Constant, List<DartType>>> tuple) {
+ return new TypedefTearOffConstant(
+ tuple.first, tuple.second.first as TearOffConstant, tuple.second.second);
+}
+
TextSerializer<TypeLiteralConstant> typeLiteralConstantSerializer =
Wrapped<DartType, TypeLiteralConstant>(
(w) => w.type, (u) => TypeLiteralConstant(u), dartTypeSerializer);
@@ -2547,7 +2643,10 @@
"set-var": variableSetSerializer,
"get-static": staticGetSerializer,
"set-static": staticSetSerializer,
- "tearoff-static": staticGetSerializer,
+ "tearoff-static": staticTearOffSerializer,
+ "tearoff-constructor": constructorTearOffSerializer,
+ "tearoff-redirecting-factory": redirectingFactoryTearOffSerializer,
+ "tearoff-typedef": typedefTearOffSerializer,
"invoke-static": staticInvocationSerializer,
"invoke-const-static": constStaticInvocationSerializer,
"invoke-constructor": constructorInvocationSerializer,
@@ -2624,7 +2723,11 @@
"const-set": setConstantSerializer,
"const-string": stringConstantSerializer,
"const-symbol": symbolConstantSerializer,
- "const-tearoff": tearOffConstantSerializer,
+ "const-tearoff-static": staticTearOffConstantSerializer,
+ "const-tearoff-constructor": constructorTearOffConstantSerializer,
+ "const-tearoff-redirecting-factory":
+ redirectingFactoryTearOffConstantSerializer,
+ "const-tearoff-typedef": typedefTearOffConstantSerializer,
"const-type": typeLiteralConstantSerializer,
"const-expr": unevaluatedConstantSerializer,
"const-object": instanceConstantSerializer,
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 4439705..e598523 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -136,9 +136,11 @@
}
class FreshTypeParameters {
- ///
+ /// The newly created type parameters.
final List<TypeParameter> freshTypeParameters;
+ /// List of [TypeParameterType]s for [TypeParameter].
final List<DartType> freshTypeArguments;
+ /// Substitution from the original type parameters to [freshTypeArguments].
final Substitution substitution;
FreshTypeParameters(
@@ -175,6 +177,8 @@
static const Substitution empty = _NullSubstitution.instance;
+ bool get isEmpty => identical(this, empty);
+
/// Substitutes each parameter to the type it maps to in [map].
static Substitution fromMap(Map<TypeParameter, DartType> map) {
if (map.isEmpty) return _NullSubstitution.instance;
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index 15a52eb..16d4c30 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -828,10 +828,13 @@
visitTypeParameterType(TypeParameterType node) {
TypeParameter parameter = node.parameter;
if (!typeParametersInScope.contains(parameter)) {
+ TreeNode? owner = parameter.parent is FunctionNode
+ ? parameter.parent!.parent
+ : parameter.parent;
problem(
currentParent,
"Type parameter '$parameter' referenced out of"
- " scope, parent is: '${parameter.parent}'.");
+ " scope, owner is: '${owner}'.");
}
if (parameter.parent is Class && !classTypeParametersAreInScope) {
problem(
diff --git a/pkg/kernel/test/verify_test.dart b/pkg/kernel/test/verify_test.dart
index 8c1a8bf..f1418df 100644
--- a/pkg/kernel/test/verify_test.dart
+++ b/pkg/kernel/test/verify_test.dart
@@ -136,7 +136,7 @@
},
(Node node, Node parent) =>
"Type parameter '$node' referenced out of scope,"
- " parent is: '$parent'.",
+ " owner is: '$parent'.",
);
negative2Test(
'Class type parameter from another class',
@@ -148,7 +148,7 @@
},
(Node node, Node parent) =>
"Type parameter '$node' referenced out of scope,"
- " parent is: '$parent'.",
+ " owner is: '$parent'.",
);
negative2Test(
'Class type parameter in static method',
@@ -208,7 +208,7 @@
},
(Node node, Node parent) =>
"Type parameter '$node' referenced out of scope,"
- " parent is: '$parent'.",
+ " owner is: '${(parent as TreeNode).parent}'.",
);
negative1Test(
'Interface type arity too low',
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index 3e08d2f..8a70226 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -557,7 +557,7 @@
@override
void setCompoundAssignmentExpressionTypes(CompoundAssignmentExpression node) {
- assert(_assignmentLikeExpressionHandlers[node as Expression] == null);
+ assert(_assignmentLikeExpressionHandlers[node] == null);
if (node is AssignmentExpression) {
var handler = _AssignmentExpressionHandler(node);
_assignmentLikeExpressionHandlers[node] = handler;
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index d307442..cb269c4 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -115,8 +115,6 @@
ThreadInterrupter::Cleanup();
SampleBlockCleanupVisitor visitor;
Isolate::VisitIsolates(&visitor);
- delete sample_block_buffer_;
- sample_block_buffer_ = nullptr;
initialized_ = false;
}
diff --git a/tools/VERSION b/tools/VERSION
index 5b933e1..8119d92 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 339
+PRERELEASE 340
PRERELEASE_PATCH 0
\ No newline at end of file