Skip to content

Commit 519786c

Browse files
srawlinscommit-bot@chromium.org
authored andcommitted
Improve method tearoff instantiation support for static methods.
* static method access with an explicit receiver * the above, with a type alias of the receiver * the two above, with a prefixed import * many test cases for unsupported things Bug: #46233 Change-Id: I982bc741aa8f57959d342b640921096170e94f0c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/205881 Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 3835374 commit 519786c

File tree

2 files changed

+292
-81
lines changed

2 files changed

+292
-81
lines changed

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

Lines changed: 132 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:analyzer/dart/ast/ast.dart';
6+
import 'package:analyzer/dart/ast/syntactic_entity.dart';
67
import 'package:analyzer/dart/element/element.dart';
78
import 'package:analyzer/dart/element/nullability_suffix.dart';
89
import 'package:analyzer/dart/element/type.dart';
@@ -12,7 +13,6 @@ import 'package:analyzer/src/dart/ast/ast_factory.dart';
1213
import 'package:analyzer/src/dart/ast/extensions.dart';
1314
import 'package:analyzer/src/dart/ast/utilities.dart';
1415
import 'package:analyzer/src/dart/element/type.dart';
15-
import 'package:analyzer/src/dart/resolver/resolution_result.dart';
1616
import 'package:analyzer/src/error/codes.dart';
1717
import 'package:analyzer/src/generated/resolver.dart';
1818

@@ -83,35 +83,46 @@ class FunctionReferenceResolver {
8383
if (function is PrefixedIdentifierImpl) {
8484
var prefixElement =
8585
_resolver.nameScope.lookup(function.prefix.name).getter;
86+
function.prefix.staticElement = prefixElement;
8687
if (prefixElement is PrefixElement) {
87-
_resolveReceiverPrefix(node, prefixElement, function);
88-
return;
88+
var functionName = function.identifier.name;
89+
var functionElement = prefixElement.scope.lookup(functionName).getter;
90+
if (functionElement == null) {
91+
_errorReporter.reportErrorForNode(
92+
CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
93+
function.identifier,
94+
[function.identifier.name, function.prefix.name],
95+
);
96+
function.staticType = DynamicTypeImpl.instance;
97+
node.staticType = DynamicTypeImpl.instance;
98+
return;
99+
} else {
100+
functionElement = _resolver.toLegacyElement(functionElement);
101+
_resolveReceiverPrefix(
102+
node, prefixElement, function, functionElement);
103+
return;
104+
}
105+
} else if (prefixElement is VariableElement) {
106+
function.prefix.staticType = prefixElement.type;
107+
} else if (prefixElement is PropertyAccessorElement) {
108+
function.prefix.staticType = prefixElement.returnType;
89109
}
90110

91-
ResolutionResult resolveTypeProperty(DartType prefixType) {
92-
return _resolver.typePropertyResolver.resolve(
93-
receiver: function.prefix,
94-
receiverType: prefixType,
95-
name: function.identifier.name,
96-
propertyErrorEntity: function.identifier,
97-
nameErrorEntity: function,
98-
);
99-
}
111+
var methodElement = _resolveTypeProperty(
112+
receiver: function.prefix,
113+
receiverElement: prefixElement,
114+
name: function.identifier,
115+
nameErrorEntity: function,
116+
);
100117

101-
function.prefix.staticElement = prefixElement;
102-
ExecutableElement? methodElement;
103-
if (prefixElement is VariableElement) {
104-
var prefixType = prefixElement.type;
105-
function.prefix.staticType = prefixType;
106-
methodElement = resolveTypeProperty(prefixType).getter;
107-
} else if (prefixElement is PropertyAccessorElement) {
108-
var prefixType = prefixElement.returnType;
109-
function.prefix.staticType = prefixType;
110-
methodElement = resolveTypeProperty(prefixType).getter;
111-
}
112118
if (methodElement is MethodElement) {
113-
_resolveFunctionReferenceMethod(
114-
node: node, function: function, element: methodElement);
119+
function.identifier.staticElement = methodElement;
120+
function.staticType = methodElement.type;
121+
_resolve(
122+
node: node,
123+
name: function.identifier.name,
124+
rawType: methodElement.type,
125+
);
115126
return;
116127
}
117128

@@ -143,11 +154,39 @@ class FunctionReferenceResolver {
143154
node.staticType = DynamicTypeImpl.instance;
144155
return;
145156
}
157+
} else if (target is PrefixedIdentifierImpl) {
158+
var prefixElement =
159+
_resolver.nameScope.lookup(target.prefix.name).getter;
160+
if (prefixElement is PrefixElement) {
161+
var prefixName = target.identifier.name;
162+
var targetElement = prefixElement.scope.lookup(prefixName).getter;
163+
164+
var methodElement = _resolveTypeProperty(
165+
receiver: target,
166+
receiverElement: targetElement,
167+
name: function.propertyName,
168+
nameErrorEntity: function,
169+
);
170+
171+
if (methodElement == null) {
172+
// TODO(srawlins): Can we get here?
173+
node.staticType = DynamicTypeImpl.instance;
174+
return;
175+
} else {
176+
_resolveReceiverPrefix(node, prefixElement, target, methodElement);
177+
return;
178+
}
179+
} else {
180+
// TODO(srawlins): Can we get here?
181+
node.staticType = DynamicTypeImpl.instance;
182+
return;
183+
}
146184
} else {
147-
// TODO(srawlins): Can we get here? PrefixedIdentifier?
185+
// TODO(srawlins): Can we get here?
148186
node.staticType = DynamicTypeImpl.instance;
149187
return;
150188
}
189+
151190
var propertyElement = _resolver.typePropertyResolver
152191
.resolve(
153192
receiver: function.realTarget,
@@ -238,55 +277,14 @@ class FunctionReferenceResolver {
238277
_resolveTypeLiteral(node: node, instantiatedType: type, name: name);
239278
}
240279

241-
void _resolveFunctionReferenceMethod({
242-
required FunctionReferenceImpl node,
243-
required PrefixedIdentifier function,
244-
required MethodElement element,
245-
}) {
246-
function.accept(_resolver);
247-
var receiver = function.prefix;
248-
var receiverType = receiver.staticType;
249-
if (receiverType == null) {
250-
// TODO(srawlins): Handle this situation; see
251-
// `test_staticMethod_explicitReceiver` test case.
252-
node.staticType = DynamicTypeImpl.instance;
253-
return;
254-
}
255-
var nameNode = function.identifier;
256-
var name = nameNode.name;
257-
var result = _resolver.typePropertyResolver.resolve(
258-
receiver: receiver,
259-
receiverType: receiverType,
260-
name: name,
261-
propertyErrorEntity: nameNode,
262-
nameErrorEntity: nameNode,
263-
);
264-
265-
var target = result.getter;
266-
if (target != null) {
267-
// TODO(srawlins): Set static type on `nameNode`?
268-
269-
_resolve(node: node, name: name, rawType: element.type);
270-
return;
271-
}
272-
273-
// TODO(srawlins): Report unresolved identifier.
274-
node.function.accept(_resolver);
275-
node.staticType = DynamicTypeImpl.instance;
276-
}
277-
278280
void _resolveReceiverPrefix(
279281
FunctionReferenceImpl node,
280282
PrefixElement prefixElement,
281283
PrefixedIdentifier prefix,
284+
Element element,
282285
) {
283286
// TODO(srawlins): Handle `loadLibrary`, as in `p.loadLibrary<int>;`.
284287

285-
var nameNode = prefix.identifier;
286-
var name = nameNode.name;
287-
var element = prefixElement.scope.lookup(name).getter;
288-
element = _resolver.toLegacyElement(element);
289-
290288
if (element is MultiplyDefinedElement) {
291289
MultiplyDefinedElement multiply = element;
292290
element = multiply.conflictingElements[0];
@@ -310,7 +308,6 @@ class FunctionReferenceResolver {
310308
return;
311309
} else if (element is TypeAliasElement) {
312310
prefix.accept(_resolver);
313-
(nameNode as SimpleIdentifierImpl).staticElement = element;
314311
_resolveTypeAlias(node: node, element: element, typeAlias: prefix);
315312
return;
316313
}
@@ -326,10 +323,26 @@ class FunctionReferenceResolver {
326323

327324
// TODO(srawlins): Report undefined prefixed identifier.
328325

329-
node.function.accept(_resolver);
330326
node.staticType = DynamicTypeImpl.instance;
331327
}
332328

329+
/// Returns the element that represents the property named [propertyName] on
330+
/// [classElement].
331+
ExecutableElement? _resolveStaticElement(
332+
ClassElement classElement, SimpleIdentifier propertyName) {
333+
String name = propertyName.name;
334+
ExecutableElement? element;
335+
if (propertyName.inSetterContext()) {
336+
element = classElement.getSetter(name);
337+
}
338+
element ??= classElement.getGetter(name);
339+
element ??= classElement.getMethod(name);
340+
if (element != null && element.isAccessibleIn(_resolver.definingLibrary)) {
341+
return element;
342+
}
343+
return null;
344+
}
345+
333346
void _resolveTypeAlias({
334347
required FunctionReferenceImpl node,
335348
required TypeAliasElement element,
@@ -358,4 +371,53 @@ class FunctionReferenceResolver {
358371
typeLiteral.staticType = _typeType;
359372
NodeReplacer.replace(node, typeLiteral);
360373
}
374+
375+
/// Resolves [name] as a property on [receiver] (with element
376+
/// [receiverElement]).
377+
///
378+
/// Returns `null` if [receiverElement] is `null`, a [TypeParameterElement],
379+
/// or a [TypeAliasElement] for a non-interface type.
380+
ExecutableElement? _resolveTypeProperty({
381+
required Expression receiver,
382+
required Element? receiverElement,
383+
required SimpleIdentifier name,
384+
required SyntacticEntity nameErrorEntity,
385+
}) {
386+
if (receiverElement == null) {
387+
return null;
388+
}
389+
if (receiverElement is TypeParameterElement) {
390+
return null;
391+
}
392+
if (receiverElement is ClassElement) {
393+
return _resolveStaticElement(receiverElement, name);
394+
} else if (receiverElement is TypeAliasElement) {
395+
var aliasedType = receiverElement.aliasedType;
396+
if (aliasedType is InterfaceType) {
397+
return _resolveStaticElement(aliasedType.element, name);
398+
} else {
399+
return null;
400+
}
401+
}
402+
403+
DartType receiverType;
404+
if (receiverElement is VariableElement) {
405+
receiverType = receiverElement.type;
406+
} else if (receiverElement is PropertyAccessorElement) {
407+
receiverType = receiverElement.returnType;
408+
} else {
409+
assert(false,
410+
'Unexpected receiverElement type: ${receiverElement.runtimeType}');
411+
return null;
412+
}
413+
return _resolver.typePropertyResolver
414+
.resolve(
415+
receiver: receiver,
416+
receiverType: receiverType,
417+
name: name.name,
418+
propertyErrorEntity: name,
419+
nameErrorEntity: nameErrorEntity,
420+
)
421+
.getter;
422+
}
361423
}

0 commit comments

Comments
 (0)