mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 16:19:07 +00:00
analyzer: Resolve extension methods on nullable Never type
Fixes https://github.com/dart-lang/sdk/issues/55000 Cq-Include-Trybots: luci.dart.try:flutter-analyze-try,analyzer-win-release-try,pkg-win-release-try Change-Id: Ie71d4762bc294028787c28976b2e0a7e604ab2fa Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/372880 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Sam Rawlins <srawlins@google.com>
This commit is contained in:
parent
89d9912790
commit
4d20dea313
|
@ -71,6 +71,10 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
|
|
||||||
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
|
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
|
||||||
|
|
||||||
|
/// Resolves the method invocation, [node].
|
||||||
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
FunctionExpressionInvocation? resolve(
|
FunctionExpressionInvocation? resolve(
|
||||||
MethodInvocationImpl node, List<WhyNotPromotedGetter> whyNotPromotedList,
|
MethodInvocationImpl node, List<WhyNotPromotedGetter> whyNotPromotedList,
|
||||||
{required DartType contextType}) {
|
{required DartType contextType}) {
|
||||||
|
@ -142,9 +146,9 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receiverType is NeverTypeImpl) {
|
if (receiverType is NeverTypeImpl) {
|
||||||
_resolveReceiverNever(node, receiver, receiverType, whyNotPromotedList,
|
return _resolveReceiverNever(
|
||||||
contextType: contextType);
|
node, receiver, receiverType, whyNotPromotedList,
|
||||||
return null;
|
contextType: contextType, nameNode: nameNode, name: name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receiverType is VoidType) {
|
if (receiverType is VoidType) {
|
||||||
|
@ -344,6 +348,10 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the method invocation, [node], as an extension member.
|
||||||
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
FunctionExpressionInvocation? _resolveExtensionMember(
|
FunctionExpressionInvocation? _resolveExtensionMember(
|
||||||
MethodInvocationImpl node,
|
MethodInvocationImpl node,
|
||||||
Identifier receiver,
|
Identifier receiver,
|
||||||
|
@ -380,6 +388,11 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the method invocation, [node], as called on an extension
|
||||||
|
/// override.
|
||||||
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
FunctionExpressionInvocation? _resolveExtensionOverride(
|
FunctionExpressionInvocation? _resolveExtensionOverride(
|
||||||
MethodInvocationImpl node,
|
MethodInvocationImpl node,
|
||||||
ExtensionOverride override,
|
ExtensionOverride override,
|
||||||
|
@ -468,9 +481,20 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
.resolveInvocation(rawType: rawType);
|
.resolveInvocation(rawType: rawType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _resolveReceiverNever(MethodInvocationImpl node, Expression receiver,
|
/// Resolves the method invocation, [node], as an instance invocation on an
|
||||||
DartType receiverType, List<WhyNotPromotedGetter> whyNotPromotedList,
|
/// expression of type `Never` or `Never?`.
|
||||||
{required DartType contextType}) {
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
|
FunctionExpressionInvocation? _resolveReceiverNever(
|
||||||
|
MethodInvocationImpl node,
|
||||||
|
Expression receiver,
|
||||||
|
DartType receiverType,
|
||||||
|
List<WhyNotPromotedGetter> whyNotPromotedList, {
|
||||||
|
required DartType contextType,
|
||||||
|
required SimpleIdentifierImpl nameNode,
|
||||||
|
required String name,
|
||||||
|
}) {
|
||||||
_setExplicitTypeArgumentTypes();
|
_setExplicitTypeArgumentTypes();
|
||||||
|
|
||||||
if (receiverType == NeverTypeImpl.instanceNullable) {
|
if (receiverType == NeverTypeImpl.instanceNullable) {
|
||||||
|
@ -485,16 +509,19 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
whyNotPromotedList,
|
whyNotPromotedList,
|
||||||
contextType: contextType,
|
contextType: contextType,
|
||||||
);
|
);
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
_setInvalidTypeResolution(node,
|
return _resolveReceiverType(
|
||||||
whyNotPromotedList: whyNotPromotedList, contextType: contextType);
|
node: node,
|
||||||
_resolver.nullableDereferenceVerifier.report(
|
receiver: receiver,
|
||||||
CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
|
receiverType: receiverType,
|
||||||
methodName,
|
nameNode: nameNode,
|
||||||
receiverType,
|
name: name,
|
||||||
|
receiverErrorNode: receiver,
|
||||||
|
whyNotPromotedList: whyNotPromotedList,
|
||||||
|
contextType: contextType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receiverType == NeverTypeImpl.instance) {
|
if (receiverType == NeverTypeImpl.instance) {
|
||||||
|
@ -514,10 +541,16 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
node.methodName.setPseudoExpressionStaticType(_dynamicType);
|
node.methodName.setPseudoExpressionStaticType(_dynamicType);
|
||||||
node.staticInvokeType = _dynamicType;
|
node.staticInvokeType = _dynamicType;
|
||||||
node.recordStaticType(NeverTypeImpl.instance, resolver: _resolver);
|
node.recordStaticType(NeverTypeImpl.instance, resolver: _resolver);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the method invocation, [node], as an instance invocation on an
|
||||||
|
/// expression of type `Null`.
|
||||||
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
FunctionExpressionInvocation? _resolveReceiverNull(
|
FunctionExpressionInvocation? _resolveReceiverNull(
|
||||||
MethodInvocationImpl node,
|
MethodInvocationImpl node,
|
||||||
SimpleIdentifierImpl nameNode,
|
SimpleIdentifierImpl nameNode,
|
||||||
|
@ -620,6 +653,11 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the method invocation, [node], as a top-level function
|
||||||
|
/// invocation, referenced with a prefix.
|
||||||
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
FunctionExpressionInvocation? _resolveReceiverPrefix(
|
FunctionExpressionInvocation? _resolveReceiverPrefix(
|
||||||
MethodInvocationImpl node,
|
MethodInvocationImpl node,
|
||||||
PrefixElement prefix,
|
PrefixElement prefix,
|
||||||
|
@ -679,6 +717,11 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the method invocation, [node], as an instance invocation a
|
||||||
|
/// `super` expression.
|
||||||
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
FunctionExpressionInvocation? _resolveReceiverSuper(
|
FunctionExpressionInvocation? _resolveReceiverSuper(
|
||||||
MethodInvocationImpl node,
|
MethodInvocationImpl node,
|
||||||
SuperExpression receiver,
|
SuperExpression receiver,
|
||||||
|
@ -740,6 +783,10 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the type of the receiver of the method invocation, [node].
|
||||||
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
FunctionExpressionInvocation? _resolveReceiverType({
|
FunctionExpressionInvocation? _resolveReceiverType({
|
||||||
required MethodInvocationImpl node,
|
required MethodInvocationImpl node,
|
||||||
required Expression? receiver,
|
required Expression? receiver,
|
||||||
|
@ -830,6 +877,11 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the method invocation, [node], as an method invocation with a
|
||||||
|
/// type literal target.
|
||||||
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
FunctionExpressionInvocation? _resolveReceiverTypeLiteral(
|
FunctionExpressionInvocation? _resolveReceiverTypeLiteral(
|
||||||
MethodInvocationImpl node,
|
MethodInvocationImpl node,
|
||||||
InterfaceElement receiver,
|
InterfaceElement receiver,
|
||||||
|
@ -882,12 +934,14 @@ class MethodInvocationResolver with ScopeHelpers {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rewrites [node] as a [FunctionExpressionInvocation].
|
||||||
|
///
|
||||||
/// We have identified that [node] is not a real [MethodInvocation],
|
/// We have identified that [node] is not a real [MethodInvocation],
|
||||||
/// because it does not invoke a method, but instead invokes the result
|
/// because it does not invoke a method, but instead invokes the result
|
||||||
/// of a getter execution, or implicitly invokes the `call` method of
|
/// of a getter execution, or implicitly invokes the `call` method of
|
||||||
/// an [InterfaceType]. So, it should be represented as instead as a
|
/// an [InterfaceType]. So, it should be represented as instead as a
|
||||||
/// [FunctionExpressionInvocation].
|
/// [FunctionExpressionInvocation].
|
||||||
FunctionExpressionInvocation? _rewriteAsFunctionExpressionInvocation(
|
FunctionExpressionInvocation _rewriteAsFunctionExpressionInvocation(
|
||||||
MethodInvocationImpl node, DartType getterReturnType,
|
MethodInvocationImpl node, DartType getterReturnType,
|
||||||
{bool isSuperAccess = false}) {
|
{bool isSuperAccess = false}) {
|
||||||
var targetType = _typeSystem.resolveToBound(getterReturnType);
|
var targetType = _typeSystem.resolveToBound(getterReturnType);
|
||||||
|
|
|
@ -267,6 +267,10 @@ class ElementResolver {
|
||||||
_resolveAnnotations(node.metadata);
|
_resolveAnnotations(node.metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the method invocation, [node].
|
||||||
|
///
|
||||||
|
/// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
|
||||||
|
/// process, then returns that new node. Otherwise, returns `null`.
|
||||||
FunctionExpressionInvocation? visitMethodInvocation(MethodInvocation node,
|
FunctionExpressionInvocation? visitMethodInvocation(MethodInvocation node,
|
||||||
{List<WhyNotPromotedGetter>? whyNotPromotedList,
|
{List<WhyNotPromotedGetter>? whyNotPromotedList,
|
||||||
required DartType contextType}) {
|
required DartType contextType}) {
|
||||||
|
|
|
@ -216,6 +216,18 @@ extension E on A? {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_methodInvocation_nuverNullable_extensionMethod() async {
|
||||||
|
await assertNoErrorsInCode(r'''
|
||||||
|
extension<X> on X {
|
||||||
|
X m() => this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> f(Never? x) async {
|
||||||
|
(await x).m();
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
|
||||||
test_prefixExpression_minus_nonNullable() async {
|
test_prefixExpression_minus_nonNullable() async {
|
||||||
await assertNoErrorsInCode(r'''
|
await assertNoErrorsInCode(r'''
|
||||||
class A {
|
class A {
|
||||||
|
|
Loading…
Reference in a new issue