mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 12:57:42 +00:00
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 <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
f042822993
commit
8e9ad1bd7a
|
@ -123,17 +123,26 @@ class RecordLiteralResolver {
|
|||
);
|
||||
}
|
||||
|
||||
void _resolveField(Expression field, DartType? contextType) {
|
||||
void _resolveField(ExpressionImpl field, DartType? contextType) {
|
||||
_resolver.analyzeExpression(field, contextType);
|
||||
_resolver.popRewrite();
|
||||
field = _resolver.popRewrite()!;
|
||||
|
||||
// Implicit cast from `dynamic`.
|
||||
if (contextType != null && field.typeOrThrow.isDynamic) {
|
||||
field.staticType = contextType;
|
||||
if (field is NamedExpressionImpl) {
|
||||
field.expression.staticType = contextType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _resolveFields(RecordLiteralImpl node, DartType? contextType) {
|
||||
if (contextType is RecordType) {
|
||||
var index = 0;
|
||||
for (final field in node.fields) {
|
||||
field as ExpressionImpl;
|
||||
DartType? fieldContextType;
|
||||
if (field is NamedExpression) {
|
||||
if (field is NamedExpressionImpl) {
|
||||
final name = field.name.label.name;
|
||||
fieldContextType = contextType.namedField(name)?.type;
|
||||
} else {
|
||||
|
@ -146,6 +155,7 @@ class RecordLiteralResolver {
|
|||
}
|
||||
} else {
|
||||
for (final field in node.fields) {
|
||||
field as ExpressionImpl;
|
||||
_resolveField(field, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,177 @@ main() {
|
|||
|
||||
@reflectiveTest
|
||||
class RecordLiteralTest extends PubPackageResolutionTest {
|
||||
test_field_rewrite_named() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
void f((int, String) r) {
|
||||
(f1: r.$0, );
|
||||
}
|
||||
''');
|
||||
|
||||
final node = findNode.recordLiteral('(f1');
|
||||
assertResolvedNodeText(node, r'''
|
||||
RecordLiteral
|
||||
leftParenthesis: (
|
||||
fields
|
||||
NamedExpression
|
||||
name: Label
|
||||
label: SimpleIdentifier
|
||||
token: f1
|
||||
staticElement: <null>
|
||||
staticType: null
|
||||
colon: :
|
||||
expression: PropertyAccess
|
||||
target: SimpleIdentifier
|
||||
token: r
|
||||
staticElement: self::@function::f::@parameter::r
|
||||
staticType: (int, String)
|
||||
operator: .
|
||||
propertyName: SimpleIdentifier
|
||||
token: $0
|
||||
staticElement: <null>
|
||||
staticType: int
|
||||
staticType: int
|
||||
rightParenthesis: )
|
||||
staticType: ({int f1})
|
||||
''');
|
||||
}
|
||||
|
||||
test_field_rewrite_positional() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
void f((int, String) r) {
|
||||
(r.$0, );
|
||||
}
|
||||
''');
|
||||
|
||||
final node = findNode.recordLiteral('(r');
|
||||
assertResolvedNodeText(node, r'''
|
||||
RecordLiteral
|
||||
leftParenthesis: (
|
||||
fields
|
||||
PropertyAccess
|
||||
target: SimpleIdentifier
|
||||
token: r
|
||||
staticElement: self::@function::f::@parameter::r
|
||||
staticType: (int, String)
|
||||
operator: .
|
||||
propertyName: SimpleIdentifier
|
||||
token: $0
|
||||
staticElement: <null>
|
||||
staticType: int
|
||||
staticType: int
|
||||
rightParenthesis: )
|
||||
staticType: (int)
|
||||
''');
|
||||
}
|
||||
|
||||
test_hasContext_implicitCallReference_named() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {
|
||||
void call() {}
|
||||
}
|
||||
|
||||
final a = A();
|
||||
final ({void Function() f1}) x = (f1: a);
|
||||
''');
|
||||
|
||||
final node = findNode.recordLiteral('(f1');
|
||||
assertResolvedNodeText(node, r'''
|
||||
RecordLiteral
|
||||
leftParenthesis: (
|
||||
fields
|
||||
NamedExpression
|
||||
name: Label
|
||||
label: SimpleIdentifier
|
||||
token: f1
|
||||
staticElement: <null>
|
||||
staticType: null
|
||||
colon: :
|
||||
expression: ImplicitCallReference
|
||||
expression: SimpleIdentifier
|
||||
token: a
|
||||
staticElement: self::@getter::a
|
||||
staticType: A
|
||||
staticElement: self::@class::A::@method::call
|
||||
staticType: void Function()
|
||||
rightParenthesis: )
|
||||
staticType: ({void Function() f1})
|
||||
''');
|
||||
}
|
||||
|
||||
test_hasContext_implicitCallReference_positional() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A {
|
||||
void call() {}
|
||||
}
|
||||
|
||||
final a = A();
|
||||
final (void Function(), ) x = (a, );
|
||||
''');
|
||||
|
||||
final node = findNode.recordLiteral('(a');
|
||||
assertResolvedNodeText(node, r'''
|
||||
RecordLiteral
|
||||
leftParenthesis: (
|
||||
fields
|
||||
ImplicitCallReference
|
||||
expression: SimpleIdentifier
|
||||
token: a
|
||||
staticElement: self::@getter::a
|
||||
staticType: A
|
||||
staticElement: self::@class::A::@method::call
|
||||
staticType: void Function()
|
||||
rightParenthesis: )
|
||||
staticType: (void Function())
|
||||
''');
|
||||
}
|
||||
|
||||
test_hasContext_implicitCast_fromDynamic_named() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
final dynamic a = 0;
|
||||
final ({int f1}) x = (f1: a);
|
||||
''');
|
||||
|
||||
final node = findNode.recordLiteral('(f1');
|
||||
assertResolvedNodeText(node, r'''
|
||||
RecordLiteral
|
||||
leftParenthesis: (
|
||||
fields
|
||||
NamedExpression
|
||||
name: Label
|
||||
label: SimpleIdentifier
|
||||
token: f1
|
||||
staticElement: <null>
|
||||
staticType: null
|
||||
colon: :
|
||||
expression: SimpleIdentifier
|
||||
token: a
|
||||
staticElement: self::@getter::a
|
||||
staticType: int
|
||||
rightParenthesis: )
|
||||
staticType: ({int f1})
|
||||
''');
|
||||
}
|
||||
|
||||
test_hasContext_implicitCast_fromDynamic_positional() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
final dynamic a = 0;
|
||||
final (int, ) x = (a, );
|
||||
''');
|
||||
|
||||
final node = findNode.recordLiteral('(a');
|
||||
assertResolvedNodeText(node, r'''
|
||||
RecordLiteral
|
||||
leftParenthesis: (
|
||||
fields
|
||||
SimpleIdentifier
|
||||
token: a
|
||||
staticElement: self::@getter::a
|
||||
staticType: int
|
||||
rightParenthesis: )
|
||||
staticType: (int)
|
||||
''');
|
||||
}
|
||||
|
||||
test_hasContext_mixed() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class A1 {}
|
||||
|
|
|
@ -924,6 +924,16 @@ class ResolvedAstPrinter extends ThrowingAstVisitor<void> {
|
|||
_withIndent(() {
|
||||
_writeNamedChildEntities(node);
|
||||
_writeParameterElement(node);
|
||||
// Types of the node and its expression must be the same.
|
||||
if (node.expression.staticType != node.staticType) {
|
||||
final nodeType = node.staticType;
|
||||
final expressionType = node.expression.staticType;
|
||||
fail(
|
||||
'Must be the same:\n'
|
||||
'nodeType: $nodeType\n'
|
||||
'expressionType: $expressionType',
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue