KT-14498: Properly check variance in expanded types.
This commit is contained in:
@@ -118,6 +118,8 @@ public interface Errors {
|
||||
DiagnosticFactory1<KtTypeProjection, ClassifierDescriptor> REDUNDANT_PROJECTION = DiagnosticFactory1.create(WARNING, VARIANCE_IN_PROJECTION);
|
||||
DiagnosticFactory1<PsiElement, VarianceConflictDiagnosticData> TYPE_VARIANCE_CONFLICT =
|
||||
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory1<PsiElement, VarianceConflictDiagnosticData> TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE =
|
||||
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
DiagnosticFactory0<PsiElement> FINITE_BOUNDS_VIOLATION = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> FINITE_BOUNDS_VIOLATION_IN_JAVA = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> EXPANSIVE_INHERITANCE = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
+18
-14
@@ -546,21 +546,25 @@ public class DefaultErrorMessages {
|
||||
|
||||
MAP.put(MISPLACED_TYPE_PARAMETER_CONSTRAINTS, "If a type parameter has multiple constraints, they all need to be placed in the 'where' clause");
|
||||
|
||||
MultiRenderer<VarianceConflictDiagnosticData> varianceConflictDataRenderer = new MultiRenderer<VarianceConflictDiagnosticData>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public String[] render(@NotNull VarianceConflictDiagnosticData data) {
|
||||
RenderingContext context =
|
||||
of(data.getTypeParameter(), data.getTypeParameter().getVariance(), data.getOccurrencePosition(),
|
||||
data.getContainingType());
|
||||
return new String[] {
|
||||
NAME.render(data.getTypeParameter(), context),
|
||||
RENDER_POSITION_VARIANCE.render(data.getTypeParameter().getVariance(), context),
|
||||
RENDER_POSITION_VARIANCE.render(data.getOccurrencePosition(), context),
|
||||
RENDER_TYPE.render(data.getContainingType(), context)
|
||||
};
|
||||
}
|
||||
};
|
||||
MAP.put(TYPE_VARIANCE_CONFLICT, "Type parameter {0} is declared as ''{1}'' but occurs in ''{2}'' position in type {3}",
|
||||
new MultiRenderer<VarianceConflictDiagnosticData>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public String[] render(@NotNull VarianceConflictDiagnosticData data) {
|
||||
RenderingContext context =
|
||||
of(data.getTypeParameter(), data.getTypeParameter().getVariance(), data.getOccurrencePosition(), data.getContainingType());
|
||||
return new String[] {
|
||||
NAME.render(data.getTypeParameter(), context),
|
||||
RENDER_POSITION_VARIANCE.render(data.getTypeParameter().getVariance(), context),
|
||||
RENDER_POSITION_VARIANCE.render(data.getOccurrencePosition(), context),
|
||||
RENDER_TYPE.render(data.getContainingType(), context)
|
||||
};
|
||||
}
|
||||
});
|
||||
varianceConflictDataRenderer);
|
||||
MAP.put(TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE, "Type parameter {0} is declared as ''{1}'' but occurs in ''{2}'' position in abbreviated type {3}",
|
||||
varianceConflictDataRenderer);
|
||||
|
||||
MAP.put(FINITE_BOUNDS_VIOLATION, "This type parameter violates the Finite Bound Restriction");
|
||||
MAP.put(FINITE_BOUNDS_VIOLATION_IN_JAVA, "Violation of Finite Bound Restriction for {0}", STRING);
|
||||
|
||||
@@ -18,9 +18,7 @@ package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
@@ -28,20 +28,27 @@ import org.jetbrains.kotlin.types.*
|
||||
|
||||
interface TypeBinding<out P : PsiElement> : TypeHolder<TypeBinding<P>> {
|
||||
val psiElement: P
|
||||
val isInAbbreviation: Boolean
|
||||
override val arguments: List<TypeArgumentBinding<P>?>
|
||||
}
|
||||
|
||||
interface TypeArgumentBinding<out P: PsiElement> : TypeHolderArgument<TypeBinding<P>>
|
||||
|
||||
fun KtTypeReference.createTypeBinding(trace: BindingContext): TypeBinding<KtTypeElement>? {
|
||||
val jetType = trace[BindingContext.TYPE, this]
|
||||
val type = trace[BindingContext.TYPE, this]
|
||||
val psiElement = typeElement
|
||||
if (jetType == null || psiElement == null) {
|
||||
return null
|
||||
}
|
||||
else {
|
||||
return ExplicitTypeBinding(trace, psiElement, jetType)
|
||||
}
|
||||
return if (type == null || psiElement == null)
|
||||
null
|
||||
else
|
||||
createTypeBindingFromPsi(trace, psiElement, type)
|
||||
}
|
||||
|
||||
private fun createTypeBindingFromPsi(trace: BindingContext, psiElement: KtTypeElement, type: KotlinType): TypeBinding<KtTypeElement> {
|
||||
val abbreviatedType = type.getAbbreviatedType()
|
||||
return if (abbreviatedType != null)
|
||||
AbbreviatedTypeBinding(type, psiElement)
|
||||
else
|
||||
ExplicitTypeBinding(trace, psiElement, type)
|
||||
}
|
||||
|
||||
fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext): TypeBinding<PsiElement>? {
|
||||
@@ -65,30 +72,30 @@ private class ExplicitTypeBinding(
|
||||
override val psiElement: KtTypeElement,
|
||||
override val type: KotlinType
|
||||
) : TypeBinding<KtTypeElement> {
|
||||
override val isInAbbreviation: Boolean get() = false
|
||||
|
||||
override val arguments: List<TypeArgumentBinding<KtTypeElement>?>
|
||||
get() {
|
||||
val psiTypeArguments = psiElement.typeArgumentsAsTypes
|
||||
assert(type.getAbbreviatedType() == null) { "Non-abbreviated type expected: $type" }
|
||||
val isErrorBinding = run {
|
||||
val sizeIsEqual = psiTypeArguments.size == type.arguments.size
|
||||
&& psiTypeArguments.size == type.constructor.parameters.size
|
||||
type.isError || !sizeIsEqual
|
||||
}
|
||||
|
||||
return psiTypeArguments.indices.map { index: Int ->
|
||||
// todo fix for List<*>
|
||||
val jetTypeReference = psiTypeArguments[index]
|
||||
val jetTypeElement = jetTypeReference?.typeElement
|
||||
if (jetTypeElement == null) return@map null
|
||||
return psiTypeArguments.indices.map { index: Int ->
|
||||
// todo fix for List<*>
|
||||
val jetTypeReference = psiTypeArguments[index]
|
||||
val jetTypeElement = jetTypeReference?.typeElement ?: return@map null
|
||||
|
||||
if (isErrorBinding) {
|
||||
val nextJetType = trace[BindingContext.TYPE, jetTypeReference]
|
||||
if (nextJetType == null) return@map null
|
||||
if (isErrorBinding) {
|
||||
val nextJetType = trace[BindingContext.TYPE, jetTypeReference] ?: return@map null
|
||||
|
||||
return@map TypeArgumentBindingImpl(
|
||||
TypeProjectionImpl(nextJetType),
|
||||
null,
|
||||
ExplicitTypeBinding(trace, jetTypeElement, nextJetType)
|
||||
createTypeBindingFromPsi(trace, jetTypeElement, nextJetType)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,17 +103,34 @@ private class ExplicitTypeBinding(
|
||||
return@map TypeArgumentBindingImpl(
|
||||
typeProjection,
|
||||
type.constructor.parameters[index],
|
||||
ExplicitTypeBinding(trace, jetTypeElement, typeProjection.type)
|
||||
createTypeBindingFromPsi(trace, jetTypeElement, typeProjection.type)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AbbreviatedTypeBinding(
|
||||
override val type: KotlinType,
|
||||
override val psiElement: KtTypeElement
|
||||
): TypeBinding<KtTypeElement> {
|
||||
override val isInAbbreviation: Boolean get() = true
|
||||
|
||||
override val arguments: List<TypeArgumentBinding<KtTypeElement>?>
|
||||
get() = type.arguments.mapIndexed { index, argument ->
|
||||
TypeArgumentBindingImpl(
|
||||
argument,
|
||||
type.constructor.parameters[index],
|
||||
AbbreviatedTypeBinding(argument.type, psiElement)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class NoTypeElementBinding<out P : PsiElement>(
|
||||
private val trace: BindingContext,
|
||||
override val psiElement: P,
|
||||
override val type: KotlinType
|
||||
): TypeBinding<P> {
|
||||
override val isInAbbreviation: Boolean get() = false
|
||||
|
||||
override val arguments: List<TypeArgumentBinding<P>?>
|
||||
get() {
|
||||
|
||||
@@ -16,30 +16,23 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure.EnrichedProjectionKind.*
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure.*
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.resolve.typeBinding.TypeBinding
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyAccessorDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.resolve.typeBinding.TypeBinding
|
||||
import org.jetbrains.kotlin.resolve.typeBinding.createTypeBinding
|
||||
import org.jetbrains.kotlin.resolve.typeBinding.createTypeBindingForReturnType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.Variance.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyAccessorDescriptorImpl
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checkTypePosition
|
||||
import org.jetbrains.kotlin.types.getAbbreviatedType
|
||||
|
||||
class ManualVariance(val descriptor: TypeParameterDescriptor, val variance: Variance)
|
||||
|
||||
@@ -167,12 +160,9 @@ class VarianceCheckerCore(
|
||||
checkTypePosition(
|
||||
position,
|
||||
{ typeParameterDescriptor, typeBinding, errorPosition ->
|
||||
diagnosticSink.report(
|
||||
Errors.TYPE_VARIANCE_CONFLICT.on(
|
||||
typeBinding.psiElement,
|
||||
VarianceConflictDiagnosticData(containingType, typeParameterDescriptor, errorPosition)
|
||||
)
|
||||
)
|
||||
val varianceConflictDiagnosticData = VarianceConflictDiagnosticData(containingType, typeParameterDescriptor, errorPosition)
|
||||
val diagnostic = if (typeBinding.isInAbbreviation) Errors.TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE else Errors.TYPE_VARIANCE_CONFLICT
|
||||
diagnosticSink.report(diagnostic.on(typeBinding.psiElement, varianceConflictDiagnosticData))
|
||||
},
|
||||
customVariance = { it.varianceWithManual() }
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user