[analyzer] Dot shorthands: Infer type parameters in constructor tearoffs.
This CL fixes co19/LanguageFeatures/Static-access-shorthand
/semantics_A05_t01.dart.
While working on this, I realized the static type was wrong and we weren't doing any inference for the constructor references so I updated the logic.
Unit tests passing, language test expectations are actually better than before and that particular co19 test passing.
Bug: https://github.com/dart-lang/sdk/issues/59835
Change-Id: I7437079c33640f53f48a4445890fadfebc9ec158
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430561
Reviewed-by: Erik Ernst <eernst@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index ead089f..18cb257 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/extensions.dart';
+import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
@@ -39,8 +40,9 @@
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
PropertyElementResolverResult resolveDotShorthand(
- DotShorthandPropertyAccessImpl node,
- ) {
+ DotShorthandPropertyAccessImpl node, {
+ required TypeImpl contextType,
+ }) {
if (_resolver.isDotShorthandContextEmpty) {
assert(
false,
@@ -76,6 +78,35 @@
}
}
+ // Infer type parameters.
+ var elementToInfer = _resolver.inferenceHelper
+ .constructorElementToInfer(
+ typeElement: context.element3,
+ constructorName: identifier,
+ definingLibrary: _resolver.definingLibrary,
+ );
+ if (elementToInfer != null &&
+ elementToInfer.typeParameters2.isNotEmpty) {
+ var inferred =
+ _resolver.inferenceHelper.inferTearOff(
+ node,
+ identifier,
+ elementToInfer.asType,
+ contextType: contextType,
+ )
+ as FunctionType;
+ var inferredType = inferred.returnType;
+ var constructorElement = ConstructorMember.from2(
+ elementToInfer.element2.baseElement,
+ inferredType as InterfaceType,
+ );
+ node.propertyName.element = constructorElement.baseElement;
+ return PropertyElementResolverResult(
+ readElementRequested2: node.propertyName.element,
+ getType: inferred.returnType,
+ );
+ }
+
return PropertyElementResolverResult(
readElementRequested2: element,
getType: element.returnType,
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index eac26ef..2fe4dda 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2524,7 +2524,10 @@
}
checkUnreachableNode(node);
- var result = _propertyElementResolver.resolveDotShorthand(node);
+ var result = _propertyElementResolver.resolveDotShorthand(
+ node,
+ contextType: contextType,
+ );
_resolvePropertyAccessRhs_common(
result,
node,
@@ -4462,7 +4465,7 @@
DartType type;
if (element is MethodElement) {
type = element.type;
- } else if (element is ConstructorElementImpl2) {
+ } else if (element is ConstructorElementMixin2) {
type = element.type;
} else if (element is GetterElement) {
type = resolverResult.getType!;
diff --git a/pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart b/pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart
index b086744..ea78ad2 100644
--- a/pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/dot_shorthand_property_access_test.dart
@@ -652,6 +652,38 @@
);
}
+ test_tearOff_constructor_generic() async {
+ await assertNoErrorsInCode(r'''
+class C<T> {
+ T t;
+ C(this.t);
+ C.id(this.t);
+}
+
+void main() {
+ Object? o = C<int>(0);
+ if (o is C<int>) {
+ o = .new;
+ if (o is Function) {
+ o(1).t;
+ }
+ }
+}
+''');
+
+ var dotShorthand = findNode.singleDotShorthandPropertyAccess;
+ assertResolvedNodeText(dotShorthand, r'''
+DotShorthandPropertyAccess
+ period: .
+ propertyName: SimpleIdentifier
+ token: new
+ element: <testLibraryFragment>::@class::C::@constructor::new#element
+ staticType: C<T> Function(T)
+ correspondingParameter: <null>
+ staticType: C<T> Function(T)
+''');
+ }
+
test_tearOff_constructor_new() async {
await assertNoErrorsInCode('''
void main() {
diff --git a/tests/language/dot_shorthands/type_parameter/type_parameter_error_test.dart b/tests/language/dot_shorthands/type_parameter/type_parameter_error_test.dart
index eb2caa0..2c5636c 100644
--- a/tests/language/dot_shorthands/type_parameter/type_parameter_error_test.dart
+++ b/tests/language/dot_shorthands/type_parameter/type_parameter_error_test.dart
@@ -58,8 +58,10 @@
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_TYPE_ARGUMENTS_FUNCTION
ET e = .new<int>;
- // ^^^^
- // [analyzer] COMPILE_TIME_ERROR.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION
+ // ^^^^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A dot shorthand constructor invocation can't have type arguments.
+ // ^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_TYPE_ARGUMENTS_FUNCTION
}