Issue 43144. Convert the bound of type parameter to legacy if necessary.
Bug: https://github.com/dart-lang/sdk/issues/43144 Change-Id: I2bf50c498d7919460133d1bed07ce2de861fce08 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/159646 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
194be0b23f
commit
c2bc119c21
@@ -166,14 +166,19 @@ class GenericInferrer {
|
||||
for (int i = 0; i < typeFormals.length; i++) {
|
||||
TypeParameterElement typeParam = typeFormals[i];
|
||||
var constraints = _constraints[typeParam];
|
||||
var typeParamBound = typeParam.bound != null
|
||||
? Substitution.fromPairs(typeFormals, inferredTypes)
|
||||
.substituteType(typeParam.bound)
|
||||
: typeProvider.dynamicType;
|
||||
|
||||
var typeParamBound = typeParam.bound;
|
||||
if (typeParamBound != null) {
|
||||
typeParamBound = Substitution.fromPairs(typeFormals, inferredTypes)
|
||||
.substituteType(typeParamBound);
|
||||
typeParamBound = _toLegacyElementIfOptOut(typeParamBound);
|
||||
} else {
|
||||
typeParamBound = typeProvider.dynamicType;
|
||||
}
|
||||
|
||||
var inferred = inferredTypes[i];
|
||||
bool success =
|
||||
constraints.every((c) => c.isSatisifedBy(_typeSystem, inferred));
|
||||
constraints.every((c) => c.isSatisfiedBy(_typeSystem, inferred));
|
||||
if (success && !typeParamBound.isDynamic) {
|
||||
// If everything else succeeded, check the `extends` constraint.
|
||||
var extendsConstraint = _TypeConstraint.fromExtends(
|
||||
@@ -182,7 +187,7 @@ class GenericInferrer {
|
||||
isNonNullableByDefault: isNonNullableByDefault,
|
||||
);
|
||||
constraints.add(extendsConstraint);
|
||||
success = extendsConstraint.isSatisifedBy(_typeSystem, inferred);
|
||||
success = extendsConstraint.isSatisfiedBy(_typeSystem, inferred);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
@@ -344,8 +349,8 @@ class GenericInferrer {
|
||||
// will fail.
|
||||
upper = _typeSystem.getGreatestLowerBound(upper, constraint.upperBound);
|
||||
lower = _typeSystem.getLeastUpperBound(lower, constraint.lowerBound);
|
||||
upper = _toLegacyType(upper);
|
||||
lower = _toLegacyType(lower);
|
||||
upper = _toLegacyElementIfOptOut(upper);
|
||||
lower = _toLegacyElementIfOptOut(lower);
|
||||
}
|
||||
|
||||
// Prefer the known bound, if any.
|
||||
@@ -405,7 +410,7 @@ class GenericInferrer {
|
||||
Iterable<_TypeConstraint> isSatisified(bool expected) => constraintsByOrigin
|
||||
.values
|
||||
.where((l) =>
|
||||
l.every((c) => c.isSatisifedBy(_typeSystem, inferred)) == expected)
|
||||
l.every((c) => c.isSatisfiedBy(_typeSystem, inferred)) == expected)
|
||||
.expand((i) => i);
|
||||
|
||||
String unsatisified = _formatConstraints(isSatisified(false));
|
||||
@@ -479,7 +484,7 @@ class GenericInferrer {
|
||||
|
||||
/// If in a legacy library, return the legacy version of the [type].
|
||||
/// Otherwise, return the original type.
|
||||
DartType _toLegacyType(DartType type) {
|
||||
DartType _toLegacyElementIfOptOut(DartType type) {
|
||||
if (isNonNullableByDefault) return type;
|
||||
return NullabilityEliminator.perform(typeProvider, type);
|
||||
}
|
||||
@@ -542,8 +547,10 @@ class _TypeConstraint extends _TypeRange {
|
||||
|
||||
bool get isDownwards => origin is! _TypeConstraintFromArgument;
|
||||
|
||||
bool isSatisifedBy(TypeSystemImpl ts, DartType type) =>
|
||||
ts.isSubtypeOf2(lowerBound, type) && ts.isSubtypeOf2(type, upperBound);
|
||||
bool isSatisfiedBy(TypeSystemImpl ts, DartType type) {
|
||||
return ts.isSubtypeOf2(lowerBound, type) &&
|
||||
ts.isSubtypeOf2(type, upperBound);
|
||||
}
|
||||
|
||||
/// Converts this constraint to a message suitable for a type inference error.
|
||||
@override
|
||||
|
||||
@@ -192,6 +192,27 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemNullSafetyTest {
|
||||
);
|
||||
}
|
||||
|
||||
void test_fromLegacy_nonNullableBound() {
|
||||
typeSystem = analysisContext.typeSystemLegacy;
|
||||
|
||||
// void Function<T extends Object>(T)
|
||||
var T = typeParameter('T', bound: objectNone);
|
||||
var rawType = functionTypeNone(
|
||||
typeFormals: [T],
|
||||
parameters: [
|
||||
requiredParameter(
|
||||
type: typeParameterTypeNone(T),
|
||||
),
|
||||
],
|
||||
returnType: voidNone,
|
||||
);
|
||||
|
||||
_assertTypes(
|
||||
_inferCall(rawType, [dynamicNone]),
|
||||
[dynamicNone],
|
||||
);
|
||||
}
|
||||
|
||||
void test_genericCastFunction() {
|
||||
// <TFrom, TTo>(TFrom) -> TTo
|
||||
var tFrom = typeParameter('TFrom');
|
||||
|
||||
@@ -10,6 +10,7 @@ import '../dart/resolution/context_collection_resolution.dart';
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(CouldNotInferTest);
|
||||
defineReflectiveTests(CouldNotInferWithNullSafetyTest);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -229,10 +230,10 @@ class Foo<T extends Pattern> {
|
||||
U method<U extends T>(U u) => u;
|
||||
}
|
||||
main() {
|
||||
new Foo<String>()./*error:COULD_NOT_INFER*/method(42);
|
||||
new Foo<String>().method(42);
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.COULD_NOT_INFER, 122, 6),
|
||||
error(CompileTimeErrorCode.COULD_NOT_INFER, 97, 6),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -247,3 +248,24 @@ main() { new C().f(<S>(S s) => s); }
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class CouldNotInferWithNullSafetyTest extends PubPackageResolutionTest
|
||||
with WithNullSafetyMixin {
|
||||
test_constructor_nullSafe_fromLegacy() async {
|
||||
newFile('$testPackageLibPath/a.dart', content: '''
|
||||
class C<T extends Object> {
|
||||
C(T t);
|
||||
}
|
||||
''');
|
||||
|
||||
await assertNoErrorsInCode('''
|
||||
// @dart = 2.8
|
||||
import 'a.dart';
|
||||
|
||||
void f(dynamic a) {
|
||||
C(a);
|
||||
}
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user