Skip to content

Commit 3ce1969

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Implement inference via type aliases with aliased InterfaceType.
Change-Id: I1d2bba09f19468bc8e095c5ef4a39c09365eb2a4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193450 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent e97f1bd commit 3ce1969

File tree

7 files changed

+399
-51
lines changed

7 files changed

+399
-51
lines changed

pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,50 @@ import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
66
import 'package:analyzer/dart/analysis/features.dart';
77
import 'package:analyzer/dart/ast/ast.dart';
88
import 'package:analyzer/dart/element/element.dart';
9+
import 'package:analyzer/dart/element/nullability_suffix.dart';
910
import 'package:analyzer/dart/element/type.dart';
1011
import 'package:analyzer/error/listener.dart';
1112
import 'package:analyzer/src/dart/ast/ast.dart';
1213
import 'package:analyzer/src/dart/ast/extensions.dart';
14+
import 'package:analyzer/src/dart/element/member.dart';
1315
import 'package:analyzer/src/dart/element/type.dart';
1416
import 'package:analyzer/src/dart/element/type_algebra.dart';
1517
import 'package:analyzer/src/dart/element/type_system.dart';
1618
import 'package:analyzer/src/error/codes.dart';
1719
import 'package:analyzer/src/generated/migration.dart';
1820
import 'package:analyzer/src/generated/resolver.dart';
1921

22+
/// Information about a constructor element to instantiate.
23+
///
24+
/// If the target is a [ClassElement], the [element] is a raw
25+
/// [ConstructorElement] from the class, and [typeParameters] are the
26+
/// type parameters of the class.
27+
///
28+
/// If the target is a [TypeAliasElement] with an [InterfaceType] as the
29+
/// aliased type, the [element] is a [ConstructorMember] created from the
30+
/// [ConstructorElement] of the corresponding class, and substituting
31+
/// the class type parameters with the type arguments specified in the alias,
32+
/// explicit types or the type parameters of the alias. The [typeParameters]
33+
/// are the type parameters of the alias.
34+
class ConstructorElementToInfer {
35+
/// The type parameters used in [element].
36+
final List<TypeParameterElement> typeParameters;
37+
38+
/// The element, might be [ConstructorMember].
39+
final ConstructorElement element;
40+
41+
ConstructorElementToInfer(this.typeParameters, this.element);
42+
43+
FunctionType get asType {
44+
return FunctionTypeImpl(
45+
typeFormals: typeParameters,
46+
parameters: element.parameters,
47+
returnType: element.returnType,
48+
nullabilitySuffix: NullabilitySuffix.star,
49+
);
50+
}
51+
}
52+
2053
class InvocationInferenceHelper {
2154
final ResolverVisitor _resolver;
2255
final ErrorReporter _errorReporter;
@@ -49,6 +82,50 @@ class InvocationInferenceHelper {
4982
}
5083
}
5184

