Skip to content

Commit

Permalink
Elements. Migrate TypeArgumentsVerifier.
Browse files Browse the repository at this point in the history
Change-Id: I520578b93bd577faaa4b409412de4dc8e1d1ccaa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/395046
Reviewed-by: Phil Quitslund <[email protected]>
Commit-Queue: Konstantin Shcheglov <[email protected]>
  • Loading branch information
scheglov authored and Commit Queue committed Nov 13, 2024
1 parent aa3eb29 commit 7c8c061
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 37 deletions.
1 change: 0 additions & 1 deletion pkg/analyzer/analyzer_use_new_elements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ lib/src/error/must_call_super_verifier.dart
lib/src/error/nullable_dereference_verifier.dart
lib/src/error/override_verifier.dart
lib/src/error/required_parameters_verifier.dart
lib/src/error/type_arguments_verifier.dart
lib/src/error/unused_local_elements_verifier.dart
lib/src/error/use_result_verifier.dart
lib/src/generated/element_resolver.dart
Expand Down
12 changes: 12 additions & 0 deletions pkg/analyzer/lib/src/dart/element/type_algebra.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_visitor.dart';
Expand All @@ -15,6 +16,7 @@ import 'package:analyzer/src/summary2/function_type_builder.dart';
import 'package:analyzer/src/summary2/named_type_builder.dart';
import 'package:analyzer/src/summary2/record_type_builder.dart';
import 'package:analyzer/src/utilities/extensions/collection.dart';
import 'package:analyzer/src/utilities/extensions/element.dart';

/// Generates a fresh copy of the given type parameters, with their bounds
/// substituted to reference the new parameters.
Expand Down Expand Up @@ -214,6 +216,16 @@ abstract class Substitution {
);
}

/// Substitutes the Nth parameter in [parameters] with the Nth type in
/// [types].
static MapSubstitution fromPairs2(
List<TypeParameterElement2> parameters,
List<DartType> types,
) {
var fragments = parameters.map((e) => e.asElement).toList();
return fromPairs(fragments, types);
}

/// Substitutes all occurrences of the given type parameters with the
/// corresponding upper or lower bound, depending on the variance of the
/// context where it occurs.
Expand Down
116 changes: 80 additions & 36 deletions pkg/analyzer/lib/src/error/type_arguments_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "dart:math" as math;
import 'package:analyzer/dart/analysis/analysis_options.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/error/error.dart';
Expand All @@ -17,10 +17,11 @@ import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/utilities/extensions/object.dart';

