From 2c4fd4e9a8ca25593c8b86c6e5c12c3cd5ccae2a Mon Sep 17 00:00:00 2001 From: Kallen Tu Date: Tue, 29 Apr 2025 14:21:41 -0700 Subject: [PATCH] [analyzer] Dot shorthands: Allow index expressions. `IndexExpressionImpl`s now have the `DotShorthandMixin` applied. We save the context at the point of resolving an index expression to be used for resolving a dot shorthand head later. Unit tests added. There's multiple co19 tests that will start passing, but rely on https://dart-review.googlesource.com/c/sdk/+/425181. Bug: https://github.com/dart-lang/sdk/issues/59835 Change-Id: I08076bb437bad1955d353a24fc119466b7dfad61 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425360 Reviewed-by: Paul Berry Commit-Queue: Kallen Tu --- pkg/analyzer/lib/src/dart/ast/ast.dart | 2 +- pkg/analyzer/lib/src/generated/resolver.dart | 11 +++++++ .../dot_shorthand_invocation_test.dart | 29 +++++++++++++++++++ .../dot_shorthand_property_access_test.dart | 25 ++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart index 345b2abe73a..4b6454cce7f 100644 --- a/pkg/analyzer/lib/src/dart/ast/ast.dart +++ b/pkg/analyzer/lib/src/dart/ast/ast.dart @@ -10091,7 +10091,7 @@ abstract final class IndexExpression } final class IndexExpressionImpl extends ExpressionImpl - with NullShortableExpressionImpl + with NullShortableExpressionImpl, DotShorthandMixin implements IndexExpression { @override Token? period; diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart index d990675180c..a851114edb7 100644 --- a/pkg/analyzer/lib/src/generated/resolver.dart +++ b/pkg/analyzer/lib/src/generated/resolver.dart @@ -3074,6 +3074,12 @@ class ResolverVisitor extends ThrowingAstVisitor TypeImpl contextType = UnknownInferredType.instance, }) { inferenceLogWriter?.enterExpression(node, contextType); + + // If [isDotShorthand] is set, cache the context type for resolution. + if (isDotShorthand(node)) { + pushDotShorthandContext(node, SharedTypeSchemaView(contextType)); + } + checkUnreachableNode(node); var target = node.target; @@ -3132,6 +3138,11 @@ class ResolverVisitor extends ThrowingAstVisitor nullShortingTermination(node, rewrittenExpression: replacement); _insertImplicitCallReference(replacement, contextType: contextType); nullSafetyDeadCodeVerifier.verifyIndexExpression(node); + + if (isDotShorthand(node)) { + popDotShorthandContext(); + } + inferenceLogWriter?.exitExpression(node); } diff --git a/pkg/analyzer/test/src/dart/resolution/dot_shorthand_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/dot_shorthand_invocation_test.dart index 507f55e958a..2b2e6e20451 100644 --- a/pkg/analyzer/test/src/dart/resolution/dot_shorthand_invocation_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/dot_shorthand_invocation_test.dart @@ -321,6 +321,35 @@ DotShorthandInvocation '''); } + test_equality_indexExpression() async { + await assertNoErrorsInCode(r''' +class C { + int x; + C(this.x); + static List instances() => [C(1)]; +} + +void main() { + print(C(1) == .instances()[0]); +} +'''); + + var identifier = findNode.singleDotShorthandInvocation; + assertResolvedNodeText(identifier, r''' +DotShorthandInvocation + period: . + memberName: SimpleIdentifier + token: instances + element: ::@class::C::@method::instances#element + staticType: List Function() + argumentList: ArgumentList + leftParenthesis: ( + rightParenthesis: ) + staticInvokeType: List Function() + staticType: List +'''); + } + test_extensionType() async { await assertNoErrorsInCode(r''' extension type C(int integer) { diff --git a/pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart b/pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart index 2d1ab7e877e..7ebbd2de706 100644 --- a/pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart @@ -270,6 +270,31 @@ DotShorthandPropertyAccess '''); } + test_equality_indexExpression() async { + await assertNoErrorsInCode(r''' +class C { + int x; + C(this.x); + static List instances = [C(1)]; +} + +void main() { + print(C(1) == .instances[0]); +} +'''); + + var identifier = findNode.singleDotShorthandPropertyAccess; + assertResolvedNodeText(identifier, r''' +DotShorthandPropertyAccess + period: . + propertyName: SimpleIdentifier + token: instances + element: ::@class::C::@getter::instances#element + staticType: List + staticType: List +'''); + } + test_equality_pattern() async { await assertNoErrorsInCode(''' enum Color { red, blue }