Version 2.14.0-336.0.dev
Merge commit 'f638d06292ae6f34ee537638b114fe893db3719f' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index ae54a38..7fc3b9f 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -860,14 +860,13 @@
/// used by the generated source, but not imported.
String? getTypeSource(DartType type, Set<Source> librariesToImport,
{StringBuffer? parametersBuffer}) {
- var aliasElement = type.aliasElement;
- var aliasArguments = type.aliasArguments;
- if (aliasElement != null && aliasArguments != null) {
+ var alias = type.alias;
+ if (alias != null) {
return _getTypeCodeElementArguments(
librariesToImport: librariesToImport,
- element: aliasElement,
+ element: alias.element,
isNullable: type.nullabilitySuffix == NullabilitySuffix.question,
- typeArguments: aliasArguments,
+ typeArguments: alias.typeArguments,
);
}
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 73619d3..337ad88 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 2.1.0
+## 2.1.0-dev
* Changed `AnalysisResult.path` to be non-nullable.
* Changed `ParsedLibraryResult.units` to be non-nullable.
* Changed `ResolvedLibraryResult.element` to be non-nullable.
@@ -11,6 +11,9 @@
`content` and `unit` were `null`, when the result actually had only errors.
Now it produces either `ResolvedUnitResult`, or `ErrorsResult`, or
some other results that might be added in the future.
+* Added `DartType.alias` with information about instantiated type alias.
+ The type alias element and arguments are present or absent together.
+* Deprecated `DartType.aliasElement` and `DartType.aliasArguments`.
## 2.0.0
* Removed deprecated `Scope.lookup2()`.
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 44efa9f..5e9079a 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -28,12 +28,19 @@
///
/// Clients may not extend, implement or mix-in this class.
abstract class DartType {
+ /// If this type is an instantiation of a type alias, information about
+ /// the alias element, and the type arguments.
+ /// Otherwise return `null`.
+ InstantiatedTypeAliasElement? get alias;
+
/// If this type is an instantiation of a type alias, return the type
/// arguments used for the instantiation. Otherwise return `null`.
+ @Deprecated('Use alias instead')
List<DartType>? get aliasArguments;
/// If this type is an instantiation of a type alias, return it.
/// Otherwise return `null`.
+ @Deprecated('Use alias instead')
TypeAliasElement? get aliasElement;
/// Return the name of this type as it should appear when presented to users
@@ -245,6 +252,17 @@
FunctionType instantiate(List<DartType> argumentTypes);
}
+/// Information about an instantiated [TypeAliasElement] and the type
+/// arguments with which it is instantiated.
+abstract class InstantiatedTypeAliasElement {
+ /// The alias element that is instantiated to produce a [DartType].
+ TypeAliasElement get element;
+
+ /// The type arguments with which the [element] was instantiated.
+ /// This list will be empty if the [element] is not generic.
+ List<DartType> get typeArguments;
+}
+
/// The type introduced by either a class or an interface, or a reference to
/// such a type.
///
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 4c232e6..a1800cd 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -5480,23 +5480,29 @@
parameters: type.parameters,
returnType: type.returnType,
nullabilitySuffix: resultNullability,
- aliasElement: this,
- aliasArguments: typeArguments,
+ alias: InstantiatedTypeAliasElementImpl(
+ element: this,
+ typeArguments: typeArguments,
+ ),
);
} else if (type is InterfaceType) {
return InterfaceTypeImpl(
element: type.element,
typeArguments: type.typeArguments,
nullabilitySuffix: resultNullability,
- aliasElement: this,
- aliasArguments: typeArguments,
+ alias: InstantiatedTypeAliasElementImpl(
+ element: this,
+ typeArguments: typeArguments,
+ ),
);
} else if (type is TypeParameterType) {
return TypeParameterTypeImpl(
element: type.element,
nullabilitySuffix: resultNullability,
- aliasElement: this,
- aliasArguments: typeArguments,
+ alias: InstantiatedTypeAliasElementImpl(
+ element: this,
+ typeArguments: typeArguments,
+ ),
);
} else {
return (type as TypeImpl).withNullability(resultNullability);
diff --git a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
index b05ab3d..f4077d4 100644
--- a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
@@ -583,7 +583,7 @@
if (typeElement != null && typeElement.hasOptionalTypeArgs) {
return;
}
- var typeAliasElement = type.aliasElement;
+ var typeAliasElement = type.alias?.element;
if (typeAliasElement != null &&
typeAliasElement.hasOptionalTypeArgs) {
return;
diff --git a/pkg/analyzer/lib/src/dart/element/replace_top_bottom_visitor.dart b/pkg/analyzer/lib/src/dart/element/replace_top_bottom_visitor.dart
index 5709733..2db9a85 100644
--- a/pkg/analyzer/lib/src/dart/element/replace_top_bottom_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/element/replace_top_bottom_visitor.dart
@@ -53,8 +53,9 @@
}
}
- if (type.aliasElement != null) {
- return _typeAliasInstantiation(type, variance);
+ var alias = type.alias;
+ if (alias != null) {
+ return _instantiatedTypeAlias(type, alias, variance);
} else if (type is InterfaceType) {
return _interfaceType(type, variance);
} else if (type is FunctionType) {
@@ -83,6 +84,34 @@
);
}
+ DartType _instantiatedTypeAlias(
+ DartType type,
+ InstantiatedTypeAliasElement alias,
+ Variance variance,
+ ) {
+ var aliasElement = alias.element;
+ var aliasArguments = alias.typeArguments;
+
+ var typeParameters = aliasElement.typeParameters;
+ assert(typeParameters.length == aliasArguments.length);
+
+ var newTypeArguments = <DartType>[];
+ for (var i = 0; i < typeParameters.length; i++) {
+ var typeParameter = typeParameters[i] as TypeParameterElementImpl;
+ newTypeArguments.add(
+ process(
+ aliasArguments[i],
+ typeParameter.variance.combine(variance),
+ ),
+ );
+ }
+
+ return aliasElement.instantiate(
+ typeArguments: newTypeArguments,
+ nullabilitySuffix: type.nullabilitySuffix,
+ );
+ }
+
DartType _interfaceType(InterfaceType type, Variance variance) {
var typeParameters = type.element.typeParameters;
if (typeParameters.isEmpty) {
@@ -105,30 +134,6 @@
);
}
- DartType _typeAliasInstantiation(DartType type, Variance variance) {
- var aliasElement = type.aliasElement!;
- var aliasArguments = type.aliasArguments!;
-
- var typeParameters = aliasElement.typeParameters;
- assert(typeParameters.length == aliasArguments.length);
-
- var newTypeArguments = <DartType>[];
- for (var i = 0; i < typeParameters.length; i++) {
- var typeParameter = typeParameters[i] as TypeParameterElementImpl;
- newTypeArguments.add(
- process(
- aliasArguments[i],
- typeParameter.variance.combine(variance),
- ),
- );
- }
-
- return aliasElement.instantiate(
- typeArguments: newTypeArguments,
- nullabilitySuffix: type.nullabilitySuffix,
- );
- }
-
/// Runs an instance of the visitor on the given [type] and returns the
/// resulting type. If the type contains no instances of Top or Bottom, the
/// original type object is returned to avoid unnecessary allocation.
diff --git a/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart b/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
index c1c1a79..638ad0f 100644
--- a/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
@@ -29,13 +29,14 @@
DartType? createFunctionType({
required FunctionType type,
- required List<DartType>? newAliasArguments,
+ required InstantiatedTypeAliasElement? newAlias,
required List<TypeParameterElement>? newTypeParameters,
required List<ParameterElement>? newParameters,
required DartType? newReturnType,
required NullabilitySuffix? newNullability,
}) {
- if (newNullability == null &&
+ if (newAlias == null &&
+ newNullability == null &&
newReturnType == null &&
newParameters == null) {
return null;
@@ -46,8 +47,7 @@
parameters: newParameters ?? type.parameters,
returnType: newReturnType ?? type.returnType,
nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
- aliasElement: type.aliasElement,
- aliasArguments: newAliasArguments ?? type.aliasArguments,
+ alias: newAlias ?? type.alias,
);
}
@@ -74,11 +74,11 @@
DartType? createInterfaceType({
required InterfaceType type,
- required List<DartType>? newAliasArguments,
+ required InstantiatedTypeAliasElement? newAlias,
required List<DartType>? newTypeArguments,
required NullabilitySuffix? newNullability,
}) {
- if (newAliasArguments == null &&
+ if (newAlias == null &&
newTypeArguments == null &&
newNullability == null) {
return null;
@@ -88,8 +88,7 @@
element: type.element,
typeArguments: newTypeArguments ?? type.typeArguments,
nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
- aliasElement: type.aliasElement,
- aliasArguments: newAliasArguments ?? type.aliasArguments,
+ alias: newAlias ?? type.alias,
);
}
@@ -136,8 +135,7 @@
element: type.element,
nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
promotedBound: newPromotedBound ?? promotedBound,
- aliasElement: type.aliasElement,
- aliasArguments: type.aliasArguments,
+ alias: type.alias,
);
}
@@ -152,8 +150,7 @@
return TypeParameterTypeImpl(
element: type.element,
nullabilitySuffix: newNullability,
- aliasElement: type.aliasElement,
- aliasArguments: type.aliasArguments,
+ alias: type.alias,
);
}
@@ -215,16 +212,24 @@
var newReturnType = visitType(node.returnType);
- List<DartType>? newAliasArguments;
- var aliasArguments = node.aliasArguments;
- if (aliasArguments != null) {
+ InstantiatedTypeAliasElement? newAlias;
+ var alias = node.alias;
+ if (alias != null) {
+ List<DartType>? newArguments;
+ var aliasArguments = alias.typeArguments;
for (var i = 0; i < aliasArguments.length; i++) {
var substitution = aliasArguments[i].accept(this);
if (substitution != null) {
- newAliasArguments ??= aliasArguments.toList(growable: false);
- newAliasArguments[i] = substitution;
+ newArguments ??= aliasArguments.toList(growable: false);
+ newArguments[i] = substitution;
}
}
+ if (newArguments != null) {
+ newAlias = InstantiatedTypeAliasElementImpl(
+ element: alias.element,
+ typeArguments: newArguments,
+ );
+ }
}
changeVariance();
@@ -253,7 +258,7 @@
return createFunctionType(
type: node,
- newAliasArguments: newAliasArguments,
+ newAlias: newAlias,
newTypeParameters: newTypeParameters,
newParameters: newParameters,
newReturnType: newReturnType,
@@ -351,13 +356,20 @@
DartType? visitInterfaceType(InterfaceType type) {
var newNullability = visitNullability(type);
- var aliasElement = type.aliasElement;
- var newAliasArguments = aliasElement != null
- ? _typeArguments(
- aliasElement.typeParameters,
- type.aliasArguments,
- )
- : null;
+ InstantiatedTypeAliasElement? newAlias;
+ var alias = type.alias;
+ if (alias != null) {
+ var newArguments = _typeArguments(
+ alias.element.typeParameters,
+ alias.typeArguments,
+ );
+ if (newArguments != null) {
+ newAlias = InstantiatedTypeAliasElementImpl(
+ element: alias.element,
+ typeArguments: newArguments,
+ );
+ }
+ }
var newTypeArguments = _typeArguments(
type.element.typeParameters,
@@ -366,7 +378,7 @@
return createInterfaceType(
type: type,
- newAliasArguments: newAliasArguments,
+ newAlias: newAlias,
newTypeArguments: newTypeArguments,
newNullability: newNullability,
);
@@ -453,12 +465,8 @@
List<DartType>? _typeArguments(
List<TypeParameterElement> parameters,
- List<DartType>? arguments,
+ List<DartType> arguments,
) {
- if (arguments == null) {
- return null;
- }
-
if (arguments.length != parameters.length) {
return null;
}
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index a123137..846f845 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -109,13 +109,12 @@
required List<ParameterElement> parameters,
required DartType returnType,
required NullabilitySuffix nullabilitySuffix,
- TypeAliasElement? aliasElement,
- List<DartType>? aliasArguments,
+ InstantiatedTypeAliasElement? alias,
}) : typeFormals = typeFormals,
parameters = _sortNamedParameters(parameters),
returnType = returnType,
nullabilitySuffix = nullabilitySuffix,
- super(null, aliasElement: aliasElement, aliasArguments: aliasArguments);
+ super(null, alias: alias);
@override
int get hashCode {
@@ -297,8 +296,7 @@
parameters: parameters,
returnType: returnType,
nullabilitySuffix: nullabilitySuffix,
- aliasElement: aliasElement,
- aliasArguments: aliasArguments,
+ alias: alias,
);
}
@@ -610,6 +608,19 @@
}
}
+class InstantiatedTypeAliasElementImpl implements InstantiatedTypeAliasElement {
+ @override
+ final TypeAliasElement element;
+
+ @override
+ final List<DartType> typeArguments;
+
+ InstantiatedTypeAliasElementImpl({
+ required this.element,
+ required this.typeArguments,
+ });
+}
+
/// A concrete implementation of an [InterfaceType].
class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
@override
@@ -631,12 +642,10 @@
required ClassElement element,
required this.typeArguments,
required this.nullabilitySuffix,
- TypeAliasElement? aliasElement,
- List<DartType>? aliasArguments,
+ InstantiatedTypeAliasElement? alias,
}) : super(
element,
- aliasElement: aliasElement,
- aliasArguments: aliasArguments,
+ alias: alias,
);
@override
@@ -1615,19 +1624,26 @@
/// representing the declared type of elements in the element model.
abstract class TypeImpl implements DartType {
@override
- final List<DartType>? aliasArguments;
-
- @override
- final TypeAliasElement? aliasElement;
+ InstantiatedTypeAliasElement? alias;
/// The element representing the declaration of this type, or `null` if the
/// type has not, or cannot, be associated with an element.
final Element? _element;
/// Initialize a newly created type to be declared by the given [element].
- TypeImpl(this._element, {this.aliasElement, this.aliasArguments})
- : assert(aliasElement == null && aliasArguments == null ||
- aliasElement != null && aliasArguments != null);
+ TypeImpl(this._element, {this.alias});
+
+ @Deprecated('Use alias instead')
+ @override
+ List<DartType>? get aliasArguments {
+ return alias?.typeArguments;
+ }
+
+ @Deprecated('Use alias instead')
+ @override
+ TypeAliasElement? get aliasElement {
+ return alias?.element;
+ }
@deprecated
@override
@@ -1774,12 +1790,10 @@
required TypeParameterElement element,
required this.nullabilitySuffix,
this.promotedBound,
- TypeAliasElement? aliasElement,
- List<DartType>? aliasArguments,
+ InstantiatedTypeAliasElement? alias,
}) : super(
element,
- aliasElement: aliasElement,
- aliasArguments: aliasArguments,
+ alias: alias,
);
@override
diff --git a/pkg/analyzer/lib/src/dart/element/type_algebra.dart b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
index 326f73a..9057b2c 100644
--- a/pkg/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
@@ -444,9 +444,13 @@
var returnType = type.returnType.accept(inner);
- var aliasArguments = type.aliasArguments;
- var newAliasArguments =
- aliasArguments != null ? _mapList(aliasArguments) : null;
+ var alias = type.alias;
+ var newAlias = alias != null
+ ? InstantiatedTypeAliasElementImpl(
+ element: alias.element,
+ typeArguments: _mapList(alias.typeArguments),
+ )
+ : null;
if (useCounter == before) return type;
@@ -455,8 +459,7 @@
parameters: parameters,
returnType: returnType,
nullabilitySuffix: type.nullabilitySuffix,
- aliasElement: type.aliasElement,
- aliasArguments: newAliasArguments,
+ alias: newAlias,
);
}
diff --git a/pkg/analyzer/lib/src/dart/element/type_demotion.dart b/pkg/analyzer/lib/src/dart/element/type_demotion.dart
index 4b1cc1a..4839abe 100644
--- a/pkg/analyzer/lib/src/dart/element/type_demotion.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_demotion.dart
@@ -38,8 +38,7 @@
return TypeParameterTypeImpl(
element: type.element,
nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
- aliasElement: type.aliasElement,
- aliasArguments: type.aliasArguments,
+ alias: type.alias,
);
}
}
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index a299c7d..711f2ab 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -628,7 +628,7 @@
appendParameters(type.returnType);
type.parameters.map((p) => p.type).forEach(appendParameters);
// TODO(scheglov) https://github.com/dart-lang/sdk/issues/44218
- type.aliasArguments?.forEach(appendParameters);
+ type.alias?.typeArguments.forEach(appendParameters);
} else if (type is InterfaceType) {
type.typeArguments.forEach(appendParameters);
}
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index e11ec7f..aa4627e 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -39,6 +39,7 @@
import 'package:analyzer/src/util/performance/operation_performance.dart';
import 'package:analyzer/src/workspace/workspace.dart';
import 'package:collection/collection.dart';
+import 'package:meta/meta.dart';
import 'package:yaml/yaml.dart';
const M = 1024 * 1024 /*1 MiB*/;
@@ -109,7 +110,8 @@
/// It is used to allow assists and fixes without resolving the same file
/// multiple times, as we compute more than one assist, or fixes when there
/// are more than one error on a line.
- final Map<String, ResolvedLibraryResult> _cachedResults = {};
+ @visibleForTesting
+ final Map<String, ResolvedLibraryResult> cachedResults = {};
FileResolver(
PerformanceLog logger,
@@ -164,7 +166,7 @@
}
// Forget all results, anything is potentially affected.
- _cachedResults.clear();
+ cachedResults.clear();
// Remove this file and all files that transitively depend on it.
var removedFiles = <FileState>[];
@@ -445,24 +447,16 @@
}
}
- var libraryUnit = resolveLibrary(
+ var libraryResult = resolveLibrary(
completionLine: completionLine,
completionColumn: completionColumn,
path: libraryFile.path,
- completionPath: path,
+ completionPath: completionLine != null ? path : null,
performance: performance,
);
- var result =
- libraryUnit.units.firstWhereOrNull((element) => element.path == path);
- // TODO(scheglov) Fix and remove.
- if (result == null) {
- throw StateError('''
-libraryFile.path: ${libraryFile.path}
-path: $path
-units: ${libraryUnit.units.map((e) => '(${e.uri} = ${e.path})').toList()}
-''');
- }
- return result;
+ return libraryResult.units.firstWhere(
+ (unitResult) => unitResult.path == path,
+ );
});
}
@@ -478,7 +472,7 @@
performance ??= OperationPerformanceImpl('<default>');
- var cachedResult = _cachedResults[path];
+ var cachedResult = cachedResults[path];
if (cachedResult != null) {
return cachedResult;
}
@@ -570,7 +564,11 @@
var libraryUnit = resolvedUnits.first;
var result = ResolvedLibraryResultImpl(contextObjects!.analysisSession,
path, libraryUnit.uri, libraryUnit.libraryElement, resolvedUnits);
- _cachedResults[path] = result;
+
+ if (completionPath == null) {
+ cachedResults[path] = result;
+ }
+
return result;
});
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/legacy_type_asserter.dart b/pkg/analyzer/lib/src/dart/resolver/legacy_type_asserter.dart
index 94c39d7..7be20ef 100644
--- a/pkg/analyzer/lib/src/dart/resolver/legacy_type_asserter.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/legacy_type_asserter.dart
@@ -144,7 +144,7 @@
return;
}
- type.aliasArguments?.forEach(_assertLegacyType);
+ type.alias?.typeArguments.forEach(_assertLegacyType);
if (type is TypeParameterType) {
_assertLegacyType(type.bound);
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index a1d8739..bfa745d 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -755,7 +755,7 @@
// not report synthetic `dynamic` in place of an unresolved type.
if ((type.element == _nullType.element ||
(type.isDynamic && name == 'dynamic')) &&
- type.aliasElement == null) {
+ type.alias == null) {
_errorReporter.reportErrorForNode(
HintCode.UNNECESSARY_QUESTION_MARK, node, [name]);
}
@@ -1048,7 +1048,7 @@
...element.typeParameters.map((tp) => tp.bound),
];
for (var type in signatureTypes) {
- var aliasElement = type?.aliasElement;
+ var aliasElement = type?.alias?.element;
if (aliasElement != null && aliasElement.hasInternal) {
_errorReporter.reportErrorForNode(
HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY,
diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
index e4a6930..55d66ce 100644
--- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
+++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
@@ -210,10 +210,10 @@
List<TypeParameterElement> typeParameters;
List<DartType> typeArguments;
- var aliasElement = type.aliasElement;
- if (aliasElement != null) {
- typeParameters = aliasElement.typeParameters;
- typeArguments = type.aliasArguments!;
+ var alias = type.alias;
+ if (alias != null) {
+ typeParameters = alias.element.typeParameters;
+ typeArguments = alias.typeArguments;
} else if (type is InterfaceType) {
typeParameters = type.element.typeParameters;
typeArguments = type.typeArguments;
@@ -277,8 +277,9 @@
// Prepare type arguments for checking for super-bounded.
type = _typeSystem.replaceTopAndBottom(type);
- if (type.aliasElement != null) {
- typeArguments = type.aliasArguments!;
+ alias = type.alias;
+ if (alias != null) {
+ typeArguments = alias.typeArguments;
} else if (type is InterfaceType) {
typeArguments = type.typeArguments;
} else {
@@ -422,9 +423,9 @@
bool _isMissingTypeArguments(AstNode node, DartType type, Element? element,
Expression? inferenceContextNode) {
List<DartType> typeArguments;
- var aliasElement = type.aliasElement;
- if (aliasElement != null) {
- typeArguments = type.aliasArguments!;
+ var alias = type.alias;
+ if (alias != null) {
+ typeArguments = alias.typeArguments;
} else if (type is InterfaceType) {
typeArguments = type.typeArguments;
} else {
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index dd65232..211a94c 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -504,6 +504,8 @@
offset: resolutionOffset,
);
+ _declareDartCoreDynamicNever();
+
InformativeDataApplier(_elementFactory, _unitsInformativeBytes)
.applyTo(libraryElement);
@@ -514,6 +516,14 @@
return libraryElement;
}
+ /// These elements are implicitly declared in `dart:core`.
+ void _declareDartCoreDynamicNever() {
+ if (_reference.name == 'dart:core') {
+ _reference.getChild('dynamic').element = DynamicElementImpl.instance;
+ _reference.getChild('Never').element = NeverElementImpl.instance;
+ }
+ }
+
ClassElementImpl _readClassElement(
CompilationUnitElementImpl unitElement,
Reference unitReference,
@@ -1541,23 +1551,29 @@
parameters: type.parameters,
returnType: type.returnType,
nullabilitySuffix: type.nullabilitySuffix,
- aliasElement: aliasElement,
- aliasArguments: aliasArguments,
+ alias: InstantiatedTypeAliasElementImpl(
+ element: aliasElement,
+ typeArguments: aliasArguments,
+ ),
);
} else if (type is InterfaceType) {
return InterfaceTypeImpl(
element: type.element,
typeArguments: type.typeArguments,
nullabilitySuffix: type.nullabilitySuffix,
- aliasElement: aliasElement,
- aliasArguments: aliasArguments,
+ alias: InstantiatedTypeAliasElementImpl(
+ element: aliasElement,
+ typeArguments: aliasArguments,
+ ),
);
} else if (type is TypeParameterType) {
return TypeParameterTypeImpl(
element: type.element,
nullabilitySuffix: type.nullabilitySuffix,
- aliasElement: aliasElement,
- aliasArguments: aliasArguments,
+ alias: InstantiatedTypeAliasElementImpl(
+ element: aliasElement,
+ typeArguments: aliasArguments,
+ ),
);
} else if (type is VoidType) {
// TODO(scheglov) add support for `void` aliasing
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index cb33459..35d4cce 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -707,10 +707,10 @@
}
void _writeTypeAliasElementArguments(DartType type) {
- var aliasElement = type.aliasElement;
- _writeElement(aliasElement);
- if (aliasElement != null) {
- _writeTypeList(type.aliasArguments!);
+ var alias = type.alias;
+ _writeElement(alias?.element);
+ if (alias != null) {
+ _writeTypeList(alias.typeArguments);
}
}
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index 3340f8a..12df589 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -117,10 +117,7 @@
unitElement: linkingUnit.element,
).buildDeclarationElementsMacro(linkingUnit.macroNode);
}
- if ('$uri' == 'dart:core') {
- localScope.declare('dynamic', reference.getChild('dynamic'));
- localScope.declare('Never', reference.getChild('Never'));
- }
+ _declareDartCoreDynamicNever();
}
void buildEnumChildren() {
@@ -202,6 +199,19 @@
}
}
+ /// These elements are implicitly declared in `dart:core`.
+ void _declareDartCoreDynamicNever() {
+ if (reference.name == 'dart:core') {
+ var dynamicRef = reference.getChild('dynamic');
+ dynamicRef.element = DynamicElementImpl.instance;
+ localScope.declare('dynamic', dynamicRef);
+
+ var neverRef = reference.getChild('Never');
+ neverRef.element = NeverElementImpl.instance;
+ localScope.declare('Never', neverRef);
+ }
+ }
+
static void build(Linker linker, LinkInputLibrary inputLibrary) {
var elementFactory = linker.elementFactory;
diff --git a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
index a449b97..e83e492 100644
--- a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
@@ -27,7 +27,6 @@
) {
ArgumentError.checkNotNull(analysisContext, 'analysisContext');
ArgumentError.checkNotNull(analysisSession, 'analysisSession');
- _declareDartCoreDynamicNever();
}
Reference get dynamicRef {
@@ -182,10 +181,22 @@
/// that the client can re-add the bundle, this time read from bytes.
void removeBundle(Set<String> uriStrSet) {
removeLibraries(uriStrSet);
+ }
- // This is the bundle with dart:core and dart:async, based on full ASTs.
- // To link them, the linker set the type provider. We are removing these
- // libraries, and we should also remove the type provider.
+ /// Remove libraries with the specified URIs from the reference tree, and
+ /// any session level caches.
+ void removeLibraries(Set<String> uriStrSet) {
+ for (var uriStr in uriStrSet) {
+ _exportsOfLibrary.remove(uriStr);
+ libraryReaders.remove(uriStr);
+ rootReference.removeChild(uriStr);
+ }
+
+ analysisSession.classHierarchy.removeOfLibraries(uriStrSet);
+ analysisSession.inheritanceManager.removeOfLibraries(uriStrSet);
+
+ // If we discard `dart:core` and `dart:async`, we should also discard
+ // the type provider.
if (uriStrSet.contains('dart:core')) {
if (!uriStrSet.contains('dart:async')) {
throw StateError(
@@ -200,23 +211,9 @@
);
}
analysisContext.clearTypeProvider();
- _declareDartCoreDynamicNever();
}
}
- /// Remove libraries with the specified URIs from the reference tree, and
- /// any session level caches.
- void removeLibraries(Set<String> uriStrSet) {
- for (var uriStr in uriStrSet) {
- _exportsOfLibrary.remove(uriStr);
- libraryReaders.remove(uriStr);
- rootReference.removeChild(uriStr);
- }
-
- analysisSession.classHierarchy.removeOfLibraries(uriStrSet);
- analysisSession.inheritanceManager.removeOfLibraries(uriStrSet);
- }
-
/// Set exports of the library with [uriStr], after building exports during
/// linking, or after reading a linked bundle.
void setExportsOfLibrary(String uriStr, List<Reference> exports) {
@@ -242,10 +239,4 @@
libraryElement.createLoadLibraryFunction();
}
-
- void _declareDartCoreDynamicNever() {
- var dartCoreRef = rootReference.getChild('dart:core');
- dartCoreRef.getChild('dynamic').element = DynamicElementImpl.instance;
- dartCoreRef.getChild('Never').element = NeverElementImpl.instance;
- }
}
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index d52b622..4afb0cc 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 2.0.0
+version: 2.1.0-dev
description: This package provides a library that performs static analysis of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
diff --git a/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart b/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart
index 632677a..ff5c8f9 100644
--- a/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart
+++ b/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart
@@ -2,6 +2,7 @@
// 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:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
@@ -155,13 +156,11 @@
nullabilitySuffix: NullabilitySuffix.none,
);
expect(_typeToString(input), 'int Function()');
- expect(input.aliasElement, same(A));
- expect(input.aliasArguments!.map(_typeToString).join(', '), 'int');
+ _assertInstantiatedAlias(input, A, 'int');
var result = NullabilityEliminator.perform(typeProvider, input);
expect(_typeToString(result), 'int* Function()*');
- expect(result.aliasElement, same(A));
- expect(result.aliasArguments!.map(_typeToString).join(', '), 'int*');
+ _assertInstantiatedAlias(result, A, 'int*');
}
test_functionType_typeParameters() {
@@ -278,8 +277,7 @@
var result = NullabilityEliminator.perform(typeProvider, input);
expect(_typeToString(result), 'List<int*>*');
- expect(result.aliasElement, same(A));
- expect(result.aliasArguments!.map(_typeToString).join(', '), 'int*');
+ _assertInstantiatedAlias(result, A, 'int*');
}
test_interfaceType_int() {
@@ -333,6 +331,13 @@
_verifySame(typeProvider.voidType);
}
+ void _assertInstantiatedAlias(
+ DartType type, Element aliasElement, String aliasArguments) {
+ var alias = type.alias!;
+ expect(alias.element, same(aliasElement));
+ expect(alias.typeArguments.map(_typeToString).join(', '), aliasArguments);
+ }
+
String _typeToString(DartType type) {
return type.getDisplayString(withNullability: true);
}
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index 93122d1..0944438 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -346,6 +346,29 @@
(fileResolver.byteStore as CiderCachedByteStore).testView!.length);
}
+ test_elements_export_dartCoreDynamic() async {
+ var a_path = convertPath('/workspace/dart/test/lib/a.dart');
+ newFile(a_path, content: r'''
+export 'dart:core' show dynamic;
+''');
+
+ // Analyze so that `dart:core` is linked.
+ var a_result = await resolveFile(a_path);
+
+ // Touch `dart:core` so that its element model is discarded.
+ var dartCorePath = a_result.session.uriConverter.uriToPath(
+ Uri.parse('dart:core'),
+ )!;
+ fileResolver.changeFile(dartCorePath);
+
+ // Analyze, this will read the element model for `dart:core`.
+ // There was a bug that `root::dart:core::dynamic` had no element set.
+ await assertNoErrorsInCode(r'''
+import 'a.dart' as p;
+p.dynamic f() {}
+''');
+ }
+
test_findReferences_class() async {
var aPath = convertPath('/workspace/dart/test/lib/a.dart');
newFile(aPath, content: r'''
@@ -1036,17 +1059,21 @@
newFile(path, content: 'var a = 0;');
// No resolved files yet.
- expect(fileResolver.testView!.resolvedFiles, isEmpty);
+ var testView = fileResolver.testView!;
+ expect(testView.resolvedFiles, isEmpty);
await resolveFile2(path);
var result1 = result;
// The file was resolved.
- expect(fileResolver.testView!.resolvedFiles, [path]);
+ expect(testView.resolvedFiles, [path]);
+
+ // The result is cached.
+ expect(fileResolver.cachedResults, contains(path));
// Ask again, no changes, not resolved.
await resolveFile2(path);
- expect(fileResolver.testView!.resolvedFiles, [path]);
+ expect(testView.resolvedFiles, [path]);
// The same result was returned.
expect(result, same(result1));
@@ -1057,12 +1084,41 @@
// The was a change to a file, no matter which, resolve again.
await resolveFile2(path);
- expect(fileResolver.testView!.resolvedFiles, [path, path]);
+ expect(testView.resolvedFiles, [path, path]);
// Get should get a new result.
expect(result, isNot(same(result1)));
}
+ test_resolveFile_dontCache_whenForCompletion() async {
+ var a_path = convertPath('/workspace/dart/test/lib/a.dart');
+ newFile(a_path, content: r'''
+part 'b.dart';
+''');
+
+ var b_path = convertPath('/workspace/dart/test/lib/b.dart');
+ newFile(b_path, content: r'''
+part of 'a.dart';
+''');
+
+ // No resolved files yet.
+ var testView = fileResolver.testView!;
+ expect(testView.resolvedFiles, isEmpty);
+
+ fileResolver.resolve(
+ path: b_path,
+ completionLine: 0,
+ completionColumn: 0,
+ );
+
+ // The file was resolved.
+ expect(testView.resolvedFiles, [a_path]);
+
+ // The completion location was set, so not units are resolved.
+ // So, the result should not be cached.
+ expect(fileResolver.cachedResults, isEmpty);
+ }
+
test_resolveLibrary() async {
var aPath = convertPath('/workspace/dart/test/lib/a.dart');
newFile(aPath, content: r'''
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 3b2f5a4..63a93db 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -754,8 +754,8 @@
required TypeAliasElement element,
required List<String> typeArguments,
}) {
- assertElement2(type.aliasElement, declaration: element);
- assertElementTypeStrings(type.aliasArguments, typeArguments);
+ assertElement2(type.alias?.element, declaration: element);
+ assertElementTypeStrings(type.alias?.typeArguments, typeArguments);
}
/// Assert that the given [identifier] is a reference to a type alias, in the
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 61f9169..982f6c8 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -758,15 +758,14 @@
_writelnWithIndent('$typeStr');
}
- var aliasElement = type.aliasElement;
- var aliasArguments = type.aliasArguments;
- if (aliasElement is TypeAliasElementImpl && aliasArguments != null) {
+ var alias = type.alias;
+ if (alias != null) {
_withIndent(() {
- _createAstPrinter().writeElement('aliasElement', aliasElement);
+ _createAstPrinter().writeElement('aliasElement', alias.element);
_writeElements<DartType>(
'aliasArguments',
- aliasArguments,
+ alias.typeArguments,
_writeType,
);
});
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index fe2372d..ae5fbb6 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -16762,8 +16762,8 @@
var unit = library.definingCompilationUnit;
var type = unit.topLevelVariables[0].type as FunctionType;
- expect(type.aliasElement, same(unit.typeAliases[0]));
- _assertTypeStrings(type.aliasArguments!, ['int']);
+ expect(type.alias!.element, same(unit.typeAliases[0]));
+ _assertTypeStrings(type.alias!.typeArguments, ['int']);
}
test_functionTypeAlias_typeParameters_variance_contravariant() async {
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index f6b890f..7d86a7f 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -1155,12 +1155,11 @@
return false;
}
- var aliasElement = type.aliasElement;
- var aliasArguments = type.aliasArguments;
- if (aliasElement != null && aliasArguments != null) {
+ var alias = type.alias;
+ if (alias != null) {
_writeTypeElementArguments(
- element: aliasElement,
- typeArguments: aliasArguments,
+ element: alias.element,
+ typeArguments: alias.typeArguments,
methodBeingCopied: methodBeingCopied,
);
_writeTypeNullability(type);
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 ae02cb6..e79afa3 100644
--- a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
@@ -7,6 +7,7 @@
import '../dill/dill_member_builder.dart';
import '../kernel/class_hierarchy_builder.dart';
+import '../kernel/constructor_tearoff_lowering.dart';
import '../kernel/forest.dart';
import '../kernel/internal_ast.dart';
import '../kernel/kernel_api.dart';
@@ -45,7 +46,8 @@
final bool isExtensionInstanceMember = false;
- late Procedure _procedureInternal;
+ final Procedure _procedureInternal;
+ final Procedure? _factoryTearOff;
SourceFactoryBuilder? actualOrigin;
@@ -65,19 +67,21 @@
AsyncMarker asyncModifier,
ProcedureNameScheme procedureNameScheme,
{String? nativeMethodName})
- : super(metadata, modifiers, returnType, name, typeVariables, formals,
+ : _procedureInternal = new Procedure(
+ procedureNameScheme.getName(ProcedureKind.Factory, name),
+ ProcedureKind.Factory,
+ new FunctionNode(null),
+ fileUri: libraryBuilder.fileUri,
+ reference: procedureReference)
+ ..startFileOffset = startCharOffset
+ ..fileOffset = charOffset
+ ..fileEndOffset = charEndOffset
+ ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault,
+ _factoryTearOff = createConstructorTearOffProcedure(
+ name, libraryBuilder, libraryBuilder.fileUri, charOffset,
+ forAbstractClassOrEnum: false),
+ super(metadata, modifiers, returnType, name, typeVariables, formals,
libraryBuilder, charOffset, nativeMethodName) {
- _procedureInternal = new Procedure(
- procedureNameScheme.getName(kind, name),
- isExtensionInstanceMember ? ProcedureKind.Method : kind,
- new FunctionNode(null),
- fileUri: libraryBuilder.fileUri,
- reference: procedureReference)
- ..startFileOffset = startCharOffset
- ..fileOffset = charOffset
- ..fileEndOffset = charEndOffset
- ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault;
-
this.asyncModifier = asyncModifier;
}
@@ -116,7 +120,7 @@
FunctionNode get function => _procedureInternal.function;
@override
- Member? get readTarget => _procedure;
+ Member? get readTarget => origin._factoryTearOff ?? _procedure;
@override
Member? get writeTarget => null;
@@ -132,6 +136,9 @@
SourceLibraryBuilder library, void Function(Member, BuiltMemberKind) f) {
Member member = build(library);
f(member, BuiltMemberKind.Method);
+ if (_factoryTearOff != null) {
+ f(_factoryTearOff!, BuiltMemberKind.Method);
+ }
}
@override
@@ -145,6 +152,11 @@
_procedureInternal.isConst = isConst;
updatePrivateMemberName(_procedureInternal, libraryBuilder);
_procedureInternal.isStatic = isStatic;
+
+ if (_factoryTearOff != null) {
+ buildConstructorTearOffProcedure(_factoryTearOff!, _procedureInternal,
+ classBuilder!.cls, libraryBuilder);
+ }
return _procedureInternal;
}
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 64c8403..d5c0140 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
@@ -38,14 +38,24 @@
}
/// Creates the parameters and body for [tearOff] based on [constructor].
-void buildConstructorTearOffProcedure(
- Procedure tearOff,
- Constructor constructor,
- Class enclosingClass,
- SourceLibraryBuilder libraryBuilder) {
+void buildConstructorTearOffProcedure(Procedure tearOff, Member constructor,
+ Class enclosingClass, SourceLibraryBuilder libraryBuilder) {
+ assert(constructor is Constructor ||
+ (constructor is Procedure && constructor.kind == ProcedureKind.Factory));
+
int fileOffset = tearOff.fileOffset;
- List<TypeParameter> classTypeParameters = enclosingClass.typeParameters;
+ FunctionNode function = constructor.function!;
+ List<TypeParameter> classTypeParameters;
+ if (constructor is Constructor) {
+ // Generative constructors implicitly have the type parameters of the
+ // enclosing class.
+ classTypeParameters = enclosingClass.typeParameters;
+ } else {
+ // Factory constructors explicitly copy over the type parameters of the
+ // enclosing class.
+ classTypeParameters = function.typeParameters;
+ }
List<TypeParameter> typeParameters;
List<DartType> typeArguments;
@@ -66,7 +76,7 @@
List<Expression> positionalArguments = [];
for (VariableDeclaration constructorParameter
- in constructor.function.positionalParameters) {
+ in function.positionalParameters) {
VariableDeclaration tearOffParameter = new VariableDeclaration(
constructorParameter.name,
type: substitution.substituteType(constructorParameter.type))
@@ -77,8 +87,7 @@
tearOffParameter.parent = tearOff.function;
}
List<NamedExpression> namedArguments = [];
- for (VariableDeclaration constructorParameter
- in constructor.function.namedParameters) {
+ for (VariableDeclaration constructorParameter in function.namedParameters) {
VariableDeclaration tearOffParameter = new VariableDeclaration(
constructorParameter.name,
type: substitution.substituteType(constructorParameter.type),
@@ -91,16 +100,22 @@
..fileOffset = fileOffset);
}
tearOff.function.returnType =
- substitution.substituteType(constructor.function.returnType);
- tearOff.function.requiredParameterCount =
- constructor.function.requiredParameterCount;
- tearOff.function.body = new ReturnStatement(
- new ConstructorInvocation(
- constructor,
- new Arguments(positionalArguments,
- named: namedArguments, types: typeArguments)
- ..fileOffset = tearOff.fileOffset)
- ..fileOffset = tearOff.fileOffset)
+ substitution.substituteType(function.returnType);
+ tearOff.function.requiredParameterCount = function.requiredParameterCount;
+
+ Arguments arguments = new Arguments(positionalArguments,
+ named: namedArguments, types: typeArguments)
+ ..fileOffset = tearOff.fileOffset;
+ Expression constructorInvocation;
+ if (constructor is Constructor) {
+ constructorInvocation = new ConstructorInvocation(constructor, arguments)
+ ..fileOffset = tearOff.fileOffset;
+ } else {
+ constructorInvocation =
+ new StaticInvocation(constructor as Procedure, arguments)
+ ..fileOffset = tearOff.fileOffset;
+ }
+ tearOff.function.body = new ReturnStatement(constructorInvocation)
..fileOffset = tearOff.fileOffset
..parent = tearOff.function;
tearOff.function.fileOffset = tearOff.fileOffset;
@@ -112,7 +127,6 @@
///
/// These might have been inferred and therefore not available when the
/// parameters were created.
-// TODO(johnniwinther): Add tests for inferred parameter types.
// TODO(johnniwinther): Avoid doing this when parameter types are not inferred.
void buildConstructorTearOffOutline(
Procedure tearOff, Constructor constructor, Class enclosingClass) {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart
new file mode 100644
index 0000000..9c6ef02
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/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() => new Class1._();
+}
+
+class Class2 {
+ Class2._();
+ factory Class2.named() => new 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) => new Class3._(field);
+}
+
+class Class4 {
+ final int? field;
+
+ Class4._([this.field]);
+ factory Class4([int? field]) => new Class4._(field);
+}
+
+class Class5 {
+ final int field1;
+ final int? field2;
+
+ Class5._(this.field1, [this.field2]);
+ factory Class5(int field1, [int? field2]) => new Class5._(field1, field2);
+}
+
+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}) =>
+ new Class6._(field1, field2: field2, field3: field3);
+}
+
+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/factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
new file mode 100644
index 0000000..aa4165c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
@@ -0,0 +1,254 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// f3a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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/factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// f5a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// f6a(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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 {
+ constructor _() → self::Class1
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ return new self::Class1::_();
+ static method _#new#tearOff() → self::Class1
+ return self::Class1::•();
+}
+class Class2 extends core::Object {
+ constructor _() → self::Class2
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ return new self::Class2::_();
+ static method _#named#tearOff() → self::Class2
+ return self::Class2::named();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ 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
+ return new self::Class3::_(field);
+ static method _#new#tearOff(core::int field) → self::Class3
+ return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ 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
+ return new self::Class4::_(field);
+ static method _#new#tearOff([core::int? field]) → self::Class4
+ return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ 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
+ return new self::Class5::_(field1, field2);
+ static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ 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
+ 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
+ return 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/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/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/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/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/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/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/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/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/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 = tearoff self::Class1::_#new#tearOff
+ #C3 = tearoff self::Class2::_#named#tearOff
+ #C4 = tearoff self::Class3::_#new#tearOff
+ #C5 = tearoff self::Class4::_#new#tearOff
+ #C6 = tearoff self::Class5::_#new#tearOff
+ #C7 = tearoff self::Class6::_#new#tearOff
+ #C8 = false
+}
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
new file mode 100644
index 0000000..3a8fa1a
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,254 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// f3a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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/factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// f5a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// f6a(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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 {
+ constructor _() → self::Class1
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ return new self::Class1::_();
+ static method _#new#tearOff() → self::Class1
+ return self::Class1::•();
+}
+class Class2 extends core::Object {
+ constructor _() → self::Class2
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ return new self::Class2::_();
+ static method _#named#tearOff() → self::Class2
+ return self::Class2::named();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ 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
+ return new self::Class3::_(field);
+ static method _#new#tearOff(core::int field) → self::Class3
+ return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ 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
+ return new self::Class4::_(field);
+ static method _#new#tearOff([core::int? field]) → self::Class4
+ return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ 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
+ return new self::Class5::_(field1, field2);
+ static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ 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
+ 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
+ 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>);
+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/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/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/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/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/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/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/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/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/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 = tearoff self::Class1::_#new#tearOff
+ #C3 = tearoff self::Class2::_#named#tearOff
+ #C4 = tearoff self::Class3::_#new#tearOff
+ #C5 = tearoff self::Class4::_#new#tearOff
+ #C6 = tearoff self::Class5::_#new#tearOff
+ #C7 = tearoff self::Class6::_#new#tearOff
+ #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..e4d0e54
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline.expect
@@ -0,0 +1,46 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+ Class1._();
+ factory Class1() => new Class1._();
+}
+
+class Class2 {
+ Class2._();
+ factory Class2.named() => new Class2._();
+}
+
+testNoArgs() {}
+
+class Class3 {
+ final int field;
+ Class3._(this.field);
+ factory Class3(int field) => new Class3._(field);
+}
+
+class Class4 {
+ final int? field;
+ Class4._([this.field]);
+ factory Class4([int? field]) => new Class4._(field);
+}
+
+class Class5 {
+ final int field1;
+ final int? field2;
+ Class5._(this.field1, [this.field2]);
+ factory Class5(int field1, [int? field2]) => new Class5._(field1, field2);
+}
+
+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}) =>
+ new Class6._(field1, field2: field2, field3: field3);
+}
+
+testArgs() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..0e60ce8
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,44 @@
+class Class1 {
+ Class1._();
+ factory Class1() => new Class1._();
+}
+
+class Class2 {
+ Class2._();
+ factory Class2.named() => new Class2._();
+}
+
+class Class3 {
+ Class3._(this.field);
+ factory Class3(int field) => new Class3._(field);
+ final int field;
+}
+
+class Class4 {
+ Class4._([this.field]);
+ factory Class4([int? field]) => new Class4._(field);
+ final int? field;
+}
+
+class Class5 {
+ Class5._(this.field1, [this.field2]);
+ factory Class5(int field1, [int? field2]) => new Class5._(field1, field2);
+ 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}) =>
+ new Class6._(field1, field2: field2, field3: field3);
+ 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/factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
new file mode 100644
index 0000000..aa4165c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
@@ -0,0 +1,254 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// f3a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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/factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// f5a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// f6a(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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 {
+ constructor _() → self::Class1
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ return new self::Class1::_();
+ static method _#new#tearOff() → self::Class1
+ return self::Class1::•();
+}
+class Class2 extends core::Object {
+ constructor _() → self::Class2
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ return new self::Class2::_();
+ static method _#named#tearOff() → self::Class2
+ return self::Class2::named();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ 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
+ return new self::Class3::_(field);
+ static method _#new#tearOff(core::int field) → self::Class3
+ return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ 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
+ return new self::Class4::_(field);
+ static method _#new#tearOff([core::int? field]) → self::Class4
+ return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ 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
+ return new self::Class5::_(field1, field2);
+ static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ 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
+ 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
+ return 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/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/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/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/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/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/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/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/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/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 = tearoff self::Class1::_#new#tearOff
+ #C3 = tearoff self::Class2::_#named#tearOff
+ #C4 = tearoff self::Class3::_#new#tearOff
+ #C5 = tearoff self::Class4::_#new#tearOff
+ #C6 = tearoff self::Class5::_#new#tearOff
+ #C7 = tearoff self::Class6::_#new#tearOff
+ #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..5366579f
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.outline.expect
@@ -0,0 +1,82 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ constructor _() → self::Class1
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ ;
+ static method _#new#tearOff() → self::Class1
+ return self::Class1::•();
+}
+class Class2 extends core::Object {
+ constructor _() → self::Class2
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ ;
+ static method _#named#tearOff() → self::Class2
+ return self::Class2::named();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ 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
+ ;
+ static method _#new#tearOff(core::int field) → self::Class3
+ return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ 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
+ ;
+ static method _#new#tearOff([core::int? field]) → self::Class4
+ return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ 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
+ ;
+ static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ 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
+ ;
+ static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+ return 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/factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..3a8fa1a
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,254 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// f3a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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/factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// f5a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// f6a(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// f6a(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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 {
+ constructor _() → self::Class1
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class1
+ return new self::Class1::_();
+ static factory •() → self::Class1
+ return new self::Class1::_();
+ static method _#new#tearOff() → self::Class1
+ return self::Class1::•();
+}
+class Class2 extends core::Object {
+ constructor _() → self::Class2
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class2
+ return new self::Class2::_();
+ static factory named() → self::Class2
+ return new self::Class2::_();
+ static method _#named#tearOff() → self::Class2
+ return self::Class2::named();
+}
+class Class3 extends core::Object {
+ final field core::int field;
+ 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
+ return new self::Class3::_(field);
+ static method _#new#tearOff(core::int field) → self::Class3
+ return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+ final field core::int? field;
+ 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
+ return new self::Class4::_(field);
+ static method _#new#tearOff([core::int? field]) → self::Class4
+ return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ 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
+ return new self::Class5::_(field1, field2);
+ static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+ return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+ final field core::int field1;
+ final field core::int? field2;
+ final field core::int field3;
+ 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
+ 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
+ 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>);
+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/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/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/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/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/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/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/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/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/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 = tearoff self::Class1::_#new#tearOff
+ #C3 = tearoff self::Class2::_#named#tearOff
+ #C4 = tearoff self::Class3::_#new#tearOff
+ #C5 = tearoff self::Class4::_#new#tearOff
+ #C6 = tearoff self::Class5::_#new#tearOff
+ #C7 = tearoff self::Class6::_#new#tearOff
+ #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart
new file mode 100644
index 0000000..a8d167a
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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() => new 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() => new Class2<T>._();
+}
+
+class Class3<T extends S, S> {
+ Class3._();
+ factory Class3() => new Class3<T, S>._();
+}
+
+class Class4<T extends Class4<T>> {
+ Class4._();
+ factory Class4() => new Class4<T>._();
+}
+
+class Class4int extends Class4<Class4int> {
+ Class4int._() : super._();
+ factory Class4int() => new 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_factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.expect
new file mode 100644
index 0000000..7dc5b5e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.expect
@@ -0,0 +1,200 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+// f1a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+// f1b<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+// f2a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_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_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 {
+ 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%>
+ return new self::Class1::_<self::Class1::•::T%>();
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ 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>
+ return new self::Class2::_<self::Class2::•::T>();
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ 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%>
+ return new self::Class3::_<self::Class3::•::T%, self::Class3::•::S%>();
+ 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 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 {
+ 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>
+ return new self::Class4::_<self::Class4::•::T>();
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ constructor _() → self::Class4int
+ : super self::Class4::_()
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ return new self::Class4int::_();
+ static method _#new#tearOff() → self::Class4int
+ return 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_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_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_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 = tearoff self::Class1::_#new#tearOff
+ #C2 = tearoff self::Class2::_#new#tearOff
+ #C3 = tearoff self::Class3::_#new#tearOff
+ #C4 = tearoff self::Class4::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.transformed.expect
new file mode 100644
index 0000000..867fcb1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,200 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+// f1a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+// f1b<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+// f2a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_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_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 {
+ 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%>
+ return new self::Class1::_<self::Class1::•::T%>();
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ 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>
+ return new self::Class2::_<self::Class2::•::T>();
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ 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%>
+ return new self::Class3::_<self::Class3::•::T%, self::Class3::•::S%>();
+ 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 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 {
+ 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>
+ return new self::Class4::_<self::Class4::•::T>();
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ constructor _() → self::Class4int
+ : super self::Class4::_()
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ return new self::Class4int::_();
+ static method _#new#tearOff() → self::Class4int
+ return 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_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_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_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 = tearoff self::Class1::_#new#tearOff
+ #C2 = tearoff self::Class2::_#new#tearOff
+ #C3 = tearoff self::Class3::_#new#tearOff
+ #C4 = tearoff self::Class4::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..b692fbf
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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() => new Class1<T>._();
+}
+
+testGeneric() {}
+
+class Class2<T extends num> {
+ Class2._();
+ factory Class2() => new Class2<T>._();
+}
+
+class Class3<T extends S, S> {
+ Class3._();
+ factory Class3() => new Class3<T, S>._();
+}
+
+class Class4<T extends Class4<T>> {
+ Class4._();
+ factory Class4() => new Class4<T>._();
+}
+
+class Class4int extends Class4<Class4int> {
+ Class4int._() : super._();
+ factory Class4int() => new Class4int._();
+}
+
+testBounded() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..c82d489
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,31 @@
+class Class1<T> {
+ Class1._();
+ factory Class1() => new Class1<T>._();
+}
+
+class Class2<T extends num> {
+ Class2._();
+ factory Class2() => new Class2<T>._();
+}
+
+class Class3<T extends S, S> {
+ Class3._();
+ factory Class3() => new Class3<T, S>._();
+}
+
+class Class4<T extends Class4<T>> {
+ Class4._();
+ factory Class4() => new Class4<T>._();
+}
+
+class Class4int extends Class4<Class4int> {
+ Class4int._() : super._();
+ factory Class4int() => new 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_factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.expect
new file mode 100644
index 0000000..7dc5b5e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.expect
@@ -0,0 +1,200 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+// f1a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+// f1b<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+// f2a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_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_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 {
+ 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%>
+ return new self::Class1::_<self::Class1::•::T%>();
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ 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>
+ return new self::Class2::_<self::Class2::•::T>();
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ 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%>
+ return new self::Class3::_<self::Class3::•::T%, self::Class3::•::S%>();
+ 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 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 {
+ 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>
+ return new self::Class4::_<self::Class4::•::T>();
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ constructor _() → self::Class4int
+ : super self::Class4::_()
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ return new self::Class4int::_();
+ static method _#new#tearOff() → self::Class4int
+ return 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_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_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_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 = tearoff self::Class1::_#new#tearOff
+ #C2 = tearoff self::Class2::_#new#tearOff
+ #C3 = tearoff self::Class3::_#new#tearOff
+ #C4 = tearoff self::Class4::_#new#tearOff
+ #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..6216fd6
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.outline.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+ 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%>
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ 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>
+ ;
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ 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%>
+ ;
+ 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 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 {
+ 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>
+ ;
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ constructor _() → self::Class4int
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ ;
+ static method _#new#tearOff() → self::Class4int
+ return 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_factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..867fcb1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,200 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+// f1a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+// f1b<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+// f2a<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_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_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 {
+ 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%>
+ return new self::Class1::_<self::Class1::•::T%>();
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+ return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+ 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>
+ return new self::Class2::_<self::Class2::•::T>();
+ static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+ return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+ 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%>
+ return new self::Class3::_<self::Class3::•::T%, self::Class3::•::S%>();
+ 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 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 {
+ 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>
+ return new self::Class4::_<self::Class4::•::T>();
+ static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+ return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+ constructor _() → self::Class4int
+ : super self::Class4::_()
+ ;
+ static method _#_#tearOff() → self::Class4int
+ return new self::Class4int::_();
+ static factory •() → self::Class4int
+ return new self::Class4int::_();
+ static method _#new#tearOff() → self::Class4int
+ return 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_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_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_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 = tearoff self::Class1::_#new#tearOff
+ #C2 = tearoff self::Class2::_#new#tearOff
+ #C3 = tearoff self::Class3::_#new#tearOff
+ #C4 = tearoff self::Class4::_#new#tearOff
+ #C5 = false
+}
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 4590a76..d307442 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -196,6 +196,8 @@
SampleBlockBuffer::~SampleBlockBuffer() {
delete[] blocks_;
blocks_ = nullptr;
+ delete memory_;
+ memory_ = nullptr;
capacity_ = 0;
cursor_ = 0;
}
@@ -345,6 +347,11 @@
cursor_ = 0;
}
+AllocationSampleBuffer::~AllocationSampleBuffer() {
+ delete memory_;
+ memory_ = nullptr;
+}
+
void AllocationSampleBuffer::FreeAllocationSample(Sample* sample) {
MutexLocker ml(&mutex_);
while (sample != nullptr) {
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index a4adbff4..dd30bcc 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -870,7 +870,7 @@
class AllocationSampleBuffer : public SampleBuffer {
public:
explicit AllocationSampleBuffer(intptr_t capacity = 60000);
- virtual ~AllocationSampleBuffer() = default;
+ virtual ~AllocationSampleBuffer();
virtual Sample* ReserveSample();
virtual Sample* ReserveSampleAndLink(Sample* previous);
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
index 54576b0..33854c7 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
@@ -85,10 +85,14 @@
gbind(f, @rest List<Object> typeArgs) {
GenericFunctionType type = JS('!', '#[#]', f, _runtimeType);
type.checkBounds(typeArgs);
- // Create a JS wrapper function that will also pass the type arguments, and
- // tag it with the instantiated function type.
+ // Create a JS wrapper function that will also pass the type arguments.
var result =
JS('', '(...args) => #.apply(null, #.concat(args))', f, typeArgs);
+ // Tag the wrapper with the original function to be used for equality checks.
+ JS('', '#["_originalFn"] = #', result, f);
+ JS('', '#["_typeArgs"] = #', result, constList(typeArgs, Object));
+
+ // Tag the wrapper with the instantiated function type.
return fn(result, type.instantiate(typeArgs));
}
diff --git a/tests/language/closure/regress46568_test.dart b/tests/language/closure/regress46568_test.dart
new file mode 100644
index 0000000..33e34b6
--- /dev/null
+++ b/tests/language/closure/regress46568_test.dart
@@ -0,0 +1,40 @@
+// 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.
+
+import 'package:expect/expect.dart';
+
+// Regression test for https://github.com/dart-lang/sdk/issues/46568.
+
+var genericTopLevelFunctionCallCount = 0;
+var genericStaticMethodCallCount = 0;
+
+T? genericTopLevelFunction<T>() {
+ genericTopLevelFunctionCallCount++;
+ return null;
+}
+
+class A {
+ static T? genericStaticMethod<T>() {
+ genericStaticMethodCallCount++;
+ return null;
+ }
+}
+
+const int? Function() cIntTopLevelFunction1 = genericTopLevelFunction;
+const int? Function() cIntStaticMethod1 = A.genericStaticMethod;
+
+void main() {
+ // Two different const generic function instantiations should not be
+ // canonicalized to the same value.
+ Expect.isFalse(identical(cIntTopLevelFunction1, cIntStaticMethod1));
+ Expect.notEquals(cIntTopLevelFunction1, cIntStaticMethod1);
+
+ cIntTopLevelFunction1();
+ Expect.equals(1, genericTopLevelFunctionCallCount);
+ Expect.equals(0, genericStaticMethodCallCount);
+
+ cIntStaticMethod1();
+ Expect.equals(1, genericTopLevelFunctionCallCount);
+ Expect.equals(1, genericStaticMethodCallCount);
+}
diff --git a/tests/language_2/closure/regress46568_test.dart b/tests/language_2/closure/regress46568_test.dart
new file mode 100644
index 0000000..1117775
--- /dev/null
+++ b/tests/language_2/closure/regress46568_test.dart
@@ -0,0 +1,42 @@
+// 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.
+
+// @dart = 2.9
+
+import 'package:expect/expect.dart';
+
+// Regression test for https://github.com/dart-lang/sdk/issues/46568.
+
+var genericTopLevelFunctionCallCount = 0;
+var genericStaticMethodCallCount = 0;
+
+T genericTopLevelFunction<T>() {
+ genericTopLevelFunctionCallCount++;
+ return null;
+}
+
+class A {
+ static T genericStaticMethod<T>() {
+ genericStaticMethodCallCount++;
+ return null;
+ }
+}
+
+const int Function() cIntTopLevelFunction1 = genericTopLevelFunction;
+const int Function() cIntStaticMethod1 = A.genericStaticMethod;
+
+void main() {
+ // Two different const generic function instantiations should not be
+ // canonicalized to the same value.
+ Expect.isFalse(identical(cIntTopLevelFunction1, cIntStaticMethod1));
+ Expect.notEquals(cIntTopLevelFunction1, cIntStaticMethod1);
+
+ cIntTopLevelFunction1();
+ Expect.equals(1, genericTopLevelFunctionCallCount);
+ Expect.equals(0, genericStaticMethodCallCount);
+
+ cIntStaticMethod1();
+ Expect.equals(1, genericTopLevelFunctionCallCount);
+ Expect.equals(1, genericStaticMethodCallCount);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 21e7eeb..b0a5cb0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 335
+PRERELEASE 336
PRERELEASE_PATCH 0
\ No newline at end of file