analyzer: resolve function type alias type instantiation
This code is a little weird because of how this type instantiation
works:
```
typedef Fn<T> = void Function(T);
var x = Fn<int>.foo;
var y = (Fn<int>).foo;
extension on Type {
int get foo => 1;
}
```
`x` is illegal under any circumstance, because calling a getter on a
type instantiation can _only_ resolve to a constructor, but function
types do not have constructors. But it's nice to resolve what we can,
and what the user may have meant, and we have to represent
`Fn<int>.foo` _somehow_. So it's a property access on a TypeLiteral.
Add two new codes because it is not correct to say that `foo` is not a
getter on 'Type' because that is beside the point. The issue is that
there is no possible getter on a type-instantiated type literal of
a function type alias (nor method, nor setter).
Add lots of tests, for calling a method, a getter, and a setter on a
function type alias literal. Add tests with prefixes, bounds, too
many and too few args.
Bug: https://github.com/dart-lang/sdk/issues/46020
Change-Id: Icdf17506a64b3382226c5e50786784130d9e3bf9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/213287
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 9c671fc..f037f8b 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -440,13 +440,16 @@
CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
CompileTimeErrorCode.UNDEFINED_FUNCTION,
CompileTimeErrorCode.UNDEFINED_GETTER,
+ CompileTimeErrorCode.UNDEFINED_GETTER_ON_FUNCTION_TYPE,
CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
CompileTimeErrorCode.UNDEFINED_IDENTIFIER_AWAIT,
CompileTimeErrorCode.UNDEFINED_METHOD,
+ CompileTimeErrorCode.UNDEFINED_METHOD_ON_FUNCTION_TYPE,
CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER,
CompileTimeErrorCode.UNDEFINED_OPERATOR,
CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
CompileTimeErrorCode.UNDEFINED_SETTER,
+ CompileTimeErrorCode.UNDEFINED_SETTER_ON_FUNCTION_TYPE,
CompileTimeErrorCode.UNDEFINED_SUPER_GETTER,
CompileTimeErrorCode.UNDEFINED_SUPER_METHOD,
CompileTimeErrorCode.UNDEFINED_SUPER_OPERATOR,
diff --git a/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart b/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart
index 513220e..1dc3670 100644
--- a/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/ast_factory.dart';
@@ -26,7 +27,9 @@
class AstRewriter {
final ErrorReporter _errorReporter;
- AstRewriter(this._errorReporter);
+ final TypeProvider _typeProvider;
+
+ AstRewriter(this._errorReporter, this._typeProvider);
/// Possibly rewrites [node] as a [MethodInvocation] with a
/// [FunctionReference] target.
@@ -45,9 +48,15 @@
var typeName = node.constructorName.type.name;
if (typeName is SimpleIdentifier) {
var element = nameScope.lookup(typeName.name).getter;
- if (element is FunctionElement || element is MethodElement) {
+ if (element is FunctionElement ||
+ element is MethodElement ||
+ element is PropertyAccessorElement) {
return _toMethodInvocationOfFunctionReference(
node: node, function: typeName);
+ } else if (element is TypeAliasElement &&
+ element.aliasedElement is GenericFunctionTypeElement) {
+ return _toMethodInvocationOfAliasedTypeLiteral(
+ node: node, function: typeName, element: element);
}
} else if (typeName is PrefixedIdentifier) {
var prefixElement = nameScope.lookup(typeName.prefix.name).getter;
@@ -57,6 +66,10 @@
if (element is FunctionElement) {
return _toMethodInvocationOfFunctionReference(
node: node, function: typeName);
+ } else if (element is TypeAliasElement &&
+ element.aliasedElement is GenericFunctionTypeElement) {
+ return _toMethodInvocationOfAliasedTypeLiteral(
+ node: node, function: typeName, element: element);
}
// If `element` is a [ClassElement], or a [TypeAliasElement] aliasing
@@ -490,6 +503,28 @@
return instanceCreationExpression;
}
+ MethodInvocation _toMethodInvocationOfAliasedTypeLiteral({
+ required InstanceCreationExpression node,
+ required Identifier function,
+ required TypeAliasElement element,
+ }) {
+ var typeName = astFactory.typeName(node.constructorName.type.name,
+ node.constructorName.type.typeArguments);
+ typeName.type = element.aliasedType;
+ typeName.name.staticType = element.aliasedType;
+ var typeLiteral = astFactory.typeLiteral(typeName: typeName);
+ typeLiteral.staticType = _typeProvider.typeType;
+ var methodInvocation = astFactory.methodInvocation(
+ typeLiteral,
+ node.constructorName.period,
+ node.constructorName.name!,
+ null,
+ node.argumentList,
+ );
+ NodeReplacer.replace(node, methodInvocation);
+ return methodInvocation;
+ }
+
MethodInvocation _toMethodInvocationOfFunctionReference({
required InstanceCreationExpression node,
required Identifier function,
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
index aabb65f..790cd79 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
@@ -564,7 +564,13 @@
// `prefix.C<int>.name` is initially represented as a [PropertyAccess]
// with a [FunctionReference] target.
if (node.parent is PropertyAccess) {
- _resolveConstructorReference(node);
+ if (element is TypeAliasElement &&
+ element.aliasedType is FunctionType) {
+ function.staticElement = element;
+ _resolveTypeAlias(node: node, element: element, typeAlias: function);
+ } else {
+ _resolveConstructorReference(node);
+ }
return;
} else if (element is ClassElement) {
function.staticElement = element;
@@ -649,6 +655,10 @@
required DartType instantiatedType,
required Identifier name,
}) {
+ // TODO(srawlins): set the static element of [typeName].
+ // This involves a fair amount of resolution, as [name] may be a prefixed
+ // identifier, etc. [TypeName]s should be resolved in [ResolutionVisitor],
+ // and this could be done for nodes like this via [AstRewriter].
var typeName = astFactory.typeName(name, node.typeArguments);
typeName.type = instantiatedType;
typeName.name.staticType = instantiatedType;
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index d5d7b50..190ab31 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -164,6 +164,21 @@
return;
}
+ if (receiver is TypeLiteralImpl &&
+ receiver.typeName.typeArguments != null &&
+ receiver.typeName.type is FunctionType) {
+ // There is no possible resolution for a property access of a function
+ // type literal (which can only be a type instantiation of a type alias
+ // of a function type).
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_METHOD_ON_FUNCTION_TYPE,
+ nameNode,
+ [name, receiver.typeName.name.name],
+ );
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
+ return;
+ }
+
_resolveReceiverType(
node: node,
receiver: receiver,
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 84c1ec2..86f1008 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -368,6 +368,26 @@
targetType = _typeSystem.promoteToNonNull(targetType);
}
+ if (target is TypeLiteral && target.typeName.type is FunctionType) {
+ // There is no possible resolution for a property access of a function
+ // type literal (which can only be a type instantiation of a type alias
+ // of a function type).
+ if (hasRead) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_GETTER_ON_FUNCTION_TYPE,
+ propertyName,
+ [propertyName.name, target.typeName.name.name],
+ );
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_SETTER_ON_FUNCTION_TYPE,
+ propertyName,
+ [propertyName.name, target.typeName.name.name],
+ );
+ }
+ return PropertyElementResolverResult();
+ }
+
var result = _resolver.typePropertyResolver.resolve(
receiver: target,
receiverType: targetType,
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index 9efde38..d25fcf6 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -116,7 +116,7 @@
unitElement,
isNonNullableByDefault,
errorReporter,
- AstRewriter(errorReporter),
+ AstRewriter(errorReporter, typeProvider),
typeNameResolver,
nameScope,
elementWalker,
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index ae429a2..c93f71d 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -13838,6 +13838,19 @@
/**
* Parameters:
+ * 0: the name of the getter
+ * 1: the name of the function type alias
+ */
+ static const CompileTimeErrorCode UNDEFINED_GETTER_ON_FUNCTION_TYPE =
+ CompileTimeErrorCode('UNDEFINED_GETTER',
+ "The getter '{0}' isn't defined for the '{1}' function type.",
+ correction: "Try wrapping the function type alias in parentheses in "
+ "order to access '{0}' as an extension getter on 'Type'.",
+ hasPublishedDocs: true,
+ uniqueName: 'UNDEFINED_GETTER_ON_FUNCTION_TYPE');
+
+ /**
+ * Parameters:
* 0: the name of the identifier
*/
// #### Description
@@ -13947,6 +13960,19 @@
/**
* Parameters:
+ * 0: the name of the method
+ * 1: the name of the function type alias
+ */
+ static const CompileTimeErrorCode UNDEFINED_METHOD_ON_FUNCTION_TYPE =
+ CompileTimeErrorCode('UNDEFINED_METHOD',
+ "The method '{0}' isn't defined for the '{1}' function type.",
+ correction: "Try wrapping the function type alias in parentheses in "
+ "order to access '{0}' as an extension method on 'Type'.",
+ hasPublishedDocs: true,
+ uniqueName: 'UNDEFINED_METHOD_ON_FUNCTION_TYPE');
+
+ /**
+ * Parameters:
* 0: the name of the requested named parameter
*/
// #### Description
@@ -14150,6 +14176,19 @@
/**
* Parameters:
+ * 0: the name of the setter
+ * 1: the name of the function type alias
+ */
+ static const CompileTimeErrorCode UNDEFINED_SETTER_ON_FUNCTION_TYPE =
+ CompileTimeErrorCode('UNDEFINED_SETTER',
+ "The setter '{0}' isn't defined for the '{1}' function type.",
+ correction: "Try wrapping the function type alias in parentheses in "
+ "order to access '{0}' as an extension getter on 'Type'.",
+ hasPublishedDocs: true,
+ uniqueName: 'UNDEFINED_SETTER_ON_FUNCTION_TYPE');
+
+ /**
+ * Parameters:
* 0: the name of the getter
* 1: the name of the enclosing type where the getter is being looked for
*/
diff --git a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
index aa9f1fe..37dddf5 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
@@ -60,25 +60,52 @@
findElement.constructor('foo'), 'dynamic');
}
+ test_dynamicTyped() async {
+ await assertErrorsInCode('''
+dynamic i = 1;
+
+void bar() {
+ i<int>;
+}
+''', [
+ error(
+ CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION, 31, 1),
+ ]);
+
+ assertFunctionReference(findNode.functionReference('i<int>;'),
+ findElement.topGet('i'), 'dynamic');
+ }
+
+ test_dynamicTyped_targetOfMethodCall() async {
+ await assertErrorsInCode('''
+dynamic i = 1;
+
+void bar() {
+ i<int>.foo();
+}
+''', [
+ error(
+ CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION, 31, 1),
+ ]);
+
+ assertFunctionReference(findNode.functionReference('i<int>.foo();'),
+ findElement.topGet('i'), 'dynamic');
+ }
+
test_explicitReceiver_dynamicTyped() async {
await assertErrorsInCode('''
-dynamic f(dynamic x) => x;
+dynamic f() => 1;
-class C {
- T instanceMethod<T>(T t) => t;
-}
-
-main() {
- C c = new C();
- f(c).instanceMethod<int>;
+foo() {
+ f().instanceMethod<int>;
}
''', [
error(CompileTimeErrorCode.GENERIC_METHOD_TYPE_INSTANTIATION_ON_DYNAMIC,
- 102, 24),
+ 29, 23),
]);
assertFunctionReference(
- findNode.functionReference('f(c).instanceMethod<int>;'),
+ findNode.functionReference('f().instanceMethod<int>;'),
null,
'dynamic');
}
@@ -702,6 +729,22 @@
assertFunctionReference(reference, findElement.parameter('foo'), 'dynamic');
}
+ test_neverTyped() async {
+ await assertErrorsInCode('''
+external Never get i;
+
+void bar() {
+ i<int>;
+}
+''', [
+ error(
+ CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION, 38, 1),
+ ]);
+
+ assertFunctionReference(findNode.functionReference('i<int>;'),
+ findElement.topGet('i'), 'dynamic');
+ }
+
test_nonGenericFunction() async {
await assertErrorsInCode('''
class A {
diff --git a/pkg/analyzer/test/src/dart/resolution/type_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/type_literal_test.dart
index 5391331..8172670 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_literal_test.dart
@@ -70,6 +70,18 @@
assertTypeLiteral(typeLiteral, findElement.class_('C'), 'C<dynamic>');
}
+ test_class_typeArgumentDoesNotMatchBound() async {
+ await assertErrorsInCode('''
+class C<T extends num> {}
+var t = C<String>;
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 36, 6),
+ ]);
+
+ var typeLiteral = findNode.typeLiteral('C<String>;');
+ assertTypeLiteral(typeLiteral, findElement.class_('C'), 'C<String>');
+ }
+
test_classAlias() async {
await assertNoErrorsInCode('''
class C<T> {}
@@ -124,6 +136,19 @@
);
}
+ test_classAlias_typeArgumentDoesNotMatchBound() async {
+ await assertErrorsInCode('''
+class C<T> {}
+typedef CA<T extends num> = C<T>;
+var t = CA<String>;
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 59, 6),
+ ]);
+
+ var typeLiteral = findNode.typeLiteral('CA<String>;');
+ assertTypeLiteral(typeLiteral, findElement.typeAlias('CA'), 'C<String>');
+ }
+
test_functionAlias() async {
await assertNoErrorsInCode('''
typedef Fn<T> = void Function(T);
@@ -135,6 +160,231 @@
typeLiteral, findElement.typeAlias('Fn'), 'void Function(int)');
}
+ test_functionAlias_importPrefix() async {
+ newFile('$testPackageLibPath/a.dart', content: '''
+typedef Fn<T> = void Function(T);
+''');
+ await assertNoErrorsInCode('''
+import 'a.dart' as a;
+var t = a.Fn<int>;
+''');
+
+ var typeLiteral = findNode.typeLiteral('Fn<int>;');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.importFind('package:test/a.dart').typeAlias('Fn'),
+ 'void Function(int)',
+ expectedPrefix: findElement.prefix('a'),
+ );
+ }
+
+ test_functionAlias_targetOfMethodCall() async {
+ await assertErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ Fn<int>.foo();
+}
+
+extension E on Type {
+ void foo() {}
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_METHOD_ON_FUNCTION_TYPE, 58, 3),
+ ]);
+
+ var typeLiteral = findNode.typeLiteral('Fn<int>');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.typeAlias('Fn'),
+ 'void Function(int)',
+ );
+ }
+
+ test_functionAlias_targetOfMethodCall_importPrefix() async {
+ newFile('$testPackageLibPath/a.dart', content: '''
+typedef Fn<T> = void Function(T);
+''');
+ await assertErrorsInCode('''
+import 'a.dart' as a;
+
+void bar() {
+ a.Fn<int>.foo();
+}
+
+extension E on Type {
+ void foo() {}
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_METHOD_ON_FUNCTION_TYPE, 48, 3),
+ ]);
+
+ var typeLiteral = findNode.typeLiteral('Fn<int>');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.importFind('package:test/a.dart').typeAlias('Fn'),
+ 'void Function(int)',
+ expectedPrefix: findElement.prefix('a'),
+ );
+ }
+
+ test_functionAlias_targetOfMethodCall_parenthesized() async {
+ await assertNoErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ (Fn<int>).foo();
+}
+
+extension E on Type {
+ void foo() {}
+}
+''');
+
+ var typeLiteral = findNode.typeLiteral('Fn<int>');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.typeAlias('Fn'),
+ 'void Function(int)',
+ );
+ }
+
+ test_functionAlias_targetOfPropertyAccess_getter() async {
+ await assertErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ Fn<int>.foo;
+}
+
+extension E on Type {
+ int get foo => 1;
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_GETTER_ON_FUNCTION_TYPE, 58, 3),
+ ]);
+
+ var typeLiteral = findNode.typeLiteral('Fn<int>');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.typeAlias('Fn'),
+ 'void Function(int)',
+ );
+ }
+
+ test_functionAlias_targetOfPropertyAccess_getter_parenthesized() async {
+ await assertNoErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ (Fn<int>).foo;
+}
+
+extension E on Type {
+ int get foo => 1;
+}
+''');
+
+ var typeLiteral = findNode.typeLiteral('Fn<int>');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.typeAlias('Fn'),
+ 'void Function(int)',
+ );
+ }
+
+ test_functionAlias_targetOfPropertyAccess_setter() async {
+ await assertErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ Fn<int>.foo = 7;
+}
+
+extension E on Type {
+ set foo(int value) {}
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_SETTER_ON_FUNCTION_TYPE, 58, 3),
+ ]);
+
+ var typeLiteral = findNode.typeLiteral('Fn<int>');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.typeAlias('Fn'),
+ 'void Function(int)',
+ );
+ }
+
+ test_functionAlias_targetOfPropertyAccess_setter_parenthesized() async {
+ await assertNoErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ (Fn<int>).foo = 7;
+}
+
+extension E on Type {
+ set foo(int value) {}
+}
+''');
+
+ var typeLiteral = findNode.typeLiteral('Fn<int>');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.typeAlias('Fn'),
+ 'void Function(int)',
+ );
+ }
+
+ test_functionAlias_tooFewTypeArgs() async {
+ await assertErrorsInCode('''
+typedef Fn<T, U> = void Function(T, U);
+var t = Fn<int>;
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 50, 5),
+ ]);
+
+ var typeLiteral = findNode.typeLiteral('Fn<int>;');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.typeAlias('Fn'),
+ 'void Function(dynamic, dynamic)',
+ );
+ }
+
+ test_functionAlias_tooManyTypeArgs() async {
+ await assertErrorsInCode('''
+typedef Fn<T> = void Function(T);
+var t = Fn<int, String>;
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 44, 13),
+ ]);
+
+ var typeLiteral = findNode.typeLiteral('Fn<int, String>;');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.typeAlias('Fn'),
+ 'void Function(dynamic)',
+ );
+ }
+
+ test_functionAlias_typeArgumentDoesNotMatchBound() async {
+ await assertErrorsInCode('''
+typedef Fn<T extends num> = void Function(T);
+var t = Fn<String>;
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 57, 6),
+ ]);
+
+ var typeLiteral = findNode.typeLiteral('Fn<String>;');
+ assertTypeLiteral(
+ typeLiteral,
+ findElement.typeAlias('Fn'),
+ 'void Function(String)',
+ );
+ }
+
test_mixin() async {
await assertNoErrorsInCode('''
mixin M<T> {}
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
index cb85d4f..ae2410c 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
@@ -388,6 +388,36 @@
@reflectiveTest
class UndefinedGetterWithNullSafetyTest extends PubPackageResolutionTest
with UndefinedGetterTestCases {
+ test_functionAlias_typeInstantiated_getter() async {
+ await assertErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ Fn<int>.foo;
+}
+
+extension E on Type {
+ int get foo => 1;
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_GETTER_ON_FUNCTION_TYPE, 58, 3),
+ ]);
+ }
+
+ test_functionAlias_typeInstantiated_getter_parenthesized() async {
+ await assertNoErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ (Fn<int>).foo;
+}
+
+extension E on Type {
+ int get foo => 1;
+}
+''');
+ }
+
test_get_from_abstract_field_final_valid() async {
await assertNoErrorsInCode('''
abstract class A {
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_method_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_method_test.dart
index 34c7247..483d1dc 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_method_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_method_test.dart
@@ -62,6 +62,50 @@
]);
}
+ test_functionAlias_notInstantiated() async {
+ await assertNoErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ Fn.foo();
+}
+
+extension E on Type {
+ void foo() {}
+}
+''');
+ }
+
+ test_functionAlias_typeInstantiated() async {
+ await assertErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ Fn<int>.foo();
+}
+
+extension E on Type {
+ void foo() {}
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_METHOD_ON_FUNCTION_TYPE, 58, 3),
+ ]);
+ }
+
+ test_functionAlias_typeInstantiated_parenthesized() async {
+ await assertNoErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ (Fn<int>).foo();
+}
+
+extension E on Type {
+ void foo() {}
+}
+''');
+ }
+
test_functionExpression_callMethod_defined() async {
await assertNoErrorsInCode(r'''
main() {
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_setter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_setter_test.dart
index d1674c6..d97a894 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_setter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_setter_test.dart
@@ -143,6 +143,36 @@
@reflectiveTest
class UndefinedSetterWithNullSafetyTest extends PubPackageResolutionTest
with UndefinedSetterTestCases {
+ test_functionAlias_typeInstantiated() async {
+ await assertErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ Fn<int>.foo = 7;
+}
+
+extension E on Type {
+ set foo(int value) {}
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_SETTER_ON_FUNCTION_TYPE, 58, 3),
+ ]);
+ }
+
+ test_functionAlias_typeInstantiated_parenthesized() async {
+ await assertNoErrorsInCode('''
+typedef Fn<T> = void Function(T);
+
+void bar() {
+ (Fn<int>).foo = 7;
+}
+
+extension E on Type {
+ set foo(int value) {}
+}
+''');
+ }
+
test_new_cascade() async {
await assertErrorsInCode('''
class C {}
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 60b5987..3b82cae 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -13547,6 +13547,8 @@
### undefined_getter
+_The getter '{0}' isn't defined for the '{1}' function type._
+
_The getter '{0}' isn't defined for the type '{1}'._
#### Description
@@ -13668,6 +13670,8 @@
### undefined_method
+_The method '{0}' isn't defined for the '{1}' function type._
+
_The method '{0}' isn't defined for the type '{1}'._
#### Description
@@ -13830,6 +13834,8 @@
### undefined_setter
+_The setter '{0}' isn't defined for the '{1}' function type._
+
_The setter '{0}' isn't defined for the type '{1}'._
#### Description