Skip to content

Commit 876118d

Browse files
kallentuCommit Queue
authored and
Commit Queue
committed
[analyzer] Dot shorthands: Selector chains, add mixin to PropertyAccess and MethodInvocation.
For supporting selector chains, I've added the DotShorthandMixin to PropertyAccess and MethodInvocation, and marked the `isDotShorthand` flag when it's the outer most selector whose context type we care about saving. Multiple language tests passing + added some unit tests for some simple selector chain cases. Bug: #59835 Change-Id: I7571eb22b4213be895a756b89ecf74f65c4cced5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/423382 Commit-Queue: Kallen Tu <[email protected]> Reviewed-by: Paul Berry <[email protected]> Reviewed-by: Chloe Stefantsova <[email protected]>
1 parent c5dc292 commit 876118d

File tree

5 files changed

+208
-2
lines changed

5 files changed

+208
-2
lines changed

pkg/analyzer/lib/src/dart/ast/ast.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -12051,7 +12051,7 @@ abstract final class MethodInvocation
1205112051
}
1205212052

1205312053
final class MethodInvocationImpl extends InvocationExpressionImpl
12054-
with NullShortableExpressionImpl
12054+
with NullShortableExpressionImpl, DotShorthandMixin
1205512055
implements MethodInvocation {
1205612056
ExpressionImpl? _target;
1205712057

@@ -14471,7 +14471,7 @@ abstract final class PropertyAccess
1447114471
}
1447214472

1447314473
final class PropertyAccessImpl extends CommentReferableExpressionImpl
14474-
with NullShortableExpressionImpl
14474+
with NullShortableExpressionImpl, DotShorthandMixin
1447514475
implements PropertyAccess {
1447614476
ExpressionImpl? _target;
1447714477

pkg/analyzer/lib/src/generated/resolver.dart

+22
Original file line numberDiff line numberDiff line change
@@ -3323,6 +3323,12 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
33233323
TypeImpl contextType = UnknownInferredType.instance,
33243324
}) {
33253325
inferenceLogWriter?.enterExpression(node, contextType);
3326+
3327+
// If [isDotShorthand] is set, cache the context type for resolution.
3328+
if (isDotShorthand(node)) {
3329+
pushDotShorthandContext(node, SharedTypeSchemaView(contextType));
3330+
}
3331+
33263332
checkUnreachableNode(node);
33273333
var whyNotPromotedArguments =
33283334
<Map<SharedTypeView, NonPromotionReason> Function()>[];
@@ -3362,6 +3368,11 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
33623368
);
33633369
_insertImplicitCallReference(replacement, contextType: contextType);
33643370
nullSafetyDeadCodeVerifier.verifyMethodInvocation(node);
3371+
3372+
if (isDotShorthand(node)) {
3373+
popDotShorthandContext();
3374+
}
3375+
33653376
inferenceLogWriter?.exitExpression(node);
33663377
}
33673378

@@ -3627,6 +3638,12 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
36273638
TypeImpl contextType = UnknownInferredType.instance,
36283639
}) {
36293640
inferenceLogWriter?.enterExpression(node, contextType);
3641+
3642+
// If [isDotShorthand] is set, cache the context type for resolution.
3643+
if (isDotShorthand(node)) {
3644+
pushDotShorthandContext(node, SharedTypeSchemaView(contextType));
3645+
}
3646+
36303647
checkUnreachableNode(node);
36313648

36323649
var target = node.target;
@@ -3640,6 +3657,11 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
36403657

36413658
checkUnreachableNode(node.propertyName);
36423659
_resolvePropertyAccessRhs(node, contextType);
3660+
3661+
if (isDotShorthand(node)) {
3662+
popDotShorthandContext();
3663+
}
3664+
36433665
inferenceLogWriter?.exitExpression(node);
36443666
}
36453667

pkg/analyzer/test/src/dart/resolution/dot_shorthand_constructor_invocation_test.dart

