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.psi.*;
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.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 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") {
@Override
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.ConstraintSystemSolution;
import org.jetbrains.jet.lang.types.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.types.inference.SolutionStatus;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
@@ -312,8 +313,9 @@ public class CallResolver {
}
@Override
public void typeInferenceFailed(@NotNull BindingTrace trace) {
trace.report(TYPE_INFERENCE_FAILED.on(call.getCallNode()));
public void typeInferenceFailed(@NotNull BindingTrace trace, SolutionStatus status) {
assert !status.isSuccessful();
trace.report(TYPE_INFERENCE_FAILED.on(call.getCallNode(), status));
}
@Override
@@ -410,6 +412,8 @@ public class CallResolver {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
}
TypeSubstitutor substituteUnknown = ConstraintSystemImpl.makeConstantSubstitutor(candidate.getTypeParameters(), ErrorUtils.createErrorType("Unknown"));
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
ResolvedValueArgument valueArgument = entry.getValue();
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
@@ -417,10 +421,14 @@ public class CallResolver {
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor);
for (JetExpression expression : valueArgument.getArgumentExpressions()) {
// JetExpression expression = valueArgument.getArgumentExpression();
// 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) {
constraintSystem.addSubtypingConstraint(type, effectiveExpectedType);
}
@@ -450,10 +458,14 @@ public class CallResolver {
for (TypeParameterDescriptor typeParameterDescriptor : candidateCall.getCandidateDescriptor().getTypeParameters()) {
candidateCall.recordTypeArgument(typeParameterDescriptor, solution.getValue(typeParameterDescriptor));
}
// Here we type check the arguments with inferred types expected
checkValueArgumentTypes(scope, candidateCall);
candidateCall.setStatus(SUCCESS);
}
else {
tracing.typeInferenceFailed(temporaryTrace);
tracing.typeInferenceFailed(temporaryTrace, solution.getStatus());
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.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.inference.SolutionStatus;
import java.util.Collection;
@@ -48,7 +49,7 @@ import java.util.Collection;
public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {}
@Override
public void typeInferenceFailed(@NotNull BindingTrace trace) {}
public void typeInferenceFailed(@NotNull BindingTrace trace, SolutionStatus status) {}
@Override
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {}
@@ -79,7 +80,7 @@ import java.util.Collection;
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);
@@ -18,5 +18,5 @@ public interface JetType extends Annotated {
JetScope getMemberScope();
@Override
public boolean equals(Object other);
boolean equals(Object other);
}
@@ -123,6 +123,8 @@ public class TypeSubstitutor {
@NotNull
private JetType unsafeSubstitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) throws SubstitutionException {
if (ErrorUtils.isErrorType(type)) return type;
TypeConstructor constructor = type.getConstructor();
TypeProjection value = substitution.get(constructor);
if (value != null) {
@@ -140,6 +142,8 @@ public class TypeSubstitutor {
}
private JetType specializeType(JetType subjectType, Variance callSiteVariance) throws SubstitutionException {
if (ErrorUtils.isErrorType(subjectType)) return subjectType;
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
List<TypeProjection> arguments = subjectType.getArguments();
for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) {
@@ -166,6 +170,8 @@ public class TypeSubstitutor {
@NotNull TypeParameterDescriptor correspondingTypeParameter,
@NotNull Variance contextCallSiteVariance) throws SubstitutionException {
JetType typeToSubstituteIn = passedProjection.getType();
if (ErrorUtils.isErrorType(typeToSubstituteIn)) return passedProjection;
Variance passedProjectionKind = passedProjection.getProjectionKind();
Variance parameterVariance = correspondingTypeParameter.getVariance();
@@ -230,7 +236,7 @@ public class TypeSubstitutor {
// 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) {
@@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.types.*;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -16,21 +17,32 @@ import java.util.Set;
*/
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 LoopInTypeVariableConstraintsException() {
}
private LoopInTypeVariableConstraintsException(String message) {
super(message);
}
private LoopInTypeVariableConstraintsException(String message, Throwable cause) {
super(message, cause);
}
private LoopInTypeVariableConstraintsException(Throwable cause) {
super(cause);
}
public LoopInTypeVariableConstraintsException() {}
}
public static abstract class TypeValue {
@@ -168,7 +180,42 @@ public class ConstraintSystemImpl implements ConstraintSystem {
private final Map<TypeParameterDescriptor, UnknownType> unknownTypes = Maps.newHashMap();
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
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b) {
TypeValue aValue = getTypeValueFor(a);
@@ -217,7 +264,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType;
}
});
}));
public ConstraintSystemImpl() {}
@@ -257,7 +304,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
}
private void mergeUnknowns(@NotNull UnknownType a, @NotNull UnknownType b) {
System.err.println("!!!mergeUnknowns() is not implemented!!!");
}
@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)
}
}