Skip to content

Commit 8e9ad1b

Browse files
scheglovCommit Queue
authored and
Commit Queue
committed
Implicit cast of RecordLiteral fields from dynamic, tests, also for ImplicitCallReference.
Change-Id: I3a04b404cf7743c3cc383a83fa58080a3b7b294f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/262662 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent f042822 commit 8e9ad1b

File tree

3 files changed

+194
-3
lines changed

3 files changed

+194
-3
lines changed

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,26 @@ class RecordLiteralResolver {
123123
);
124124
}
125125

126-
void _resolveField(Expression field, DartType? contextType) {
126+
void _resolveField(ExpressionImpl field, DartType? contextType) {
127127
_resolver.analyzeExpression(field, contextType);
128-
_resolver.popRewrite();
128+
field = _resolver.popRewrite()!;
129+
130+
// Implicit cast from `dynamic`.
131+
if (contextType != null && field.typeOrThrow.isDynamic) {
132+
field.staticType = contextType;
133+
if (field is NamedExpressionImpl) {
134+
field.expression.staticType = contextType;
135+
}
136+
}
129137
}
130138

131139
void _resolveFields(RecordLiteralImpl node, DartType? contextType) {
132140
if (contextType is RecordType) {
133141
var index = 0;
134142
for (final field in node.fields) {
143+
field as ExpressionImpl;
135144
DartType? fieldContextType;
136-
if (field is NamedExpression) {
145+
if (field is NamedExpressionImpl) {
137146
final name = field.name.label.name;
138147
fieldContextType = contextType.namedField(name)?.type;
139148
} else {
@@ -146,6 +155,7 @@ class RecordLiteralResolver {
146155
}
147156
} else {
148157
for (final field in node.fields) {
158+
field as ExpressionImpl;
149159
_resolveField(field, null);
150160
}
151161
}

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

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,177 @@ main() {
1414

1515
@reflectiveTest
1616
class RecordLiteralTest extends PubPackageResolutionTest {
17+
test_field_rewrite_named() async {
18+
await assertNoErrorsInCode(r'''
19+
void f((int, String) r) {
20+
(f1: r.$0, );
21+
}
22+
''');
23+
24+
final node = findNode.recordLiteral('(f1');
25+
assertResolvedNodeText(node, r'''
26+
RecordLiteral
27+
leftParenthesis: (
28+
fields
29+
NamedExpression
30+
name: Label
31+
label: SimpleIdentifier
32+
token: f1
33+
staticElement: <null>
34+
staticType: null
35+
colon: :
36+
expression: PropertyAccess
37+
target: SimpleIdentifier
38+
token: r
39+
staticElement: self::@function::f::@parameter::r
40+
staticType: (int, String)
41+
operator: .
42+
propertyName: SimpleIdentifier
43+
token: $0
44+
staticElement: <null>
45+
staticType: int
46+
staticType: int
47+
rightParenthesis: )
48+
staticType: ({int f1})
49+
''');
50+
}
51+
52+
test_field_rewrite_positional() async {
53+
await assertNoErrorsInCode(r'''
54+
void f((int, String) r) {
55+
(r.$0, );
56+
}
57+
''');
58+
59+
final node = findNode.recordLiteral('(r');
60+
assertResolvedNodeText(node, r'''
61+
RecordLiteral
62+
leftParenthesis: (
63+
fields
64+
PropertyAccess
65+
target: SimpleIdentifier
66+
token: r
67+
staticElement: self::@function::f::@parameter::r
68+
staticType: (int, String)
69+
operator: .
70+
propertyName: SimpleIdentifier
71+
token: $0
72+
staticElement: <null>
73+
staticType: int
74+
staticType: int
75+
rightParenthesis: )
76+
staticType: (int)
77+
''');
78+
}
79+
80+
test_hasContext_implicitCallReference_named() async {
81+
await assertNoErrorsInCode(r'''
82+
class A {
83+
void call() {}
84+
}
85+
86+
final a = A();
87+
final ({void Function() f1}) x = (f1: a);
88+
''');
89+
90+
final node = findNode.recordLiteral('(f1');
91+
assertResolvedNodeText(node, r'''
92+
RecordLiteral
93+
leftParenthesis: (
94+
fields
95+
NamedExpression
96+
name: Label
97+
label: SimpleIdentifier
98+
token: f1
99+
staticElement: <null>
100+
staticType: null
101+
colon: :
102+
expression: ImplicitCallReference
103+
expression: SimpleIdentifier
104+
token: a
105+
staticElement: self::@getter::a
106+
staticType: A
107+
staticElement: self::@class::A::@method::call
108+
staticType: void Function()
109+
rightParenthesis: )
110+
staticType: ({void Function() f1})
111+
''');
112+
}
113+
114+
test_hasContext_implicitCallReference_positional() async {
115+
await assertNoErrorsInCode(r'''
116+
class A {
117+
void call() {}
118+
}
119+
120+
final a = A();
121+
final (void Function(), ) x = (a, );
122+
''');
123+
124+
final node = findNode.recordLiteral('(a');
125+
assertResolvedNodeText(node, r'''
126+
RecordLiteral
127+
leftParenthesis: (
128+
fields
129+
ImplicitCallReference
130+
expression: SimpleIdentifier
131+
token: a
132+
staticElement: self::@getter::a
133+
staticType: A
134+
staticElement: self::@class::A::@method::call
135+
staticType: void Function()
136+
rightParenthesis: )
137+
staticType: (void Function())
138+
''');
139+
}
140+
141+
test_hasContext_implicitCast_fromDynamic_named() async {
142+
await assertNoErrorsInCode(r'''
143+
final dynamic a = 0;
144+
final ({int f1}) x = (f1: a);
145+
''');
146+
147+
final node = findNode.recordLiteral('(f1');
148+
assertResolvedNodeText(node, r'''
149+
RecordLiteral
150+
leftParenthesis: (
151+
fields
152+
NamedExpression
153+
name: Label
154+
label: SimpleIdentifier
155+
token: f1
156+
staticElement: <null>
157+
staticType: null
158+
colon: :
159+
expression: SimpleIdentifier
160+
token: a
161+
staticElement: self::@getter::a
162+
staticType: int
163+
rightParenthesis: )
164+
staticType: ({int f1})
165+
''');
166+
}
167+
168+
test_hasContext_implicitCast_fromDynamic_positional() async {
169+
await assertNoErrorsInCode(r'''
170+
final dynamic a = 0;
171+
final (int, ) x = (a, );
172+
''');
173+
174+
final node = findNode.recordLiteral('(a');
175+
assertResolvedNodeText(node, r'''
176+
RecordLiteral
177+
leftParenthesis: (
178+
fields
179+
SimpleIdentifier
180+
token: a
181+
staticElement: self::@getter::a
182+
staticType: int
183+
rightParenthesis: )
184+
staticType: (int)
185+
''');
186+
}
187+
17188
test_hasContext_mixed() async {
18189
await assertNoErrorsInCode(r'''
19190
class A1 {}

pkg/analyzer/test/src/summary/resolved_ast_printer.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,16 @@ class ResolvedAstPrinter extends ThrowingAstVisitor<void> {
924924
_withIndent(() {
925925
_writeNamedChildEntities(node);
926926
_writeParameterElement(node);
927+
// Types of the node and its expression must be the same.
928+
if (node.expression.staticType != node.staticType) {
929+
final nodeType = node.staticType;
930+
final expressionType = node.expression.staticType;
931+
fail(
932+
'Must be the same:\n'
933+
'nodeType: $nodeType\n'
934+
'expressionType: $expressionType',
935+
);
936+
}
927937
});
928938
}
929939

0 commit comments

Comments
 (0)