Make getUpperBoundsAsType an utility, remove from TypeParameterDescriptor

This commit is contained in:
Alexander Udalov
2015-10-23 20:05:14 +03:00
parent 12d6b6e7e4
commit 86bc21da30
15 changed files with 48 additions and 62 deletions
@@ -32,14 +32,13 @@ import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolverKt; import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolverKt;
import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils; import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.TypeSubstitutor;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.Variance;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.jetbrains.kotlin.load.java.components.TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT; import static org.jetbrains.kotlin.load.java.components.TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT;
import static org.jetbrains.kotlin.load.java.components.TypeUsage.UPPER_BOUND; import static org.jetbrains.kotlin.load.java.components.TypeUsage.UPPER_BOUND;
@@ -140,13 +139,16 @@ public class AlternativeMethodSignatureData extends ElementAlternativeSignatureD
for (TypeParameterDescriptor parameter : methodTypeParameters) { for (TypeParameterDescriptor parameter : methodTypeParameters) {
int index = parameter.getIndex(); int index = parameter.getIndex();
KotlinType substituted = substitutor.substitute(parameter.getUpperBoundsAsType(), Variance.INVARIANT); KotlinType upperBoundsAsType = TypeIntersector.getUpperBoundsAsType(parameter);
KotlinType substituted = substitutor.substitute(upperBoundsAsType, Variance.INVARIANT);
assert substituted != null; assert substituted != null;
if (!TypeUtils.equalTypes(substituted, altTypeParameters.get(index).getUpperBoundsAsType())) { KotlinType altUpperBoundsAsType = TypeIntersector.getUpperBoundsAsType(altTypeParameters.get(index));
if (!TypeUtils.equalTypes(substituted, altUpperBoundsAsType)) {
throw new AlternativeSignatureMismatchException( throw new AlternativeSignatureMismatchException(
"Type parameter's upper bound changed for method which overrides another: " "Type parameter's upper bound changed for method which overrides another: "
+ altTypeParameters.get(index).getUpperBoundsAsType() + ", was: " + parameter.getUpperBoundsAsType()); + altUpperBoundsAsType + ", was: " + upperBoundsAsType
);
} }
} }
@@ -150,7 +150,7 @@ public class TypeTransformingVisitor extends KtVisitor<KotlinType, Void> {
KtScope memberScope; KtScope memberScope;
if (typeConstructorClassifier instanceof TypeParameterDescriptor) { if (typeConstructorClassifier instanceof TypeParameterDescriptor) {
memberScope = ((TypeParameterDescriptor) typeConstructorClassifier).getUpperBoundsAsType().getMemberScope(); memberScope = typeConstructorClassifier.getDefaultType().getMemberScope();
} }
else if (typeConstructorClassifier instanceof ClassDescriptor) { else if (typeConstructorClassifier instanceof ClassDescriptor) {
memberScope = ((ClassDescriptor) typeConstructorClassifier).getMemberScope(altArguments); memberScope = ((ClassDescriptor) typeConstructorClassifier).getMemberScope(altArguments);
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.Constrain
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeIntersector
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
@@ -324,7 +325,7 @@ public object Renderers {
} }
val explanation: String val explanation: String
val upperBound = typeParameterWithCapturedConstraint.getUpperBoundsAsType() val upperBound = TypeIntersector.getUpperBoundsAsType(typeParameterWithCapturedConstraint)
if (!KotlinBuiltIns.isNullableAny(upperBound) && capturedTypeConstructor.typeProjection.getProjectionKind() == Variance.IN_VARIANCE) { if (!KotlinBuiltIns.isNullableAny(upperBound) && capturedTypeConstructor.typeProjection.getProjectionKind() == Variance.IN_VARIANCE) {
explanation = "Type parameter has an upper bound '" + result.getTypeRenderer().render(upperBound) + "'" + explanation = "Type parameter has an upper bound '" + result.getTypeRenderer().render(upperBound) + "'" +
" that cannot be satisfied capturing 'in' projection" " that cannot be satisfied capturing 'in' projection"
@@ -62,7 +62,8 @@ import java.util.*;
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*; import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*;
import static org.jetbrains.kotlin.diagnostics.Errors.*; import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.lexer.KtTokens.*; import static org.jetbrains.kotlin.lexer.KtTokens.*;
import static org.jetbrains.kotlin.resolve.BindingContext.*; import static org.jetbrains.kotlin.resolve.BindingContext.CONSTRUCTOR;
import static org.jetbrains.kotlin.resolve.BindingContext.PACKAGE_TO_FILES;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveModalityFromModifiers; import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveModalityFromModifiers;
import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveVisibilityFromModifiers; import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
@@ -539,7 +540,7 @@ public class DescriptorResolver {
@NotNull TypeParameterDescriptor parameter, @NotNull TypeParameterDescriptor parameter,
@NotNull KtTypeParameter typeParameter @NotNull KtTypeParameter typeParameter
) { ) {
if (KotlinBuiltIns.isNothing(parameter.getUpperBoundsAsType())) { if (KotlinBuiltIns.isNothing(TypeIntersector.getUpperBoundsAsType(parameter))) {
trace.report(CONFLICTING_UPPER_BOUNDS.on(typeParameter, parameter)); trace.report(CONFLICTING_UPPER_BOUNDS.on(typeParameter, parameter));
} }
} }
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE
import org.jetbrains.kotlin.resolve.scopes.KtScope import org.jetbrains.kotlin.resolve.scopes.KtScope
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeIntersector
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.oneMoreSpecificThanAnother import org.jetbrains.kotlin.types.oneMoreSpecificThanAnother
@@ -74,7 +75,7 @@ object OverloadUtil {
val classifier = constructor.declarationDescriptor val classifier = constructor.declarationDescriptor
return when (classifier) { return when (classifier) {
is ClassDescriptor -> this is ClassDescriptor -> this
is TypeParameterDescriptor -> classifier.upperBoundsAsType is TypeParameterDescriptor -> TypeIntersector.getUpperBoundsAsType(classifier)
else -> error("Unknown type constructor: $this") else -> error("Unknown type constructor: $this")
} }
} }
@@ -40,9 +40,7 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.Variance.INVARIANT import org.jetbrains.kotlin.types.Variance.*
import org.jetbrains.kotlin.types.Variance.IN_VARIANCE
import org.jetbrains.kotlin.types.Variance.OUT_VARIANCE
public class TypeResolver( public class TypeResolver(
private val annotationResolver: AnnotationResolver, private val annotationResolver: AnnotationResolver,
@@ -323,12 +321,10 @@ public class TypeResolver(
} }
private fun getScopeForTypeParameter(c: TypeResolutionContext, typeParameterDescriptor: TypeParameterDescriptor): KtScope { private fun getScopeForTypeParameter(c: TypeResolutionContext, typeParameterDescriptor: TypeParameterDescriptor): KtScope {
if (c.checkBounds) { return when {
return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope() c.checkBounds -> TypeIntersector.getUpperBoundsAsType(typeParameterDescriptor).memberScope
} else -> LazyScopeAdapter(LockBasedStorageManager.NO_LOCKS.createLazyValue {
else { TypeIntersector.getUpperBoundsAsType(typeParameterDescriptor).memberScope
return LazyScopeAdapter(LockBasedStorageManager.NO_LOCKS.createLazyValue {
typeParameterDescriptor.getUpperBoundsAsType().getMemberScope()
}) })
} }
} }
@@ -88,9 +88,9 @@ public fun CallableDescriptor.hasInferredReturnType(constraintSystem: Constraint
public fun getErasedReceiverType(receiverParameterDescriptor: ReceiverParameterDescriptor, descriptor: CallableDescriptor): KotlinType { public fun getErasedReceiverType(receiverParameterDescriptor: ReceiverParameterDescriptor, descriptor: CallableDescriptor): KotlinType {
var receiverType = receiverParameterDescriptor.getType() var receiverType = receiverParameterDescriptor.getType()
for (typeParameter in descriptor.getTypeParameters()) { for (typeParameter in descriptor.typeParameters) {
if (typeParameter.getTypeConstructor() == receiverType.getConstructor()) { if (typeParameter.typeConstructor == receiverType.constructor) {
receiverType = typeParameter.getUpperBoundsAsType() receiverType = TypeIntersector.getUpperBoundsAsType(typeParameter)
} }
} }
val fakeTypeArguments = ContainerUtil.newSmartList<TypeProjection>() val fakeTypeArguments = ContainerUtil.newSmartList<TypeProjection>()
@@ -77,7 +77,7 @@ public class ConstraintsUtil {
return type; return type;
} }
//todo may be error type //todo may be error type
return typeParameter.getUpperBoundsAsType(); return TypeIntersector.getUpperBoundsAsType(typeParameter);
} }
public static boolean checkUpperBoundIsSatisfied( public static boolean checkUpperBoundIsSatisfied(
@@ -119,7 +119,6 @@ public class LazyTypeParameterDescriptor extends AbstractLazyTypeParameterDescri
getOriginal(); getOriginal();
ForceResolveUtil.forceResolveAllContents(getTypeConstructor()); ForceResolveUtil.forceResolveAllContents(getTypeConstructor());
ForceResolveUtil.forceResolveAllContents(getUpperBounds()); ForceResolveUtil.forceResolveAllContents(getUpperBounds());
getUpperBoundsAsType();
getVariance(); getVariance();
} }
} }
@@ -60,7 +60,7 @@ public class BoundsSubstitutor {
// todo assert: no loops // todo assert: no loops
for (TypeParameterDescriptor descriptor : topologicallySortTypeParameters(typeParameters)) { for (TypeParameterDescriptor descriptor : topologicallySortTypeParameters(typeParameters)) {
KotlinType upperBoundsAsType = descriptor.getUpperBoundsAsType(); KotlinType upperBoundsAsType = TypeIntersector.getUpperBoundsAsType(descriptor);
KotlinType substitutedUpperBoundsAsType = substitutor.substitute(upperBoundsAsType, Variance.INVARIANT); KotlinType substitutedUpperBoundsAsType = substitutor.substitute(upperBoundsAsType, Variance.INVARIANT);
mutableSubstitution.put(descriptor.getTypeConstructor(), new TypeProjectionImpl(substitutedUpperBoundsAsType)); mutableSubstitution.put(descriptor.getTypeConstructor(), new TypeProjectionImpl(substitutedUpperBoundsAsType));
} }
@@ -33,9 +33,6 @@ public interface TypeParameterDescriptor extends ClassifierDescriptor {
@NotNull @NotNull
List<KotlinType> getUpperBounds(); List<KotlinType> getUpperBounds();
@NotNull
KotlinType getUpperBoundsAsType();
@NotNull @NotNull
List<KotlinType> getLowerBounds(); List<KotlinType> getLowerBounds();
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.resolve.scopes.LazyScopeAdapter;
import org.jetbrains.kotlin.storage.NotNullLazyValue; import org.jetbrains.kotlin.storage.NotNullLazyValue;
import org.jetbrains.kotlin.storage.StorageManager; import org.jetbrains.kotlin.storage.StorageManager;
import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -50,7 +49,6 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip
private final NotNullLazyValue<TypeConstructor> typeConstructor; private final NotNullLazyValue<TypeConstructor> typeConstructor;
private final NotNullLazyValue<KotlinType> defaultType; private final NotNullLazyValue<KotlinType> defaultType;
private final NotNullLazyValue<List<KotlinType>> upperBounds; private final NotNullLazyValue<List<KotlinType>> upperBounds;
private final NotNullLazyValue<KotlinType> upperBoundsAsType;
protected AbstractTypeParameterDescriptor( protected AbstractTypeParameterDescriptor(
@NotNull final StorageManager storageManager, @NotNull final StorageManager storageManager,
@@ -104,12 +102,6 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip
return resolveUpperBounds(); return resolveUpperBounds();
} }
}, FALLBACK_UPPER_BOUNDS_ON_RECURSION); }, FALLBACK_UPPER_BOUNDS_ON_RECURSION);
this.upperBoundsAsType = storageManager.createLazyValue(new Function0<KotlinType>() {
@Override
public KotlinType invoke() {
return computeUpperBoundsAsType();
}
});
} }
@NotNull @NotNull
@@ -140,20 +132,6 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip
return upperBounds.invoke(); return upperBounds.invoke();
} }
@NotNull
@Override
public KotlinType getUpperBoundsAsType() {
return upperBoundsAsType.invoke();
}
@NotNull
private KotlinType computeUpperBoundsAsType() {
List<KotlinType> upperBounds = getUpperBounds();
assert !upperBounds.isEmpty() : "Upper bound list is empty in " + getName();
KotlinType upperBoundsAsType = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, upperBounds);
return upperBoundsAsType != null ? upperBoundsAsType : getBuiltIns(this).getNothingType();
}
@NotNull @NotNull
@Override @Override
public TypeConstructor getTypeConstructor() { public TypeConstructor getTypeConstructor() {
@@ -34,6 +34,7 @@ import java.util.*;
import static org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImplKt.registerTypeVariables; import static org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImplKt.registerTypeVariables;
import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.SPECIAL; import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.SPECIAL;
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns;
public class TypeIntersector { public class TypeIntersector {
@@ -139,7 +140,20 @@ public class TypeIntersector {
); );
} }
// TODO : check intersectibility, don't use a chanied scope /**
* Note: this method was used in overload and override bindings to approximate type parameters with several bounds,
* but as it turned out at some point, that logic was inconsistent with Java rules, so it was simplified.
* Most of the other usages of this method are left untouched but probably should be investigated closely if they're still valid.
*/
@NotNull
public static KotlinType getUpperBoundsAsType(@NotNull TypeParameterDescriptor descriptor) {
List<KotlinType> upperBounds = descriptor.getUpperBounds();
assert !upperBounds.isEmpty() : "Upper bound list is empty: " + descriptor;
KotlinType upperBoundsAsType = intersectTypes(KotlinTypeChecker.DEFAULT, upperBounds);
return upperBoundsAsType != null ? upperBoundsAsType : getBuiltIns(descriptor).getNothingType();
}
// TODO: check intersectability, don't use a chained scope
private static class IntersectionScope extends ChainedScope { private static class IntersectionScope extends ChainedScope {
public IntersectionScope(@NotNull TypeConstructor constructor, @NotNull KtScope[] scopes) { public IntersectionScope(@NotNull TypeConstructor constructor, @NotNull KtScope[] scopes) {
super(null, "member scope for intersection type " + constructor, scopes); super(null, "member scope for intersection type " + constructor, scopes);
@@ -47,7 +47,7 @@ fun FuzzyType.isAlmostEverything(): Boolean {
if (freeParameters.isEmpty()) return false if (freeParameters.isEmpty()) return false
val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false
if (typeParameter !in freeParameters) return false if (typeParameter !in freeParameters) return false
return typeParameter.upperBoundsAsType.isAnyOrNullableAny() return typeParameter.upperBounds.singleOrNull()?.isAnyOrNullableAny() ?: false
} }
class FuzzyType( class FuzzyType(
@@ -21,17 +21,14 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.refactoring.memberInfo.getClassDescriptorIfAny import org.jetbrains.kotlin.idea.refactoring.memberInfo.getClassDescriptorIfAny
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitution import org.jetbrains.kotlin.types.substitutions.getTypeSubstitution
import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.keysToMap
import java.util.* import java.util.*
@@ -60,7 +57,7 @@ class KotlinPullUpData(val sourceClass: KtClassOrObject,
val substitution = LinkedHashMap<TypeConstructor, TypeProjection>() val substitution = LinkedHashMap<TypeConstructor, TypeProjection>()
typeParametersInSourceClassContext.forEach { typeParametersInSourceClassContext.forEach {
substitution[it.typeConstructor] = TypeProjectionImpl(it.upperBoundsAsType) substitution[it.typeConstructor] = TypeProjectionImpl(TypeIntersector.getUpperBoundsAsType(it))
} }
val superClassSubstitution = getTypeSubstitution(targetClassDescriptor.defaultType, sourceClassDescriptor.defaultType) val superClassSubstitution = getTypeSubstitution(targetClassDescriptor.defaultType, sourceClassDescriptor.defaultType)
@@ -77,4 +74,4 @@ class KotlinPullUpData(val sourceClass: KtClassOrObject,
} }
val isInterfaceTarget: Boolean = targetClassDescriptor.kind == ClassKind.INTERFACE val isInterfaceTarget: Boolean = targetClassDescriptor.kind == ClassKind.INTERFACE
} }