From 2c9d8924e316bf821a746993e6d1adc2c25709b4 Mon Sep 17 00:00:00 2001 From: Dmitry Stefantsov Date: Tue, 22 May 2018 13:06:11 +0000 Subject: [PATCH] [fasta] Make explicit Object in bound a constraint during type inference Change-Id: I1da9c822e83663dd285880a074e5a36ff295003c Reviewed-on: https://dart-review.googlesource.com/55897 Commit-Queue: Dmitry Stefantsov Reviewed-by: Kevin Millikin --- .../type_schema_environment.dart | 26 +++++++++++++------ pkg/kernel/lib/type_algebra.dart | 6 +++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart index 6554d8e49b6..0297c473332 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart @@ -267,7 +267,22 @@ class TypeSchemaEnvironment extends TypeEnvironment { downwardsInferPhase: formalTypes == null); } - /// Use the given [constraints] to substitute for type variables.. + bool hasOmittedBound(TypeParameter parameter) { + // If the bound was omitted by the programmer, the Kernel representation for + // the parameter will look similar to the following: + // + // T extends Object = dynamic + // + // Note that it's not possible to receive [Object] as [TypeParameter.bound] + // and `dynamic` as [TypeParameter.defaultType] from the front end in any + // other way. + DartType bound = parameter.bound; + return bound is InterfaceType && + identical(bound.classNode, coreTypes.objectClass) && + parameter.defaultType is DynamicType; + } + + /// Use the given [constraints] to substitute for type variables. /// /// [typeParametersToInfer] is the set of type parameters that should be /// substituted for. [inferredTypes] should be a list of the same length. @@ -293,7 +308,7 @@ class TypeSchemaEnvironment extends TypeEnvironment { var typeParamBound = typeParam.bound; DartType extendsConstraint; - if (!_isObjectOrDynamic(typeParamBound)) { + if (!hasOmittedBound(typeParam)) { extendsConstraint = Substitution .fromPairs(typeParametersToInfer, inferredTypes) .substituteType(typeParamBound); @@ -326,7 +341,7 @@ class TypeSchemaEnvironment extends TypeEnvironment { var inferred = inferredTypes[i]; bool success = typeSatisfiesConstraint(inferred, constraint); - if (success && !_isObjectOrDynamic(typeParamBound)) { + if (success && !hasOmittedBound(typeParam)) { // If everything else succeeded, check the `extends` constraint. var extendsConstraint = typeParamBound; success = isSubtypeOf(inferred, extendsConstraint); @@ -666,11 +681,6 @@ class TypeSchemaEnvironment extends TypeEnvironment { return hierarchy.getClassicLeastUpperBound(type1, type2); } - bool _isObjectOrDynamic(DartType type) => - type is DynamicType || - (type is InterfaceType && - identical(type.classNode, coreTypes.objectClass)); - DartType _typeParameterLeastUpperBound(DartType type1, DartType type2) { // This currently just implements a simple least upper bound to // handle some common cases. It also avoids some termination issues diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart index ad6017b61e9..821f9d5ba7d 100644 --- a/pkg/kernel/lib/type_algebra.dart +++ b/pkg/kernel/lib/type_algebra.dart @@ -229,6 +229,12 @@ FreshTypeParameters getFreshTypeParameters(List typeParameters) { } for (int i = 0; i < typeParameters.length; ++i) { freshParameters[i].bound = substitute(typeParameters[i].bound, map); + + // [defaultType] is populated using instantiate-to-bound algorithm, so it + // shouldn't refer to type parameters from the same declaration. However, + // if a transformation changes [defaultType], it may get such references, + // and the line below should invoke [substitute], like for [bound] above. + freshParameters[i].defaultType = typeParameters[i].defaultType; } return new FreshTypeParameters(freshParameters, Substitution.fromMap(map)); }