[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 <paulberry@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
Kallen Tu
2025-04-29 14:21:41 -07:00
committed by Commit Queue
parent c31a282435
commit 2c4fd4e9a8
4 changed files with 66 additions and 1 deletions
+1 -1
View File
@@ -10091,7 +10091,7 @@ abstract final class IndexExpression
}
final class IndexExpressionImpl extends ExpressionImpl
with NullShortableExpressionImpl
with NullShortableExpressionImpl, DotShorthandMixin
implements IndexExpression {
@override
Token? period;
@@ -3074,6 +3074,12 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
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<void>
nullShortingTermination(node, rewrittenExpression: replacement);
_insertImplicitCallReference(replacement, contextType: contextType);
nullSafetyDeadCodeVerifier.verifyIndexExpression(node);
if (isDotShorthand(node)) {
popDotShorthandContext();
}
inferenceLogWriter?.exitExpression(node);
}
@@ -321,6 +321,35 @@ DotShorthandInvocation
''');
}
test_equality_indexExpression() async {
await assertNoErrorsInCode(r'''
class C {
int x;
C(this.x);
static List<C> instances() => [C(1)];
}
void main() {
print(C(1) == .instances()[0]);
}
''');
var identifier = findNode.singleDotShorthandInvocation;
assertResolvedNodeText(identifier, r'''
DotShorthandInvocation
period: .
memberName: SimpleIdentifier
token: instances
element: <testLibraryFragment>::@class::C::@method::instances#element
staticType: List<C> Function()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: List<C> Function()
staticType: List<C>
''');
}
test_extensionType() async {
await assertNoErrorsInCode(r'''
extension type C(int integer) {
@@ -270,6 +270,31 @@ DotShorthandPropertyAccess
''');
}
test_equality_indexExpression() async {
await assertNoErrorsInCode(r'''
class C {
int x;
C(this.x);
static List<C> instances = [C(1)];
}
void main() {
print(C(1) == .instances[0]);
}
''');
var identifier = findNode.singleDotShorthandPropertyAccess;
assertResolvedNodeText(identifier, r'''
DotShorthandPropertyAccess
period: .
propertyName: SimpleIdentifier
token: instances
element: <testLibraryFragment>::@class::C::@getter::instances#element
staticType: List<C>
staticType: List<C>
''');
}
test_equality_pattern() async {
await assertNoErrorsInCode('''
enum Color { red, blue }