85+
/// If the constructor referenced by the [constructorName] is generic,
86+
/// and the [constructorName] does not have explicit type arguments,
87+
/// return the element and type parameters to infer. Otherwise return `null`.
88+
ConstructorElementToInfer? constructorElementToInfer({
89+
required ConstructorName constructorName,
90+
required LibraryElement definingLibrary,
91+
}) {
92+
List<TypeParameterElement>? typeParameters;
93+
ConstructorElement? rawElement;
94+
95+
var typeName = constructorName.type;
96+
var typeArguments = typeName.typeArguments;
97+
var typeElement = typeName.name.staticElement;
98+
if (typeElement is ClassElement) {
99+
typeParameters = typeElement.typeParameters;
100+
if (typeParameters.isNotEmpty && typeArguments == null) {
101+
var constructorIdentifier = constructorName.name;
102+
if (constructorIdentifier == null) {
103+
rawElement = typeElement.unnamedConstructor;
104+
} else {
105+
var name = constructorIdentifier.name;
106+
rawElement = typeElement.getNamedConstructor(name);
107+
}
108+
}
109+
} else if (typeElement is TypeAliasElement) {
110+
typeParameters = typeElement.typeParameters;
111+
var aliasedType = typeElement.aliasedType;
112+
if (aliasedType is InterfaceType) {
113+
if (typeParameters.isNotEmpty && typeArguments == null) {
114+
var constructorIdentifier = constructorName.name;
115+
rawElement = aliasedType.lookUpConstructor(
116+
constructorIdentifier?.name,
117+
definingLibrary,
118+
);
119+
}
120+
}
121+
}
122+
123+
if (typeParameters != null && rawElement != null) {
124+
rawElement = _resolver.toLegacyElement(rawElement);
125+
return ConstructorElementToInfer(typeParameters, rawElement);
126+
}
127+
}
128+
52129
FunctionType? inferArgumentTypesForGeneric(AstNode inferenceNode,
53130
DartType? uninstantiatedType, TypeArgumentList? typeArguments,
54131
{AstNode? errorNode, bool isConst = false}) {

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2258,22 +2258,24 @@ class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers {
22582258

22592259
void _inferArgumentTypesForInstanceCreate(
22602260
covariant InstanceCreationExpressionImpl node) {
2261-
var constructor = node.constructorName;
2262-
TypeName classTypeName = constructor.type;
2263-
// if (classTypeName == null) {
2264-
// return;
2265-
// }
2261+
var constructorName = node.constructorName;
2262+
2263+
var typeName = constructorName.type;
2264+
var typeArguments = typeName.typeArguments;
2265+
2266+
var elementToInfer = inferenceHelper.constructorElementToInfer(
2267+
constructorName: constructorName,
2268+
definingLibrary: definingLibrary,
2269+
);
22662270

2267-
var originalElement = constructor.staticElement;
22682271
FunctionType? inferred;
22692272
// If the constructor is generic, we'll have a ConstructorMember that
22702273
// substitutes in type arguments (possibly `dynamic`) from earlier in
22712274
// resolution.
22722275
//
22732276
// Otherwise we'll have a ConstructorElement, and we can skip inference
22742277
// because there's nothing to infer in a non-generic type.
2275-
if (classTypeName.typeArguments == null &&
2276-
originalElement is ConstructorMember) {
2278+
if (elementToInfer != null) {
22772279
// TODO(leafp): Currently, we may re-infer types here, since we
22782280
// sometimes resolve multiple times. We should really check that we
22792281
// have not already inferred something. However, the obvious ways to
@@ -2284,14 +2286,11 @@ class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers {
22842286
// Get back to the uninstantiated generic constructor.
22852287
// TODO(jmesserly): should we store this earlier in resolution?
22862288
// Or look it up, instead of jumping backwards through the Member?
2287-
var rawElement = originalElement.declaration;
2288-
rawElement = toLegacyElement(rawElement);
2289-
2290-
FunctionType constructorType =
2291-
typeAnalyzer.constructorToGenericFunctionType(rawElement);
2289+
var rawElement = elementToInfer.element;
2290+
var constructorType = elementToInfer.asType;
22922291

22932292
inferred = inferenceHelper.inferArgumentTypesForGeneric(
2294-
node, constructorType, constructor.type.typeArguments,
2293+
node, constructorType, typeArguments,
22952294
isConst: node.isConst, errorNode: node.constructorName);
22962295

22972296
if (inferred != null) {
@@ -2301,23 +2300,25 @@ class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers {
23012300
arguments.correspondingStaticParameters =
23022301
resolveArgumentsToParameters(arguments, inferred.parameters, null);
23032302

2304-
constructor.type.type = inferred.returnType;
2303+
constructorName.type.type = inferred.returnType;
23052304

23062305
// Update the static element as well. This is used in some cases, such
23072306
// as computing constant values. It is stored in two places.
23082307
var constructorElement = ConstructorMember.from(
23092308
rawElement,
23102309
inferred.returnType as InterfaceType,
23112310
);
2312-
constructorElement = toLegacyElement(constructorElement);
2313-
constructor.staticElement = constructorElement;
2311+
constructorName.staticElement = constructorElement;
23142312
}
23152313
}
23162314

23172315
if (inferred == null) {
2318-
var type = originalElement?.type;
2319-
type = type != null ? toLegacyTypeIfOptOut(type) as FunctionType : null;
2320-
InferenceContext.setType(node.argumentList, type);
2316+
var constructorElement = constructorName.staticElement;
2317+
if (constructorElement != null) {
2318+
var type = constructorElement.type;
2319+
type = toLegacyTypeIfOptOut(type) as FunctionType;
2320+
InferenceContext.setType(node.argumentList, type);
2321+
}
23212322
}
23222323
}
23232324

pkg/analyzer/lib/src/generated/static_type_analyzer.dart

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -362,18 +362,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
362362
/// Given an instance creation of a possibly generic type, infer the type
363363
/// arguments using the current context type as well as the argument types.
364364
void _inferInstanceCreationExpression(InstanceCreationExpressionImpl node) {
365-
var constructor = node.constructorName;
366-
var originalElement = constructor.staticElement;
367-
// If the constructor is generic, we'll have a ConstructorMember that
368-
// substitutes in type arguments (possibly `dynamic`) from earlier in
369-
// resolution.
370-
//
371-
// Otherwise we'll have a ConstructorElement, and we can skip inference
372-
// because there's nothing to infer in a non-generic type.
373-
if (originalElement is! ConstructorMember) {
374-
return;
375-
}
376-
377365
// TODO(leafp): Currently, we may re-infer types here, since we
378366
// sometimes resolve multiple times. We should really check that we
379367
// have not already inferred something. However, the obvious ways to
@@ -384,35 +372,39 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
384372
// Get back to the uninstantiated generic constructor.
385373
// TODO(jmesserly): should we store this earlier in resolution?
386374
// Or look it up, instead of jumping backwards through the Member?
387-
var rawElement = originalElement.declaration;
388-
rawElement = _resolver.toLegacyElement(rawElement);
375+
var constructorName = node.constructorName;
376+
var elementToInfer = _resolver.inferenceHelper.constructorElementToInfer(
377+
constructorName: constructorName,
378+
definingLibrary: _resolver.definingLibrary,
379+
);
380+
381+
// If the constructor is not generic, we are done.
382+
if (elementToInfer == null) {
383+
return;
384+
}
389385

390-
FunctionType constructorType = constructorToGenericFunctionType(rawElement);
386+
var typeName = constructorName.type;
387+
var typeArguments = typeName.typeArguments;
391388

389+
var constructorType = elementToInfer.asType;
392390
var arguments = node.argumentList;
393391
var inferred = _resolver.inferenceHelper.inferGenericInvoke(
394-
node,
395-
constructorType,
396-
constructor.type.typeArguments,
397-
arguments,
398-
node.constructorName,
392+
node, constructorType, typeArguments, arguments, constructorName,
399393
isConst: node.isConst);
400394

401-
if (inferred != null && inferred != originalElement.type) {
402-
inferred = _resolver.toLegacyTypeIfOptOut(inferred) as FunctionType;
395+
if (inferred != null) {
403396
// Fix up the parameter elements based on inferred method.
404397
arguments.correspondingStaticParameters =
405398
ResolverVisitor.resolveArgumentsToParameters(
406399
arguments, inferred.parameters, null);
407-
constructor.type.type = inferred.returnType;
400+
typeName.type = inferred.returnType;
408401
// Update the static element as well. This is used in some cases, such as
409402
// computing constant values. It is stored in two places.
410403
var constructorElement = ConstructorMember.from(
411-
rawElement,
404+
elementToInfer.element,
412405
inferred.returnType as InterfaceType,
413406
);
414-
constructorElement = _resolver.toLegacyElement(constructorElement);
415-
constructor.staticElement = constructorElement;
407+
constructorName.staticElement = constructorElement;
416408
}
417409
}
418410
}

0 commit comments

Comments
 (0)