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.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) {
|
||||
|
||||
+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.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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user