Skip to content

Commit a4afb06

Browse files
srawlinscommit-bot@chromium.org
authored andcommitted
Move InstanceCreationExpression resolution to a separate class.
This resolver may need to rewrite the AST if the TypeName resolves to be a function reference or a constructor reference with type-instantiation. Bug: #46020 #46721 Change-Id: Ie6a9aa3c04d739becc0c902c117a7151f9c1fcf1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/208540 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 5896978 commit a4afb06

File tree

2 files changed

+160
-77
lines changed

2 files changed

+160
-77
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analyzer/dart/ast/ast.dart';
6+
import 'package:analyzer/dart/element/type.dart';
7+
import 'package:analyzer/src/dart/ast/ast.dart';
8+
import 'package:analyzer/src/dart/element/member.dart';
9+
import 'package:analyzer/src/generated/resolver.dart';
10+
11+
/// A resolver for [InstanceCreationExpression] nodes.
12+
///
13+
/// This resolver is responsible for rewriting a given
14+
/// [InstanceCreationExpression] as a [MethodInvocation] if the parsed
15+
/// [ConstructorName]'s `type` resolves to a [FunctionReference] or
16+
/// [ConstructorReference], instead of a [TypeName].
17+
class InstanceCreationExpressionResolver {
18+
/// The resolver driving this participant.
19+
final ResolverVisitor _resolver;
20+
21+
InstanceCreationExpressionResolver(this._resolver);
22+
23+
void resolve(InstanceCreationExpressionImpl node) {
24+
// The parser can parse certain code as [InstanceCreationExpression] when it
25+
// might be an invocation of a method on a [FunctionReference] or
26+
// [ConstructorReference]. In such a case, it is this resolver's
27+
// responsibility to rewrite. For example, given:
28+
//
29+
// a.m<int>.apply();
30+
//
31+
// the parser will give an InstanceCreationExpression (`a.m<int>.apply()`)
32+
// with a name of `a.m<int>.apply` (ConstructorName) with a type of
33+
// `a.m<int>` (TypeName with a name of `a.m` (PrefixedIdentifier) and
34+
// typeArguments of `<int>`) and a name of `apply` (SimpleIdentifier). If
35+
// `a.m<int>` is actually a function reference, then the
36+
// InstanceCreationExpression needs to be rewritten as a MethodInvocation
37+
// with a target of `a.m<int>` (a FunctionReference) and a name of `apply`.
38+
if (node.keyword == null) {
39+
var typeNameTypeArguments = node.constructorName.type.typeArguments;
40+
if (typeNameTypeArguments != null) {
41+
// This could be a method call on a function reference or a constructor
42+
// reference.
43+
_resolveWithTypeNameWithTypeArguments(node, typeNameTypeArguments);
44+
return;
45+
}
46+
}
47+
48+
_resolveInstanceCreationExpression(node);
49+
}
50+
51+
void _inferArgumentTypes(covariant InstanceCreationExpressionImpl node) {
52+
var constructorName = node.constructorName;
53+
var typeName = constructorName.type;
54+
var typeArguments = typeName.typeArguments;
55+
var elementToInfer = _resolver.inferenceHelper.constructorElementToInfer(
56+
constructorName: constructorName,
57+
definingLibrary: _resolver.definingLibrary,
58+
);
59+
FunctionType? inferred;
60+
61+
// If the constructor is generic, we'll have a ConstructorMember that
62+
// substitutes in type arguments (possibly `dynamic`) from earlier in
63+
// resolution.
64+
//
65+
// Otherwise we'll have a ConstructorElement, and we can skip inference
66+
// because there's nothing to infer in a non-generic type.
67+
if (elementToInfer != null) {
68+
// TODO(leafp): Currently, we may re-infer types here, since we
69+
// sometimes resolve multiple times. We should really check that we
70+
// have not already inferred something. However, the obvious ways to
71+
// check this don't work, since we may have been instantiated
72+
// to bounds in an earlier phase, and we *do* want to do inference
73+
// in that case.
74+
75+
// Get back to the uninstantiated generic constructor.
76+
// TODO(jmesserly): should we store this earlier in resolution?
77+
// Or look it up, instead of jumping backwards through the Member?
78+
var rawElement = elementToInfer.element;
79+
var constructorType = elementToInfer.asType;
80+
81+
inferred = _resolver.inferenceHelper.inferArgumentTypesForGeneric(
82+
node, constructorType, typeArguments,
83+
isConst: node.isConst, errorNode: node.constructorName);
84+
85+
if (inferred != null) {
86+
var arguments = node.argumentList;
87+
InferenceContext.setType(arguments, inferred);
88+
// Fix up the parameter elements based on inferred method.
89+
arguments.correspondingStaticParameters =
90+
ResolverVisitor.resolveArgumentsToParameters(
91+
arguments, inferred.parameters, null);
92+
93+
constructorName.type.type = inferred.returnType;
94+
95+
// Update the static element as well. This is used in some cases, such
96+
// as computing constant values. It is stored in two places.
97+
var constructorElement = ConstructorMember.from(
98+
rawElement,
99+
inferred.returnType as InterfaceType,
100+
);
101+
constructorName.staticElement = constructorElement;
102+
}
103+
}
104+
105+
if (inferred == null) {
106+
var constructorElement = constructorName.staticElement;
107+
if (constructorElement != null) {
108+
var type = constructorElement.type;
109+
type = _resolver.toLegacyTypeIfOptOut(type) as FunctionType;
110+
InferenceContext.setType(node.argumentList, type);
111+
}
112+
}
113+
}
114+
115+
void _resolveInstanceCreationExpression(InstanceCreationExpressionImpl node) {
116+
var whyNotPromotedList = <WhyNotPromotedGetter>[];
117+
node.constructorName.accept(_resolver);
118+
_inferArgumentTypes(node);
119+
_resolver.visitArgumentList(node.argumentList,
120+
whyNotPromotedList: whyNotPromotedList);
121+
node.accept(_resolver.elementResolver);
122+
node.accept(_resolver.typeAnalyzer);
123+
_resolver.checkForArgumentTypesNotAssignableInList(
124+
node.argumentList, whyNotPromotedList);
125+
}
126+
127+
/// Resolve [node] which has a [TypeName] with type arguments (given as
128+
/// [typeNameTypeArguments]).
129+
///
130+
/// The instance creation expression may actually be a method call on a
131+
/// type-instantiated function reference or constructor reference.
132+
void _resolveWithTypeNameWithTypeArguments(
133+
InstanceCreationExpressionImpl node,
134+
TypeArgumentListImpl typeNameTypeArguments,
135+
) {
136+
var typeNameName = node.constructorName.type.name;
137+
if (typeNameName is SimpleIdentifierImpl) {
138+
// TODO(srawlins): Lookup the name and potentially rewrite `node` as a
139+
// [MethodInvocation].
140+
_resolveInstanceCreationExpression(node);
141+
return;
142+
} else if (typeNameName is PrefixedIdentifierImpl) {
143+
// TODO(srawlins): Lookup the name and potentially rewrite `node` as a
144+
// [MethodInvocation].
145+
_resolveInstanceCreationExpression(node);
146+
} else {
147+
assert(
148+
false, 'Unexpected typeNameName type: ${typeNameName.runtimeType}');
149+
_resolveInstanceCreationExpression(node);
150+
}
151+
}
152+
}

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

