KT-442 Type inference fails on with()
This commit is contained in:
@@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.inference.SolutionStatus;
|
||||||
import org.jetbrains.jet.lexer.JetKeywordToken;
|
import org.jetbrains.jet.lexer.JetKeywordToken;
|
||||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||||
|
|
||||||
@@ -390,7 +391,7 @@ public interface Errors {
|
|||||||
SimpleDiagnosticFactory NO_RECEIVER_ADMITTED = SimpleDiagnosticFactory.create(ERROR, "No receiver can be passed to this function or property");
|
SimpleDiagnosticFactory NO_RECEIVER_ADMITTED = SimpleDiagnosticFactory.create(ERROR, "No receiver can be passed to this function or property");
|
||||||
|
|
||||||
SimpleDiagnosticFactory CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS = SimpleDiagnosticFactory.create(ERROR, "Can not create an instance of an abstract class");
|
SimpleDiagnosticFactory CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS = SimpleDiagnosticFactory.create(ERROR, "Can not create an instance of an abstract class");
|
||||||
SimpleDiagnosticFactory TYPE_INFERENCE_FAILED = SimpleDiagnosticFactory.create(ERROR, "Type inference failed");
|
ParameterizedDiagnosticFactory1<SolutionStatus> TYPE_INFERENCE_FAILED = ParameterizedDiagnosticFactory1.create(ERROR, "Type inference failed: {0}");
|
||||||
ParameterizedDiagnosticFactory1<Integer> WRONG_NUMBER_OF_TYPE_ARGUMENTS = new ParameterizedDiagnosticFactory1<Integer>(ERROR, "{0} type arguments expected") {
|
ParameterizedDiagnosticFactory1<Integer> WRONG_NUMBER_OF_TYPE_ARGUMENTS = new ParameterizedDiagnosticFactory1<Integer>(ERROR, "{0} type arguments expected") {
|
||||||
@Override
|
@Override
|
||||||
protected String makeMessageFor(@NotNull Integer argument) {
|
protected String makeMessageFor(@NotNull Integer argument) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
|||||||
import org.jetbrains.jet.lang.types.inference.ConstraintSystem;
|
import org.jetbrains.jet.lang.types.inference.ConstraintSystem;
|
||||||
import org.jetbrains.jet.lang.types.inference.ConstraintSystemSolution;
|
import org.jetbrains.jet.lang.types.inference.ConstraintSystemSolution;
|
||||||
import org.jetbrains.jet.lang.types.inference.ConstraintSystemImpl;
|
import org.jetbrains.jet.lang.types.inference.ConstraintSystemImpl;
|
||||||
|
import org.jetbrains.jet.lang.types.inference.SolutionStatus;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -312,8 +313,9 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void typeInferenceFailed(@NotNull BindingTrace trace) {
|
public void typeInferenceFailed(@NotNull BindingTrace trace, SolutionStatus status) {
|
||||||
trace.report(TYPE_INFERENCE_FAILED.on(call.getCallNode()));
|
assert !status.isSuccessful();
|
||||||
|
trace.report(TYPE_INFERENCE_FAILED.on(call.getCallNode(), status));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -410,6 +412,8 @@ public class CallResolver {
|
|||||||
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
|
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeSubstitutor substituteUnknown = ConstraintSystemImpl.makeConstantSubstitutor(candidate.getTypeParameters(), ErrorUtils.createErrorType("Unknown"));
|
||||||
|
|
||||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
|
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
|
||||||
ResolvedValueArgument valueArgument = entry.getValue();
|
ResolvedValueArgument valueArgument = entry.getValue();
|
||||||
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
|
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
|
||||||
@@ -417,10 +421,14 @@ public class CallResolver {
|
|||||||
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor);
|
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor);
|
||||||
|
|
||||||
for (JetExpression expression : valueArgument.getArgumentExpressions()) {
|
for (JetExpression expression : valueArgument.getArgumentExpressions()) {
|
||||||
// JetExpression expression = valueArgument.getArgumentExpression();
|
|
||||||
// TODO : more attempts, with different expected types
|
// TODO : more attempts, with different expected types
|
||||||
ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, temporaryTrace);
|
|
||||||
JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE);
|
// Here we type check expecting an error type (that is a subtype of any type and a supertype of any type
|
||||||
|
// and throw the results away
|
||||||
|
// We'll type check the arguments later, with the inferred types expected
|
||||||
|
TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(temporaryTrace);
|
||||||
|
ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, traceForUnknown);
|
||||||
|
JetType type = temporaryServices.getType(scope, expression, substituteUnknown.substitute(valueParameterDescriptor.getOutType(), Variance.INVARIANT));
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
constraintSystem.addSubtypingConstraint(type, effectiveExpectedType);
|
constraintSystem.addSubtypingConstraint(type, effectiveExpectedType);
|
||||||
}
|
}
|
||||||
@@ -450,10 +458,14 @@ public class CallResolver {
|
|||||||
for (TypeParameterDescriptor typeParameterDescriptor : candidateCall.getCandidateDescriptor().getTypeParameters()) {
|
for (TypeParameterDescriptor typeParameterDescriptor : candidateCall.getCandidateDescriptor().getTypeParameters()) {
|
||||||
candidateCall.recordTypeArgument(typeParameterDescriptor, solution.getValue(typeParameterDescriptor));
|
candidateCall.recordTypeArgument(typeParameterDescriptor, solution.getValue(typeParameterDescriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Here we type check the arguments with inferred types expected
|
||||||
|
checkValueArgumentTypes(scope, candidateCall);
|
||||||
|
|
||||||
candidateCall.setStatus(SUCCESS);
|
candidateCall.setStatus(SUCCESS);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tracing.typeInferenceFailed(temporaryTrace);
|
tracing.typeInferenceFailed(temporaryTrace, solution.getStatus());
|
||||||
candidateCall.setStatus(OTHER_ERROR);
|
candidateCall.setStatus(OTHER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
|||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.inference.SolutionStatus;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ import java.util.Collection;
|
|||||||
public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {}
|
public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void typeInferenceFailed(@NotNull BindingTrace trace) {}
|
public void typeInferenceFailed(@NotNull BindingTrace trace, SolutionStatus status) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {}
|
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {}
|
||||||
@@ -79,7 +80,7 @@ import java.util.Collection;
|
|||||||
|
|
||||||
void instantiationOfAbstractClass(@NotNull BindingTrace trace);
|
void instantiationOfAbstractClass(@NotNull BindingTrace trace);
|
||||||
|
|
||||||
void typeInferenceFailed(@NotNull BindingTrace trace);
|
void typeInferenceFailed(@NotNull BindingTrace trace, SolutionStatus status);
|
||||||
|
|
||||||
void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type);
|
void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type);
|
||||||
|
|
||||||
|
|||||||
@@ -18,5 +18,5 @@ public interface JetType extends Annotated {
|
|||||||
JetScope getMemberScope();
|
JetScope getMemberScope();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other);
|
boolean equals(Object other);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,6 +123,8 @@ public class TypeSubstitutor {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JetType unsafeSubstitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) throws SubstitutionException {
|
private JetType unsafeSubstitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) throws SubstitutionException {
|
||||||
|
if (ErrorUtils.isErrorType(type)) return type;
|
||||||
|
|
||||||
TypeConstructor constructor = type.getConstructor();
|
TypeConstructor constructor = type.getConstructor();
|
||||||
TypeProjection value = substitution.get(constructor);
|
TypeProjection value = substitution.get(constructor);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
@@ -140,6 +142,8 @@ public class TypeSubstitutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JetType specializeType(JetType subjectType, Variance callSiteVariance) throws SubstitutionException {
|
private JetType specializeType(JetType subjectType, Variance callSiteVariance) throws SubstitutionException {
|
||||||
|
if (ErrorUtils.isErrorType(subjectType)) return subjectType;
|
||||||
|
|
||||||
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
|
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
|
||||||
List<TypeProjection> arguments = subjectType.getArguments();
|
List<TypeProjection> arguments = subjectType.getArguments();
|
||||||
for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) {
|
for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) {
|
||||||
@@ -166,6 +170,8 @@ public class TypeSubstitutor {
|
|||||||
@NotNull TypeParameterDescriptor correspondingTypeParameter,
|
@NotNull TypeParameterDescriptor correspondingTypeParameter,
|
||||||
@NotNull Variance contextCallSiteVariance) throws SubstitutionException {
|
@NotNull Variance contextCallSiteVariance) throws SubstitutionException {
|
||||||
JetType typeToSubstituteIn = passedProjection.getType();
|
JetType typeToSubstituteIn = passedProjection.getType();
|
||||||
|
if (ErrorUtils.isErrorType(typeToSubstituteIn)) return passedProjection;
|
||||||
|
|
||||||
Variance passedProjectionKind = passedProjection.getProjectionKind();
|
Variance passedProjectionKind = passedProjection.getProjectionKind();
|
||||||
Variance parameterVariance = correspondingTypeParameter.getVariance();
|
Variance parameterVariance = correspondingTypeParameter.getVariance();
|
||||||
|
|
||||||
@@ -230,7 +236,7 @@ public class TypeSubstitutor {
|
|||||||
// throw new SubstitutionException(""); // TODO : error message
|
// throw new SubstitutionException(""); // TODO : error message
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
return new TypeProjection(effectiveProjectionKindValue, specializeType(effectiveTypeValue, effectiveContextVariance));
|
return new TypeProjection(effectiveProjectionKindValue, specializeType(effectiveTypeValue, effectiveContextVariance));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Variance asymmetricOr(Variance a, Variance b) {
|
private static Variance asymmetricOr(Variance a, Variance b) {
|
||||||
|
|||||||
+64
-17
@@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
|||||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -16,21 +17,32 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class ConstraintSystemImpl implements ConstraintSystem {
|
public class ConstraintSystemImpl implements ConstraintSystem {
|
||||||
|
|
||||||
|
public static TypeSubstitutor makeConstantSubstitutor(Collection<TypeParameterDescriptor> typeParameterDescriptors, JetType type) {
|
||||||
|
final Set<TypeConstructor> constructors = Sets.newHashSet();
|
||||||
|
for (TypeParameterDescriptor typeParameterDescriptor : typeParameterDescriptors) {
|
||||||
|
constructors.add(typeParameterDescriptor.getTypeConstructor());
|
||||||
|
}
|
||||||
|
final TypeProjection projection = new TypeProjection(type);
|
||||||
|
|
||||||
|
return TypeSubstitutor.create(new TypeSubstitutor.TypeSubstitution() {
|
||||||
|
@Override
|
||||||
|
public TypeProjection get(TypeConstructor key) {
|
||||||
|
if (constructors.contains(key)) {
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class LoopInTypeVariableConstraintsException extends RuntimeException {
|
private static class LoopInTypeVariableConstraintsException extends RuntimeException {
|
||||||
private LoopInTypeVariableConstraintsException() {
|
public LoopInTypeVariableConstraintsException() {}
|
||||||
}
|
|
||||||
|
|
||||||
private LoopInTypeVariableConstraintsException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LoopInTypeVariableConstraintsException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LoopInTypeVariableConstraintsException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class TypeValue {
|
public static abstract class TypeValue {
|
||||||
@@ -168,7 +180,42 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
private final Map<TypeParameterDescriptor, UnknownType> unknownTypes = Maps.newHashMap();
|
private final Map<TypeParameterDescriptor, UnknownType> unknownTypes = Maps.newHashMap();
|
||||||
private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
||||||
|
|
||||||
private final JetTypeChecker.TypeCheckingProcedure constraintExpander = new JetTypeChecker.TypeCheckingProcedure(new JetTypeChecker.TypingConstraintBuilder() {
|
private static final class TypeConstraintBuilderAdapter implements JetTypeChecker.TypingConstraintBuilder {
|
||||||
|
private final JetTypeChecker.TypingConstraintBuilder delegate;
|
||||||
|
|
||||||
|
private TypeConstraintBuilderAdapter(JetTypeChecker.TypingConstraintBuilder delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b) {
|
||||||
|
boolean result = delegate.assertEqualTypes(a, b);
|
||||||
|
if (!result) {
|
||||||
|
println("-- Failed to equate " + a + " and " + b);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
boolean result = delegate.assertSubtype(subtype, supertype);
|
||||||
|
if (!result) {
|
||||||
|
println("-- " + subtype + " can't be a subtype of " + supertype);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
boolean result = delegate.noCorrespondingSupertype(subtype, supertype);
|
||||||
|
if (!result) {
|
||||||
|
println("-- " + subtype + " has supertype corresponding to " + supertype);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final JetTypeChecker.TypeCheckingProcedure constraintExpander = new JetTypeChecker.TypeCheckingProcedure(new TypeConstraintBuilderAdapter(new JetTypeChecker.TypingConstraintBuilder() {
|
||||||
@Override
|
@Override
|
||||||
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b) {
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b) {
|
||||||
TypeValue aValue = getTypeValueFor(a);
|
TypeValue aValue = getTypeValueFor(a);
|
||||||
@@ -217,7 +264,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType;
|
return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
}));
|
||||||
|
|
||||||
public ConstraintSystemImpl() {}
|
public ConstraintSystemImpl() {}
|
||||||
|
|
||||||
@@ -257,7 +304,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void mergeUnknowns(@NotNull UnknownType a, @NotNull UnknownType b) {
|
private void mergeUnknowns(@NotNull UnknownType a, @NotNull UnknownType b) {
|
||||||
|
System.err.println("!!!mergeUnknowns() is not implemented!!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// KT-442 Type inference fails on with()
|
||||||
|
|
||||||
|
fun <T> funny(f : fun() : T) : T = f()
|
||||||
|
|
||||||
|
fun testFunny() {
|
||||||
|
val a : Int = funny {1}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> funny2(f : fun(t : T) : T) : T <!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>{}<!>
|
||||||
|
|
||||||
|
fun testFunny2() {
|
||||||
|
val a : Int = funny2 {it}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
return generic_invoker { it }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> generic_invoker(gen : fun (String) : T) : T {
|
||||||
|
return gen("")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> T.with(f : fun T.()) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
val a = 1 with {
|
||||||
|
plus(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user