Inference for type alias constructor type arguments: better error reporting.
This commit is contained in:
@@ -40,14 +40,11 @@ import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_B
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.UPPER_BOUND
|
||||
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.derivedFrom
|
||||
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
|
||||
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.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.io.PrintWriter
|
||||
@@ -270,14 +267,16 @@ object Renderers {
|
||||
LOG.assertTrue(status.hasViolatedUpperBound(),
|
||||
debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData))
|
||||
|
||||
val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(ConstraintPositionKind.TYPE_BOUND_POSITION)
|
||||
val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(TYPE_BOUND_POSITION)
|
||||
val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull {
|
||||
!ConstraintsUtil.checkUpperBoundIsSatisfied(systemWithoutWeakConstraints, it, inferenceErrorData.call, true)
|
||||
}
|
||||
|
||||
if (typeParameterDescriptor == null) {
|
||||
if (inferenceErrorData.descriptor is TypeAliasConstructorDescriptor) {
|
||||
renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(inferenceErrorData, result, systemWithoutWeakConstraints)?.let {
|
||||
renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
|
||||
inferenceErrorData, result, systemWithoutWeakConstraints
|
||||
)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
@@ -342,11 +341,20 @@ object Renderers {
|
||||
return result
|
||||
}
|
||||
|
||||
val inferredTypeSubstitutor = systemWithoutWeakConstraints.resultingSubstitutor
|
||||
val inferredTypesForTypeParameters = descriptor.typeParameters.map {
|
||||
val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), it)
|
||||
systemWithoutWeakConstraints.getTypeBounds(typeVariable).value
|
||||
}
|
||||
val inferredTypeSubstitutor = TypeSubstitutor.create(object : TypeConstructorSubstitution() {
|
||||
override fun get(key: TypeConstructor): TypeProjection? {
|
||||
val typeDescriptor = key.declarationDescriptor as? TypeParameterDescriptor ?: return null
|
||||
if (typeDescriptor.containingDeclaration != descriptor.typeAliasDescriptor) return null
|
||||
return inferredTypesForTypeParameters[typeDescriptor.index]?.let { TypeProjectionImpl(it) }
|
||||
}
|
||||
})
|
||||
|
||||
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)
|
||||
|
||||
+10
-7
@@ -18,7 +18,9 @@ package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
|
||||
@@ -33,11 +35,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.inference.constraintPosition.ValidityConstraintForConstituentType
|
||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSafeReceiver
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE
|
||||
@@ -122,20 +123,22 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
||||
|
||||
val typeParameter = typeConstructor.parameters[i]
|
||||
addValidityConstraintsForTypeArgument(builder, typeProjection, typeParameter, boundsSubstitutor)
|
||||
|
||||
addValidityConstraintsForConstituentTypes(builder, typeProjection.type)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addValidityConstraintsForTypeArgument(
|
||||
builder: ConstraintSystem.Builder,
|
||||
typeProjection: TypeProjection,
|
||||
substitutedArgument: TypeProjection,
|
||||
typeParameter: TypeParameterDescriptor,
|
||||
boundsSubstitutor: TypeSubstitutor
|
||||
) {
|
||||
val typeArgument = typeProjection.type
|
||||
val substitutedType = substitutedArgument.type
|
||||
for (upperBound in typeParameter.upperBounds) {
|
||||
val substitutedUpperBound = boundsSubstitutor.safeSubstitute(upperBound, Variance.INVARIANT)
|
||||
val constraintPosition = ValidityConstraintForConstituentType(typeArgument, typeParameter, substitutedUpperBound)
|
||||
builder.addSubtypeConstraint(typeArgument, substitutedUpperBound, constraintPosition)
|
||||
val constraintPosition = ValidityConstraintForConstituentType(substitutedType, typeParameter, substitutedUpperBound)
|
||||
builder.addSubtypeConstraint(substitutedType, substitutedUpperBound, constraintPosition)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+13
-9
@@ -1,26 +1,30 @@
|
||||
class Num<Tn : Number>(val x: Tn)
|
||||
typealias N<T> = Num<T>
|
||||
|
||||
val test0 = N(1)
|
||||
val test1 = <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED(Type parameter bound for Tn in type inferred from type alias expansion for fun <T> <init>\(x: T\): Num<T>
|
||||
is not satisfied: inferred type String is not a subtype of Number)!>N<!>("1")
|
||||
|
||||
|
||||
class Cons<T>(val head: T, val tail: Cons<T>?)
|
||||
typealias C<T> = Cons<T>
|
||||
typealias CC<T> = C<C<T>>
|
||||
|
||||
val test2 = <!TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR!>C<!>(1, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)
|
||||
val test3 = <!TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR!>CC<!>(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)
|
||||
val test4 = CC(C(1, null), null)
|
||||
|
||||
|
||||
class Pair<X, Y>(val x: X, val y: Y)
|
||||
typealias PL<T> = Pair<T, List<T>>
|
||||
typealias PN<T> = Pair<T, Num<T>>
|
||||
|
||||
val test5 = <!TYPE_INFERENCE_INCORPORATION_ERROR!>PL<!>(1, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
|
||||
class Bound<X, Y : X>(val x: X, val y: Y)
|
||||
typealias B<X, Y> = Bound<X, Y>
|
||||
|
||||
class Foo<T>(val p: Pair<T, T>)
|
||||
typealias F<T> = Foo<T>
|
||||
|
||||
val test0 = N(1)
|
||||
val test1 = <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED!>N<!>("1")
|
||||
val test2 = <!TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR!>C<!>(1, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)
|
||||
val test3 = <!TYPE_INFERENCE_INCORPORATION_ERROR!>PL<!>(1, <!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
val test4 = <!TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR!>CC<!>(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>)
|
||||
val test4a = CC(C(1, null), null)
|
||||
|
||||
fun testProjections1(x: Pair<in Int, out String>) = <!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>F<!>(x)
|
||||
fun testProjections2(x: Pair<in Int, out Number>) = <!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>F<!>(x)
|
||||
fun testProjections3(x: Pair<in Number, out Int>) = <!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>F<!>(x)
|
||||
|
||||
Vendored
+4
-13
@@ -3,23 +3,14 @@ package
|
||||
public val test0: Num<kotlin.Int>
|
||||
public val test1: [ERROR : Type for N("1")]
|
||||
public val test2: Cons<kotlin.Int>
|
||||
public val test3: Pair<kotlin.Int, kotlin.collections.List<kotlin.Int>>
|
||||
public val test4: [ERROR : Type for CC(1, 2)]
|
||||
public val test4a: Cons<Cons<kotlin.Int>>
|
||||
public val test3: [ERROR : Type for CC(1, 2)]
|
||||
public val test4: Cons<Cons<kotlin.Int>>
|
||||
public val test5: Pair<kotlin.Int, kotlin.collections.List<kotlin.Int>>
|
||||
public fun testProjections1(/*0*/ x: Pair<in kotlin.Int, out kotlin.String>): [ERROR : Error function type]
|
||||
public fun testProjections2(/*0*/ x: Pair<in kotlin.Int, out kotlin.Number>): [ERROR : Error function type]
|
||||
public fun testProjections3(/*0*/ x: Pair<in kotlin.Number, out kotlin.Int>): [ERROR : Error function type]
|
||||
public fun testProjections4(/*0*/ x: Pair<in kotlin.Int, in kotlin.Int>): [ERROR : Error function type]
|
||||
|
||||
public final class Bound</*0*/ X, /*1*/ Y : X> {
|
||||
public constructor Bound</*0*/ X, /*1*/ Y : X>(/*0*/ x: X, /*1*/ y: Y)
|
||||
public final val x: X
|
||||
public final val y: Y
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Cons</*0*/ T> {
|
||||
public constructor Cons</*0*/ T>(/*0*/ head: T, /*1*/ tail: Cons<T>?)
|
||||
public final val head: T
|
||||
@@ -53,9 +44,9 @@ public final class Pair</*0*/ X, /*1*/ Y> {
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
public typealias B</*0*/ X, /*1*/ Y> = Bound<X, Y>
|
||||
public typealias C</*0*/ T> = Cons<T>
|
||||
public typealias CC</*0*/ T> = C<C<T>>
|
||||
public typealias F</*0*/ T> = Foo<T>
|
||||
public typealias N</*0*/ T> = Num<T>
|
||||
public typealias PL</*0*/ T> = Pair<T, kotlin.collections.List<T>>
|
||||
public typealias PN</*0*/ T> = Pair<T, Num<T>>
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class Cons<T : Number>(val head: T, val tail: Cons<T>?)
|
||||
typealias C<T> = Cons<T>
|
||||
|
||||
val test1 = C(1, C(2, null))
|
||||
val test2 = C(1, <!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>C<!>("", null))
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package
|
||||
|
||||
public val test1: Cons<kotlin.Int>
|
||||
public val test2: Cons<kotlin.Int>
|
||||
|
||||
public final class Cons</*0*/ T : kotlin.Number> {
|
||||
public constructor Cons</*0*/ T : kotlin.Number>(/*0*/ head: T, /*1*/ tail: Cons<T>?)
|
||||
public final val head: T
|
||||
public final val tail: Cons<T>?
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
public typealias C</*0*/ T> = Cons<T>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
class Foo<A : Number>
|
||||
class Bar<B : CharSequence>
|
||||
|
||||
class Hr<A, B, C, D>(val a: A, val b: B)
|
||||
|
||||
typealias Test<A, B> = Hr<A, B, Foo<A>, Bar<B>>
|
||||
|
||||
val test1 = Test(1, "")
|
||||
val test2 = <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED(Type parameter bound for B in type inferred from type alias expansion for fun <A, B> <init>\(a: A, b: B\): Hr<A, B, Foo<A>, Bar<B>>
|
||||
is not satisfied: inferred type Int is not a subtype of CharSequence)!>Test<!>(1, 2)
|
||||
|
||||
|
||||
typealias Bas<T> = Hr<T, T, Foo<T>, Bar<T>>
|
||||
|
||||
val test3 = <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED(Type parameter bound for B in type inferred from type alias expansion for fun <T> <init>\(a: T, b: T\): Hr<T, T, Foo<T>, Bar<T>>
|
||||
is not satisfied: inferred type Int is not a subtype of CharSequence)!>Bas<!>(1, 1)
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package
|
||||
|
||||
public val test1: Hr<kotlin.Int, kotlin.String, Foo<kotlin.Int>, Bar<kotlin.String>>
|
||||
public val test2: [ERROR : Type for Test(1, 2)]
|
||||
public val test3: [ERROR : Type for Bas(1, 1)]
|
||||
|
||||
public final class Bar</*0*/ B : kotlin.CharSequence> {
|
||||
public constructor Bar</*0*/ B : kotlin.CharSequence>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Foo</*0*/ A : kotlin.Number> {
|
||||
public constructor Foo</*0*/ A : kotlin.Number>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Hr</*0*/ A, /*1*/ B, /*2*/ C, /*3*/ D> {
|
||||
public constructor Hr</*0*/ A, /*1*/ B, /*2*/ C, /*3*/ D>(/*0*/ a: A, /*1*/ b: B)
|
||||
public final val a: A
|
||||
public final val b: B
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
public typealias Bas</*0*/ T> = Hr<T, T, Foo<T>, Bar<T>>
|
||||
public typealias Test</*0*/ A, /*1*/ B> = Hr<A, B, Foo<A>, Bar<B>>
|
||||
@@ -21058,6 +21058,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.kt")
|
||||
public void testTypeAliasConstructorTypeArgumentsInferenceWithNestedCalls() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasConstructorTypeArgumentsInferenceWithPhantomTypes.kt")
|
||||
public void testTypeAliasConstructorTypeArgumentsInferenceWithPhantomTypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithPhantomTypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeAliasConstructorWrongClass.kt")
|
||||
public void testTypeAliasConstructorWrongClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasConstructorWrongClass.kt");
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
<!-- upperBoundViolatedInTypeAliasConstructorCall1 -->
|
||||
Type parameter bound for Tn in type inferred from type alias expansion for fun <T> <init>(x: T): Num<T>
|
||||
is not satisfied: inferred type T is not a subtype of Number
|
||||
is not satisfied: inferred type String is not a subtype of Number
|
||||
Reference in New Issue
Block a user