Skip to content

Commit

Permalink
Version 2.14.0-271.0.dev
Browse files Browse the repository at this point in the history
Merge commit 'b1db8a3c6525a83b660652e5835dfd5facfb88b7' into 'dev'
  • Loading branch information
Dart CI committed Jul 2, 2021
2 parents 3c78c06 + b1db8a3 commit f860b70
Show file tree
Hide file tree
Showing 20 changed files with 1,516 additions and 1,072 deletions.
1 change: 1 addition & 0 deletions pkg/analyzer/lib/error/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR,
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_EXTENSION,
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_FUNCTION,
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_POSITION,
Expand Down
3 changes: 3 additions & 0 deletions pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,9 @@ class ExitDetector extends GeneralizingAstVisitor<bool> {
return true;
}

@override
bool visitTypeLiteral(TypeLiteral node) => _nodeExits(node.typeName);

@override
bool visitTypeName(TypeName node) => false;

Expand Down
269 changes: 193 additions & 76 deletions pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

import 'package:analyzer/dart/ast/ast.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/ast/ast_factory.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/resolver/resolution_result.dart';
import 'package:analyzer/src/error/codes.dart';
Expand All @@ -22,25 +25,54 @@ class FunctionReferenceResolver {
/// The resolver driving this participant.
final ResolverVisitor _resolver;

FunctionReferenceResolver(this._resolver);
final bool _isNonNullableByDefault;

/// The type representing the type 'type'.
final InterfaceType _typeType;

FunctionReferenceResolver(this._resolver, this._isNonNullableByDefault)
: _typeType = _resolver.typeProvider.typeType;

ErrorReporter get _errorReporter => _resolver.errorReporter;

NullabilitySuffix get _nullabilitySuffixForTypeNames =>
_isNonNullableByDefault ? NullabilitySuffix.none : NullabilitySuffix.star;

void resolve(FunctionReferenceImpl node) {
var function = node.function;
node.typeArguments?.accept(_resolver);

if (function is SimpleIdentifierImpl) {
var element = _resolver.nameScope.lookup(function.name).getter;
if (element is ExecutableElement) {

// Classes and type aliases are checked first so as to include a
// PropertyAccess parent check, which does not need to be done for
// functions.
if (element is ClassElement || element is TypeAliasElement) {
// A type-instantiated constructor tearoff like `C<int>.name` or
// `prefix.C<int>.name` is initially represented as a [PropertyAccess]
// with a [FunctionReference] target.
if (node.parent is PropertyAccess) {
_resolveConstructorReference(node);
return;
} else if (element is ClassElement) {
function.staticElement = element;
_resolveDirectTypeLiteral(node, function, element);
return;
} else if (element is TypeAliasElement) {
function.staticElement = element;
_resolveTypeAlias(node: node, element: element, typeAlias: function);
return;
}
} else if (element is ExecutableElement) {
function.staticElement = element;
_resolve(node: node, rawType: element.type);
_resolve(node: node, name: element.name, rawType: element.type);
return;
} else if (element is VariableElement) {
var functionType = element.type;
if (functionType is FunctionType) {
function.accept(_resolver);
_resolve(node: node, rawType: functionType);
_resolve(node: node, name: element.name ?? '', rawType: functionType);
return;
}
}
Expand All @@ -52,32 +84,7 @@ class FunctionReferenceResolver {
var prefixElement =
_resolver.nameScope.lookup(function.prefix.name).getter;
if (prefixElement is PrefixElement) {
var nameNode = function.identifier;
var name = nameNode.name;
_resolveReceiverPrefix(node, prefixElement, nameNode, name);
return;
}

if (prefixElement is ClassElement) {
// TODO(srawlins): Rewrite `node` as a [TypeLiteral], then resolve the
// [TypeLiteral] instead of `function`.
function.accept(_resolver);
node.staticType = DynamicTypeImpl.instance;
return;
} else if (prefixElement is TypeAliasElement) {
var aliasedType = prefixElement.aliasedType;
if (aliasedType is InterfaceType) {
// TODO(srawlins): Rewrite `node` as a [TypeLiteral], then resolve
// the [TypeLiteral] instead of `function`.
function.accept(_resolver);
node.staticType = DynamicTypeImpl.instance;
return;
}
} else if (prefixElement is ExtensionElement) {
// TODO(srawlins): Rewrite `node` as a [TypeLiteral], then resolve the
// [TypeLiteral] instead of `function`.
function.accept(_resolver);
node.staticType = DynamicTypeImpl.instance;
_resolveReceiverPrefix(node, prefixElement, function);
return;
}

Expand All @@ -103,23 +110,61 @@ class FunctionReferenceResolver {
methodElement = resolveTypeProperty(prefixType).getter;
}
if (methodElement is MethodElement) {
_resolveFunctionReferenceMethod(node: node, function: function);
_resolveFunctionReferenceMethod(
node: node, function: function, element: methodElement);
return;
}

// TODO(srawlins): Check for [ConstructorElement] and rewrite to
// [ConstructorReference] before resolving.
// TODO(srawlins): Need to report cases where [methodElement] is not
// generic. The 'test_instanceGetter_explicitReceiver' test case needs to
// be updated to handle this.

function.accept(_resolver);
node.staticType = DynamicTypeImpl.instance;
return;
}

if (function is PropertyAccess) {
if (function is PropertyAccessImpl) {
function.accept(_resolver);
DartType functionType = function.typeOrThrow;
var target = function.target;
DartType targetType;
if (target is SuperExpressionImpl) {
targetType = target.typeOrThrow;
} else if (target is ThisExpressionImpl) {
targetType = target.typeOrThrow;
} else if (target is SimpleIdentifierImpl) {
var targetElement = _resolver.nameScope.lookup(target.name).getter;
if (targetElement is VariableElement) {
targetType = targetElement.type;
} else if (targetElement is PropertyAccessorElement) {
targetType = targetElement.returnType;
} else {
// TODO(srawlins): Can we get here?
node.staticType = DynamicTypeImpl.instance;
return;
}
} else {
// TODO(srawlins): Can we get here? PrefixedIdentifier?
node.staticType = DynamicTypeImpl.instance;
return;
}
var propertyElement = _resolver.typePropertyResolver
.resolve(
receiver: function.realTarget,
receiverType: targetType,
name: function.propertyName.name,
propertyErrorEntity: function.propertyName,
nameErrorEntity: function,
)
.getter;

if (functionType is FunctionType) {
_resolve(node: node, rawType: function.staticType as FunctionType);
var functionType = function.typeOrThrow;
if (functionType is FunctionType && propertyElement != null) {
_resolve(
node: node,
name: propertyElement.name,
rawType: functionType,
);
return;
}

Expand All @@ -133,45 +178,70 @@ class FunctionReferenceResolver {
node.staticType = DynamicTypeImpl.instance;
}

/// Resolves [node]'s static type, as an instantiated function type, and type
/// argument types, using [rawType] as the uninstantiated function type.
void _resolve({
required FunctionReferenceImpl node,
required FunctionType rawType,
}) {
// `node.typeArguments`, coming from the parser, is never null.
var typeArgumentList = node.typeArguments!;
var typeParameters = rawType.typeFormals;

List<DartType> typeArguments;
List<DartType> _checkTypeArguments(
TypeArgumentList typeArgumentList,
String name,
List<TypeParameterElement> typeParameters,
CompileTimeErrorCode errorCode,
) {
if (typeArgumentList.arguments.length != typeParameters.length) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
errorCode,
typeArgumentList,
[
rawType,
typeParameters.length,
typeArgumentList.arguments.length,
],
);
typeArguments = List.filled(
typeParameters.length,
DynamicTypeImpl.instance,
[name, typeParameters.length, typeArgumentList.arguments.length],
);
return List.filled(typeParameters.length, DynamicTypeImpl.instance);
} else {
typeArguments = typeArgumentList.arguments
.map((typeArgument) => typeArgument.typeOrThrow)
return typeArgumentList.arguments
.map((typeAnnotation) => typeAnnotation.typeOrThrow)
.toList();
}
}

/// Resolves [node]'s static type, as an instantiated function type, and type
/// argument types, using [rawType] as the uninstantiated function type.
void _resolve({
required FunctionReferenceImpl node,
required String name,
required FunctionType rawType,
}) {
var typeArguments = _checkTypeArguments(
// `node.typeArguments`, coming from the parser, is never null.
node.typeArguments!, name, rawType.typeFormals,
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_FUNCTION,
);

var invokeType = rawType.instantiate(typeArguments);
node.typeArgumentTypes = typeArguments;
node.staticType = invokeType;
}

void _resolveConstructorReference(FunctionReferenceImpl node) {
// TODO(srawlins): Rewrite and resolve [node] as a constructor reference.
node.function.accept(_resolver);
node.staticType = DynamicTypeImpl.instance;
}

/// Resolves [node] as a [TypeLiteral] referencing an interface type directly
/// (not through a type alias).
void _resolveDirectTypeLiteral(
FunctionReferenceImpl node, Identifier name, ClassElement element) {
var typeArguments = _checkTypeArguments(
// `node.typeArguments`, coming from the parser, is never null.
node.typeArguments!, name.name, element.typeParameters,
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
);
var type = element.instantiate(
typeArguments: typeArguments,
nullabilitySuffix: _nullabilitySuffixForTypeNames,
);
_resolveTypeLiteral(node: node, instantiatedType: type, name: name);
}

void _resolveFunctionReferenceMethod({
required FunctionReferenceImpl node,
required PrefixedIdentifier function,
required MethodElement element,
}) {
function.accept(_resolver);
var receiver = function.prefix;
Expand All @@ -196,10 +266,7 @@ class FunctionReferenceResolver {
if (target != null) {
// TODO(srawlins): Set static type on `nameNode`?

_resolve(
node: node,
rawType: function.staticType as FunctionType,
);
_resolve(node: node, name: name, rawType: element.type);
return;
}

Expand All @@ -210,15 +277,15 @@ class FunctionReferenceResolver {

void _resolveReceiverPrefix(
FunctionReferenceImpl node,
PrefixElement prefix,
SimpleIdentifierImpl nameNode,
String name,
PrefixElement prefixElement,
PrefixedIdentifier prefix,
) {
// TODO(srawlins): Handle `loadLibrary`, as in `p.loadLibrary<int>;`.

var element = prefix.scope.lookup(name).getter;
var nameNode = prefix.identifier;
var name = nameNode.name;
var element = prefixElement.scope.lookup(name).getter;
element = _resolver.toLegacyElement(element);
nameNode.staticElement = element;

if (element is MultiplyDefinedElement) {
MultiplyDefinedElement multiply = element;
Expand All @@ -227,18 +294,68 @@ class FunctionReferenceResolver {
// TODO(srawlins): Add a resolution test for this case.
}

if (element is ExecutableElement) {
var function = node.function;
function.accept(_resolver);
return _resolve(
node: node, rawType: function.typeOrThrow as FunctionType);
// Classes and type aliases are checked first so as to include a
// PropertyAccess parent check, which does not need to be done for
// functions.
if (element is ClassElement || element is TypeAliasElement) {
// A type-instantiated constructor tearoff like `prefix.C<int>.name` is
// initially represented as a [PropertyAccess] with a
// [FunctionReference] 'target'.
if (node.parent is PropertyAccess) {
_resolveConstructorReference(node);
return;
} else if (element is ClassElement) {
node.function.accept(_resolver);
_resolveDirectTypeLiteral(node, prefix, element);
return;
} else if (element is TypeAliasElement) {
prefix.accept(_resolver);
(nameNode as SimpleIdentifierImpl).staticElement = element;
_resolveTypeAlias(node: node, element: element, typeAlias: prefix);
return;
}
} else if (element is ExecutableElement) {
node.function.accept(_resolver);
_resolve(
node: node,
name: element.name,
rawType: node.function.typeOrThrow as FunctionType,
);
return;
}

// TODO(srawlins): Handle prefixed constructor references and type literals.

// TODO(srawlins): Report undefined prefixed identifier.

node.function.accept(_resolver);
node.staticType = DynamicTypeImpl.instance;
}

void _resolveTypeAlias({
required FunctionReferenceImpl node,
required TypeAliasElement element,
required Identifier typeAlias,
}) {
var typeArguments = _checkTypeArguments(
// `node.typeArguments`, coming from the parser, is never null.
node.typeArguments!, element.name, element.typeParameters,
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
);
var type = element.instantiate(
typeArguments: typeArguments,
nullabilitySuffix: _nullabilitySuffixForTypeNames);
_resolveTypeLiteral(node: node, instantiatedType: type, name: typeAlias);
}

void _resolveTypeLiteral({
required FunctionReferenceImpl node,
required DartType instantiatedType,
required Identifier name,
}) {
var typeName = astFactory.typeName(name, node.typeArguments);
typeName.type = instantiatedType;
typeName.name.staticType = instantiatedType;
var typeLiteral = astFactory.typeLiteral(typeName: typeName);
typeLiteral.staticType = _typeType;
NodeReplacer.replace(node, typeLiteral);
}
}

0 comments on commit f860b70

Please sign in to comment.