diff --git a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart index 52fab94c47a..641f80f1af8 100644 --- a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart +++ b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart @@ -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 diff --git a/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart b/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart index bc84dbdfa28..970191b094e 100644 --- a/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart +++ b/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart @@ -192,6 +192,27 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemNullSafetyTest { ); } + void test_fromLegacy_nonNullableBound() { + typeSystem = analysisContext.typeSystemLegacy; + + // void Function(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 var tFrom = typeParameter('TFrom'); diff --git a/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart b/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart index 73ddb62f98f..951fcbd6ff8 100644 --- a/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart +++ b/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart @@ -10,6 +10,7 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(CouldNotInferTest); + defineReflectiveTests(CouldNotInferWithNullSafetyTest); }); } @@ -229,10 +230,10 @@ class Foo { U method(U u) => u; } main() { - new Foo()./*error:COULD_NOT_INFER*/method(42); + new Foo().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); } ]); } } + +@reflectiveTest +class CouldNotInferWithNullSafetyTest extends PubPackageResolutionTest + with WithNullSafetyMixin { + test_constructor_nullSafe_fromLegacy() async { + newFile('$testPackageLibPath/a.dart', content: ''' +class C { + C(T t); +} +'''); + + await assertNoErrorsInCode(''' +// @dart = 2.8 +import 'a.dart'; + +void f(dynamic a) { + C(a); +} +'''); + } +}