KT-442 Type inference fails on with()

This commit is contained in:
Andrey Breslav
2011-11-10 23:18:54 +03:00
parent 2c0ac86973
commit 4a87566fa2
7 changed files with 126 additions and 28 deletions
@@ -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) {
@@ -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)
}
}