Infer type arguments of type alias constructors.
This commit is contained in:
@@ -38,10 +38,11 @@ import org.jetbrains.kotlin.resolve.calls.inference.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.Bound
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.UPPER_BOUND
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ValidityConstraintForConstituentType
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.getValidityConstraintForConstituentType
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeIntersector
|
||||
@@ -52,6 +53,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.lang.AssertionError
|
||||
import java.util.*
|
||||
|
||||
object Renderers {
|
||||
|
||||
@@ -273,12 +275,20 @@ object Renderers {
|
||||
val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull {
|
||||
!ConstraintsUtil.checkUpperBoundIsSatisfied(systemWithoutWeakConstraints, it, inferenceErrorData.call, true)
|
||||
}
|
||||
if (typeParameterDescriptor == null && status.hasConflictingConstraints()) {
|
||||
return renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
|
||||
}
|
||||
|
||||
if (typeParameterDescriptor == null) {
|
||||
LOG.error(debugMessage("There is no type parameter with violated upper bound for 'upper bound violated' error", inferenceErrorData))
|
||||
return result
|
||||
if (inferenceErrorData.descriptor is TypeAliasConstructorDescriptor) {
|
||||
renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(inferenceErrorData, result, systemWithoutWeakConstraints)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
return if (status.hasConflictingConstraints())
|
||||
renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
|
||||
else {
|
||||
LOG.error(debugMessage("There is no type parameter with violated upper bound for 'upper bound violated' error", inferenceErrorData))
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor)
|
||||
@@ -322,6 +332,42 @@ object Renderers {
|
||||
return result
|
||||
}
|
||||
|
||||
private fun renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
|
||||
inferenceErrorData: InferenceErrorData,
|
||||
result: TabledDescriptorRenderer,
|
||||
systemWithoutWeakConstraints: ConstraintSystem
|
||||
): TabledDescriptorRenderer? {
|
||||
val descriptor = inferenceErrorData.descriptor
|
||||
if (descriptor !is TypeAliasConstructorDescriptor) {
|
||||
LOG.error("Type alias constructor descriptor expected: $descriptor")
|
||||
return result
|
||||
}
|
||||
|
||||
val inferredTypeSubstitutor = systemWithoutWeakConstraints.resultingSubstitutor
|
||||
|
||||
for (constraintError in inferenceErrorData.constraintSystem.status.constraintErrors) {
|
||||
val constraintInfo = constraintError.constraintPosition.getValidityConstraintForConstituentType() ?: continue
|
||||
if (constraintInfo.typeParameter.variance == Variance.IN_VARIANCE) continue
|
||||
|
||||
val violatedUpperBound = inferredTypeSubstitutor.safeSubstitute(constraintInfo.bound, Variance.INVARIANT)
|
||||
val violatingInferredType = inferredTypeSubstitutor.safeSubstitute(constraintInfo.typeArgument, Variance.INVARIANT)
|
||||
|
||||
val context = RenderingContext.of(violatingInferredType, violatedUpperBound)
|
||||
val typeRenderer = result.typeRenderer
|
||||
|
||||
result.text(newText().normal("Type parameter bound for ").strong(constraintInfo.typeParameter.name)
|
||||
.normal(" in type inferred from type alias expansion for "))
|
||||
.table(newTable().descriptor(inferenceErrorData.descriptor))
|
||||
|
||||
result.text(newText().normal(" is not satisfied: inferred type ").error(typeRenderer.render(violatingInferredType, context))
|
||||
.normal(" is not a subtype of ").strong(typeRenderer.render(violatedUpperBound, context)))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic fun renderCannotCaptureTypeParameterError(
|
||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||
): TabledDescriptorRenderer {
|
||||
|
||||
@@ -115,7 +115,7 @@ class CandidateResolver(
|
||||
if (candidateCall.knownTypeParametersSubstitutor != null) {
|
||||
candidateCall.setResultingSubstitutor(candidateCall.knownTypeParametersSubstitutor!!)
|
||||
}
|
||||
else if (ktTypeArguments.isNotEmpty() || candidateDescriptor is TypeAliasConstructorDescriptor) {
|
||||
else if (ktTypeArguments.isNotEmpty()) {
|
||||
// Explicit type arguments passed
|
||||
|
||||
val typeArguments = ArrayList<KotlinType>()
|
||||
|
||||
+37
-3
@@ -18,9 +18,8 @@ package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.*
|
||||
@@ -34,8 +33,10 @@ import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionResultsCache
|
||||
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ValidityConstraintForConstituentType
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.TYPE_BOUND_POSITION
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
|
||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSafeReceiver
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
@@ -74,6 +75,11 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
||||
}
|
||||
}
|
||||
|
||||
if (candidate is TypeAliasConstructorDescriptor) {
|
||||
val substitutedReturnType = builder.compositeSubstitutor().safeSubstitute(candidate.returnType, Variance.INVARIANT)
|
||||
addValidityConstraintsForConstituentTypes(builder, substitutedReturnType)
|
||||
}
|
||||
|
||||
// Receiver
|
||||
// Error is already reported if something is missing
|
||||
val receiverArgument = candidateCall.extensionReceiver
|
||||
@@ -105,6 +111,34 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
||||
return OTHER_ERROR
|
||||
}
|
||||
|
||||
private fun addValidityConstraintsForConstituentTypes(builder: ConstraintSystem.Builder, type: KotlinType) {
|
||||
val typeConstructor = type.constructor
|
||||
if (typeConstructor.declarationDescriptor is TypeParameterDescriptor) return
|
||||
|
||||
val boundsSubstitutor = TypeSubstitutor.create(type)
|
||||
|
||||
type.arguments.forEachIndexed forEachArgument@{ i, typeProjection ->
|
||||
if (typeProjection.isStarProjection) return@forEachArgument // continue
|
||||
|
||||
val typeParameter = typeConstructor.parameters[i]
|
||||
addValidityConstraintsForTypeArgument(builder, typeProjection, typeParameter, boundsSubstitutor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addValidityConstraintsForTypeArgument(
|
||||
builder: ConstraintSystem.Builder,
|
||||
typeProjection: TypeProjection,
|
||||
typeParameter: TypeParameterDescriptor,
|
||||
boundsSubstitutor: TypeSubstitutor
|
||||
) {
|
||||
val typeArgument = typeProjection.type
|
||||
for (upperBound in typeParameter.upperBounds) {
|
||||
val substitutedUpperBound = boundsSubstitutor.safeSubstitute(upperBound, Variance.INVARIANT)
|
||||
val constraintPosition = ValidityConstraintForConstituentType(typeArgument, typeParameter, substitutedUpperBound)
|
||||
builder.addSubtypeConstraint(typeArgument, substitutedUpperBound, constraintPosition)
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a substitutor which maps types to their representation in the constraint system.
|
||||
// In case when some type parameter descriptor is represented by more than one variable in the system, the behavior is undefined.
|
||||
private fun ConstraintSystem.Builder.compositeSubstitutor(): TypeSubstitutor {
|
||||
|
||||
+21
-1
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.inference.constraintPosition
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
enum class ConstraintPositionKind {
|
||||
RECEIVER_POSITION,
|
||||
@@ -71,4 +73,22 @@ class CompoundConstraintPosition(vararg positions: ConstraintPosition) : Constra
|
||||
|
||||
fun ConstraintPosition.derivedFrom(kind: ConstraintPositionKind): Boolean {
|
||||
return if (this !is CompoundConstraintPosition) this.kind == kind else positions.any { it.kind == kind }
|
||||
}
|
||||
}
|
||||
|
||||
class ValidityConstraintForConstituentType(
|
||||
val typeArgument: KotlinType,
|
||||
val typeParameter: TypeParameterDescriptor,
|
||||
val bound: KotlinType
|
||||
) : ConstraintPosition {
|
||||
override val kind: ConstraintPositionKind get() = TYPE_BOUND_POSITION
|
||||
}
|
||||
|
||||
fun ConstraintPosition.getValidityConstraintForConstituentType(): ValidityConstraintForConstituentType? =
|
||||
when (this) {
|
||||
is ValidityConstraintForConstituentType ->
|
||||
this
|
||||
is CompoundConstraintPosition ->
|
||||
positions.asSequence().map { it.getValidityConstraintForConstituentType() }.firstOrNull { it != null }
|
||||
else ->
|
||||
null
|
||||
}
|
||||
Reference in New Issue
Block a user