mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
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:
parent
0ad3f77424
commit
421ffd331a
3 changed files with 132 additions and 2 deletions
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue