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