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>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
index 6fd8abf..cf79edf 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
@@ -158,13 +158,13 @@
/// 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].
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
index b809dbe..ef27adf 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -42,7 +42,10 @@
}
// 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.
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 4e91889..4462b02 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -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`.
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 2f479bd..806186f 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -176,6 +176,7 @@
///
/// 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);
}
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index dcef43d..113b883 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1063,6 +1063,7 @@
return false;
}
+ @Deprecated('Use TypeSystem.resolveToBound() instead')
@override
DartType resolveToBound(DartType objectType) => this;
@@ -1201,6 +1202,7 @@
return parameters.contains(element);
}
+ @Deprecated('Use TypeSystem.resolveToBound() instead')
@override
DartType resolveToBound(DartType objectType) {
final promotedBound = this.promotedBound;
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index d420c963..5208c75 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -1468,26 +1468,26 @@
@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;
- var resolved = resolveToBound(bound) as TypeImpl;
+ final newNullabilitySuffix = uniteNullabilities(
+ uniteNullabilities(
+ type.nullabilitySuffix,
+ bound.nullabilitySuffix,
+ ),
+ resolved.nullabilitySuffix,
+ );
+
return resolved.withNullability(newNullabilitySuffix);
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 6d8741a..0906db3 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -233,13 +233,6 @@
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 @@
}
var leftType = leftOperand.typeOrThrow;
- leftType = _resolveTypeParameter(leftType);
+ leftType = _typeSystem.resolveToBound(leftType);
if (identical(leftType, NeverTypeImpl.instance)) {
_resolver.errorReporter.reportErrorForNode(
@@ -354,7 +347,7 @@
leftType = leftOperand.extendedType!;
} else {
leftType = leftOperand.typeOrThrow;
- leftType = _resolveTypeParameter(leftType);
+ leftType = _typeSystem.resolveToBound(leftType);
}
if (identical(leftType, NeverTypeImpl.instance)) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart
index f43eecf..5cebadf 100644
--- a/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart
@@ -7,6 +7,7 @@
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 @@
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 @@
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) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
index dceec2d..4784ae4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
@@ -9,6 +9,7 @@
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 @@
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 @@
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
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index e7d3b26..8fdaa1a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -868,15 +868,6 @@
}
}
- /// 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 @@
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);
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index 8e8bce1..47bfe31 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -68,7 +68,7 @@
}
var targetType = target.typeOrThrow;
- targetType = _resolveTypeParameter(targetType);
+ targetType = _typeSystem.resolveToBound(targetType);
if (targetType.isVoid) {
// TODO(scheglov) Report directly in TypePropertyResolver?
@@ -815,15 +815,6 @@
);
}
- /// 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;
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
index fc870ea..6e9f0cc 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
@@ -282,7 +282,7 @@
bool ifNullSafe = false,
}) {
if (_typeSystem.isNonNullableByDefault ? ifNullSafe : ifLegacy) {
- return type.resolveToBound(_typeProvider.objectType);
+ return _typeSystem.resolveToBound(type);
} else {
return type;
}
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index d5a1aac..039fbff 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -2393,7 +2393,7 @@
// 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
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index d105672..6873d5f 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -789,6 +789,7 @@
expect(types[1], stringNone);
}
+ @deprecated
void test_resolveToBound() {
var type = functionTypeNone(
typeFormals: [],
@@ -1235,6 +1236,7 @@
expect(0 == typeA.hashCode, isFalse);
}
+ @deprecated
void test_resolveToBound() {
var type = interfaceTypeStar(ElementFactory.classElement2('A'));
@@ -1414,6 +1416,7 @@
expect(type.element, element);
}
+ @deprecated
void test_resolveToBound_bound() {
ClassElementImpl classS = class_(name: 'A');
TypeParameterElementImpl element = TypeParameterElementImpl('E', -1);
@@ -1422,6 +1425,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
expect(U_T.resolveToBound(objectQuestion), A_none);
}
+ @deprecated
void test_resolveToBound_unbound() {
TypeParameterTypeImpl type =
typeParameterTypeStar(TypeParameterElementImpl('E', -1));
@@ -1597,6 +1611,7 @@
expect(_voidType.isVoid, isTrue);
}
+ @deprecated
void test_resolveToBound() {
// Returns this.
expect(_voidType.resolveToBound(objectNone), same(_voidType));
diff --git a/pkg/analyzer/test/src/dart/element/resolve_to_bound_test.dart b/pkg/analyzer/test/src/dart/element/resolve_to_bound_test.dart
new file mode 100644
index 0000000..b733568
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/element/resolve_to_bound_test.dart
@@ -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);
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/element/test_all.dart b/pkg/analyzer/test/src/dart/element/test_all.dart
index f3019b9..8d78853 100644
--- a/pkg/analyzer/test/src/dart/element/test_all.dart
+++ b/pkg/analyzer/test/src/dart/element/test_all.dart
@@ -21,6 +21,7 @@
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 @@
nullability_eliminator.main();
nullable.main();
replace_top_bottom.main();
+ resolve_to_bound.main();
runtime_type_equality.main();
subtype.main();
top_merge.main();
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 013e482..d6bfd32 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -7,6 +7,7 @@
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 @@
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 @@
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;
+ }
+}