Skip to content

Commit 73d6821

Browse files
kallentuCommit Queue
authored and
Commit Queue
committed
[analyzer] Dot shorthands: Report error when type arguments are not assignable.
This is a bug fix of the current implementation of dot shorthands type argument resolution. We want to make sure we're doing inference with the proper context type given at that point (with the element based on the dot shorthand context type we've saved). Then I made sure there was proper argument checking, not just for `FunctionExpressionInvocation`s, but with `DotShorthandInvocation`s as well. Tested with unit tests and language tests. Bug: #59835 Change-Id: I795046502214628389c6471e9424aca7152657e2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425780 Reviewed-by: Chloe Stefantsova <[email protected]> Commit-Queue: Kallen Tu <[email protected]>
1 parent 4ef2725 commit 73d6821

File tree

5 files changed

+89
-30
lines changed

5 files changed

+89
-30
lines changed

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

+10-7
Original file line numberDiff line numberDiff line change
@@ -258,23 +258,26 @@ class MethodInvocationResolver with ScopeHelpers {
258258
/// node. Otherwise, returns `null`.
259259
RewrittenMethodInvocationImpl? resolveDotShorthand(
260260
DotShorthandInvocationImpl node,
261-
List<WhyNotPromotedGetter> whyNotPromotedArguments,
262-
) {
261+
List<WhyNotPromotedGetter> whyNotPromotedArguments, {
262+
required TypeImpl contextType,
263+
}) {
263264
_invocation = node;
264265

265-
TypeImpl contextType =
266+
TypeImpl dotShorthandContextType =
266267
_resolver.getDotShorthandContext().unwrapTypeSchemaView();
267268

268269
// The static namespace denoted by `S` is also the namespace denoted by
269270
// `FutureOr<S>`.
270-
contextType = _resolver.typeSystem.futureOrBase(contextType);
271+
dotShorthandContextType = _resolver.typeSystem.futureOrBase(
272+
dotShorthandContextType,
273+
);
271274

272275
// TODO(kallentu): Dot shorthands work - Support other context types
273-
if (contextType is InterfaceTypeImpl) {
274-
var contextElement = contextType.element3;
276+
if (dotShorthandContextType is InterfaceTypeImpl) {
277+
var receiver = dotShorthandContextType.element3;
275278
return _resolveReceiverTypeLiteralForDotShorthand(
276279
node,
277-
contextElement,
280+
receiver,
278281
node.memberName,
279282
node.memberName.name,
280283
whyNotPromotedArguments,

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

+1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ class ElementResolver {
193193
return _methodInvocationResolver.resolveDotShorthand(
194194
node,
195195
whyNotPromotedArguments,
196+
contextType: contextType,
196197
);
197198
}
198199

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

+13-11
Original file line numberDiff line numberDiff line change
@@ -2467,24 +2467,26 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
24672467
whyNotPromotedArguments,
24682468
contextType: contextType,
24692469
);
2470-
2471-
var replacement = insertGenericFunctionInstantiation(
2472-
node,
2473-
contextType: contextType,
2474-
);
2475-
checkForArgumentTypesNotAssignableInList(
2476-
node.argumentList,
2477-
whyNotPromotedArguments,
2478-
);
2479-
_insertImplicitCallReference(replacement, contextType: contextType);
2480-
24812470
case DotShorthandConstructorInvocationImpl():
24822471
_instanceCreationExpressionResolver.resolveDotShorthand(
24832472
rewrittenExpression,
24842473
contextType: contextType,
24852474
);
24862475
}
24872476

2477+
if (rewrittenExpression is FunctionExpressionInvocationImpl ||
2478+
rewrittenExpression == null) {
2479+
var replacement = insertGenericFunctionInstantiation(
2480+
node,
2481+
contextType: contextType,
2482+
);
2483+
checkForArgumentTypesNotAssignableInList(
2484+
node.argumentList,
2485+
whyNotPromotedArguments,
2486+
);
2487+
_insertImplicitCallReference(replacement, contextType: contextType);
2488+
}
2489+
24882490
if (isDotShorthand(node)) {
24892491
popDotShorthandContext();
24902492
}

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

+53
Original file line numberDiff line numberDiff line change
@@ -618,4 +618,57 @@ DotShorthandInvocation
618618
dynamic
619619
''');
620620
}
621+
622+
test_typeParameters_inference() async {
623+
await assertNoErrorsInCode(r'''
624+
class C<T> {
625+
static C<X> foo<X>(X x) => new C<X>();
626+
C<U> cast<U>() => new C<U>();
627+
}
628+
void main() {
629+
C<bool> c = .foo("String").cast();
630+
print(c);
631+
}
632+
''');
633+
634+
var identifier = findNode.singleDotShorthandInvocation;
635+
assertResolvedNodeText(identifier, r'''
636+
DotShorthandInvocation
637+
period: .
638+
memberName: SimpleIdentifier
639+
token: foo
640+
element: <testLibraryFragment>::@class::C::@method::foo#element
641+
staticType: C<X> Function<X>(X)
642+
argumentList: ArgumentList
643+
leftParenthesis: (
644+
arguments
645+
SimpleStringLiteral
646+
literal: "String"
647+
rightParenthesis: )
648+
staticInvokeType: C<String> Function(String)
649+
staticType: C<String>
650+
typeArgumentTypes
651+
String
652+
''');
653+
}
654+
655+
test_typeParameters_notAssignable() async {
656+
await assertErrorsInCode(
657+
r'''
658+
class C<T> {
659+
static C<int> member() => C(1);
660+
661+
final T t;
662+
C(this.t);
663+
}
664+
665+
void main() {
666+
C<bool> c = .member();
667+
print(c);
668+
}
669+
670+
''',
671+
[error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 105, 9)],
672+
);
673+
}
621674
}

tests/language/dot_shorthands/member/static_method_type_parameter_error_test.dart

+12-12
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,22 @@ import '../dot_shorthand_helper.dart';
1111

1212
void main() {
1313
StaticMember<bool> s = .member();
14-
// ^
15-
// [analyzer] unspecified
16-
// [cfe] unspecified
14+
// ^^^^^^^^^
15+
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
16+
// [cfe] A value of type 'StaticMember<int>' can't be assigned to a variable of type 'StaticMember<bool>'.
1717

1818
StaticMember<int> sTypeParameters = .memberType("s");
19-
// ^
20-
// [analyzer] unspecified
21-
// [cfe] unspecified
19+
// ^^^
20+
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
21+
// [cfe] The argument type 'String' can't be assigned to the parameter type 'int'.
2222

2323
StaticMemberExt<bool> sExt = .member();
24-
// ^
25-
// [analyzer] unspecified
26-
// [cfe] unspecified
24+
// ^^^^^^^^^
25+
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
26+
// [cfe] A value of type 'StaticMemberExt<int>' can't be assigned to a variable of type 'StaticMemberExt<bool>'.
2727

2828
StaticMemberExt<int> sTypeParametersExt = .memberType("s");
29-
// ^
30-
// [analyzer] unspecified
31-
// [cfe] unspecified
29+
// ^^^
30+
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
31+
// [cfe] The argument type 'String' can't be assigned to the parameter type 'int'.
3232
}

0 commit comments

Comments
 (0)