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 b5d04a21d8e..176524e2c9a 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 @@ -101,7 +101,7 @@ public class CallResolver { } @Nullable - public FunctionDescriptor resolveSimpleCallToFunctionDescriptor( + private FunctionDescriptor resolveSimpleCallToFunctionDescriptor( @NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull final Call call, @@ -439,7 +439,7 @@ public class CallResolver { ResolutionDebugInfo.Data debugInfo = trace.get(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, task.getCall().getCallElement()); - ConstraintSystem constraintSystem = new ConstraintSystemImpl(new DebugConstraintResolutionListener(debugInfo)); + ConstraintSystem constraintSystem = new ConstraintSystemWithPriorities(new DebugConstraintResolutionListener(candidateCall, debugInfo)); // If the call is recursive, e.g. // fun foo(t : T) : T = foo(t) @@ -472,7 +472,7 @@ public class CallResolver { TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(temporaryTrace); ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, traceForUnknown); JetType type = temporaryServices.getType(scope, expression, substituteDontCare.substitute(valueParameterDescriptor.getOutType(), Variance.INVARIANT)); - if (type != null) { + if (type != null && !ErrorUtils.isErrorType(type)) { constraintSystem.addSubtypingConstraint(VALUE_ARGUMENT.assertSubtyping(type, effectiveExpectedType)); } else { @@ -513,7 +513,16 @@ public class CallResolver { } else { tracing.typeInferenceFailed(temporaryTrace, solution.getStatus()); - candidateCall.setStatus(checkAllValueArguments(scope, tracing, task, candidateCall)); +// // Substitute DONT_CARE types to make further type checking as tolerant as possible +// D candidateWithDontCares = (D) candidate.substitute(TypeSubstitutor.makeConstantSubstitutor(candidate.getTypeParameters(), DONT_CARE)); +// if (candidateWithDontCares == null) { +// candidateWithDontCares = (D) candidate.substitute(TypeSubstitutor.makeConstantSubstitutor(candidate.getTypeParameters(), Variance.INVARIANT, DONT_CARE)); +// } +// if (!ErrorUtils.isErrorType(candidateWithDontCares.getReturnType())) { +// // Returning an error type provokes overload resolution ambiguities that mask errors +// candidateCall.setResultingDescriptor(candidateWithDontCares); +// } + candidateCall.setStatus(OTHER_ERROR.combine(checkAllValueArguments(scope, tracing, task, candidateCall))); } } else { @@ -699,7 +708,7 @@ public class CallResolver { for (JetExpression argumentExpression : argumentExpressions) { ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, candidateCall.getTrace()); JetType type = temporaryServices.getType(scope, argumentExpression, parameterType, dataFlowInfo); - if (type == null) { + if (type == null || ErrorUtils.isErrorType(type)) { candidateCall.argumentHasNoType(); } else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionDebugInfo.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionDebugInfo.java index d254ac771e4..91d2e14013b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionDebugInfo.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionDebugInfo.java @@ -20,12 +20,13 @@ import java.util.Map; public class ResolutionDebugInfo { public static final WritableSlice>> TASKS = Slices.createSimpleSlice(); public static final WritableSlice> RESULT = Slices.createSimpleSlice(); - public static final WritableSlice ERRORS = Slices.createSimpleSlice(); - public static final WritableSlice LOG = Slices.createSimpleSlice(); - public static final WritableSlice> BOUNDS_FOR_UNKNOWNS = Slices.createSimpleSlice(); - public static final WritableSlice> BOUNDS_FOR_KNOWNS = Slices.createSimpleSlice(); - public static final WritableSlice SOLUTION = Slices.createSimpleSlice(); - public static final WritableSlice> UNKNOWNS = Slices.createSimpleSlice(); + + public static final WritableSlice, StringBuilder> ERRORS = Slices.createSimpleSlice(); + public static final WritableSlice, StringBuilder> LOG = Slices.createSimpleSlice(); + public static final WritableSlice, Map> BOUNDS_FOR_UNKNOWNS = Slices.createSimpleSlice(); + public static final WritableSlice, Map> BOUNDS_FOR_KNOWNS = Slices.createSimpleSlice(); + public static final WritableSlice, ConstraintSystemSolution> SOLUTION = Slices.createSimpleSlice(); + public static final WritableSlice, Collection> UNKNOWNS = Slices.createSimpleSlice(); static { BasicWritableSlice.initSliceDebugNames(ResolutionDebugInfo.class); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java index dc2f978517c..7057b8d556a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java @@ -13,7 +13,7 @@ import java.util.Collection; * * @author abreslav */ -/*package*/ class ResolutionTask { +public class ResolutionTask { private final Call call; private final Collection> candidates; private final DataFlowInfo dataFlowInfo; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemWithPriorities.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemWithPriorities.java index fd408957971..3da752a9950 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemWithPriorities.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemWithPriorities.java @@ -10,7 +10,10 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure; import org.jetbrains.jet.lang.types.checker.TypingConstraints; -import java.util.*; +import java.util.Comparator; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.PARAMETER_BOUND; @@ -200,7 +203,7 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { else { // One unknown and one known if (upper.isKnown()) { - if (TypeUtils.canHaveSubtypes(typeChecker, upper.getType())) { + if (!TypeUtils.canHaveSubtypes(typeChecker, upper.getType())) { // Upper bound is final -> we have to equate the lower bounds to it return expandEqualityConstraint(lower, upper); } @@ -225,17 +228,8 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { Solution solution = new Solution(); // At this point we only have type values, no bounds added for them, no values computed for unknown types - // Generate low-priority constraints from bounds - for (Map.Entry entry : Sets.newHashSet(unknownTypes.entrySet())) { - TypeParameterDescriptor typeParameterDescriptor = entry.getKey(); - TypeValue typeValue = entry.getValue(); - for (JetType upperBound : typeParameterDescriptor.getUpperBounds()) { - addSubtypingConstraint(PARAMETER_BOUND.assertSubtyping(typeValue.getOriginalType(), getTypeValueFor(upperBound).getOriginalType())); - } - for (JetType lowerBound : typeParameterDescriptor.getLowerBounds()) { - addSubtypingConstraint(PARAMETER_BOUND.assertSubtyping(getTypeValueFor(lowerBound).getOriginalType(), typeValue.getOriginalType())); - } - } + // After the parameters are inferred we will make sure the initial constraints are satisfied + PriorityQueue constraintsToEnsureAfterInference = new PriorityQueue(constraintQueue); // Expand and solve constraints while (!constraintQueue.isEmpty()) { @@ -247,7 +241,7 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { boolean success = expandSubtypingConstraint(lower, upper); if (!success) { solution.registerError(constraint.getErrorMessage()); - break; +// break; } // (???) Propagate info @@ -256,25 +250,6 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { if (unsolvedUnknowns.isEmpty()) break; } - // Now, let's check the rest of the constraints - - // Expand custom bounds, e.g. List <: List -// for (Map.Entry entry : Sets.newHashSet(knownTypes.entrySet())) { -// JetType jetType = entry.getKey(); -// TypeValue typeValue = entry.getValue(); -// -// for (TypeValue upperBound : typeValue.getUpperBounds()) { -// if (upperBound.isKnown()) { -// boolean ok = constraintExpander.isSubtypeOf(jetType, upperBound.getType()); -// if (!ok) { -// listener.error("Error while expanding '" + jetType + " :< " + upperBound.getType() + "'"); -// return new Solution().registerError("Mismatch while expanding constraints"); -// } -// } -// } -// -// // Lower bounds. Probably not needed for known types, as everything is symmetrical anyway -// } // effective bounds for each node // Set visited = Sets.newHashSet(); @@ -282,6 +257,16 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { // transitiveClosure(unknownType, visited); // } + assert constraintQueue.isEmpty() || unsolvedUnknowns.isEmpty() : constraintQueue + " " + unsolvedUnknowns; + + for (TypeValue unknown : unsolvedUnknowns) { + if (!computeValueFor(unknown)) { + listener.error("Not enough data to compute value for ", unknown); + solution.registerError("Not enough data to compute value for " + unknown + ". Please, specify type arguments explicitly"); + } + } + + // Logging for (TypeValue unknownType : unknownTypes.values()) { listener.constraintsForUnknown(unknownType.getTypeParameterDescriptor(), unknownType); } @@ -289,23 +274,117 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { listener.constraintsForKnownType(knownType.getType(), knownType); } + // Now, let's check the rest of the constraints and re-check the initial ones + + // Add constraints for the declared bounds for parameters + // Maybe these bounds could reconcile some resolution earlier? Then, move them up + for (Map.Entry entry : Sets.newHashSet(unknownTypes.entrySet())) { + TypeParameterDescriptor typeParameterDescriptor = entry.getKey(); + TypeValue unknown = entry.getValue(); + for (JetType upperBound : typeParameterDescriptor.getUpperBounds()) { + constraintsToEnsureAfterInference.add(PARAMETER_BOUND.assertSubtyping(unknown.getOriginalType(), getTypeValueFor(upperBound).getOriginalType())); +// unknown.addUpperBound(new TypeValue(upperBound)); + } + for (JetType lowerBound : typeParameterDescriptor.getLowerBounds()) { + constraintsToEnsureAfterInference.add(PARAMETER_BOUND.assertSubtyping(getTypeValueFor(lowerBound).getOriginalType(), unknown.getOriginalType())); +// unknown.addLowerBound(new TypeValue(lowerBound)); + } + } + + // Find inconsistencies - // Compute values and check that all bounds are respected by solutions: + // Check that all bounds are respected by solutions: // we have set some of them from equality constraints with known types // and thus the bounds may be violated if some of the constraints conflict - for (TypeValue unknownType : unknownTypes.values()) { - check(unknownType, solution); - } - for (TypeValue knownType : knownTypes.values()) { - check(knownType, solution); + + + for (SubtypingConstraint constraint : constraintsToEnsureAfterInference) { + JetType substitutedSubtype = solution.getSubstitutor().substitute(constraint.getSubtype(), Variance.INVARIANT); // TODO + if (substitutedSubtype == null) continue; + JetType substitutedSupertype = solution.getSubstitutor().substitute(constraint.getSupertype(), Variance.INVARIANT); // TODO + if (substitutedSupertype == null) continue; + + if (!typeChecker.isSubtypeOf(substitutedSubtype, substitutedSupertype)) { + solution.registerError(constraint.getErrorMessage()); + listener.error("Constraint violation: ", substitutedSubtype, " :< ", substitutedSupertype, " message: ", constraint.getErrorMessage()); + } } + +// for (TypeValue unknownType : unknownTypes.values()) { +// check(unknownType, solution); +// } +// +// for (TypeValue knownType : knownTypes.values()) { +// check(knownType, solution); +// } + + listener.done(solution, unknownTypes.keySet()); return solution; } + private final Set beingComputed = Sets.newHashSet(); + + public boolean computeValueFor(TypeValue unknown) { + assert !unknown.isKnown(); + if (beingComputed.contains(unknown)) { + throw new LoopInTypeVariableConstraintsException(); + } + if (!unknown.hasValue()) { + beingComputed.add(unknown); + try { + if (unknown.getPositionVariance() == Variance.IN_VARIANCE) { + // maximal solution + throw new UnsupportedOperationException(); + } + else { + // minimal solution + + Set lowerBounds = unknown.getLowerBounds(); + Set upperBounds = unknown.getUpperBounds(); + if (!lowerBounds.isEmpty()) { + Set types = getTypes(lowerBounds); + + JetType commonSupertype = CommonSupertypes.commonSupertype(types); + for (TypeValue upperBound : upperBounds) { + if (!typeChecker.isSubtypeOf(commonSupertype, upperBound.getType())) { + return false; + } + } + + listener.log("minimal solution from lower bounds for ", this, " is ", commonSupertype); + assignValueTo(unknown, commonSupertype); + } + else if (!upperBounds.isEmpty()) { + Set types = getTypes(upperBounds); + JetType intersect = TypeUtils.intersect(typeChecker, types); + + if (intersect == null) return false; + + assignValueTo(unknown, intersect); + } + else { + return false; // No bounds to compute the value from + } + } + } finally { + beingComputed.remove(unknown); + } + } + return true; + } + + private static Set getTypes(Set lowerBounds) { + Set types = Sets.newHashSet(); + for (TypeValue lowerBound : lowerBounds) { + types.add(lowerBound.getType()); + } + return types; + } + private void transitiveClosure(TypeValue current, Set visited) { if (!visited.add(current)) { return; @@ -324,6 +403,7 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { } private void check(TypeValue typeValue, Solution solution) { + if (!typeValue.hasValue()) return; try { JetType resultingType = typeValue.getType(); JetType type = solution.getSubstitutor().substitute(resultingType, Variance.INVARIANT); // TODO @@ -377,7 +457,11 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { if (!unknownTypes.containsKey(descriptor)) return null; - TypeProjection typeProjection = new TypeProjection(getValue(descriptor)); + JetType value = getValue(descriptor); + if (value == null) { + return null; + } + TypeProjection typeProjection = new TypeProjection(value); listener.log(descriptor, " |-> ", typeProjection); @@ -411,7 +495,8 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { @Override public JetType getValue(TypeParameterDescriptor typeParameterDescriptor) { - return getTypeVariable(typeParameterDescriptor).getType(); + TypeValue typeVariable = getTypeVariable(typeParameterDescriptor); + return typeVariable.hasValue() ? typeVariable.getType() : null; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/DebugConstraintResolutionListener.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/DebugConstraintResolutionListener.java index 52edf22c3f0..6f3415538a0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/DebugConstraintResolutionListener.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/DebugConstraintResolutionListener.java @@ -2,8 +2,10 @@ package org.jetbrains.jet.lang.resolve.calls.inference; import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; import java.util.Map; @@ -17,18 +19,20 @@ import static org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo.*; public class DebugConstraintResolutionListener implements ConstraintResolutionListener { private final ResolutionDebugInfo.Data debugInfo; + private final ResolvedCall candidateCall; - public DebugConstraintResolutionListener(@NotNull ResolutionDebugInfo.Data debugInfo) { + public DebugConstraintResolutionListener(@NotNull ResolvedCall candidateCall, @NotNull ResolutionDebugInfo.Data debugInfo) { this.debugInfo = debugInfo; + this.candidateCall = candidateCall; } @Override public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue) { if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return; - Map map = debugInfo.get(BOUNDS_FOR_UNKNOWNS); + Map map = debugInfo.getByKey(BOUNDS_FOR_UNKNOWNS, candidateCall); if (map == null) { map = Maps.newLinkedHashMap(); - debugInfo.set(BOUNDS_FOR_UNKNOWNS, map); + debugInfo.putByKey(BOUNDS_FOR_UNKNOWNS, candidateCall, map); } map.put(typeParameterDescriptor, typeValue); } @@ -36,10 +40,10 @@ public class DebugConstraintResolutionListener implements ConstraintResolutionLi @Override public void constraintsForKnownType(JetType type, BoundsOwner typeValue) { if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return; - Map map = debugInfo.get(BOUNDS_FOR_KNOWNS); + Map map = debugInfo.getByKey(BOUNDS_FOR_KNOWNS, candidateCall); if (map == null) { map = Maps.newLinkedHashMap(); - debugInfo.set(BOUNDS_FOR_KNOWNS, map); + debugInfo.putByKey(BOUNDS_FOR_KNOWNS, candidateCall, map); } map.put(type, typeValue); } @@ -47,17 +51,17 @@ public class DebugConstraintResolutionListener implements ConstraintResolutionLi @Override public void done(ConstraintSystemSolution solution, Set typeParameterDescriptors) { if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return; - debugInfo.set(SOLUTION, solution); - debugInfo.set(UNKNOWNS, typeParameterDescriptors); + debugInfo.putByKey(SOLUTION, candidateCall, solution); + debugInfo.putByKey(UNKNOWNS, candidateCall, typeParameterDescriptors); } @Override public void log(Object... messageFragments) { if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return; - StringBuilder stringBuilder = debugInfo.get(LOG); + StringBuilder stringBuilder = debugInfo.getByKey(LOG, candidateCall); if (stringBuilder == null) { stringBuilder = new StringBuilder(); - debugInfo.set(LOG, stringBuilder); + debugInfo.putByKey(LOG, candidateCall, stringBuilder); } for (Object m : messageFragments) { stringBuilder.append(m); @@ -68,10 +72,10 @@ public class DebugConstraintResolutionListener implements ConstraintResolutionLi @Override public void error(Object... messageFragments) { if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return; - StringBuilder stringBuilder = debugInfo.get(ERRORS); + StringBuilder stringBuilder = debugInfo.getByKey(ERRORS, candidateCall); if (stringBuilder == null) { stringBuilder = new StringBuilder(); - debugInfo.set(ERRORS, stringBuilder); + debugInfo.putByKey(ERRORS, candidateCall, stringBuilder); } for (Object m : messageFragments) { stringBuilder.append(m); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/SubtypingConstraint.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/SubtypingConstraint.java index 5f62fb11233..77e01ea7303 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/SubtypingConstraint.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/SubtypingConstraint.java @@ -36,4 +36,9 @@ public class SubtypingConstraint { public String getErrorMessage() { return type.makeErrorMessage(this); } + + @Override + public String toString() { + return getSubtype() + " :< " + getSupertype(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeValue.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeValue.java index 837036e003f..48d6e24c57e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeValue.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeValue.java @@ -32,6 +32,7 @@ public class TypeValue implements BoundsOwner { this.positionVariance = null; this.typeParameterDescriptor = null; this.originalType = knownType; + this.value = knownType; } public boolean isKnown() { @@ -42,6 +43,11 @@ public class TypeValue implements BoundsOwner { return typeParameterDescriptor; } + @NotNull + public Variance getPositionVariance() { + return positionVariance; + } + @Override @NotNull public Set getUpperBounds() { @@ -79,4 +85,9 @@ public class TypeValue implements BoundsOwner { public boolean hasValue() { return value != null; } + + @Override + public String toString() { + return isKnown() ? getType().toString() : (getTypeParameterDescriptor() + (hasValue() ? " |-> " + getType() : "")); + } } 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 55c861b18c8..d3e77c5b6b1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -20,7 +20,7 @@ public class TypeSubstitutor { } final TypeProjection projection = new TypeProjection(type); - return create(new TypeSubstitution() { + return TypeSubstitutor.create(new TypeSubstitutor.TypeSubstitution() { @Override public TypeProjection get(TypeConstructor key) { if (constructors.contains(key)) { diff --git a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.jet b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.jet index 5e6ef793f1d..7e36dc38033 100644 --- a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.jet +++ b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.jet @@ -42,7 +42,7 @@ fun main(args : Array) { val b = fooT2()(1) b : Int - fooT2()(1) // : Any? + fooT2()(1) // : Any? 1() 1{} diff --git a/compiler/testData/diagnostics/tests/ResolveOfJavaGenerics.jet b/compiler/testData/diagnostics/tests/ResolveOfJavaGenerics.jet index ae44ace8caf..44264b416f4 100644 --- a/compiler/testData/diagnostics/tests/ResolveOfJavaGenerics.jet +++ b/compiler/testData/diagnostics/tests/ResolveOfJavaGenerics.jet @@ -6,7 +6,8 @@ fun test(a : annotation.RetentionPolicy) { } fun test() { - java.util.Collections.emptyList() + java.util.Collections.emptyList() + val a : java.util.Collection? = java.util.Collections.emptyList() } fun test(a : java.lang.Comparable) { diff --git a/compiler/testData/diagnostics/tests/ResolveToJava.jet b/compiler/testData/diagnostics/tests/ResolveToJava.jet index ff4d34b1cf7..28d49d5ee3f 100644 --- a/compiler/testData/diagnostics/tests/ResolveToJava.jet +++ b/compiler/testData/diagnostics/tests/ResolveToJava.jet @@ -21,7 +21,7 @@ fun test(l : java.util.List) { Collections.emptyList Collections.emptyList Collections.emptyList() - Collections.emptyList() + Collections.emptyList() Collections.singleton(1) : Set? Collections.singleton(1.0) diff --git a/compiler/testData/diagnostics/tests/inference/NoInferenceFromDeclaredBounds.jet b/compiler/testData/diagnostics/tests/inference/NoInferenceFromDeclaredBounds.jet new file mode 100644 index 00000000000..4436d18abf9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/NoInferenceFromDeclaredBounds.jet @@ -0,0 +1,9 @@ +fun fooT2() : fun(t : T) : T { + return {it} +} + +val n : Nothing = null.sure() + +fun test() { + fooT2()(1) +} diff --git a/compiler/testData/diagnostics/tests/regressions/kt353.jet b/compiler/testData/diagnostics/tests/regressions/kt353.jet index dffdaa68d48..bc2a4f6df2f 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt353.jet +++ b/compiler/testData/diagnostics/tests/regressions/kt353.jet @@ -9,15 +9,15 @@ fun foo(a: A) { a.gen() //it works: Unit is derived } - val u: Unit = a.gen() //type mismatch, but Unit can be derived + val u: Unit = a.gen() // Unit should be inferred if (true) { - a.gen() //it works: Unit is derived + a.gen() // Shouldn't work: no info for inference } val b : fun() : Unit = { if (true) { - a.gen() //type mismatch, but Unit can be derived + a.gen() // unit can be inferred } else { () @@ -28,5 +28,5 @@ fun foo(a: A) { a.gen() //type mismatch, but Int can be derived } - a.gen() //it works: Unit is derived + a.gen() // Shouldn't work: no info for inference } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/runtime/JetNpeTest.java b/compiler/tests/org/jetbrains/jet/runtime/JetNpeTest.java index a4ad31bfa9b..61e0397f34c 100644 --- a/compiler/tests/org/jetbrains/jet/runtime/JetNpeTest.java +++ b/compiler/tests/org/jetbrains/jet/runtime/JetNpeTest.java @@ -24,7 +24,7 @@ public class JetNpeTest extends CodegenTestCase { } public void testNull () throws Exception { - loadText("fun box() = if(null.sure() == 10) \"OK\" else \"fail\""); + loadText("fun box() = if((null : Int?).sure() == 10) \"OK\" else \"fail\""); // System.out.println(generateToText()); Method box = generateFunction("box"); assertThrows(box, NullPointerException.class, null); diff --git a/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java b/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java index 4b9a6fbc102..8f04d3eb557 100644 --- a/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java +++ b/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java @@ -28,11 +28,8 @@ import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo; -import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; -import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument; +import org.jetbrains.jet.lang.resolve.calls.*; import org.jetbrains.jet.lang.resolve.calls.inference.BoundsOwner; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.JetFileType; @@ -43,6 +40,7 @@ import org.jetbrains.jet.util.slicedmap.WritableSlice; import javax.swing.*; import java.awt.*; +import java.util.List; import java.util.Map; import static org.jetbrains.jet.lang.resolve.BindingContext.*; @@ -52,6 +50,9 @@ import static org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo.*; * @author abreslav */ public class ResolveToolwindow extends JPanel { + + public static final String BAR = "\n\n===\n\n"; + public static class Factory implements ToolWindowFactory { @Override public void createToolWindowContent(Project project, ToolWindow toolWindow) { @@ -176,36 +177,49 @@ public class ResolveToolwindow extends JPanel { } private String renderDebugInfo(PsiElement currentElement, @Nullable ResolutionDebugInfo.Data debugInfo, @Nullable ResolvedCall call) { - final String bar = "\n\n===\n\n"; - StringBuilder result = new StringBuilder(); - + if (debugInfo != null) { - StringBuilder errors = debugInfo.get(ERRORS); - if (errors != null) { - result.append("Errors: \n").append(errors).append(bar); + List> resolutionTasks = debugInfo.get(TASKS); + for (ResolutionTask resolutionTask : resolutionTasks) { + for (ResolvedCallImpl resolvedCall : resolutionTask.getCandidates()) { + renderResolutionLogForCall(debugInfo, resolvedCall, result); + } } - StringBuilder log = debugInfo.get(LOG); - if (log != null) { - result.append("Log: \n").append(log).append(bar); - } - - Map knowns = debugInfo.get(BOUNDS_FOR_KNOWNS); - renderMap(knowns, result); - Map unknowns = debugInfo.get(BOUNDS_FOR_UNKNOWNS); - renderMap(unknowns, result); - - result.append(bar); - call = debugInfo.get(RESULT); } - renderCall(result, call); + if (call != null) { + renderCall(result, call); + } + else { + result.append("Resolved call is null\n"); + } result.append(currentElement + ": " + currentElement.getText()); return result.toString(); } - + + private void renderResolutionLogForCall(Data debugInfo, ResolvedCallImpl resolvedCall, StringBuilder result) { + result.append("Trying to call ").append(resolvedCall.getCandidateDescriptor()).append("\n"); + StringBuilder errors = debugInfo.getByKey(ERRORS, resolvedCall); + if (errors != null) { + result.append("Errors: \n").append(errors).append(BAR); + } + + StringBuilder log = debugInfo.getByKey(LOG, resolvedCall); + if (log != null) { + result.append("Log: \n").append(log).append(BAR); + } + + Map knowns = debugInfo.getByKey(BOUNDS_FOR_KNOWNS, resolvedCall); + renderMap(knowns, result); + Map unknowns = debugInfo.getByKey(BOUNDS_FOR_UNKNOWNS, resolvedCall); + renderMap(unknowns, result); + + result.append(BAR); + } + private void renderMap(Map map, StringBuilder builder) { if (map == null) return; diff --git a/idea/testData/checker/ResolveToJava.jet b/idea/testData/checker/ResolveToJava.jet index e8cb67fceb3..6dfda6ac032 100644 --- a/idea/testData/checker/ResolveToJava.jet +++ b/idea/testData/checker/ResolveToJava.jet @@ -19,7 +19,7 @@ fun test(l : java.util.List) { Collections.emptyList Collections.emptyList Collections.emptyList() - Collections.emptyList() + Collections.emptyList() Collections.singleton(1) : Set? Collections.singleton(1.0)