Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

Commit

Permalink
Version 2.17.0-93.0.dev
Browse files Browse the repository at this point in the history
Merge commit 'f481cbf2fa27ca7d72ababdccc561b4465bd1660' into 'dev'
  • Loading branch information
Dart CI committed Feb 9, 2022
2 parents 516530f + f481cbf commit 7e3310b
Show file tree
Hide file tree
Showing 23 changed files with 469 additions and 96 deletions.
2 changes: 2 additions & 0 deletions pkg/analyzer/lib/error/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.DUPLICATE_PART,
CompileTimeErrorCode.ENUM_CONSTANT_SAME_NAME_AS_ENCLOSING,
CompileTimeErrorCode.ENUM_CONSTANT_WITH_NON_CONST_CONSTRUCTOR,
CompileTimeErrorCode.ENUM_INSTANTIATED_TO_BOUNDS_IS_NOT_WELL_BOUNDED,
CompileTimeErrorCode.ENUM_MIXIN_WITH_INSTANCE_VARIABLE,
CompileTimeErrorCode.ENUM_WITH_ABSTRACT_MEMBER,
CompileTimeErrorCode.EQUAL_ELEMENTS_IN_CONST_SET,
Expand Down Expand Up @@ -478,6 +479,7 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.URI_WITH_INTERPOLATION,
CompileTimeErrorCode.USE_OF_NATIVE_EXTENSION,
CompileTimeErrorCode.USE_OF_VOID_RESULT,
CompileTimeErrorCode.VALUES_DECLARATION_IN_ENUM,
CompileTimeErrorCode.VARIABLE_TYPE_MISMATCH,
CompileTimeErrorCode.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR,
Expand Down
13 changes: 10 additions & 3 deletions pkg/analyzer/lib/src/dart/analysis/index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ class _IndexContributor extends GeneralizingAstVisitor {
}

@override
visitEnumConstantDeclaration(node) {
void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
var constructorElement = node.constructorElement;
if (constructorElement != null) {
int offset;
Expand All @@ -657,8 +657,15 @@ class _IndexContributor extends GeneralizingAstVisitor {
offset = node.name.end;
length = 0;
}
recordRelationOffset(constructorElement, IndexRelationKind.IS_INVOKED_BY,
offset, length, true);
recordRelationOffset(
constructorElement,
node.arguments == null
? IndexRelationKind.IS_INVOKED_BY_ENUM_CONSTANT_WITHOUT_ARGUMENTS
: IndexRelationKind.IS_INVOKED_BY,
offset,
length,
true,
);
}

super.visitEnumConstantDeclaration(node);
Expand Down
2 changes: 2 additions & 0 deletions pkg/analyzer/lib/src/dart/ast/ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3699,6 +3699,8 @@ abstract class ExpressionImpl extends AstNodeImpl
var parent = child.parent;
if (parent is ConstantContextForExpressionImpl) {
return true;
} else if (parent is EnumConstantArguments) {
return true;
} else if (parent is TypedLiteralImpl && parent.constKeyword != null) {
// Inside an explicitly `const` list or map literal.
return true;
Expand Down
10 changes: 10 additions & 0 deletions pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
}
}

@override
visitEnumConstantDeclaration(node) {
super.visitEnumConstantDeclaration(node);

var argumentList = node.arguments?.argumentList;
if (argumentList != null) {
_validateConstantArguments(argumentList);
}
}

