Constraint incorporation
In a constraint system a new bound is incorporated: all new constrains that can be derived from it (and from existing ones) are added
This commit is contained in:
@@ -459,6 +459,7 @@ public interface Errors {
|
||||
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CANNOT_CAPTURE_TYPES = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> TYPE_INFERENCE_INCORPORATION_ERROR = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<JetExpression, JetType, JetType> TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
|
||||
+1
@@ -593,6 +593,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(TYPE_INFERENCE_CANNOT_CAPTURE_TYPES, "Type inference failed: {0}", TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER);
|
||||
MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Type inference failed: {0}", TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER);
|
||||
MAP.put(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH, "Type inference failed: {0}", TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH_RENDERER);
|
||||
MAP.put(TYPE_INFERENCE_INCORPORATION_ERROR, "Type inference failed. Please try to specify type arguments explicitly.");
|
||||
MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "{0}", TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER);
|
||||
MAP.put(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH, "Type inference failed. Expected type mismatch: found: {1} required: {0}", RENDER_TYPE, RENDER_TYPE);
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ public object Renderers {
|
||||
|
||||
return result
|
||||
.text(newText().normal("Not enough information to infer parameter ")
|
||||
.strong(firstUnknownParameter!!.getName())
|
||||
.strong(firstUnknownParameter.getName())
|
||||
.normal(" in "))
|
||||
.table(newTable()
|
||||
.descriptor(inferenceErrorData.descriptor)
|
||||
@@ -246,7 +246,7 @@ public object Renderers {
|
||||
|
||||
val systemWithoutWeakConstraints = constraintSystem.getSystemWithoutWeakConstraints()
|
||||
val typeParameterDescriptor = inferenceErrorData.descriptor.getTypeParameters().firstOrNull {
|
||||
!ConstraintsUtil.checkUpperBoundIsSatisfied(systemWithoutWeakConstraints, it, true)
|
||||
!ConstraintsUtil.checkUpperBoundIsSatisfied(systemWithoutWeakConstraints, it, true)
|
||||
}
|
||||
if (typeParameterDescriptor == null && status.hasConflictingConstraints()) {
|
||||
return renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
|
||||
|
||||
@@ -55,7 +55,7 @@ import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumen
|
||||
import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
|
||||
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.DEPENDENT;
|
||||
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
|
||||
import static org.jetbrains.kotlin.resolve.calls.inference.InferencePackage.createCorrespondingFunctionTypeForFunctionPlaceholder;
|
||||
import static org.jetbrains.kotlin.resolve.calls.inference.InferencePackage.createTypeForFunctionPlaceholder;
|
||||
import static org.jetbrains.kotlin.types.TypeUtils.DONT_CARE;
|
||||
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
|
||||
@@ -85,7 +85,7 @@ public class ArgumentTypeResolver {
|
||||
@NotNull JetType expectedType
|
||||
) {
|
||||
if (ErrorUtils.isFunctionPlaceholder(actualType)) {
|
||||
JetType functionType = createCorrespondingFunctionTypeForFunctionPlaceholder(actualType, expectedType);
|
||||
JetType functionType = createTypeForFunctionPlaceholder(actualType, expectedType);
|
||||
return JetTypeChecker.DEFAULT.isSubtypeOf(functionType, expectedType);
|
||||
}
|
||||
return JetTypeChecker.DEFAULT.isSubtypeOf(actualType, expectedType);
|
||||
|
||||
@@ -44,6 +44,9 @@ import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.expressions.DataFlowUtils
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
|
||||
public class CallCompleter(
|
||||
val argumentTypeResolver: ArgumentTypeResolver,
|
||||
@@ -151,8 +154,6 @@ public class CallCompleter(
|
||||
}
|
||||
}
|
||||
|
||||
(getConstraintSystem() as ConstraintSystemImpl).processDeclaredBoundConstraints()
|
||||
|
||||
if (returnType != null && expectedType === TypeUtils.UNIT_EXPECTED_TYPE) {
|
||||
updateSystemIfSuccessful {
|
||||
system ->
|
||||
@@ -161,6 +162,9 @@ public class CallCompleter(
|
||||
}
|
||||
}
|
||||
|
||||
val constraintSystem = getConstraintSystem() as ConstraintSystemImpl
|
||||
constraintSystem.fixVariables()
|
||||
|
||||
setResultingSubstitutor(getConstraintSystem()!!.getResultingSubstitutor())
|
||||
}
|
||||
|
||||
@@ -280,7 +284,8 @@ public class CallCompleter(
|
||||
argumentExpression: JetExpression,
|
||||
trace: BindingTrace
|
||||
): JetType? {
|
||||
if (recordedType == updatedType || updatedType == null) return updatedType
|
||||
//workaround for KT-8218
|
||||
if ((!ErrorUtils.containsErrorType(recordedType) && recordedType == updatedType) || updatedType == null) return updatedType
|
||||
|
||||
fun deparenthesizeOrGetSelector(expression: JetExpression?): JetExpression? {
|
||||
val deparenthesized = JetPsiUtil.deparenthesizeOnce(expression, /* deparenthesizeBinaryExpressionWithTypeRHS = */ false)
|
||||
|
||||
+5
-9
@@ -70,11 +70,9 @@ class GenericCandidateResolver(
|
||||
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
|
||||
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate)
|
||||
|
||||
val typeVariables = Maps.newLinkedHashMap<TypeParameterDescriptor, Variance>()
|
||||
for (typeParameterDescriptor in candidateWithFreshVariables.getTypeParameters()) {
|
||||
typeVariables.put(typeParameterDescriptor, Variance.INVARIANT) // TODO: variance of the occurrences
|
||||
}
|
||||
constraintSystem.registerTypeVariables(typeVariables)
|
||||
val backConversion = candidateWithFreshVariables.getTypeParameters().zip(candidate.getTypeParameters()).toMap()
|
||||
|
||||
constraintSystem.registerTypeVariables(candidateWithFreshVariables.getTypeParameters(), { Variance.INVARIANT })
|
||||
|
||||
val substituteDontCare = makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE)
|
||||
|
||||
@@ -111,9 +109,7 @@ class GenericCandidateResolver(
|
||||
}
|
||||
|
||||
// Restore type variables before alpha-conversion
|
||||
val constraintSystemWithRightTypeParameters = constraintSystem.substituteTypeVariables {
|
||||
candidate.getTypeParameters().get(it.getIndex())
|
||||
}
|
||||
val constraintSystemWithRightTypeParameters = constraintSystem.substituteTypeVariables { backConversion.get(it) }
|
||||
candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters)
|
||||
|
||||
|
||||
@@ -174,7 +170,7 @@ class GenericCandidateResolver(
|
||||
val valueParameterDescriptor = entry.getKey()
|
||||
|
||||
for (valueArgument in resolvedValueArgument.getArguments()) {
|
||||
addConstraintForFunctionLiteral<D>(valueArgument, valueParameterDescriptor, constraintSystem, context)
|
||||
addConstraintForFunctionLiteral(valueArgument, valueParameterDescriptor, constraintSystem, context)
|
||||
}
|
||||
}
|
||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor())
|
||||
|
||||
+3
@@ -233,6 +233,9 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
|
||||
else if (status.hasConflictingConstraints()) {
|
||||
trace.report(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS.on(reference, data));
|
||||
}
|
||||
else if (status.hasTypeInferenceIncorporationError()) {
|
||||
trace.report(TYPE_INFERENCE_INCORPORATION_ERROR.on(reference));
|
||||
}
|
||||
else {
|
||||
assert status.hasUnknownParameters();
|
||||
trace.report(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data));
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ public class ResolutionTaskHolder<D : CallableDescriptor, F : D>(
|
||||
val lazyCandidates = {
|
||||
candidatesList[candidateIndex]().filter { priorityProvider.getPriority(it) == priority }.toReadOnlyList()
|
||||
}
|
||||
tasks.add(ResolutionTask(basicCallResolutionContext, tracing, lazyCandidates))
|
||||
tasks.add(ResolutionTask<D, F>(basicCallResolutionContext, tracing, lazyCandidates))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
package foo
|
||||
|
||||
open class A {
|
||||
val B.w: Int by <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED!>MyProperty<!>()
|
||||
val B.w: Int by <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>MyProperty<!>()
|
||||
}
|
||||
|
||||
val B.r: Int by <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED!>MyProperty<!>()
|
||||
val B.r: Int by <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>MyProperty<!>()
|
||||
|
||||
val A.e: Int by MyProperty()
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -7,6 +7,6 @@ fun <T, C: Collection<T>> convert(src: Collection<T>, dest: C): C = throw Except
|
||||
|
||||
fun test(l: List<Int>) {
|
||||
//todo should be inferred
|
||||
val r = <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED!>convert<!>(l, <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>HashSet<!>())
|
||||
checkSubtype<Int>(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>r<!>)
|
||||
val r = convert(l, HashSet())
|
||||
checkSubtype<Collection<Int>>(r)
|
||||
}
|
||||
|
||||
+2
-4
@@ -29,8 +29,7 @@ fun test3() {
|
||||
fun <T, R: T> emptyStrangeMap1(t: T): Map<T, R> = throw Exception("$t")
|
||||
|
||||
fun test4() {
|
||||
//todo we may infer 'Int' for 'R' here
|
||||
<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>emptyStrangeMap1<!>(1)
|
||||
emptyStrangeMap1(1)
|
||||
}
|
||||
|
||||
//--------------
|
||||
@@ -38,8 +37,7 @@ fun test4() {
|
||||
fun <T: A, R: T> emptyStrangeMap2(t: T): Map<T, R> where R: A = throw Exception("$t")
|
||||
|
||||
fun test5(a: A) {
|
||||
//todo we may infer 'A' for 'R' here
|
||||
<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>emptyStrangeMap2<!>(a)
|
||||
emptyStrangeMap2(a)
|
||||
}
|
||||
|
||||
//--------------
|
||||
|
||||
@@ -16,11 +16,10 @@ public class HS<T> extends Base<T> {}
|
||||
|
||||
import foo.*;
|
||||
|
||||
import java.util.HashSet
|
||||
fun <T, C: Base<T>> convert(src: HS<T>, dest: C): C = throw Exception("$src $dest")
|
||||
|
||||
fun test(l: HS<Int>) {
|
||||
//todo should be inferred
|
||||
val r = <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED!>convert<!>(l, <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>HS<!>())
|
||||
checkSubtype<Int>(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>r<!>)
|
||||
val r = convert(l, HS())
|
||||
checkSubtype<Base<Int>>(r)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
fun bar() {
|
||||
fun <T: <!CYCLIC_GENERIC_UPPER_BOUND!>T?<!>> foo() {}
|
||||
foo()
|
||||
<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo<!>()
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
interface Inv<I>
|
||||
|
||||
fun <S, T: S> Inv<T>.reduce2(): S = null!!
|
||||
|
||||
fun test(a: Inv<Int>): Int {
|
||||
val b = 1 <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> a.reduce2()
|
||||
return <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>b<!>
|
||||
val b = 1 + a.reduce2()
|
||||
return b
|
||||
}
|
||||
+6
-1
@@ -6,7 +6,12 @@ fun <D, E : D> List<ResolutionTask<D, E>>.bar(t: ResolutionTask<D, E>) = t
|
||||
|
||||
public class ResolutionTaskHolder<F, G : F> {
|
||||
fun test(candidate: ResolutionCandidate<F>, tasks: MutableList<ResolutionTask<F, G>>) {
|
||||
tasks.bar(ResolutionTask(candidate))
|
||||
tasks.bar(ResolutionTask<F, G>(candidate))
|
||||
tasks.add(ResolutionTask<F, G>(candidate))
|
||||
|
||||
//todo the problem is the type of ResolutionTask is inferred as ResolutionTask<F, F> too early
|
||||
tasks.<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>bar<!>(ResolutionTask(candidate))
|
||||
tasks.<!NONE_APPLICABLE!>add<!>(ResolutionTask(candidate))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ fun main(args:Array<String>) {
|
||||
val startTimeNanos = System.nanoTime()
|
||||
|
||||
// the problem sits on the next line:
|
||||
val pi = 4.0.toDouble() * delta <!OVERLOAD_RESOLUTION_AMBIGUITY!>*<!> (1..n).reduce(
|
||||
val pi = 4.0.toDouble() * delta <!OVERLOAD_RESOLUTION_AMBIGUITY!>*<!> (1..n).<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>reduce<!>(
|
||||
{t, i ->
|
||||
val x = (i - 0.5) * delta
|
||||
<!TYPE_MISMATCH!>t + 1.0 / (1.0 + x * x)<!>
|
||||
t + 1.0 / (1.0 + x * x)
|
||||
|
||||
})
|
||||
// !!! pi has error type here
|
||||
|
||||
@@ -12,7 +12,7 @@ fun bar() {
|
||||
Resolved call:
|
||||
|
||||
Candidate descriptor: fun <T> foo(t: T): Unit defined in root package
|
||||
Resulting descriptor: fun <T> foo(t: List<???>): Unit defined in root package
|
||||
Resulting descriptor: fun <T> foo(t: ???): Unit defined in root package
|
||||
|
||||
Explicit receiver kind = NO_EXPLICIT_RECEIVER
|
||||
Dispatch receiver = NO_RECEIVER
|
||||
@@ -20,4 +20,4 @@ Extension receiver = NO_RECEIVER
|
||||
|
||||
Value arguments mapping:
|
||||
|
||||
MATCH_MODULO_UNINFERRED_TYPES t : List<???> = someList()
|
||||
MATCH_MODULO_UNINFERRED_TYPES t : ??? = someList()
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ fun bar() {
|
||||
Resolved call:
|
||||
|
||||
Candidate descriptor: fun <T> foo(t: T): Unit defined in root package
|
||||
Resulting descriptor: fun <T> foo(t: MutableList<???>): Unit defined in root package
|
||||
Resulting descriptor: fun <T> foo(t: ???): Unit defined in root package
|
||||
|
||||
Explicit receiver kind = NO_EXPLICIT_RECEIVER
|
||||
Dispatch receiver = NO_RECEIVER
|
||||
@@ -20,4 +20,4 @@ Extension receiver = NO_RECEIVER
|
||||
|
||||
Value arguments mapping:
|
||||
|
||||
MATCH_MODULO_UNINFERRED_TYPES t : MutableList<???> = someList()
|
||||
MATCH_MODULO_UNINFERRED_TYPES t : ??? = someList()
|
||||
|
||||
+11
-11
@@ -36,9 +36,10 @@ import java.util.LinkedHashMap
|
||||
import java.util.regex.Pattern
|
||||
|
||||
abstract public class AbstractConstraintSystemTest() : JetLiteFixture() {
|
||||
private val typePattern = """([\w|<|>|\(|\)]+)"""
|
||||
val constraintPattern = Pattern.compile("""(SUBTYPE|SUPERTYPE)\s+$typePattern\s+$typePattern\s*(weak)?""")
|
||||
private val typePattern = """([\w|<|\,|>|?|\(|\)]+)"""
|
||||
val constraintPattern = Pattern.compile("""(SUBTYPE|SUPERTYPE|EQUAL)\s+$typePattern\s+$typePattern\s*(weak)?""")
|
||||
val variablesPattern = Pattern.compile("VARIABLES\\s+(.*)")
|
||||
val fixVariablesPattern = "FIX_VARIABLES"
|
||||
|
||||
private var _typeResolver: TypeResolver? = null
|
||||
private val typeResolver: TypeResolver
|
||||
@@ -83,12 +84,10 @@ abstract public class AbstractConstraintSystemTest() : JetLiteFixture() {
|
||||
|
||||
val constraintSystem = ConstraintSystemImpl()
|
||||
|
||||
val typeParameterDescriptors = LinkedHashMap<TypeParameterDescriptor, Variance>()
|
||||
val variables = parseVariables(constraintsFileText)
|
||||
for (variable in variables) {
|
||||
typeParameterDescriptors.put(testDeclarations.getParameterDescriptor(variable), Variance.INVARIANT)
|
||||
}
|
||||
constraintSystem.registerTypeVariables(typeParameterDescriptors)
|
||||
val fixVariables = constraintsFileText.contains(fixVariablesPattern)
|
||||
val typeParameterDescriptors = variables.map { testDeclarations.getParameterDescriptor(it) }
|
||||
constraintSystem.registerTypeVariables(typeParameterDescriptors, { Variance.INVARIANT })
|
||||
|
||||
val constraints = parseConstraints(constraintsFileText)
|
||||
for (constraint in constraints) {
|
||||
@@ -98,17 +97,18 @@ abstract public class AbstractConstraintSystemTest() : JetLiteFixture() {
|
||||
when (constraint.kind) {
|
||||
MyConstraintKind.SUBTYPE -> constraintSystem.addSubtypeConstraint(firstType, secondType, position)
|
||||
MyConstraintKind.SUPERTYPE -> constraintSystem.addSupertypeConstraint(firstType, secondType, position)
|
||||
MyConstraintKind.EQUAL -> constraintSystem.addConstraint(ConstraintSystemImpl.ConstraintKind.EQUAL, firstType, secondType, position)
|
||||
}
|
||||
}
|
||||
constraintSystem.processDeclaredBoundConstraints()
|
||||
if (fixVariables) constraintSystem.fixVariables()
|
||||
|
||||
val resultingStatus = Renderers.RENDER_CONSTRAINT_SYSTEM_SHORT.render(constraintSystem)
|
||||
|
||||
val resultingSubstitutor = constraintSystem.getResultingSubstitutor()
|
||||
val result = StringBuilder() append "result:\n"
|
||||
for ((typeParameter, variance) in typeParameterDescriptors) {
|
||||
for (typeParameter in typeParameterDescriptors) {
|
||||
val parameterType = testDeclarations.getType(typeParameter.getName().asString())
|
||||
val resultType = resultingSubstitutor.substitute(parameterType, variance)
|
||||
val resultType = resultingSubstitutor.substitute(parameterType, Variance.INVARIANT)
|
||||
result append "${typeParameter.getName()}=${resultType?.let{ DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it) }}\n"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ abstract public class AbstractConstraintSystemTest() : JetLiteFixture() {
|
||||
|
||||
class MyConstraint(val kind: MyConstraintKind, val firstType: String, val secondType: String, val isWeak: Boolean)
|
||||
enum class MyConstraintKind {
|
||||
SUBTYPE, SUPERTYPE
|
||||
SUBTYPE, SUPERTYPE, EQUAL
|
||||
}
|
||||
|
||||
private fun parseVariables(text: String): List<String> {
|
||||
|
||||
Reference in New Issue
Block a user