+8-77
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ import 'package:analyzer/src/dart/ast/ast.dart';
2121
import 'package:analyzer/src/dart/ast/extensions.dart';
2222
import 'package:analyzer/src/dart/element/element.dart';
2323
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
24-
import 'package:analyzer/src/dart/element/member.dart'
25-
show ConstructorMember, Member;
24+
import 'package:analyzer/src/dart/element/member.dart' show Member;
2625
import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
2726
import 'package:analyzer/src/dart/element/scope.dart';
2827
import 'package:analyzer/src/dart/element/type.dart';
@@ -38,6 +37,7 @@ import 'package:analyzer/src/dart/resolver/for_resolver.dart';
3837
import 'package:analyzer/src/dart/resolver/function_expression_invocation_resolver.dart';
3938
import 'package:analyzer/src/dart/resolver/function_expression_resolver.dart';
4039
import 'package:analyzer/src/dart/resolver/function_reference_resolver.dart';
40+
import 'package:analyzer/src/dart/resolver/instance_creation_expression_resolver.dart';
4141
import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
4242
import 'package:analyzer/src/dart/resolver/lexical_lookup.dart';
4343
import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
@@ -253,6 +253,9 @@ class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers {
253253

254254
late final FunctionReferenceResolver _functionReferenceResolver;
255255

256+
late final InstanceCreationExpressionResolver
257+
_instanceCreationExpressionResolver;
258+
256259
/// Initialize a newly created visitor to resolve the nodes in an AST node.
257260
///
258261
/// The [definingLibrary] is the element for the library containing the node
@@ -373,6 +376,8 @@ class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers {
373376
typeAnalyzer = StaticTypeAnalyzer(this, migrationResolutionHooks);
374377
_functionReferenceResolver =
375378
FunctionReferenceResolver(this, _isNonNullableByDefault);
379+
_instanceCreationExpressionResolver =
380+
InstanceCreationExpressionResolver(this);
376381
}
377382

378383
/// Return the element representing the function containing the current node,
@@ -1677,15 +1682,7 @@ class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers {
16771682
@override
16781683
void visitInstanceCreationExpression(
16791684
covariant InstanceCreationExpressionImpl node) {
1680-
var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
1681-
node.constructorName.accept(this);
1682-
_inferArgumentTypesForInstanceCreate(node);
1683-
visitArgumentList(node.argumentList,
1684-
whyNotPromotedList: whyNotPromotedList);
1685-
node.accept(elementResolver);
1686-
node.accept(typeAnalyzer);
1687-
checkForArgumentTypesNotAssignableInList(
1688-
node.argumentList, whyNotPromotedList);
1685+
_instanceCreationExpressionResolver.resolve(node);
16891686
}
16901687

16911688
@override
@@ -2176,72 +2173,6 @@ class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers {
21762173
return typeProvider.futureOrType(type);
21772174
}
21782175

2179-
void _inferArgumentTypesForInstanceCreate(
2180-
covariant InstanceCreationExpressionImpl node) {
2181-
var constructorName = node.constructorName;
2182-
2183-
var typeName = constructorName.type;
2184-
var typeArguments = typeName.typeArguments;
2185-
2186-
var elementToInfer = inferenceHelper.constructorElementToInfer(
2187-
constructorName: constructorName,
2188-
definingLibrary: definingLibrary,
2189-
);
2190-
2191-
FunctionType? inferred;
2192-
// If the constructor is generic, we'll have a ConstructorMember that
2193-
// substitutes in type arguments (possibly `dynamic`) from earlier in
2194-
// resolution.
2195-
//
2196-
// Otherwise we'll have a ConstructorElement, and we can skip inference
2197-
// because there's nothing to infer in a non-generic type.
2198-
if (elementToInfer != null) {
2199-
// TODO(leafp): Currently, we may re-infer types here, since we
2200-
// sometimes resolve multiple times. We should really check that we
2201-
// have not already inferred something. However, the obvious ways to
2202-
// check this don't work, since we may have been instantiated
2203-
// to bounds in an earlier phase, and we *do* want to do inference
2204-
// in that case.
2205-
2206-
// Get back to the uninstantiated generic constructor.
2207-
// TODO(jmesserly): should we store this earlier in resolution?
2208-
// Or look it up, instead of jumping backwards through the Member?
2209-
var rawElement = elementToInfer.element;
2210-
var constructorType = elementToInfer.asType;
2211-
2212-
inferred = inferenceHelper.inferArgumentTypesForGeneric(
2213-
node, constructorType, typeArguments,
2214-
isConst: node.isConst, errorNode: node.constructorName);
2215-
2216-
if (inferred != null) {
2217-
var arguments = node.argumentList;
2218-
InferenceContext.setType(arguments, inferred);
2219-
// Fix up the parameter elements based on inferred method.
2220-
arguments.correspondingStaticParameters =
2221-
resolveArgumentsToParameters(arguments, inferred.parameters, null);
2222-
2223-
constructorName.type.type = inferred.returnType;
2224-
2225-
// Update the static element as well. This is used in some cases, such
2226-
// as computing constant values. It is stored in two places.
2227-
var constructorElement = ConstructorMember.from(
2228-
rawElement,
2229-
inferred.returnType as InterfaceType,
2230-
);
2231-
constructorName.staticElement = constructorElement;
2232-
}
2233-
}
2234-
2235-
if (inferred == null) {
2236-
var constructorElement = constructorName.staticElement;
2237-
if (constructorElement != null) {
2238-
var type = constructorElement.type;
2239-
type = toLegacyTypeIfOptOut(type) as FunctionType;
2240-
InferenceContext.setType(node.argumentList, type);
2241-
}
2242-
}
2243-
}
2244-
22452176
/// Continues resolution of a [FunctionExpressionInvocation] that was created
22462177
/// from a rewritten [MethodInvocation]. The target function is already
22472178
/// resolved.

0 commit comments

Comments
 (0)