Replace DartType.resolveToBound() with TypeSystem.resolveToBound()

Bug: https://github.com/dart-lang/sdk/issues/48952
Change-Id: I38add3e0d633f947640283eda46b5399f4559ef8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243702
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2022-05-05 20:35:16 +00:00 committed by Commit Bot
parent 56765625e0
commit d78797d014
17 changed files with 299 additions and 58 deletions

View file

@ -158,13 +158,13 @@ class FeatureComputer {
/// offset is within the given [node], or `null` if the context does not
/// impose any type.
DartType? computeContextType(AstNode node, int offset) {
var type = node
.accept(_ContextTypeVisitor(typeProvider, offset))
?.resolveToBound(typeProvider.objectType);
if (type == null || type.isDynamic) {
final contextType = node.accept(
_ContextTypeVisitor(typeProvider, offset),
);
if (contextType == null || contextType.isDynamic) {
return null;
}
return type;
return typeSystem.resolveToBound(contextType);
}
/// Return the element kind used to compute relevance for the given [element].

View file

@ -42,7 +42,10 @@ class TypeMemberContributor extends DartCompletionContributor {
}
// Determine the target expression's type.
var type = expression.staticType?.resolveToBound(request.objectType);
final expressionType = expression.staticType;
var type = expressionType != null
? request.libraryElement.typeSystem.resolveToBound(expressionType)
: null;
if (type == null || type.isDynamic) {
// If the expression does not provide a good type, then attempt to get a
// better type from the element.

View file

@ -2,6 +2,7 @@
* Deprecated `ParameterElement.isNotOptional`, use `isRequired` instead.
* Deprecated `ResourceProviderMixin.newFile2`, use `newFile` instead.
* Deprecated `ResourceProviderMixin.newAnalysisOptionsYamlFile2`, use `newAnalysisOptionsYamlFile` instead.
* Deprecated `DartType.resolveToBound`, use `TypeSystem.resolveToBound` instead.
## 4.0.0
* Removed deprecated `UriKind` and `Source.uriKind`.

View file

@ -176,6 +176,7 @@ abstract class DartType {
///
/// For any other type, returns `this`. Applies recursively -- if the bound is
/// itself a type parameter, that is resolved too.
@Deprecated('Use TypeSystem.resolveToBound() instead')
DartType resolveToBound(DartType objectType);
}

View file

@ -1063,6 +1063,7 @@ abstract class TypeImpl implements DartType {
return false;
}
@Deprecated('Use TypeSystem.resolveToBound() instead')
@override
DartType resolveToBound(DartType objectType) => this;
@ -1201,6 +1202,7 @@ class TypeParameterTypeImpl extends TypeImpl implements TypeParameterType {
return parameters.contains(element);
}
@Deprecated('Use TypeSystem.resolveToBound() instead')
@override
DartType resolveToBound(DartType objectType) {
final promotedBound = this.promotedBound;

View file

@ -1468,26 +1468,26 @@ class TypeSystemImpl implements TypeSystem {
@override
DartType resolveToBound(DartType type) {
if (type is TypeParameterTypeImpl) {
var element = type.element;
final promotedBound = type.promotedBound;
if (promotedBound != null) {
return resolveToBound(promotedBound);
}
var bound = element.bound;
final bound = type.element.bound;
if (bound == null) {
return typeProvider.objectType;
return isNonNullableByDefault ? objectQuestion : objectStar;
}
NullabilitySuffix nullabilitySuffix = type.nullabilitySuffix;
NullabilitySuffix newNullabilitySuffix;
if (nullabilitySuffix == NullabilitySuffix.question ||
bound.nullabilitySuffix == NullabilitySuffix.question) {
newNullabilitySuffix = NullabilitySuffix.question;
} else if (nullabilitySuffix == NullabilitySuffix.star ||
bound.nullabilitySuffix == NullabilitySuffix.star) {
newNullabilitySuffix = NullabilitySuffix.star;
} else {
newNullabilitySuffix = NullabilitySuffix.none;
}
final resolved = resolveToBound(bound) as TypeImpl;
final newNullabilitySuffix = uniteNullabilities(
uniteNullabilities(
type.nullabilitySuffix,
bound.nullabilitySuffix,
),
resolved.nullabilitySuffix,
);
var resolved = resolveToBound(bound) as TypeImpl;
return resolved.withNullability(newNullabilitySuffix);
}

View file

@ -233,13 +233,6 @@ class BinaryExpressionResolver {
contextType: contextType);
}
/// If the given [type] is a type parameter, resolve it to the type that should
/// be used when looking up members. Otherwise, return the original type.
///
/// TODO(scheglov) this is duplicate
DartType _resolveTypeParameter(DartType type) =>
type.resolveToBound(_typeProvider.objectType);
void _resolveUnsupportedOperator(BinaryExpressionImpl node,
{required DartType? contextType}) {
node.leftOperand.accept(_resolver);
@ -304,7 +297,7 @@ class BinaryExpressionResolver {
}
var leftType = leftOperand.typeOrThrow;
leftType = _resolveTypeParameter(leftType);
leftType = _typeSystem.resolveToBound(leftType);
if (identical(leftType, NeverTypeImpl.instance)) {
_resolver.errorReporter.reportErrorForNode(
@ -354,7 +347,7 @@ class BinaryExpressionResolver {
leftType = leftOperand.extendedType!;
} else {
leftType = leftOperand.typeOrThrow;
leftType = _resolveTypeParameter(leftType);
leftType = _typeSystem.resolveToBound(leftType);
}
if (identical(leftType, NeverTypeImpl.instance)) {

View file

@ -7,6 +7,7 @@ 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/type_provider.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
import 'package:analyzer/src/generated/resolver.dart';
@ -21,6 +22,8 @@ class CommentReferenceResolver {
CommentReferenceResolver(this._typeProvider, this._resolver)
: _typePropertyResolver = _resolver.typePropertyResolver;
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
/// Resolves [commentReference].
void resolve(CommentReference commentReference) {
_resolver.errorReporter.lockLevel++;
@ -150,8 +153,9 @@ class CommentReferenceResolver {
if (enclosingExtension == null) {
return null;
}
var extendedType = enclosingExtension.extendedType
.resolveToBound(_typeProvider.objectType);
var extendedType = _typeSystem.resolveToBound(
enclosingExtension.extendedType,
);
if (extendedType is InterfaceType) {
enclosingType = extendedType;
} else if (extendedType is FunctionType) {

View file

@ -9,6 +9,7 @@ import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/typed_literal_resolver.dart';
import 'package:analyzer/src/error/codes.dart';
@ -22,6 +23,8 @@ class ForResolver {
required ResolverVisitor resolver,
}) : _resolver = resolver;
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
void resolveElement(ForElementImpl node, CollectionLiteralContext? context) {
var forLoopParts = node.forLoopParts;
void visitBody() {
@ -57,8 +60,7 @@ class ForResolver {
DartType? _computeForEachElementType(Expression iterable, bool isAsync) {
var iterableType = iterable.staticType;
if (iterableType == null) return null;
iterableType =
iterableType.resolveToBound(_resolver.typeProvider.objectType);
iterableType = _typeSystem.resolveToBound(iterableType);
ClassElement iteratedElement = isAsync
? _resolver.typeProvider.streamElement

View file

@ -868,15 +868,6 @@ class MethodInvocationResolver {
}
}
/// 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;
}
/// We have identified that [node] is not a real [MethodInvocation],
/// because it does not invoke a method, but instead invokes the result
/// of a getter execution, or implicitly invokes the `call` method of
@ -885,7 +876,7 @@ class MethodInvocationResolver {
void _rewriteAsFunctionExpressionInvocation(
MethodInvocationImpl node, DartType getterReturnType,
{required DartType? contextType}) {
var targetType = _resolveTypeParameter(getterReturnType);
var targetType = _typeSystem.resolveToBound(getterReturnType);
_inferenceHelper.recordStaticType(node.methodName, targetType,
contextType: contextType);

View file

@ -68,7 +68,7 @@ class PropertyElementResolver {
}
var targetType = target.typeOrThrow;
targetType = _resolveTypeParameter(targetType);
targetType = _typeSystem.resolveToBound(targetType);
if (targetType.isVoid) {
// TODO(scheglov) Report directly in TypePropertyResolver?
@ -815,15 +815,6 @@ class PropertyElementResolver {
);
}
/// 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;
}
PropertyElementResolverResult _toIndexResult(ResolutionResult result) {
var readElement = result.getter;
var writeElement = result.setter;

View file

@ -282,7 +282,7 @@ class TypePropertyResolver {
bool ifNullSafe = false,
}) {
if (_typeSystem.isNonNullableByDefault ? ifNullSafe : ifLegacy) {
return type.resolveToBound(_typeProvider.objectType);
return _typeSystem.resolveToBound(type);
} else {
return type;
}

View file

@ -2393,7 +2393,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
// The object being iterated has to implement Iterable<T> for some T that
// is assignable to the variable's type.
// TODO(rnystrom): Move this into mostSpecificTypeArgument()?
iterableType = iterableType.resolveToBound(_typeProvider.objectType);
iterableType = typeSystem.resolveToBound(iterableType);
var requiredSequenceType = awaitKeyword != null
? _typeProvider.streamDynamicType

View file

@ -789,6 +789,7 @@ class FunctionTypeImplTest extends AbstractTypeSystemTest {
expect(types[1], stringNone);
}
@deprecated
void test_resolveToBound() {
var type = functionTypeNone(
typeFormals: [],
@ -1235,6 +1236,7 @@ class InterfaceTypeImplTest extends AbstractTypeSystemTest {
expect(0 == typeA.hashCode, isFalse);
}
@deprecated
void test_resolveToBound() {
var type = interfaceTypeStar(ElementFactory.classElement2('A'));
@ -1414,6 +1416,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(type.element, element);
}
@deprecated
void test_resolveToBound_bound() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@ -1422,6 +1425,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(type.resolveToBound(objectNone), interfaceTypeStar(classS));
}
@deprecated
void test_resolveToBound_bound_nullableInner() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@ -1430,6 +1434,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(type.resolveToBound(objectNone), same(element.bound));
}
@deprecated
void test_resolveToBound_bound_nullableInnerOuter() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@ -1439,6 +1444,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(type.resolveToBound(objectNone), same(element.bound));
}
@deprecated
void test_resolveToBound_bound_nullableInnerStarOuter() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@ -1449,6 +1455,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
type.resolveToBound(objectNone), equals(interfaceTypeQuestion(classS)));
}
@deprecated
void test_resolveToBound_bound_nullableOuter() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@ -1459,6 +1466,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
type.resolveToBound(objectNone), equals(interfaceTypeQuestion(classS)));
}
@deprecated
void test_resolveToBound_bound_starInner() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@ -1467,6 +1475,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(type.resolveToBound(objectNone), same(element.bound));
}
@deprecated
void test_resolveToBound_bound_starInnerNullableOuter() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@ -1476,6 +1485,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(type.resolveToBound(objectNone), same(element.bound));
}
@deprecated
void test_resolveToBound_bound_starOuter() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@ -1485,6 +1495,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(type.resolveToBound(objectNone), interfaceTypeStar(classS));
}
@deprecated
void test_resolveToBound_nestedBound() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl elementE = TypeParameterElementImpl('E', -1);
@ -1496,6 +1507,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(typeF.resolveToBound(objectNone), interfaceTypeStar(classS));
}
@deprecated
void test_resolveToBound_promotedBound_interfaceType() {
var A = class_(name: 'A');
var A_none = interfaceTypeNone(A);
@ -1505,6 +1517,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(T_A.resolveToBound(objectQuestion), A_none);
}
@deprecated
void test_resolveToBound_promotedBound_typeParameterType_interfaceType() {
var A = class_(name: 'A');
var A_none = interfaceTypeNone(A);
@ -1517,6 +1530,7 @@ class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
expect(U_T.resolveToBound(objectQuestion), A_none);
}
@deprecated
void test_resolveToBound_unbound() {
TypeParameterTypeImpl type =
typeParameterTypeStar(TypeParameterElementImpl('E', -1));
@ -1597,6 +1611,7 @@ class VoidTypeImplTest extends AbstractTypeSystemTest {
expect(_voidType.isVoid, isTrue);
}
@deprecated
void test_resolveToBound() {
// Returns this.
expect(_voidType.resolveToBound(objectNone), same(_voidType));

View file

@ -0,0 +1,225 @@
// 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/type.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../../generated/type_system_test.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ResolveToBoundTest);
defineReflectiveTests(ResolveToBoundWithoutNullSafetyTest);
});
}
@reflectiveTest
class ResolveToBoundTest extends AbstractTypeSystemTest {
test_dynamic() {
_check(dynamicType, 'dynamic');
}
test_functionType() {
_check(
functionTypeNone(returnType: voidNone),
'void Function()',
);
}
test_interfaceType() {
_check(intNone, 'int');
_check(intQuestion, 'int?');
_check(intStar, 'int*');
}
test_typeParameter_bound() {
_check(
typeParameterTypeNone(
typeParameter('T', bound: intNone),
),
'int',
);
_check(
typeParameterTypeNone(
typeParameter('T', bound: intQuestion),
),
'int?',
);
_check(
typeParameterTypeStar(
typeParameter('T', bound: intStar),
),
'int*',
);
}
test_typeParameter_bound_functionType() {
_check(
typeParameterTypeNone(
typeParameter(
'T',
bound: functionTypeNone(
returnType: voidNone,
),
),
),
'void Function()',
);
}
test_typeParameter_bound_nested_noBound() {
final T = typeParameter('T');
final U = typeParameter(
'U',
bound: typeParameterTypeNone(T),
);
_check(typeParameterTypeNone(U), 'Object?');
}
test_typeParameter_bound_nested_none() {
final T = typeParameter('T', bound: intNone);
final U = typeParameter(
'U',
bound: typeParameterTypeNone(T),
);
_check(typeParameterTypeNone(U), 'int');
}
test_typeParameter_bound_nested_none_outerNullable() {
final T = typeParameter('T', bound: intNone);
final U = typeParameter(
'U',
bound: typeParameterTypeQuestion(T),
);
_check(typeParameterTypeNone(U), 'int?');
}
test_typeParameter_bound_nested_question() {
final T = typeParameter('T', bound: intQuestion);
final U = typeParameter(
'U',
bound: typeParameterTypeNone(T),
);
_check(typeParameterTypeNone(U), 'int?');
}
test_typeParameter_bound_nullableInner() {
_check(
typeParameterTypeNone(
typeParameter('T', bound: intQuestion),
),
'int?',
);
}
test_typeParameter_bound_nullableInnerOuter() {
_check(
typeParameterTypeQuestion(
typeParameter('T', bound: intQuestion),
),
'int?',
);
}
test_typeParameter_bound_nullableOuter() {
_check(
typeParameterTypeQuestion(
typeParameter('T', bound: intNone),
),
'int?',
);
}
test_typeParameter_noBound() {
_check(
typeParameterTypeNone(
typeParameter('T'),
),
'Object?',
);
}
test_typeParameter_promotedBound() {
_check(
typeParameterTypeNone(
typeParameter('T', bound: numNone),
promotedBound: intNone,
),
'int',
);
_check(
typeParameterTypeNone(
typeParameter('T', bound: numQuestion),
promotedBound: intQuestion,
),
'int?',
);
_check(
typeParameterTypeNone(
typeParameter('T', bound: numStar),
promotedBound: intStar,
),
'int*',
);
}
test_void() {
_check(voidNone, 'void');
}
void _check(DartType type, String expectedStr) {
var result = typeSystem.resolveToBound(type);
var resultStr = _typeString(result);
expect(resultStr, expectedStr);
}
String _typeString(DartType type) {
return type.getDisplayString(withNullability: true);
}
}
@reflectiveTest
class ResolveToBoundWithoutNullSafetyTest
extends AbstractTypeSystemWithoutNullSafetyTest {
test_dynamic() {
_check(dynamicType, 'dynamic');
}
test_typeParameter_bound() {
_check(
typeParameterTypeStar(
typeParameter('T', bound: intStar),
),
'int*',
);
}
test_typeParameter_noBound() {
_check(
typeParameterTypeNone(
typeParameter('T'),
),
'Object*',
);
}
test_void() {
_check(voidNone, 'void');
}
void _check(DartType type, String expectedStr) {
var result = typeSystem.resolveToBound(type);
var resultStr = _typeString(result);
expect(resultStr, expectedStr);
}
String _typeString(DartType type) {
return type.getDisplayString(withNullability: true);
}
}

View file

@ -21,6 +21,7 @@ import 'normalize_type_test.dart' as normalize_type;
import 'nullability_eliminator_test.dart' as nullability_eliminator;
import 'nullable_test.dart' as nullable;
import 'replace_top_bottom_test.dart' as replace_top_bottom;
import 'resolve_to_bound_test.dart' as resolve_to_bound;
import 'runtime_type_equality_test.dart' as runtime_type_equality;
import 'subtype_test.dart' as subtype;
import 'top_merge_test.dart' as top_merge;
@ -52,6 +53,7 @@ main() {
nullability_eliminator.main();
nullable.main();
replace_top_bottom.main();
resolve_to_bound.main();
runtime_type_equality.main();
subtype.main();
top_merge.main();

View file

@ -7,6 +7,7 @@ import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.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/dart/element/type_provider.dart';
import 'package:analyzer/dart/element/type_system.dart';
@ -280,8 +281,7 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType>
if (targetType != null) {
var enclosingElement = baseElement!.enclosingElement;
if (enclosingElement is ClassElement) {
if (targetType.type!.resolveToBound(typeProvider.dynamicType)
is InterfaceType &&
if (targetType.type.explicitBound is InterfaceType &&
enclosingElement.typeParameters.isNotEmpty) {
substitution = _decoratedClassHierarchy!
.asInstanceOf(targetType, enclosingElement)
@ -3971,3 +3971,14 @@ class _ConditionInfo {
trueDemonstratesNonNullIntent: falseDemonstratesNonNullIntent,
falseDemonstratesNonNullIntent: trueDemonstratesNonNullIntent);
}
extension on DartType? {
DartType? get explicitBound {
final self = this;
if (self is TypeParameterType &&
self.nullabilitySuffix == NullabilitySuffix.star) {
return self.element.bound.explicitBound;
}
return self;
}
}