@override
void visitFunctionExpression(FunctionExpression node) {
super.visitFunctionExpression(node);
Expand Down
12 changes: 12 additions & 0 deletions pkg/analyzer/lib/src/dart/element/type_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/element/type_schema_elimination.dart';
import 'package:analyzer/src/dart/element/well_bounded.dart';

/// The [TypeSystem] implementation.
class TypeSystemImpl implements TypeSystem {
Expand Down Expand Up @@ -1178,6 +1179,17 @@ class TypeSystemImpl implements TypeSystem {
return false;
}

/// See `15.2 Super-bounded types` in the language specification.
TypeBoundedResult isWellBounded(
DartType type, {
required bool allowSuperBounded,
}) {
return TypeBoundedHelper(this).isWellBounded(
type,
allowSuperBounded: allowSuperBounded,
);
}

/// Returns the least closure of [type] with respect to [typeParameters].
///
/// https://github.com/dart-lang/language
Expand Down
138 changes: 138 additions & 0 deletions pkg/analyzer/lib/src/dart/element/well_bounded.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright (c) 2022, 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/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_system.dart';

class NotWellBoundedTypeResult implements TypeBoundedResult {
final String elementName;
final List<TypeArgumentIssue> issues;

NotWellBoundedTypeResult._({
required this.elementName,
required this.issues,
});
}

class RegularBoundedTypeResult implements WellBoundedTypeResult {
const RegularBoundedTypeResult._();
}

class SuperBoundedTypeResult implements WellBoundedTypeResult {
const SuperBoundedTypeResult._();
}

class TypeArgumentIssue {
/// The index for type argument within the passed type arguments.
final int index;

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

/// The substituted bound of the [parameter].
final DartType parameterBound;

/// The type argument that violated the [parameterBound].
final DartType argument;

TypeArgumentIssue(
this.index,
this.parameter,
this.parameterBound,
this.argument,
);

@override
String toString() {
return 'TypeArgumentIssue(index=$index, parameter=$parameter, '
'parameterBound=$parameterBound, argument=$argument)';
}
}

/// Helper for checking whether a type if well-bounded.
///
/// See `15.2 Super-bounded types` in the language specification.
class TypeBoundedHelper {
final TypeSystemImpl typeSystem;

TypeBoundedHelper(this.typeSystem);

TypeBoundedResult isWellBounded(
DartType type, {
required bool allowSuperBounded,
}) {
var result = _isRegularBounded(type);
if (!allowSuperBounded) {
return result;
}

return _isSuperBounded(type);
}

TypeBoundedResult _isRegularBounded(DartType type) {
List<TypeArgumentIssue>? issues;

final String elementName;
final List<TypeParameterElement> typeParameters;
final List<DartType> typeArguments;
final alias = type.alias;
if (alias != null) {
elementName = alias.element.name;
typeParameters = alias.element.typeParameters;
typeArguments = alias.typeArguments;
} else if (type is InterfaceType) {
elementName = type.element.name;
typeParameters = type.element.typeParameters;
typeArguments = type.typeArguments;
} else {
return const RegularBoundedTypeResult._();
}

final substitution = Substitution.fromPairs(typeParameters, typeArguments);
for (var i = 0; i < typeParameters.length; i++) {
var typeParameter = typeParameters[i];
var typeArgument = typeArguments[i];

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

bound = typeSystem.toLegacyType(bound);
bound = substitution.substituteType(bound);

if (!typeSystem.isSubtypeOf(typeArgument, bound)) {
issues ??= <TypeArgumentIssue>[];
issues.add(
TypeArgumentIssue(i, typeParameter, bound, typeArgument),
);
}
}

if (issues == null) {
return const RegularBoundedTypeResult._();
} else {
return NotWellBoundedTypeResult._(
elementName: elementName,
issues: issues,
);
}
}

TypeBoundedResult _isSuperBounded(DartType type) {
final invertedType = typeSystem.replaceTopAndBottom(type);
var result = _isRegularBounded(invertedType);
if (result is RegularBoundedTypeResult) {
return const SuperBoundedTypeResult._();
} else {
return result;
}
}
}

abstract class TypeBoundedResult {}

class WellBoundedTypeResult implements TypeBoundedResult {}
14 changes: 14 additions & 0 deletions pkg/analyzer/lib/src/error/codes.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3671,6 +3671,13 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
correctionMessage: "Try invoking a const generative constructor.",
);

static const CompileTimeErrorCode
ENUM_INSTANTIATED_TO_BOUNDS_IS_NOT_WELL_BOUNDED = CompileTimeErrorCode(
'ENUM_INSTANTIATED_TO_BOUNDS_IS_NOT_WELL_BOUNDED',
"The result of instantiating the enum to bounds is not well-bounded.",
correctionMessage: "Try using different bounds for type parameters.",
);

static const CompileTimeErrorCode ENUM_MIXIN_WITH_INSTANCE_VARIABLE =
CompileTimeErrorCode(
'ENUM_MIXIN_WITH_INSTANCE_VARIABLE',
Expand Down Expand Up @@ -15583,6 +15590,13 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
hasPublishedDocs: true,
);

static const CompileTimeErrorCode VALUES_DECLARATION_IN_ENUM =
CompileTimeErrorCode(
'VALUES_DECLARATION_IN_ENUM',
"A member named 'values' can't be declared in an enum.",
correctionMessage: "Try using a different name.",
);

/**
* Parameters:
* 0: the type of the object being assigned.
Expand Down
17 changes: 12 additions & 5 deletions pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,9 @@ class DuplicateDefinitionVerifier {
var staticGetters = <String, Element>{};
var staticSetters = <String, Element>{};

var valuesField = enumElement.valuesField;
if (valuesField != null) {
staticGetters['values'] = valuesField;
}

for (EnumConstantDeclaration constant in node.constants) {
_checkDuplicateIdentifier(staticGetters, constant.name);
_checkValuesDeclarationInEnum(constant.name);
}

for (var member in node.members) {
Expand Down Expand Up @@ -89,13 +85,15 @@ class DuplicateDefinitionVerifier {
identifier,
setterScope: member.isStatic ? staticSetters : instanceSetters,
);
_checkValuesDeclarationInEnum(identifier);
}
} else if (member is MethodDeclaration) {
_checkDuplicateIdentifier(
member.isStatic ? staticGetters : instanceGetters,
member.name,
setterScope: member.isStatic ? staticSetters : instanceSetters,
);
_checkValuesDeclarationInEnum(member.name);
}
}

Expand Down Expand Up @@ -514,6 +512,15 @@ class DuplicateDefinitionVerifier {
}
}

void _checkValuesDeclarationInEnum(SimpleIdentifier name) {
if (name.name == 'values') {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.VALUES_DECLARATION_IN_ENUM,
name,
);
}
}

ExecutableElement? _getInheritedMember(
ClassElement element, String baseName) {
var libraryUri = _currentLibrary.source.uri;
Expand Down
6 changes: 4 additions & 2 deletions pkg/analyzer/lib/src/error/inheritance_override.dart
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,11 @@ class _ClassVerifier {
var fieldElement = field.declaredElement as FieldElement;
_checkDeclaredMember(field.name, libraryUri, fieldElement.getter);
_checkDeclaredMember(field.name, libraryUri, fieldElement.setter);
if (!member.isStatic && !classElement.isEnum) {
_checkIllegalEnumValuesDeclaration(field.name);
}
if (!member.isStatic) {
_checkIllegalNonAbstractEnumIndex(field.name);
_checkIllegalEnumValuesDeclaration(field.name);
}
}
} else if (member is MethodDeclaration) {
Expand All @@ -210,7 +212,7 @@ class _ClassVerifier {

_checkDeclaredMember(member.name, libraryUri, member.declaredElement,
methodParameterNodes: member.parameters?.parameters);
if (!member.isStatic) {
if (!member.isStatic && !classElement.isEnum) {
_checkIllegalEnumValuesDeclaration(member.name);
}
if (!(member.isStatic || member.isAbstract || member.isSetter)) {
Expand Down
23 changes: 21 additions & 2 deletions pkg/analyzer/lib/src/generated/error_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/element/well_bounded.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/dart/resolver/variance.dart';
import 'package:analyzer/src/diagnostic/diagnostic_factory.dart';
Expand Down Expand Up @@ -582,12 +583,11 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
_checkClassInheritance(node, null, withClause, implementsClause);
}

// TODO(scheglov) implement
// _checkForConflictingClassMembers();
_constructorFieldsVerifier.enterEnum(node);
_checkForFinalNotInitializedInClass(node.members);
_checkForWrongTypeParameterVarianceInSuperinterfaces();
_checkForMainFunction(node.name);
_checkForEnumInstantiatedToBoundsIsNotWellBounded(node, element);

super.visitEnumDeclaration(node);
} finally {
Expand Down Expand Up @@ -2463,6 +2463,25 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
return true;
}

void _checkForEnumInstantiatedToBoundsIsNotWellBounded(
EnumDeclaration node,
EnumElementImpl element,
) {
var valuesFieldType = element.valuesField?.type;
if (valuesFieldType is InterfaceType) {
var isWellBounded = typeSystem.isWellBounded(
valuesFieldType.typeArguments.single,
allowSuperBounded: true,
);
if (isWellBounded is NotWellBoundedTypeResult) {
errorReporter.reportErrorForNode(
CompileTimeErrorCode.ENUM_INSTANTIATED_TO_BOUNDS_IS_NOT_WELL_BOUNDED,
node.name,
);
}
}
}

/// Check that if the visiting library is not system, then any given library
/// should not be SDK internal library. The [exportElement] is the
/// [ExportElement] retrieved from the node, if the element in the node was
Expand Down
6 changes: 6 additions & 0 deletions pkg/analyzer/lib/src/summary/format.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ enum IndexRelationKind : byte {
/// Right: location.
IS_INVOKED_BY,

/// Left: an unnamed constructor.
/// Is invoked by an enum constant, without arguments, which is special
/// because when the name given, an empty argument list must be added.
/// Right: location.
IS_INVOKED_BY_ENUM_CONSTANT_WITHOUT_ARGUMENTS,

/// Left: any element.
/// Is referenced (and not invoked, read/written) at.
/// Right: location.
Expand Down
Loading

0 comments on commit 7e3310b

Please sign in to comment.