class TypeArgumentsVerifier {
final AnalysisOptions _options;
final LibraryElement _libraryElement;
final LibraryElement2 _libraryElement;
final ErrorReporter _errorReporter;

TypeArgumentsVerifier(
Expand All @@ -33,19 +34,26 @@ class TypeArgumentsVerifier {
_libraryElement.typeSystem as TypeSystemImpl;

void checkConstructorReference(ConstructorReference node) {
var classElement = node.constructorName.type.element;
List<TypeParameterElement> typeParameters;
if (classElement is TypeAliasElement) {
typeParameters = classElement.typeParameters;
} else if (classElement is InterfaceElement) {
typeParameters = classElement.typeParameters;
var classElement = node.constructorName.type.element2;
List<TypeParameterElement2> typeParameters;
if (classElement is TypeAliasElement2) {
typeParameters = classElement.typeParameters2;
} else if (classElement is InterfaceElement2) {
typeParameters = classElement.typeParameters2;
} else {
return;
}

if (typeParameters.isEmpty) {
return;
}

for (var typeParameter in typeParameters) {
if (typeParameter.name3 == null) {
return;
}
}

var typeArgumentList = node.constructorName.type.typeArguments;
if (typeArgumentList == null) {
return;
Expand All @@ -66,7 +74,7 @@ class TypeArgumentsVerifier {
return;
}
var typeArgumentListLength = typeArgumentList.arguments.length;
var substitution = Substitution.fromPairs(typeParameters, typeArguments);
var substitution = Substitution.fromPairs2(typeParameters, typeArguments);
for (var i = 0; i < typeArguments.length; i++) {
var typeParameter = typeParameters[i];
var typeArgument = typeArguments[i];
Expand All @@ -84,20 +92,26 @@ class TypeArgumentsVerifier {
_errorReporter.atNode(
errorNode,
CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
arguments: [typeArgument, typeParameter.name, bound],
arguments: [typeArgument, typeParameter.name3!, bound],
);
}
}
}

void checkEnumConstantDeclaration(EnumConstantDeclaration node) {
var constructorElement = node.constructorElement;
var constructorElement = node.constructorElement2;
if (constructorElement == null) {
return;
}

var enumElement = constructorElement.enclosingElement3;
var typeParameters = enumElement.typeParameters;
var enumElement = constructorElement.enclosingElement2;
var typeParameters = enumElement.typeParameters2;

for (var typeParameter in typeParameters) {
if (typeParameter.name3 == null) {
return;
}
}

var typeArgumentList = node.arguments?.typeArguments;
var typeArgumentNodes = typeArgumentList?.arguments;
Expand All @@ -117,7 +131,7 @@ class TypeArgumentsVerifier {

// Check that type arguments are regular-bounded.
var typeArguments = constructorElement.returnType.typeArguments;
var substitution = Substitution.fromPairs(typeParameters, typeArguments);
var substitution = Substitution.fromPairs2(typeParameters, typeArguments);
for (var i = 0; i < typeArguments.length; i++) {
var typeParameter = typeParameters[i];
var typeArgument = typeArguments[i];
Expand All @@ -134,7 +148,7 @@ class TypeArgumentsVerifier {
_errorReporter.atEntity(
errorTarget,
CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
arguments: [typeArgument, typeParameter.name, bound],
arguments: [typeArgument, typeParameter.name3!, bound],
);
}
}
Expand Down Expand Up @@ -246,7 +260,7 @@ class TypeArgumentsVerifier {
return;
}
var type = node.typeOrThrow;
if (_isMissingTypeArguments(node, type, node.element)) {
if (_isMissingTypeArguments(node, type, node.element2)) {
AstNode unwrappedParent = parentEscapingTypeArguments(node);
if (unwrappedParent is AsExpression ||
unwrappedParent is CastPattern ||
Expand All @@ -272,34 +286,44 @@ class TypeArgumentsVerifier {
return;
}

List<TypeParameterElement> typeParameters;
String elementName;
List<TypeParameterElement2> typeParameters;
String? elementName;
List<DartType> typeArguments;
var alias = type.alias;
if (alias != null) {
elementName = alias.element.name;
typeParameters = alias.element.typeParameters;
elementName = alias.element2.name3;
typeParameters = alias.element2.typeParameters2;
typeArguments = alias.typeArguments;
} else if (type is InterfaceType) {
elementName = type.element.name;
typeParameters = type.element.typeParameters;
elementName = type.element3.name3;
typeParameters = type.element3.typeParameters2;
typeArguments = type.typeArguments;
} else {
return;
}

if (elementName == null) {
return;
}

if (typeParameters.isEmpty) {
return;
}

// Check for regular-bounded.
List<_TypeArgumentIssue>? issues;
var substitution = Substitution.fromPairs(typeParameters, typeArguments);
var substitution = Substitution.fromPairs2(typeParameters, typeArguments);
for (var i = 0; i < typeArguments.length; i++) {
var typeParameter = typeParameters[i];
var typeParameterName = typeParameter.name3;
if (typeParameterName == null) {
return;
}

var typeArgument = typeArguments[i];

if (typeArgument is FunctionType && typeArgument.typeFormals.isNotEmpty) {
if (typeArgument is FunctionType &&
typeArgument.typeParameters.isNotEmpty) {
if (!_libraryElement.featureSet.isEnabled(Feature.generic_metadata)) {
_errorReporter.atNode(
_typeArgumentErrorNode(namedType, i),
Expand All @@ -319,7 +343,8 @@ class TypeArgumentsVerifier {
if (!_typeSystem.isSubtypeOf(typeArgument, bound)) {
issues ??= <_TypeArgumentIssue>[];
issues.add(
_TypeArgumentIssue(i, typeParameter, bound, typeArgument),
_TypeArgumentIssue(
i, typeParameter, typeParameterName, bound, typeArgument),
);
}
}
Expand Down Expand Up @@ -378,7 +403,7 @@ class TypeArgumentsVerifier {
CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
arguments: [
issue.argument,
issue.parameter.name,
issue.parameterName,
issue.parameterBound
],
contextMessages: buildContextMessages(),
Expand All @@ -400,12 +425,17 @@ class TypeArgumentsVerifier {
}

// Check for super-bounded.
var invertedSubstitution = Substitution.fromPairs(
var invertedSubstitution = Substitution.fromPairs2(
typeParameters,
invertedTypeArguments,
);
for (var i = 0; i < invertedTypeArguments.length; i++) {
var typeParameter = typeParameters[i];
var typeParameterName = typeParameter.name3;
if (typeParameterName == null) {
return;
}

var typeArgument = invertedTypeArguments[i];

var bound = typeParameter.bound;
Expand All @@ -419,7 +449,7 @@ class TypeArgumentsVerifier {
_errorReporter.atNode(
_typeArgumentErrorNode(namedType, i),
CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
arguments: [typeArgument, typeParameter.name, bound],
arguments: [typeArgument, typeParameterName, bound],
contextMessages: buildContextMessages(
invertedTypeArguments: invertedTypeArguments,
),
Expand All @@ -443,7 +473,7 @@ class TypeArgumentsVerifier {
return;
}

var fnTypeParams = genericType.typeFormals;
var fnTypeParams = genericType.typeParameters;
var typeArgs = typeArgumentList.map((t) => t.typeOrThrow).toList();

// If the amount mismatches, clean up the lists to be substitutable. The
Expand All @@ -464,7 +494,7 @@ class TypeArgumentsVerifier {
//
DartType argType = typeArgs[i];

if (argType is FunctionType && argType.typeFormals.isNotEmpty) {
if (argType is FunctionType && argType.typeParameters.isNotEmpty) {
if (!_libraryElement.featureSet.isEnabled(Feature.generic_metadata)) {
_errorReporter.atNode(
typeArgumentList[i],
Expand All @@ -475,18 +505,23 @@ class TypeArgumentsVerifier {
}

var fnTypeParam = fnTypeParams[i];
var fnTypeParamName = fnTypeParam.name3;
if (fnTypeParamName == null) {
continue;
}

var rawBound = fnTypeParam.bound;
if (rawBound == null) {
continue;
}

var substitution = Substitution.fromPairs(fnTypeParams, typeArgs);
var substitution = Substitution.fromPairs2(fnTypeParams, typeArgs);
var bound = substitution.substituteType(rawBound);
if (!_typeSystem.isSubtypeOf(argType, bound)) {
_errorReporter.atNode(
typeArgumentList[i],
CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
arguments: [argType, fnTypeParam.name, bound],
arguments: [argType, fnTypeParamName, bound],
);
}
}
Expand Down Expand Up @@ -572,7 +607,12 @@ class TypeArgumentsVerifier {
///
/// - [type] does not have any `dynamic` type arguments.
/// - the element is marked with `@optionalTypeArgs` from "package:meta".
bool _isMissingTypeArguments(AstNode node, DartType type, Element? element) {
bool _isMissingTypeArguments(AstNode node, DartType type, Element2? element) {
var elementMetadata = element.ifTypeOrNull<Annotatable>()?.metadata2;
if (elementMetadata == null) {
return false;
}

List<DartType> typeArguments;
var alias = type.alias;
if (alias != null) {
Expand All @@ -586,7 +626,7 @@ class TypeArgumentsVerifier {
// Check if this type has type arguments and at least one is dynamic.
// If so, we may need to issue a strict-raw-types error.
if (typeArguments.any((t) => t is DynamicType)) {
if (element != null && element.hasOptionalTypeArgs) {
if (element != null && elementMetadata.hasOptionalTypeArgs) {
return false;
}
return true;
Expand All @@ -608,7 +648,7 @@ class TypeArgumentsVerifier {
return false;
}

if (namedType.type?.element is ExtensionTypeElement) {
if (namedType.type?.element3 is ExtensionTypeElement2) {
return false;
}

Expand All @@ -630,7 +670,10 @@ class _TypeArgumentIssue {
final int index;

/// The type parameter with the bound that was violated.
final TypeParameterElement parameter;
final TypeParameterElement2 parameter;

/// The non-null name of the [parameter].
final String parameterName;

/// The substituted bound of the [parameter].
final DartType parameterBound;
Expand All @@ -641,6 +684,7 @@ class _TypeArgumentIssue {
_TypeArgumentIssue(
this.index,
this.parameter,
this.parameterName,
this.parameterBound,
this.argument,
);
Expand Down
6 changes: 6 additions & 0 deletions pkg/analyzer/lib/src/utilities/extensions/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,9 @@ extension ParameterElementExtension on ParameterElement {
return declaration as ParameterElementImpl;
}
}

extension TypeParameterElement2Extension on TypeParameterElement2 {
TypeParameterElement get asElement {
return firstFragment as TypeParameterElement;
}
}

0 comments on commit 7c8c061

Please sign in to comment.