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.resolve.jvm.JavaDescriptorResolverKt;
import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeSubstitutor;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.Variance;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
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.UPPER_BOUND;
@@ -140,13 +139,16 @@ public class AlternativeMethodSignatureData extends ElementAlternativeSignatureD
for (TypeParameterDescriptor parameter : methodTypeParameters) {
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;
if (!TypeUtils.equalTypes(substituted, altTypeParameters.get(index).getUpperBoundsAsType())) {
KotlinType altUpperBoundsAsType = TypeIntersector.getUpperBoundsAsType(altTypeParameters.get(index));
if (!TypeUtils.equalTypes(substituted, altUpperBoundsAsType)) {
throw new AlternativeSignatureMismatchException(
"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;
if (typeConstructorClassifier instanceof TypeParameterDescriptor) {
memberScope = ((TypeParameterDescriptor) typeConstructorClassifier).getUpperBoundsAsType().getMemberScope();
memberScope = typeConstructorClassifier.getDefaultType().getMemberScope();
}
else if (typeConstructorClassifier instanceof ClassDescriptor) {
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.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeIntersector
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
@@ -324,7 +325,7 @@ public object Renderers {
}
val explanation: String
val upperBound = typeParameterWithCapturedConstraint.getUpperBoundsAsType()
val upperBound = TypeIntersector.getUpperBoundsAsType(typeParameterWithCapturedConstraint)
if (!KotlinBuiltIns.isNullableAny(upperBound) && capturedTypeConstructor.typeProjection.getProjectionKind() == Variance.IN_VARIANCE) {
explanation = "Type parameter has an upper bound '" + result.getTypeRenderer().render(upperBound) + "'" +
" 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.diagnostics.Errors.*;
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.ModifiersChecker.resolveModalityFromModifiers;
import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
@@ -539,7 +540,7 @@ public class DescriptorResolver {
@NotNull TypeParameterDescriptor parameter,
@NotNull KtTypeParameter typeParameter
) {
if (KotlinBuiltIns.isNothing(parameter.getUpperBoundsAsType())) {
if (KotlinBuiltIns.isNothing(TypeIntersector.getUpperBoundsAsType(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.scopes.KtScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeIntersector
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.oneMoreSpecificThanAnother
@@ -74,7 +75,7 @@ object OverloadUtil {
val classifier = constructor.declarationDescriptor
return when (classifier) {
is ClassDescriptor -> this
is TypeParameterDescriptor -> classifier.upperBoundsAsType
is TypeParameterDescriptor -> TypeIntersector.getUpperBoundsAsType(classifier)
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.StorageManager
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.Variance.INVARIANT
import org.jetbrains.kotlin.types.Variance.IN_VARIANCE
import org.jetbrains.kotlin.types.Variance.OUT_VARIANCE
import org.jetbrains.kotlin.types.Variance.*
public class TypeResolver(
private val annotationResolver: AnnotationResolver,
@@ -323,12 +321,10 @@ public class TypeResolver(
}
private fun getScopeForTypeParameter(c: TypeResolutionContext, typeParameterDescriptor: TypeParameterDescriptor): KtScope {
if (c.checkBounds) {
return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope()
}
else {
return LazyScopeAdapter(LockBasedStorageManager.NO_LOCKS.createLazyValue {
typeParameterDescriptor.getUpperBoundsAsType().getMemberScope()
return when {
c.checkBounds -> TypeIntersector.getUpperBoundsAsType(typeParameterDescriptor).memberScope
else -> LazyScopeAdapter(LockBasedStorageManager.NO_LOCKS.createLazyValue {
TypeIntersector.getUpperBoundsAsType(typeParameterDescriptor).memberScope
})
}
}
@@ -88,9 +88,9 @@ public fun CallableDescriptor.hasInferredReturnType(constraintSystem: Constraint
public fun getErasedReceiverType(receiverParameterDescriptor: ReceiverParameterDescriptor, descriptor: CallableDescriptor): KotlinType {
var receiverType = receiverParameterDescriptor.getType()
for (typeParameter in descriptor.getTypeParameters()) {
if (typeParameter.getTypeConstructor() == receiverType.getConstructor()) {
receiverType = typeParameter.getUpperBoundsAsType()
for (typeParameter in descriptor.typeParameters) {
if (typeParameter.typeConstructor == receiverType.constructor) {
receiverType = TypeIntersector.getUpperBoundsAsType(typeParameter)
}
}
val fakeTypeArguments = ContainerUtil.newSmartList<TypeProjection>()
@@ -77,7 +77,7 @@ public class ConstraintsUtil {
return type;
}
//todo may be error type
return typeParameter.getUpperBoundsAsType();
return TypeIntersector.getUpperBoundsAsType(typeParameter);
}
public static boolean checkUpperBoundIsSatisfied(
@@ -119,7 +119,6 @@ public class LazyTypeParameterDescriptor extends AbstractLazyTypeParameterDescri
getOriginal();
ForceResolveUtil.forceResolveAllContents(getTypeConstructor());
ForceResolveUtil.forceResolveAllContents(getUpperBounds());
getUpperBoundsAsType();
getVariance();
}
}
@@ -60,7 +60,7 @@ public class BoundsSubstitutor {
// todo assert: no loops
for (TypeParameterDescriptor descriptor : topologicallySortTypeParameters(typeParameters)) {
KotlinType upperBoundsAsType = descriptor.getUpperBoundsAsType();
KotlinType upperBoundsAsType = TypeIntersector.getUpperBoundsAsType(descriptor);
KotlinType substitutedUpperBoundsAsType = substitutor.substitute(upperBoundsAsType, Variance.INVARIANT);
mutableSubstitution.put(descriptor.getTypeConstructor(), new TypeProjectionImpl(substitutedUpperBoundsAsType));
}
@@ -33,9 +33,6 @@ public interface TypeParameterDescriptor extends ClassifierDescriptor {
@NotNull
List<KotlinType> getUpperBounds();
@NotNull
KotlinType getUpperBoundsAsType();
@NotNull
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.StorageManager;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import java.util.ArrayList;
import java.util.Collections;
@@ -50,7 +49,6 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip
private final NotNullLazyValue<TypeConstructor> typeConstructor;
private final NotNullLazyValue<KotlinType> defaultType;
private final NotNullLazyValue<List<KotlinType>> upperBounds;
private final NotNullLazyValue<KotlinType> upperBoundsAsType;
protected AbstractTypeParameterDescriptor(
@NotNull final StorageManager storageManager,
@@ -104,12 +102,6 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip
return resolveUpperBounds();
}
}, FALLBACK_UPPER_BOUNDS_ON_RECURSION);
this.upperBoundsAsType = storageManager.createLazyValue(new Function0<KotlinType>() {
@Override
public KotlinType invoke() {
return computeUpperBoundsAsType();
}
});
}
@NotNull
@@ -140,20 +132,6 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip
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
@Override
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.constraintPosition.ConstraintPositionKind.SPECIAL;
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns;
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 {
public IntersectionScope(@NotNull TypeConstructor constructor, @NotNull KtScope[] scopes) {
super(null, "member scope for intersection type " + constructor, scopes);
@@ -47,7 +47,7 @@ fun FuzzyType.isAlmostEverything(): Boolean {
if (freeParameters.isEmpty()) return false
val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false
if (typeParameter !in freeParameters) return false
return typeParameter.upperBoundsAsType.isAnyOrNullableAny()
return typeParameter.upperBounds.singleOrNull()?.isAnyOrNullableAny() ?: false
}
class FuzzyType(
@@ -21,17 +21,14 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
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.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitution
import org.jetbrains.kotlin.utils.keysToMap
import java.util.*
@@ -60,7 +57,7 @@ class KotlinPullUpData(val sourceClass: KtClassOrObject,
val substitution = LinkedHashMap<TypeConstructor, TypeProjection>()
typeParametersInSourceClassContext.forEach {
substitution[it.typeConstructor] = TypeProjectionImpl(it.upperBoundsAsType)
substitution[it.typeConstructor] = TypeProjectionImpl(TypeIntersector.getUpperBoundsAsType(it))
}
val superClassSubstitution = getTypeSubstitution(targetClassDescriptor.defaultType, sourceClassDescriptor.defaultType)
@@ -77,4 +74,4 @@ class KotlinPullUpData(val sourceClass: KtClassOrObject,
}
val isInterfaceTarget: Boolean = targetClassDescriptor.kind == ClassKind.INTERFACE
}
}