diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 024eae017e2..da7edd9d6fe 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -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 TYPE_INFERENCE_FAILED = ParameterizedDiagnosticFactory1.create(ERROR, "Type inference failed: {0}"); ParameterizedDiagnosticFactory1 WRONG_NUMBER_OF_TYPE_ARGUMENTS = new ParameterizedDiagnosticFactory1(ERROR, "{0} type arguments expected") { @Override protected String makeMessageFor(@NotNull Integer argument) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index e6db420488d..0d6ab9209ec 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -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 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); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java index d06b99d2068..40d06bf6999 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java @@ -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); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetType.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetType.java index 35d0c24f26a..0fbef22c2d8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetType.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetType.java @@ -18,5 +18,5 @@ public interface JetType extends Annotated { JetScope getMemberScope(); @Override - public boolean equals(Object other); + boolean equals(Object other); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java index 0093d9536df..48699139afd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -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 newArguments = new ArrayList(); List 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) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemImpl.java index 43cc85b9f99..db786b2b28d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemImpl.java @@ -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 typeParameterDescriptors, JetType type) { + final Set 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 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 diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt442.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt442.jet new file mode 100644 index 00000000000..3138ed71587 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt442.jet @@ -0,0 +1,31 @@ +// KT-442 Type inference fails on with() + +fun funny(f : fun() : T) : T = f() + +fun testFunny() { + val a : Int = funny {1} +} + +fun funny2(f : fun(t : T) : T) : T {} + +fun testFunny2() { + val a : Int = funny2 {it} +} + +fun box() : String { + return generic_invoker { it } +} + +fun generic_invoker(gen : fun (String) : T) : T { + return gen("") +} + +fun T.with(f : fun T.()) { + f() +} + +fun main(args : Array) { + val a = 1 with { + plus(1) + } +} \ No newline at end of file