Extension type. Issue 55006. An extension type with nullable suffix is nullable, for properties.

Bug: https://github.com/dart-lang/sdk/issues/55006
Change-Id: I5adf6029194b117470eb36f7bb62202ddc5ac92b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/354180
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2024-02-26 16:48:49 +00:00 committed by Commit Queue
parent 0ad3f77424
commit 421ffd331a
3 changed files with 132 additions and 2 deletions

View file

@ -5,6 +5,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/syntactic_entity.dart';
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/diagnostic/diagnostic.dart';
import 'package:analyzer/src/dart/element/element.dart';
@ -87,8 +88,14 @@ class TypePropertyResolver {
return _toResult();
}
if (_typeSystem.isPotentiallyNullable(receiverType) &&
!receiverType.isExtensionType) {
bool isNullable;
if (receiverType.isExtensionType) {
isNullable = receiverType.nullabilitySuffix == NullabilitySuffix.question;
} else {
isNullable = _typeSystem.isPotentiallyNullable(receiverType);
}
if (isNullable) {
_lookupInterfaceType(_typeProvider.objectType);
if (_hasGetterOrSetter) {
return _toResult();

View file

@ -4320,6 +4320,71 @@ MethodInvocation
''');
}
test_hasReceiver_interfaceType_extensionType_declared_nullableType() async {
await assertErrorsInCode(r'''
extension type A(int it) {
int foo() => 0;
}
void f(A? a) {
a.foo();
}
''', [
error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
67, 3),
]);
final node = findNode.singleMethodInvocation;
assertResolvedNodeText(node, r'''
MethodInvocation
target: SimpleIdentifier
token: a
staticElement: self::@function::f::@parameter::a
staticType: A?
operator: .
methodName: SimpleIdentifier
token: foo
staticElement: self::@extensionType::A::@method::foo
staticType: int Function()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: int Function()
staticType: int
''');
}
test_hasReceiver_interfaceType_extensionType_declared_nullableType_nullAware() async {
await assertNoErrorsInCode(r'''
extension type A(int it) {
int foo() => 0;
}
void f(A? a) {
a?.foo();
}
''');
final node = findNode.singleMethodInvocation;
assertResolvedNodeText(node, r'''
MethodInvocation
target: SimpleIdentifier
token: a
staticElement: self::@function::f::@parameter::a
staticType: A?
operator: ?.
methodName: SimpleIdentifier
token: foo
staticElement: self::@extensionType::A::@method::foo
staticType: int Function()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: int Function()
staticType: int?
''');
}
test_hasReceiver_interfaceType_extensionType_exposed() async {
await assertNoErrorsInCode(r'''
class A {

View file

@ -850,6 +850,64 @@ PrefixedIdentifier
''');
}
test_ofExtensionType_read_nullableType() async {
await assertErrorsInCode(r'''
extension type A(int it) {
int get foo => 0;
}
void f(A? a) {
a.foo;
}
''', [
error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
69, 3),
]);
final node = findNode.singlePrefixedIdentifier;
assertResolvedNodeText(node, r'''
PrefixedIdentifier
prefix: SimpleIdentifier
token: a
staticElement: self::@function::f::@parameter::a
staticType: A?
period: .
identifier: SimpleIdentifier
token: foo
staticElement: self::@extensionType::A::@getter::foo
staticType: int
staticElement: self::@extensionType::A::@getter::foo
staticType: int
''');
}
test_ofExtensionType_read_nullableType_nullAware() async {
await assertNoErrorsInCode(r'''
extension type A(int it) {
int get foo => 0;
}
void f(A? a) {
a?.foo;
}
''');
final node = findNode.singlePropertyAccess;
assertResolvedNodeText(node, r'''
PropertyAccess
target: SimpleIdentifier
token: a
staticElement: self::@function::f::@parameter::a
staticType: A?
operator: ?.
propertyName: SimpleIdentifier
token: foo
staticElement: self::@extensionType::A::@getter::foo
staticType: int
staticType: int?
''');
}
test_ofExtensionType_write() async {
await assertNoErrorsInCode(r'''
extension type A(int it) {