| // Copyright (c) 2020, 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/analysis/features.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/nullability_suffix.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/error/listener.dart'; |
| import 'package:analyzer/src/dart/ast/ast.dart'; |
| import 'package:analyzer/src/dart/element/member.dart'; |
| import 'package:analyzer/src/dart/element/type.dart'; |
| import 'package:analyzer/src/dart/element/type_constraint_gatherer.dart'; |
| import 'package:analyzer/src/dart/element/type_system.dart'; |
| import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart'; |
| import 'package:analyzer/src/generated/resolver.dart'; |
| |
| /// Information about a constructor element to instantiate. |
| /// |
| /// If the target is a [ClassElement], the [element] is a raw |
| /// [ConstructorElement] from the class, and [typeParameters] are the |
| /// type parameters of the class. |
| /// |
| /// If the target is a [TypeAliasElement] with an [InterfaceType] as the |
| /// aliased type, the [element] is a [ConstructorMember] created from the |
| /// [ConstructorElement] of the corresponding class, and substituting |
| /// the class type parameters with the type arguments specified in the alias, |
| /// explicit types or the type parameters of the alias. The [typeParameters] |
| /// are the type parameters of the alias. |
| class ConstructorElementToInfer { |
| /// The type parameters used in [element]. |
| final List<TypeParameterElement> typeParameters; |
| |
| /// The element, might be [ConstructorMember]. |
| final ConstructorElement element; |
| |
| ConstructorElementToInfer(this.typeParameters, this.element); |
| |
| /// Return the equivalent generic function type that we could use to |
| /// forward to the constructor, or for a non-generic type simply returns |
| /// the constructor type. |
| /// |
| /// For example given the type `class C<T> { C(T arg); }`, the generic |
| /// function type is `<T>(T) -> C<T>`. |
| FunctionType get asType { |
| return typeParameters.isEmpty |
| ? element.type |
| : FunctionTypeImpl( |
| typeFormals: typeParameters, |
| parameters: element.parameters, |
| returnType: element.returnType, |
| nullabilitySuffix: NullabilitySuffix.none, |
| ); |
| } |
| } |
| |
| class InvocationInferenceHelper { |
| final ResolverVisitor _resolver; |
| final ErrorReporter _errorReporter; |
| final TypeSystemImpl _typeSystem; |
| final bool _genericMetadataIsEnabled; |
| final bool _inferenceUsingBoundsIsEnabled; |
| final TypeConstraintGenerationDataForTesting? dataForTesting; |
| |
| InvocationInferenceHelper({ |
| required ResolverVisitor resolver, |
| required ErrorReporter errorReporter, |
| required TypeSystemImpl typeSystem, |
| required this.dataForTesting, |
| }) : _resolver = resolver, |
| _errorReporter = errorReporter, |
| _typeSystem = typeSystem, |
| _genericMetadataIsEnabled = resolver.definingLibrary.featureSet |
| .isEnabled(Feature.generic_metadata), |
| _inferenceUsingBoundsIsEnabled = resolver.definingLibrary.featureSet |
| .isEnabled(Feature.inference_using_bounds); |
| |
| /// If the constructor referenced by the [constructorName] is generic, |
| /// and the [constructorName] does not have explicit type arguments, |
| /// return the element and type parameters to infer. Otherwise return `null`. |
| ConstructorElementToInfer? constructorElementToInfer({ |
| required ConstructorName constructorName, |
| required LibraryElement definingLibrary, |
| }) { |
| List<TypeParameterElement> typeParameters; |
| ConstructorElement? rawElement; |
| |
| var typeName = constructorName.type; |
| var typeElement = typeName.element; |
| if (typeElement is InterfaceElement) { |
| var augmented = typeElement.augmented; |
| typeParameters = typeElement.typeParameters; |
| var constructorIdentifier = constructorName.name; |
| if (constructorIdentifier == null) { |
| rawElement = augmented.unnamedConstructor; |
| } else { |
| var name = constructorIdentifier.name; |
| rawElement = augmented.getNamedConstructor(name); |
| if (rawElement != null && !rawElement.isAccessibleIn(definingLibrary)) { |
| rawElement = null; |
| } |
| } |
| } else if (typeElement is TypeAliasElement) { |
| typeParameters = typeElement.typeParameters; |
| var aliasedType = typeElement.aliasedType; |
| if (aliasedType is InterfaceType) { |
| var constructorIdentifier = constructorName.name; |
| rawElement = aliasedType.lookUpConstructor( |
| constructorIdentifier?.name, |
| definingLibrary, |
| ); |
| } |
| } else { |
| return null; |
| } |
| |
| if (rawElement == null) { |
| return null; |
| } |
| return ConstructorElementToInfer(typeParameters, rawElement); |
| } |
| |
| /// Given an uninstantiated generic function type, referenced by the |
| /// [identifier] in the tear-off [expression], try to infer the instantiated |
| /// generic function type from the surrounding context. |
| DartType inferTearOff(Expression expression, SimpleIdentifierImpl identifier, |
| DartType tearOffType, |
| {required DartType contextType}) { |
| if (contextType is FunctionType && tearOffType is FunctionType) { |
| var typeArguments = _typeSystem.inferFunctionTypeInstantiation( |
| contextType, |
| tearOffType, |
| errorReporter: _errorReporter, |
| errorNode: expression, |
| genericMetadataIsEnabled: _genericMetadataIsEnabled, |
| inferenceUsingBoundsIsEnabled: _inferenceUsingBoundsIsEnabled, |
| strictInference: _resolver.analysisOptions.strictInference, |
| strictCasts: _resolver.analysisOptions.strictCasts, |
| typeSystemOperations: _resolver.flowAnalysis.typeOperations, |
| dataForTesting: dataForTesting, |
| nodeForTesting: expression, |
| ); |
| identifier.tearOffTypeArgumentTypes = typeArguments; |
| if (typeArguments.isNotEmpty) { |
| return tearOffType.instantiate(typeArguments); |
| } |
| } |
| return tearOffType; |
| } |
| |
| /// Finish resolution of the [MethodInvocation]. |
| /// |
| /// We have already found the invoked [ExecutableElement], and the [rawType] |
| /// is its not yet instantiated type. Here we perform downwards inference, |
| /// resolution of arguments, and upwards inference. |
| void resolveMethodInvocation({ |
| required MethodInvocationImpl node, |
| required FunctionType rawType, |
| required List<WhyNotPromotedGetter> whyNotPromotedList, |
| required DartType contextType, |
| }) { |
| var returnType = MethodInvocationInferrer( |
| resolver: _resolver, |
| node: node, |
| argumentList: node.argumentList, |
| contextType: contextType, |
| whyNotPromotedList: whyNotPromotedList, |
| ).resolveInvocation(rawType: rawType); |
| |
| node.recordStaticType(returnType, resolver: _resolver); |
| } |
| } |