KT-3184 Type inference seems partially broken
#KT-3184 fixed
This commit is contained in:
+41
-5
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.calls.inference;
|
package org.jetbrains.jet.lang.resolve.calls.inference;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -177,15 +178,29 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
assert subjectType != TypeUtils.NO_EXPECTED_TYPE : "Subject type shouldn't be NO_EXPECTED_TYPE (in position " + constraintPosition + " )";
|
assert subjectType != TypeUtils.NO_EXPECTED_TYPE : "Subject type shouldn't be NO_EXPECTED_TYPE (in position " + constraintPosition + " )";
|
||||||
if (ErrorUtils.isErrorType(subjectType)) return;
|
if (ErrorUtils.isErrorType(subjectType)) return;
|
||||||
|
|
||||||
|
DeclarationDescriptor subjectTypeDescriptor = subjectType.getConstructor().getDeclarationDescriptor();
|
||||||
|
|
||||||
|
KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance();
|
||||||
if (constrainingType == PLACEHOLDER_FUNCTION_TYPE) {
|
if (constrainingType == PLACEHOLDER_FUNCTION_TYPE) {
|
||||||
if (!KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(subjectType)) {
|
if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(subjectType)) {
|
||||||
|
if (subjectTypeDescriptor instanceof TypeParameterDescriptor && typeParameterConstraints.get(subjectTypeDescriptor) != null) {
|
||||||
|
// a constraint binds type parameter and any function type, so there is no new info and no error
|
||||||
|
return;
|
||||||
|
}
|
||||||
errorConstraintPositions.add(constraintPosition);
|
errorConstraintPositions.add(constraintPosition);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo temporary hack
|
||||||
|
// function literal without declaring receiver type { x -> ... }
|
||||||
|
// can be considered as extension function if one is expected
|
||||||
|
// (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
|
||||||
|
if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(constrainingType) && kotlinBuiltIns.isExtensionFunctionType(subjectType)) {
|
||||||
|
constrainingType = createCorrespondingExtensionFunctionType(constrainingType, DONT_CARE);
|
||||||
|
}
|
||||||
|
|
||||||
DeclarationDescriptor constrainingTypeDescriptor = constrainingType.getConstructor().getDeclarationDescriptor();
|
DeclarationDescriptor constrainingTypeDescriptor = constrainingType.getConstructor().getDeclarationDescriptor();
|
||||||
DeclarationDescriptor subjectTypeDescriptor = subjectType.getConstructor().getDeclarationDescriptor();
|
|
||||||
|
|
||||||
if (subjectTypeDescriptor instanceof TypeParameterDescriptor) {
|
if (subjectTypeDescriptor instanceof TypeParameterDescriptor) {
|
||||||
TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) subjectTypeDescriptor;
|
TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) subjectTypeDescriptor;
|
||||||
@@ -204,7 +219,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
if (constrainingTypeDescriptor instanceof TypeParameterDescriptor) {
|
if (constrainingTypeDescriptor instanceof TypeParameterDescriptor) {
|
||||||
assert typeParameterConstraints.get(constrainingTypeDescriptor) == null : "Constraining type contains type variable " + constrainingTypeDescriptor.getName();
|
assert typeParameterConstraints.get(constrainingTypeDescriptor) == null : "Constraining type contains type variable " + constrainingTypeDescriptor.getName();
|
||||||
}
|
}
|
||||||
if (constraintKind == SUB_TYPE && KotlinBuiltIns.getInstance().isNothingOrNullableNothing(constrainingType)) {
|
if (constraintKind == SUB_TYPE && kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) {
|
||||||
// following constraints are always true:
|
// following constraints are always true:
|
||||||
// 'Nothing' is a subtype of any type
|
// 'Nothing' is a subtype of any type
|
||||||
if (!constrainingType.isNullable()) return;
|
if (!constrainingType.isNullable()) return;
|
||||||
@@ -217,7 +232,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
switch (constraintKind) {
|
switch (constraintKind) {
|
||||||
case SUB_TYPE: {
|
case SUB_TYPE: {
|
||||||
if (KotlinBuiltIns.getInstance().isNothingOrNullableNothing(constrainingType)) break;
|
if (kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) break;
|
||||||
JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(constrainingType, subjectType);
|
JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(constrainingType, subjectType);
|
||||||
if (correspondingSupertype != null) {
|
if (correspondingSupertype != null) {
|
||||||
constrainingType = correspondingSupertype;
|
constrainingType = correspondingSupertype;
|
||||||
@@ -225,7 +240,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SUPER_TYPE: {
|
case SUPER_TYPE: {
|
||||||
if (KotlinBuiltIns.getInstance().isNothingOrNullableNothing(subjectType)) break;
|
if (kotlinBuiltIns.isNothingOrNullableNothing(subjectType)) break;
|
||||||
JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(subjectType, constrainingType);
|
JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(subjectType, constrainingType);
|
||||||
if (correspondingSupertype != null) {
|
if (correspondingSupertype != null) {
|
||||||
subjectType = correspondingSupertype;
|
subjectType = correspondingSupertype;
|
||||||
@@ -388,4 +403,25 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
public TypeSubstitutor getCurrentSubstitutor() {
|
public TypeSubstitutor getCurrentSubstitutor() {
|
||||||
return currentSubstitutor;
|
return currentSubstitutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JetType createCorrespondingExtensionFunctionType(@NotNull JetType functionType, @NotNull JetType receiverType) {
|
||||||
|
assert KotlinBuiltIns.getInstance().isFunctionType(functionType);
|
||||||
|
|
||||||
|
List<TypeProjection> typeArguments = functionType.getArguments();
|
||||||
|
assert !typeArguments.isEmpty();
|
||||||
|
|
||||||
|
List<JetType> arguments = Lists.newArrayList();
|
||||||
|
// excluding the last type argument of the function type, which is the return type
|
||||||
|
int index = 0;
|
||||||
|
int lastIndex = typeArguments.size() - 1;
|
||||||
|
for (TypeProjection typeArgument : typeArguments) {
|
||||||
|
if (index < lastIndex) {
|
||||||
|
arguments.add(typeArgument.getType());
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
JetType returnType = typeArguments.get(lastIndex).getType();
|
||||||
|
return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
//KT-3184 Type inference seems partially broken
|
||||||
|
package a
|
||||||
|
|
||||||
|
import java.util.HashMap
|
||||||
|
|
||||||
|
private fun <T> test(value: T, extf: String.(value: T)->Unit) {
|
||||||
|
"".extf(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
test(1, {(value) -> println(value)})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tests() {
|
||||||
|
val dict = HashMap<String, (String) -> Unit>()
|
||||||
|
dict["0"] = { str -> println(str) }
|
||||||
|
dict["1"] = { println(it) }
|
||||||
|
|
||||||
|
dict.set("1", { println(it) })
|
||||||
|
dict["1"] = { r -> println(r) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// from standard library
|
||||||
|
fun <K, V> MutableMap<K, V>.set(key : K, value : V) : V<!BASE_WITH_NULLABLE_UPPER_BOUND!>?<!> = this.put(key, value)
|
||||||
|
|
||||||
|
fun println(message : Any?) = System.out.println(message)
|
||||||
@@ -2036,6 +2036,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
doTest("compiler/testData/diagnostics/tests/inference/kt1293.kt");
|
doTest("compiler/testData/diagnostics/tests/inference/kt1293.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt3184.kt")
|
||||||
|
public void testKt3184() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/inference/kt3184.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt619.kt")
|
@TestMetadata("kt619.kt")
|
||||||
public void testKt619() throws Exception {
|
public void testKt619() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/inference/kt619.kt");
|
doTest("compiler/testData/diagnostics/tests/inference/kt619.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user