Constraint priorities integrated

This commit is contained in:
Andrey Breslav
2011-12-14 13:12:36 +04:00
parent 54336a285d
commit be0165f1e5
16 changed files with 237 additions and 98 deletions
@@ -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) : 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)) {
@@ -20,12 +20,13 @@ import java.util.Map;
public class ResolutionDebugInfo {
public static final WritableSlice<One, List<? extends ResolutionTask<? extends CallableDescriptor>>> TASKS = Slices.createSimpleSlice();
public static final WritableSlice<One, ResolvedCall<? extends CallableDescriptor>> RESULT = Slices.createSimpleSlice();
public static final WritableSlice<One, StringBuilder> ERRORS = Slices.createSimpleSlice();
public static final WritableSlice<One, StringBuilder> LOG = Slices.createSimpleSlice();
public static final WritableSlice<One, Map<TypeParameterDescriptor, BoundsOwner>> BOUNDS_FOR_UNKNOWNS = Slices.createSimpleSlice();
public static final WritableSlice<One, Map<JetType, BoundsOwner>> BOUNDS_FOR_KNOWNS = Slices.createSimpleSlice();
public static final WritableSlice<One, ConstraintSystemSolution> SOLUTION = Slices.createSimpleSlice();
public static final WritableSlice<One, Collection<TypeParameterDescriptor>> UNKNOWNS = Slices.createSimpleSlice();
public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, StringBuilder> ERRORS = Slices.createSimpleSlice();
public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, StringBuilder> LOG = Slices.createSimpleSlice();
public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, Map<TypeParameterDescriptor, BoundsOwner>> BOUNDS_FOR_UNKNOWNS = Slices.createSimpleSlice();
public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, Map<JetType, BoundsOwner>> BOUNDS_FOR_KNOWNS = Slices.createSimpleSlice();
public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, ConstraintSystemSolution> SOLUTION = Slices.createSimpleSlice();
public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, Collection<TypeParameterDescriptor>> UNKNOWNS = Slices.createSimpleSlice();
static {
BasicWritableSlice.initSliceDebugNames(ResolutionDebugInfo.class);
@@ -13,7 +13,7 @@ import java.util.Collection;
*
* @author abreslav
*/
/*package*/ class ResolutionTask<D extends CallableDescriptor> {
public class ResolutionTask<D extends CallableDescriptor> {
private final Call call;
private final Collection<ResolvedCallImpl<D>> candidates;
private final DataFlowInfo dataFlowInfo;
@@ -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<TypeParameterDescriptor, TypeValue> 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<SubtypingConstraint> constraintsToEnsureAfterInference = new PriorityQueue<SubtypingConstraint>(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<T> <: List<Int>
// for (Map.Entry<JetType, TypeValue> 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<TypeValue> 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<TypeParameterDescriptor, TypeValue> 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<TypeValue> 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<TypeValue> lowerBounds = unknown.getLowerBounds();
Set<TypeValue> upperBounds = unknown.getUpperBounds();
if (!lowerBounds.isEmpty()) {
Set<JetType> 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<JetType> 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<JetType> getTypes(Set<TypeValue> lowerBounds) {
Set<JetType> types = Sets.newHashSet();
for (TypeValue lowerBound : lowerBounds) {
types.add(lowerBound.getType());
}
return types;
}
private void transitiveClosure(TypeValue current, Set<TypeValue> 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
@@ -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<? extends CallableDescriptor> candidateCall;
public DebugConstraintResolutionListener(@NotNull ResolutionDebugInfo.Data debugInfo) {
public DebugConstraintResolutionListener(@NotNull ResolvedCall<? extends CallableDescriptor> candidateCall, @NotNull ResolutionDebugInfo.Data debugInfo) {
this.debugInfo = debugInfo;
this.candidateCall = candidateCall;
}
@Override
public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue) {
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
Map<TypeParameterDescriptor, BoundsOwner> map = debugInfo.get(BOUNDS_FOR_UNKNOWNS);
Map<TypeParameterDescriptor, BoundsOwner> 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<JetType,BoundsOwner> map = debugInfo.get(BOUNDS_FOR_KNOWNS);
Map<JetType,BoundsOwner> 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<TypeParameterDescriptor> 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);
@@ -36,4 +36,9 @@ public class SubtypingConstraint {
public String getErrorMessage() {
return type.makeErrorMessage(this);
}
@Override
public String toString() {
return getSubtype() + " :< " + getSupertype();
}
}
@@ -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<TypeValue> 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() : ""));
}
}
@@ -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)) {
@@ -42,7 +42,7 @@ fun main(args : Array<String>) {
val b = fooT2<Int>()(1)
b : Int
fooT2()(1) // : Any?
<!TYPE_INFERENCE_FAILED!>fooT2()<!>(1) // : Any?
<!CALLEE_NOT_A_FUNCTION!>1<!>()
<!CALLEE_NOT_A_FUNCTION!>1<!>{}
@@ -6,7 +6,8 @@ fun test(<!UNUSED_PARAMETER!>a<!> : annotation.RetentionPolicy) {
}
fun test() {
java.util.Collections.emptyList()
java.util.Collections.<!TYPE_INFERENCE_FAILED!>emptyList()<!>
val <!UNUSED_VARIABLE!>a<!> : java.util.Collection<String>? = java.util.Collections.emptyList()
}
fun test(<!UNUSED_PARAMETER!>a<!> : java.lang.Comparable<Int>) {
@@ -21,7 +21,7 @@ fun test(<!UNUSED_PARAMETER!>l<!> : java.util.List<Int>) {
Collections.<!UNRESOLVED_REFERENCE!>emptyList<!>
Collections.emptyList<Int>
Collections.emptyList<Int>()
Collections.emptyList()
Collections.<!TYPE_INFERENCE_FAILED!>emptyList()<!>
Collections.singleton<Int>(1) : Set<Int>?
Collections.singleton<Int>(<!ERROR_COMPILE_TIME_VALUE!>1.0<!>)
@@ -0,0 +1,9 @@
fun fooT2<T>() : fun(t : T) : T {
return {it}
}
val n : Nothing = null.sure()
fun test() {
<!TYPE_INFERENCE_FAILED!>fooT2()<!>(1)
}
@@ -9,15 +9,15 @@ fun foo(a: A) {
a.gen() //it works: Unit is derived
}
val <!UNUSED_VARIABLE!>u<!>: Unit = a.gen() //type mismatch, but Unit can be derived
val <!UNUSED_VARIABLE!>u<!>: Unit = a.gen() // Unit should be inferred
if (true) {
a.gen() //it works: Unit is derived
a.<!TYPE_INFERENCE_FAILED!>gen()<!> // Shouldn't work: no info for inference
}
val <!UNUSED_VARIABLE!>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.<!TYPE_INFERENCE_FAILED!>gen()<!> // Shouldn't work: no info for inference
}
@@ -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);
@@ -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<? extends CallableDescriptor> 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<? extends ResolutionTask<? extends CallableDescriptor>> resolutionTasks = debugInfo.get(TASKS);
for (ResolutionTask<? extends CallableDescriptor> resolutionTask : resolutionTasks) {
for (ResolvedCallImpl<? extends CallableDescriptor> resolvedCall : resolutionTask.getCandidates()) {
renderResolutionLogForCall(debugInfo, resolvedCall, result);
}
}
StringBuilder log = debugInfo.get(LOG);
if (log != null) {
result.append("Log: \n").append(log).append(bar);
}
Map<JetType, BoundsOwner> knowns = debugInfo.get(BOUNDS_FOR_KNOWNS);
renderMap(knowns, result);
Map<TypeParameterDescriptor, BoundsOwner> 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<? extends CallableDescriptor> 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<JetType, BoundsOwner> knowns = debugInfo.getByKey(BOUNDS_FOR_KNOWNS, resolvedCall);
renderMap(knowns, result);
Map<TypeParameterDescriptor, BoundsOwner> unknowns = debugInfo.getByKey(BOUNDS_FOR_UNKNOWNS, resolvedCall);
renderMap(unknowns, result);
result.append(BAR);
}
private <K> void renderMap(Map<K, BoundsOwner> map, StringBuilder builder) {
if (map == null) return;
+1 -1
View File
@@ -19,7 +19,7 @@ fun test(<warning>l</warning> : java.util.List<Int>) {
Collections.<error>emptyList</error>
Collections.emptyList<Int>
Collections.emptyList<Int>()
Collections.emptyList()
Collections.<error>emptyList()</error>
Collections.singleton<Int>(1) : Set<Int>?
Collections.singleton<Int>(<error>1.0</error>)