blob: 7fe150540895472cd84095e7b4ab890822530a20 [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
import 'package:analyzer/src/dart/resolver/resolution_result.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/super_context.dart';
import 'package:analyzer/src/generated/variable_type_provider.dart';
class MethodInvocationResolver {
static final _nameCall = new Name(null, 'call');
/// The resolver driving this participant.
final ResolverVisitor _resolver;
/// The type representing the type 'dynamic'.
final DynamicTypeImpl _dynamicType = DynamicTypeImpl.instance;
/// The type representing the type 'type'.
final InterfaceType _typeType;
/// The manager for the inheritance mappings.
final InheritanceManager3 _inheritance;
/// The element for the library containing the compilation unit being visited.
final LibraryElement _definingLibrary;
/// The URI of [_definingLibrary].
final Uri _definingLibraryUri;
/// The object providing promoted or declared types of variables.
final LocalVariableTypeProvider _localVariableTypeProvider;
/// Helper for extension method resolution.
final ExtensionMemberResolver _extensionResolver;
/// The invocation being resolved.
MethodInvocationImpl _invocation;
/// The [Name] object of the invocation being resolved by [resolve].
Name _currentName;
MethodInvocationResolver(this._resolver)
: _typeType = _resolver.typeProvider.typeType,
_inheritance = _resolver.inheritance,
_definingLibrary = _resolver.definingLibrary,
_definingLibraryUri = _resolver.definingLibrary.source.uri,
_localVariableTypeProvider = _resolver.localVariableTypeProvider,
_extensionResolver = _resolver.extensionResolver;
/// The scope used to resolve identifiers.
Scope get nameScope => _resolver.nameScope;
void resolve(MethodInvocation node) {
_invocation = node;
SimpleIdentifier nameNode = node.methodName;
String name = nameNode.name;
_currentName = Name(_definingLibraryUri, name);
//
// Synthetic identifiers have been already reported during parsing.
//
if (nameNode.isSynthetic) {
return;
}
Expression receiver = node.realTarget;
if (receiver == null) {
_resolveReceiverNull(node, nameNode, name);
return;
}
if (receiver is NullLiteral) {
_setDynamicResolution(node);
return;
}
if (receiver is SimpleIdentifier) {
var receiverElement = receiver.staticElement;
if (receiverElement is PrefixElement) {
_resolveReceiverPrefix(node, receiver, receiverElement, nameNode, name);
return;
}
}
if (receiver is Identifier) {
var receiverElement = receiver.staticElement;
if (receiverElement is ExtensionElement) {
_resolveExtensionMember(
node, receiver, receiverElement, nameNode, name);
return;
}
}
if (receiver is SuperExpression) {
_resolveReceiverSuper(node, receiver, nameNode, name);
return;
}
if (receiver is ExtensionOverride) {
_resolveExtensionOverride(node, receiver, nameNode, name);
return;
}
ClassElement typeReference = getTypeReference(receiver);
if (typeReference != null) {
_resolveReceiverTypeLiteral(node, typeReference, nameNode, name);
return;
}
DartType receiverType = receiver.staticType;
receiverType = _resolveTypeParameter(receiverType);
if (receiverType is InterfaceType) {
_resolveReceiverInterfaceType(node, receiverType, nameNode, name);
return;
}
if (receiverType is DynamicTypeImpl) {
_resolveReceiverDynamic(node, name);
return;
}
if (receiverType is FunctionType) {
_resolveReceiverFunctionType(
node, receiver, receiverType, nameNode, name);
return;
}
if (receiverType is VoidType) {
_reportUseOfVoidType(node, receiver);
return;
}
if (receiverType == BottomTypeImpl.instance) {
_reportUseOfNeverType(node, receiver);
return;
}
}
/// Given an [argumentList] and the executable [element] that will be invoked
/// using those arguments, compute the list of parameters that correspond to
/// the list of arguments. Return the parameters that correspond to the
/// arguments, or `null` if no correspondence could be computed.
List<ParameterElement> _computeCorrespondingParameters(
ArgumentList argumentList, DartType type) {
if (type is InterfaceType) {
MethodElement callMethod =
type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary);
if (callMethod != null) {
return _resolveArgumentsToFunction(false, argumentList, callMethod);
}
} else if (type is FunctionType) {
return _resolveArgumentsToParameters(
false, argumentList, type.parameters);
}
return null;
}
/// If the invoked [target] is a getter, then actually the return type of
/// the [target] is invoked. So, remember the [target] into
/// [MethodInvocationImpl.methodNameType] and return the actual invoked type.
DartType _getCalleeType(MethodInvocation node, ExecutableElement target) {
if (target.kind == ElementKind.GETTER) {
(node as MethodInvocationImpl).methodNameType = target.type;
var calleeType = target.returnType;
calleeType = _resolveTypeParameter(calleeType);
return calleeType;
}
return target.type;
}
/// Check for a generic type, and apply type arguments.
FunctionType _instantiateFunctionType(
FunctionType invokeType, TypeArgumentList typeArguments, AstNode node) {
var typeFormals = invokeType.typeFormals;
var arguments = typeArguments?.arguments;
if (arguments != null && arguments.length != typeFormals.length) {
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
node,
[invokeType, typeFormals.length, arguments?.length ?? 0]);
arguments = null;
}
if (typeFormals.isNotEmpty) {
if (arguments == null) {
var typeArguments =
_resolver.typeSystem.instantiateTypeFormalsToBounds(typeFormals);
_invocation.typeArgumentTypes = typeArguments;
return invokeType.instantiate(typeArguments);
} else {
var typeArguments = arguments.map((n) => n.type).toList();
_invocation.typeArgumentTypes = typeArguments;
return invokeType.instantiate(typeArguments);
}
} else {
_invocation.typeArgumentTypes = const <DartType>[];
}
return invokeType;
}
bool _isCoreFunction(DartType type) {
// TODO(scheglov) Can we optimize this?
return type is InterfaceType && type.isDartCoreFunction;
}
ExecutableElement _lookUpClassMember(ClassElement element, String name) {
// TODO(scheglov) Use class hierarchy.
return element.lookUpMethod(name, _definingLibrary);
}
void _reportInvocationOfNonFunction(MethodInvocation node) {
_setDynamicResolution(node, setNameTypeToDynamic: false);
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION,
node.methodName,
[node.methodName.name],
);
}
void _reportPrefixIdentifierNotFollowedByDot(SimpleIdentifier target) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
target,
[target.name],
);
}
void _reportUndefinedFunction(
MethodInvocation node, Identifier ignorableIdentifier) {
_setDynamicResolution(node);
// TODO(scheglov) This is duplication.
if (nameScope.shouldIgnoreUndefined(ignorableIdentifier)) {
return;
}
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.UNDEFINED_FUNCTION,
node.methodName,
[node.methodName.name],
);
}
void _reportUndefinedMethod(
MethodInvocation node, String name, ClassElement typeReference) {
_setDynamicResolution(node);
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.UNDEFINED_METHOD,
node.methodName,
[name, typeReference.displayName],
);
}
void _reportUseOfNeverType(MethodInvocation node, AstNode errorNode) {
_setDynamicResolution(node);
_resolver.errorReporter.reportErrorForNode(
StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
errorNode,
);
}
void _reportUseOfVoidType(MethodInvocation node, AstNode errorNode) {
_setDynamicResolution(node);
_resolver.errorReporter.reportErrorForNode(
StaticWarningCode.USE_OF_VOID_RESULT,
errorNode,
);
}
/// Given an [argumentList] and the [executableElement] that will be invoked
/// using those argument, compute the list of parameters that correspond to the
/// list of arguments. An error will be reported if any of the arguments cannot
/// be matched to a parameter. The flag [reportAsError] should be `true` if a
/// compile-time error should be reported; or `false` if a compile-time warning
/// should be reported. Return the parameters that correspond to the arguments,
/// or `null` if no correspondence could be computed.
List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError,
ArgumentList argumentList, ExecutableElement executableElement) {
if (executableElement == null) {
return null;
}
List<ParameterElement> parameters = executableElement.parameters;
return _resolveArgumentsToParameters(
reportAsError, argumentList, parameters);
}
/// Given an [argumentList] and the [parameters] related to the element that
/// will be invoked using those arguments, compute the list of parameters that
/// correspond to the list of arguments. An error will be reported if any of
/// the arguments cannot be matched to a parameter. The flag [reportAsError]
/// should be `true` if a compile-time error should be reported; or `false` if
/// a compile-time warning should be reported. Return the parameters that
/// correspond to the arguments.
List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError,
ArgumentList argumentList, List<ParameterElement> parameters) {
return ResolverVisitor.resolveArgumentsToParameters(
argumentList, parameters, _resolver.errorReporter.reportErrorForNode,
reportAsError: reportAsError);
}
/// Given that we are accessing a property of the given [classElement] with the
/// given [propertyName], return the element that represents the property.
Element _resolveElement(
ClassElement classElement, SimpleIdentifier propertyName) {
// TODO(scheglov) Replace with class hierarchy.
String name = propertyName.name;
Element element = null;
if (propertyName.inSetterContext()) {
element = classElement.getSetter(name);
}
if (element == null) {
element = classElement.getGetter(name);
}
if (element == null) {
element = classElement.getMethod(name);
}
if (element != null && element.isAccessibleIn(_definingLibrary)) {
return element;
}
return null;
}
/// If there is an extension matching the [receiverType] and defining a
/// member with the given [name], resolve to the corresponding extension
/// method. Return a result indicating whether the [node] was resolved and if
/// not why.
ResolutionResult _resolveExtension(
MethodInvocation node,
DartType receiverType,
SimpleIdentifier nameNode,
String name,
) {
var result = _extensionResolver.findExtension(
receiverType,
name,
nameNode,
ElementKind.METHOD,
);
if (!result.isSingle) {
_setDynamicResolution(node);
return result;
}
ExecutableElement member = result.element;
nameNode.staticElement = member;
if (member.isStatic) {
_setDynamicResolution(node);
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
nameNode,
[name, member.kind.displayName, member.enclosingElement.name]);
return result;
}
var calleeType = _getCalleeType(node, member);
_setResolution(node, calleeType);
return result;
}
void _resolveExtensionMember(MethodInvocation node, Identifier receiver,
ExtensionElement extension, SimpleIdentifier nameNode, String name) {
ExecutableElement element =
extension.getMethod(name) ?? extension.getGetter(name);
if (element is ExecutableElement) {
if (!element.isStatic) {
_resolver.errorReporter.reportErrorForNode(
StaticWarningCode.STATIC_ACCESS_TO_INSTANCE_MEMBER,
nameNode,
[name]);
}
nameNode.staticElement = element;
_setResolution(node, _getCalleeType(node, element));
} else {
_reportUndefinedFunction(node, receiver);
}
}
void _resolveExtensionOverride(MethodInvocation node,
ExtensionOverride override, SimpleIdentifier nameNode, String name) {
var member = _extensionResolver.getOverrideMember(
override, name, ElementKind.METHOD) ??
_extensionResolver.getOverrideMember(
override, name, ElementKind.GETTER);
if (member == null) {
_setDynamicResolution(node);
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.UNDEFINED_EXTENSION_METHOD,
nameNode,
[name, override.staticElement.name],
);
return;
}
if (member.isStatic) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
nameNode,
);
}
if (node.isCascaded) {
// TODO(brianwilkerson) Report this error and decide how to recover.
throw new UnsupportedError('cascaded extension override');
}
nameNode.staticElement = member;
var calleeType = _getCalleeType(node, member);
_setResolution(node, calleeType);
}
void _resolveReceiverDynamic(MethodInvocation node, String name) {
_setDynamicResolution(node);
}
void _resolveReceiverFunctionType(MethodInvocation node, Expression receiver,
FunctionType receiverType, SimpleIdentifier nameNode, String name) {
if (name == FunctionElement.CALL_METHOD_NAME) {
_setResolution(node, receiverType);
// TODO(scheglov) Replace this with using FunctionType directly.
// Here was erase resolution that _setResolution() sets.
nameNode.staticElement = null;
nameNode.staticType = _dynamicType;
return;
}
ResolutionResult result = _extensionResolver.findExtension(
receiverType, name, nameNode, ElementKind.METHOD);
if (result.isSingle) {
nameNode.staticElement = result.element;
var calleeType = _getCalleeType(node, result.element);
return _setResolution(node, calleeType);
} else if (result.isAmbiguous) {
return;
}
// We can invoke Object methods on Function.
var member = _inheritance.getMember(
_resolver.typeProvider.functionType,
new Name(null, name),
);
if (member != null) {
nameNode.staticElement = member;
return _setResolution(node, member.type);
}
_reportUndefinedMethod(
node,
name,
_resolver.typeProvider.functionType.element,
);
}
void _resolveReceiverInterfaceType(MethodInvocation node,
InterfaceType receiverType, SimpleIdentifier nameNode, String name) {
if (_isCoreFunction(receiverType) &&
name == FunctionElement.CALL_METHOD_NAME) {
_setDynamicResolution(node);
return;
}
var target = _inheritance.getMember(receiverType, _currentName);
if (target != null) {
nameNode.staticElement = target;
var calleeType = _getCalleeType(node, target);
return _setResolution(node, calleeType);
}
// Look for an applicable extension.
var result = _resolveExtension(node, receiverType, nameNode, name);
if (result.isSingle) {
return;
}
// The interface of the receiver does not have an instance member.
// Try to recover and find a member in the class.
var targetElement = _lookUpClassMember(receiverType.element, name);
if (targetElement != null && targetElement.isStatic) {
nameNode.staticElement = targetElement;
_setDynamicResolution(node);
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
nameNode,
[
name,
targetElement.kind.displayName,
targetElement.enclosingElement.displayName,
],
);
return;
}
_setDynamicResolution(node);
if (result.isNone) {
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.UNDEFINED_METHOD,
nameNode,
[name, receiverType.element.displayName],
);
}
}
void _resolveReceiverNull(
MethodInvocation node, SimpleIdentifier nameNode, String name) {
var element = nameScope.lookup(nameNode, _definingLibrary);
if (element != null) {
nameNode.staticElement = element;
if (element is MultiplyDefinedElement) {
MultiplyDefinedElement multiply = element;
element = multiply.conflictingElements[0];
}
if (element is ExecutableElement) {
var calleeType = _getCalleeType(node, element);
return _setResolution(node, calleeType);
}
if (element is VariableElement) {
var targetType = _localVariableTypeProvider.getType(nameNode);
return _setResolution(node, targetType);
}
// TODO(scheglov) This is a questionable distinction.
if (element is PrefixElement) {
_setDynamicResolution(node);
return _reportPrefixIdentifierNotFollowedByDot(nameNode);
}
return _reportInvocationOfNonFunction(node);
}
InterfaceType receiverType;
ClassElement enclosingClass = _resolver.enclosingClass;
if (enclosingClass == null) {
if (_resolver.enclosingExtension == null) {
return _reportUndefinedFunction(node, node.methodName);
}
var extendedType =
_resolveTypeParameter(_resolver.enclosingExtension.extendedType);
if (extendedType is InterfaceType) {
receiverType = extendedType;
} else if (extendedType is FunctionType) {
receiverType = _resolver.typeProvider.functionType;
} else {
return _reportUndefinedFunction(node, node.methodName);
}
enclosingClass = receiverType.element;
} else {
receiverType = enclosingClass.type;
}
var target = _inheritance.getMember(receiverType, _currentName);
if (target != null) {
nameNode.staticElement = target;
var calleeType = _getCalleeType(node, target);
return _setResolution(node, calleeType);
}
var targetElement = _lookUpClassMember(enclosingClass, name);
if (targetElement != null && targetElement.isStatic) {
nameNode.staticElement = targetElement;
_setDynamicResolution(node);
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
nameNode,
[receiverType.displayName],
);
return;
}
var result = _extensionResolver.findExtension(
receiverType, name, nameNode, ElementKind.METHOD);
if (result.isSingle) {
var target = result.element;
if (target != null) {
nameNode.staticElement = target;
var calleeType = _getCalleeType(node, target);
_setResolution(node, calleeType);
return;
}
}
return _reportUndefinedMethod(node, name, enclosingClass);
}
void _resolveReceiverPrefix(MethodInvocation node, SimpleIdentifier receiver,
PrefixElement prefix, SimpleIdentifier nameNode, String name) {
if (node.operator.type == TokenType.QUESTION_PERIOD) {
_reportPrefixIdentifierNotFollowedByDot(receiver);
}
if (name == FunctionElement.LOAD_LIBRARY_NAME) {
var imports = _definingLibrary.getImportsWithPrefix(prefix);
if (imports.length == 1 && imports[0].isDeferred) {
var importedLibrary = imports[0].importedLibrary;
var loadLibraryFunction = importedLibrary?.loadLibraryFunction;
nameNode.staticElement = loadLibraryFunction;
node.staticInvokeType = loadLibraryFunction?.type;
node.staticType = loadLibraryFunction?.returnType;
_setExplicitTypeArgumentTypes();
return;
}
}
// TODO(scheglov) I don't like how we resolve prefixed names.
// But maybe this is the only one solution.
var prefixedName = new PrefixedIdentifierImpl.temp(receiver, nameNode);
var element = nameScope.lookup(prefixedName, _definingLibrary);
nameNode.staticElement = element;
if (element is MultiplyDefinedElement) {
MultiplyDefinedElement multiply = element;
element = multiply.conflictingElements[0];
}
if (element is ExecutableElement) {
var calleeType = _getCalleeType(node, element);
return _setResolution(node, calleeType);
}
_reportUndefinedFunction(node, prefixedName);
}
void _resolveReceiverSuper(MethodInvocation node, SuperExpression receiver,
SimpleIdentifier nameNode, String name) {
var enclosingClass = _resolver.enclosingClass;
if (SuperContext.of(receiver) != SuperContext.valid) {
return;
}
var receiverType = enclosingClass.type;
var target = _inheritance.getMember(
receiverType,
_currentName,
forSuper: true,
);
// If there is that concrete dispatch target, then we are done.
if (target != null) {
nameNode.staticElement = target;
var calleeType = _getCalleeType(node, target);
_setResolution(node, calleeType);
return;
}
// Otherwise, this is an error.
// But we would like to give the user at least some resolution.
// So, we try to find the interface target.
target = _inheritance.getInherited(receiverType, _currentName);
if (target != null) {
nameNode.staticElement = target;
var calleeType = _getCalleeType(node, target);
_setResolution(node, calleeType);
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
nameNode,
[target.kind.displayName, name]);
return;
}
// Nothing help, there is no target at all.
_setDynamicResolution(node);
_resolver.errorReporter.reportErrorForNode(
StaticTypeWarningCode.UNDEFINED_SUPER_METHOD,
nameNode,
[name, enclosingClass.displayName]);
}
void _resolveReceiverTypeLiteral(MethodInvocation node, ClassElement receiver,
SimpleIdentifier nameNode, String name) {
if (node.isCascaded) {
receiver = _typeType.element;
}
var element = _resolveElement(receiver, nameNode);
if (element != null) {
if (element is ExecutableElement) {
nameNode.staticElement = element;
var calleeType = _getCalleeType(node, element);
_setResolution(node, calleeType);
} else {
_reportInvocationOfNonFunction(node);
}
return;
}
_reportUndefinedMethod(node, name, receiver);
}
/// If the given [type] is a type parameter, replace with its bound.
/// Otherwise, return the original type.
DartType _resolveTypeParameter(DartType type) {
if (type is TypeParameterType) {
return type.resolveToBound(_resolver.typeProvider.objectType);
}
return type;
}
void _setDynamicResolution(MethodInvocation node,
{bool setNameTypeToDynamic: true}) {
if (setNameTypeToDynamic) {
node.methodName.staticType = _dynamicType;
}
node.staticInvokeType = _dynamicType;
node.staticType = _dynamicType;
_setExplicitTypeArgumentTypes();
}
/// Set explicitly specified type argument types, or empty if not specified.
/// Inference is done in type analyzer, so inferred type arguments might be
/// set later.
void _setExplicitTypeArgumentTypes() {
var typeArgumentList = _invocation.typeArguments;
if (typeArgumentList != null) {
var arguments = typeArgumentList.arguments;
_invocation.typeArgumentTypes = arguments.map((n) => n.type).toList();
} else {
_invocation.typeArgumentTypes = [];
}
}
void _setResolution(MethodInvocation node, DartType type) {
// TODO(scheglov) We need this for StaticTypeAnalyzer to run inference.
// But it seems weird. Do we need to know the raw type of a function?!
node.methodName.staticType = type;
if (type == _dynamicType || _isCoreFunction(type)) {
_setDynamicResolution(node, setNameTypeToDynamic: false);
return;
}
if (type is InterfaceType) {
var call = _inheritance.getMember(type, _nameCall);
if (call == null) {
var result = _extensionResolver.findExtension(
type, _nameCall.name, node.methodName, ElementKind.METHOD);
if (result.isSingle) {
call = result.element;
} else if (result.isAmbiguous) {
return;
}
}
if (call != null && call.kind == ElementKind.METHOD) {
type = call.type;
}
}
if (type is FunctionType) {
// TODO(scheglov) Extract this when receiver is already FunctionType?
var instantiatedType = _instantiateFunctionType(
type,
node.typeArguments,
node.methodName,
);
instantiatedType = _toSyntheticFunctionType(instantiatedType);
node.staticInvokeType = instantiatedType;
node.staticType = instantiatedType.returnType;
// TODO(scheglov) too much magic
node.argumentList.correspondingStaticParameters =
_computeCorrespondingParameters(
node.argumentList,
instantiatedType,
);
return;
}
if (type is VoidType) {
return _reportUseOfVoidType(node, node.methodName);
}
if (type == BottomTypeImpl.instance) {
return _reportUseOfNeverType(node, node.methodName);
}
_reportInvocationOfNonFunction(node);
}
/// Checks whether the given [expression] is a reference to a class. If it is
/// then the element representing the class is returned, otherwise `null` is
/// returned.
static ClassElement getTypeReference(Expression expression) {
if (expression is Identifier) {
Element staticElement = expression.staticElement;
if (staticElement is ClassElement) {
return staticElement;
}
}
return null;
}
/// As an experiment for using synthetic [FunctionType]s, we replace some
/// function types with the equivalent synthetic function type instance.
/// The assumption that we try to prove is that only the set of parameters,
/// with their names, types and kinds is important, but the element that
/// encloses them is not (`null` for synthetic function types).
static FunctionType _toSyntheticFunctionType(FunctionType type) {
// if (type.element is GenericFunctionTypeElement) {
// var synthetic = FunctionTypeImpl.synthetic(
// type.returnType,
// type.typeFormals.map((e) {
// return TypeParameterElementImpl.synthetic(e.name)..bound = e.bound;
// }).toList(),
// type.parameters.map((p) {
// return ParameterElementImpl.synthetic(
// p.name,
// p.type,
// // ignore: deprecated_member_use_from_same_package
// p.parameterKind,
// );
// }).toList(),
// );
// return synthetic;
// }
return type;
}
}