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:
Konstantin Shcheglov
2020-08-21 20:18:10 +00:00
committed by commit-bot@chromium.org
parent 194be0b23f
commit c2bc119c21
3 changed files with 64 additions and 14 deletions
@@ -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);
}
''');
}
}