+68
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,74 @@ main() {
1717
@reflectiveTest
1818
class DotShorthandConstructorInvocationResolutionTest
1919
extends PubPackageResolutionTest {
20+
test_chain_method() async {
21+
await assertNoErrorsInCode(r'''
22+
class C {
23+
int x;
24+
C(this.x);
25+
C method() => C(1);
26+
}
27+
28+
void main() {
29+
C c = .new(1).method();
30+
print(c);
31+
}
32+
''');
33+
34+
var identifier = findNode.singleDotShorthandConstructorInvocation;
35+
assertResolvedNodeText(identifier, r'''
36+
DotShorthandConstructorInvocation
37+
period: .
38+
constructorName: SimpleIdentifier
39+
token: new
40+
element: <testLibraryFragment>::@class::C::@constructor::new#element
41+
staticType: null
42+
argumentList: ArgumentList
43+
leftParenthesis: (
44+
arguments
45+
IntegerLiteral
46+
literal: 1
47+
correspondingParameter: <testLibraryFragment>::@class::C::@constructor::new::@parameter::x#element
48+
staticType: int
49+
rightParenthesis: )
50+
staticType: C
51+
''');
52+
}
53+
54+
test_chain_property() async {
55+
await assertNoErrorsInCode(r'''
56+
class C {
57+
int x;
58+
C(this.x);
59+
C get property => C(1);
60+
}
61+
62+
void main() {
63+
C c = .new(1).property;
64+
print(c);
65+
}
66+
''');
67+
68+
var identifier = findNode.singleDotShorthandConstructorInvocation;
69+
assertResolvedNodeText(identifier, r'''
70+
DotShorthandConstructorInvocation
71+
period: .
72+
constructorName: SimpleIdentifier
73+
token: new
74+
element: <testLibraryFragment>::@class::C::@constructor::new#element
75+
staticType: null
76+
argumentList: ArgumentList
77+
leftParenthesis: (
78+
arguments
79+
IntegerLiteral
80+
literal: 1
81+
correspondingParameter: <testLibraryFragment>::@class::C::@constructor::new::@parameter::x#element
82+
staticType: int
83+
rightParenthesis: )
84+
staticType: C
85+
''');
86+
}
87+
2088
test_constructor_named() async {
2189
await assertNoErrorsInCode(r'''
2290
class C {

pkg/analyzer/test/src/dart/resolution/dot_shorthand_invocation_test.dart

+62
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,68 @@ FunctionExpressionInvocation
222222
''');
223223
}
224224

225+
test_chain_method() async {
226+
await assertNoErrorsInCode(r'''
227+
class C {
228+
static C member() => C(1);
229+
int x;
230+
C(this.x);
231+
C method() => C(1);
232+
}
233+
234+
void main() {
235+
C c = .member().method();
236+
print(c);
237+
}
238+
''');
239+
240+
var identifier = findNode.singleDotShorthandInvocation;
241+
assertResolvedNodeText(identifier, r'''
242+
DotShorthandInvocation
243+
period: .
244+
memberName: SimpleIdentifier
245+
token: member
246+
element: <testLibraryFragment>::@class::C::@method::member#element
247+
staticType: C Function()
248+
argumentList: ArgumentList
249+
leftParenthesis: (
250+
rightParenthesis: )
251+
staticInvokeType: C Function()
252+
staticType: C
253+
''');
254+
}
255+
256+
test_chain_property() async {
257+
await assertNoErrorsInCode(r'''
258+
class C {
259+
static C member() => C(1);
260+
int x;
261+
C(this.x);
262+
C get property => C(1);
263+
}
264+
265+
void main() {
266+
C c = .member().property;
267+
print(c);
268+
}
269+
''');
270+
271+
var identifier = findNode.singleDotShorthandInvocation;
272+
assertResolvedNodeText(identifier, r'''
273+
DotShorthandInvocation
274+
period: .
275+
memberName: SimpleIdentifier
276+
token: member
277+
element: <testLibraryFragment>::@class::C::@method::member#element
278+
staticType: C Function()
279+
argumentList: ArgumentList
280+
leftParenthesis: (
281+
rightParenthesis: )
282+
staticInvokeType: C Function()
283+
staticType: C
284+
''');
285+
}
286+
225287
test_equality() async {
226288
await assertNoErrorsInCode('''
227289
class C {

pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart

+54
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,60 @@ main() {
1717
@reflectiveTest
1818
class DotShorthandPropertyAccessResolutionTest
1919
extends PubPackageResolutionTest {
20+
test_chain_method() async {
21+
await assertNoErrorsInCode(r'''
22+
class C {
23+
static C get member => C(1);
24+
int x;
25+
C(this.x);
26+
C method() => C(1);
27+
}
28+
29+
void main() {
30+
C c = .member.method();
31+
print(c);
32+
}
33+
''');
34+
35+
var identifier = findNode.singleDotShorthandPropertyAccess;
36+
assertResolvedNodeText(identifier, r'''
37+
DotShorthandPropertyAccess
38+
period: .
39+
propertyName: SimpleIdentifier
40+
token: member
41+
element: <testLibraryFragment>::@class::C::@getter::member#element
42+
staticType: C
43+
staticType: C
44+
''');
45+
}
46+
47+
test_chain_property() async {
48+
await assertNoErrorsInCode(r'''
49+
class C {
50+
static C get member => C(1);
51+
int x;
52+
C(this.x);
53+
C get property => C(1);
54+
}
55+
56+
void main() {
57+
C c = .member.property;
58+
print(c);
59+
}
60+
''');
61+
62+
var identifier = findNode.singleDotShorthandPropertyAccess;
63+
assertResolvedNodeText(identifier, r'''
64+
DotShorthandPropertyAccess
65+
period: .
66+
propertyName: SimpleIdentifier
67+
token: member
68+
element: <testLibraryFragment>::@class::C::@getter::member#element
69+
staticType: C
70+
staticType: C
71+
''');
72+
}
73+
2074
test_class_basic() async {
2175
await assertNoErrorsInCode('''
2276
class C {

0 commit comments

Comments
 (0)