Debug info for overload resolution/type inference

This commit is contained in:
Andrey Breslav
2011-12-07 19:45:21 +04:00
parent 2d94248731
commit ae03b4531e
8 changed files with 460 additions and 106 deletions
@@ -13,16 +13,13 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.inference.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.resolve.calls.inference.SolutionStatus;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
@@ -241,6 +238,12 @@ public class CallResolver {
@NotNull JetType expectedType,
@NotNull final List<ResolutionTask<D>> prioritizedTasks, // high to low priority
@NotNull final JetReferenceExpression reference) {
ResolutionDebugInfo.Data debugInfo = ResolutionDebugInfo.create();
trace.record(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, call.getCallElement(), debugInfo);
debugInfo.set(ResolutionDebugInfo.TASKS, prioritizedTasks);
TracingStrategy tracing = new TracingStrategy() {
@Override
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl<D> resolvedCall) {
@@ -371,6 +374,9 @@ public class CallResolver {
OverloadResolutionResults<D> results = performResolution(temporaryTrace, scope, expectedType, task, tracing);
if (results.isSuccess()) {
temporaryTrace.commit();
debugInfo.set(ResolutionDebugInfo.RESULT, results.getResult());
return results.getResult();
}
if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty()) {
@@ -381,6 +387,9 @@ public class CallResolver {
if (traceForFirstNonemptyCandidateSet != null) {
traceForFirstNonemptyCandidateSet.commit();
if (resultsForFirstNonemptyCandidateSet.singleDescriptor()) {
debugInfo.set(ResolutionDebugInfo.RESULT, resultsForFirstNonemptyCandidateSet.getResult());
return resultsForFirstNonemptyCandidateSet.getResult();
}
}
@@ -420,7 +429,10 @@ public class CallResolver {
if (!candidate.getTypeParameters().isEmpty()) {
// Type argument inference
ConstraintSystem constraintSystem = new ConstraintSystemImpl();
ResolutionDebugInfo.Data debugInfo = trace.get(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, task.getCall().getCallElement());
ConstraintSystem constraintSystem = new ConstraintSystemImpl(new DebugConstraintResolutionListener(debugInfo));
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
}
@@ -0,0 +1,115 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.util.slicedmap.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
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, ConstraintSystemImpl.TypeValue>> BOUNDS_FOR_UNKNOWNS = Slices.createSimpleSlice();
public static final WritableSlice<One, Map<JetType, ConstraintSystemImpl.TypeValue>> BOUNDS_FOR_KNOWNS = Slices.createSimpleSlice();
public static final WritableSlice<One, ConstraintSystemSolution> SOLUTION = Slices.createSimpleSlice();
public static final WritableSlice<One, Collection<TypeParameterDescriptor>> UNKNOWNS = Slices.createSimpleSlice();
static {
BasicWritableSlice.initSliceDebugNames(ResolutionDebugInfo.class);
}
public static boolean RESOLUTION_DEBUG_INFO_ENABLED = false;
public static boolean isResolutionDebugEnabled() {
Application application = ApplicationManager.getApplication();
return (RESOLUTION_DEBUG_INFO_ENABLED || application.isInternal()) && !application.isUnitTestMode();
}
public static final Data NO_DEBUG_INFO = new AbstractData() {
@Override
public String toString() {
return "NO_DEBUG_INFO";
}
@Override
public <K, V> V getByKey(ReadOnlySlice<K, V> slice, K key) {
return SlicedMap.DO_NOTHING.get(slice, key);
}
@Override
public <K, V> void putByKey(WritableSlice<K, V> slice, K key, V value) {
}
};
public static final WritableSlice<PsiElement, Data> RESOLUTION_DEBUG_INFO = new BasicWritableSlice<PsiElement, Data>(Slices.ONLY_REWRITE_TO_EQUAL) {
@Override
public boolean check(PsiElement key, Data value) {
return isResolutionDebugEnabled();
}
@Override
public Data computeValue(SlicedMap map, PsiElement key, Data value, boolean valueNotFound) {
if (valueNotFound) return NO_DEBUG_INFO;
return super.computeValue(map, key, value, valueNotFound);
}
};
public static Data create() {
return isResolutionDebugEnabled() ? new DataImpl() : NO_DEBUG_INFO;
}
public enum One { KEY }
public interface Data {
<K, V> V getByKey(ReadOnlySlice<K, V> slice, K key);
<K, V> void putByKey(WritableSlice<K, V> slice, K key, V value);
<V> void set(WritableSlice<One, ? super V> slice, V value);
<V> V get(ReadOnlySlice<One, V> slice);
}
private static abstract class AbstractData implements Data {
@Override
public <V> void set(WritableSlice<One, ? super V> slice, V value) {
putByKey(slice, One.KEY, value);
}
@Override
public <V> V get(ReadOnlySlice<One, V> slice) {
return getByKey(slice, One.KEY);
}
}
private static class DataImpl extends AbstractData {
private final MutableSlicedMap map = SlicedMapImpl.create();
@Override
public <K, V> V getByKey(ReadOnlySlice<K, V> slice, K key) {
return map.get(slice, key);
}
@Override
public <K, V> void putByKey(WritableSlice<K, V> slice, K key, V value) {
map.put(slice, key, value);
}
}
public static void println(Object message) {
if (isResolutionDebugEnabled()) {
System.out.println(message);
}
}
}
@@ -0,0 +1,19 @@
package org.jetbrains.jet.lang.resolve.calls.inference;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Set;
/**
* @author abreslav
*/
public interface ConstraintResolutionListener {
void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue);
void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue);
void done(ConstraintSystemSolution solution, Set<TypeParameterDescriptor> typeParameterDescriptors);
void log(Object message);
void error(Object message);
}
@@ -44,7 +44,6 @@ public class ConstraintSystemImpl implements ConstraintSystem {
});
}
private static class LoopInTypeVariableConstraintsException extends RuntimeException {
public LoopInTypeVariableConstraintsException() {}
}
@@ -80,6 +79,8 @@ public class ConstraintSystemImpl implements ConstraintSystem {
public abstract boolean equate(TypeValue other);
}
//==========================================================================================================================================================
private class UnknownType extends TypeValue {
private final TypeParameterDescriptor typeParameterDescriptor;
@@ -142,7 +143,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
}
}
println("minimal solution from lowerbounds for " + this + " is " + commonSupertype);
listener.log("minimal solution from lowerbounds for " + this + " is " + commonSupertype);
value = new KnownType(commonSupertype);
}
else {
@@ -238,16 +239,18 @@ public class ConstraintSystemImpl implements ConstraintSystem {
private static final class TypeConstraintBuilderAdapter implements TypingConstraints {
private final TypingConstraints delegate;
private final ConstraintResolutionListener listener;
private TypeConstraintBuilderAdapter(TypingConstraints delegate) {
private TypeConstraintBuilderAdapter(TypingConstraints delegate, ConstraintResolutionListener listener) {
this.delegate = delegate;
this.listener = listener;
}
@Override
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) {
boolean result = delegate.assertEqualTypes(a, b, typeCheckingProcedure);
if (!result) {
println("-- Failed to equate " + a + " and " + b);
listener.error("-- Failed to equate " + a + " and " + b);
}
return result;
}
@@ -256,7 +259,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
boolean result = delegate.assertEqualTypeConstructors(a, b);
if (!result) {
println("-- Type constructors are not equal: " + a + " and " + b);
listener.error("-- Type constructors are not equal: " + a + " and " + b);
}
return result;
}
@@ -265,7 +268,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) {
boolean result = delegate.assertSubtype(subtype, supertype, typeCheckingProcedure);
if (!result) {
println("-- " + subtype + " can't be a subtype of " + supertype);
listener.error("-- " + subtype + " can't be a subtype of " + supertype);
}
return result;
}
@@ -274,60 +277,67 @@ public class ConstraintSystemImpl implements ConstraintSystem {
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
boolean result = delegate.noCorrespondingSupertype(subtype, supertype);
if (!result) {
println("-- " + subtype + " has no supertype corresponding to " + supertype);
listener.error("-- " + subtype + " has no supertype corresponding to " + supertype);
}
return result;
}
}
private final TypeCheckingProcedure constraintExpander = new TypeCheckingProcedure(new TypeConstraintBuilderAdapter(new TypingConstraints() {
@Override
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) {
TypeValue aValue = getTypeValueFor(a);
TypeValue bValue = getTypeValueFor(b);
return aValue.equate(bValue);
}
private final TypeCheckingProcedure constraintExpander;
private final ConstraintResolutionListener listener;
@Override
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
return a.equals(b)
|| unknownTypes.containsKey(a.getDeclarationDescriptor())
|| unknownTypes.containsKey(b.getDeclarationDescriptor());
}
public ConstraintSystemImpl(ConstraintResolutionListener listener) {
this.listener = listener;
this.constraintExpander = createConstraintExpander();
}
@Override
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) {
TypeValue subtypeValue = getTypeValueFor(subtype);
TypeValue supertypeValue = getTypeValueFor(supertype);
private TypeCheckingProcedure createConstraintExpander() {
return new TypeCheckingProcedure(new TypeConstraintBuilderAdapter(new TypingConstraints() {
@Override
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) {
TypeValue aValue = getTypeValueFor(a);
TypeValue bValue = getTypeValueFor(b);
if (someUnknown(subtypeValue, supertypeValue)) {
addSubtypingConstraintOnTypeValues(subtypeValue, supertypeValue);
return aValue.equate(bValue);
}
return true;
}
@Override
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
// If some of the types is an unknown, the constraint must be generated, and we should carry on
// otherwise there can be no solution, and we should fail
TypeValue subTypeValue = getTypeValueFor(subtype);
TypeValue superTypeValue = getTypeValueFor(supertype);
boolean someUnknown = someUnknown(subTypeValue, superTypeValue);
if (someUnknown) {
addSubtypingConstraintOnTypeValues(subTypeValue, superTypeValue);
@Override
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
return a.equals(b)
|| unknownTypes.containsKey(a.getDeclarationDescriptor())
|| unknownTypes.containsKey(b.getDeclarationDescriptor());
}
return someUnknown;
}
private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) {
return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType;
}
@Override
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) {
TypeValue subtypeValue = getTypeValueFor(subtype);
TypeValue supertypeValue = getTypeValueFor(supertype);
}))
;
if (someUnknown(subtypeValue, supertypeValue)) {
addSubtypingConstraintOnTypeValues(subtypeValue, supertypeValue);
}
return true;
}
public ConstraintSystemImpl() {}
@Override
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
// If some of the types is an unknown, the constraint must be generated, and we should carry on
// otherwise there can be no solution, and we should fail
TypeValue subTypeValue = getTypeValueFor(subtype);
TypeValue superTypeValue = getTypeValueFor(supertype);
boolean someUnknown = someUnknown(subTypeValue, superTypeValue);
if (someUnknown) {
addSubtypingConstraintOnTypeValues(subTypeValue, superTypeValue);
}
return someUnknown;
}
private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) {
return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType;
}
}, listener));
}
@NotNull
private TypeValue getTypeValueFor(@NotNull JetType type) {
@@ -368,7 +378,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
}
private void mergeUnknowns(@NotNull UnknownType a, @NotNull UnknownType b) {
System.err.println("!!!mergeUnknowns() is not implemented!!!");
listener.error("!!!mergeUnknowns() is not implemented!!!");
}
@Override
@@ -379,7 +389,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
}
private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) {
println(typeValueForLower + " :< " + typeValueForUpper);
listener.log("Constraint added: " + typeValueForLower + " :< " + typeValueForUpper);
if (typeValueForLower != typeValueForUpper) {
typeValueForLower.addUpperBound(typeValueForUpper);
typeValueForUpper.addLowerBound(typeValueForLower);
@@ -424,13 +434,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
}
for (UnknownType unknownType : unknownTypes.values()) {
println("Constraints for " + unknownType.getTypeParameterDescriptor());
printTypeValue(unknownType);
listener.constraintsForUnknown(unknownType.getTypeParameterDescriptor(), unknownType);
}
for (KnownType knownType : knownTypes.values()) {
println("Constraints for " + knownType.getType());
printTypeValue(knownType);
listener.constraintsForKnownType(knownType.getType(), knownType);
}
// Find inconsistencies
@@ -447,22 +455,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
// 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
println("====================================");
println("");
println("");
listener.done(solution, unknownTypes.keySet());
return solution;
}
private void printTypeValue(TypeValue typeValue) {
for (TypeValue bound : typeValue.getUpperBounds()) {
println(" :< " + bound);
}
for (TypeValue bound : typeValue.getLowerBounds()) {
println(" :> " + bound);
}
}
private void check(TypeValue typeValue, Solution solution) {
try {
KnownType resultingValue = typeValue.getValue();
@@ -471,33 +468,20 @@ public class ConstraintSystemImpl implements ConstraintSystem {
JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT);
if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO
solution.registerError("Constraint violation: " + type + " is not a subtype of " + boundingType);
println("Constraint violation: " + type + " :< " + boundingType);
listener.error("Constraint violation: " + type + " :< " + boundingType);
}
}
for (TypeValue lowerBound : typeValue.getLowerBounds()) {
JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT);
if (!typeChecker.isSubtypeOf(boundingType, type)) {
solution.registerError("Constraint violation: " + boundingType + " is not a subtype of " + type);
println("Constraint violation: " + boundingType + " :< " + type);
listener.error("Constraint violation: " + boundingType + " :< " + type);
}
}
}
catch (LoopInTypeVariableConstraintsException e) {
println("-------------------------------------------------------------------");
for (Map.Entry<TypeParameterDescriptor, UnknownType> entry : unknownTypes.entrySet()) {
println("Unknown: " + entry.getKey());
UnknownType unknownType = entry.getValue();
println("Lower bounds: ");
for (TypeValue lowerBound : unknownType.getLowerBounds()) {
println(" " + lowerBound);
}
println("Upper bounds: ");
for (TypeValue lowerBound : unknownType.getUpperBounds()) {
println(" " + lowerBound);
}
}
listener.error("Loop detected");
solution.registerError("[TODO] Loop in constraints");
// e.printStackTrace();
}
}
@@ -544,9 +528,14 @@ public class ConstraintSystemImpl implements ConstraintSystem {
DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
if (declarationDescriptor instanceof TypeParameterDescriptor) {
TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
if (!unknownTypes.containsKey(descriptor)) return null;
println(descriptor + " |-> " + getValue(descriptor));
return new TypeProjection(getValue(descriptor));
TypeProjection typeProjection = new TypeProjection(getValue(descriptor));
listener.log(descriptor + " |-> " + typeProjection);
return typeProjection;
}
return null;
}
@@ -588,7 +577,4 @@ public class ConstraintSystemImpl implements ConstraintSystem {
}
private static void println(String message) {
// System.out.println(message);
}
}
@@ -0,0 +1,75 @@
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.TypeParameterDescriptor;
import org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo.*;
/**
* @author abreslav
*/
public class DebugConstraintResolutionListener implements ConstraintResolutionListener {
private final ResolutionDebugInfo.Data debugInfo;
public DebugConstraintResolutionListener(@NotNull ResolutionDebugInfo.Data debugInfo) {
this.debugInfo = debugInfo;
}
@Override
public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue) {
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
Map<TypeParameterDescriptor, ConstraintSystemImpl.TypeValue> map = debugInfo.get(BOUNDS_FOR_UNKNOWNS);
if (map == null) {
map = Maps.newLinkedHashMap();
debugInfo.set(BOUNDS_FOR_UNKNOWNS, map);
}
map.put(typeParameterDescriptor, typeValue);
}
@Override
public void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue) {
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
Map<JetType,ConstraintSystemImpl.TypeValue> map = debugInfo.get(BOUNDS_FOR_KNOWNS);
if (map == null) {
map = Maps.newLinkedHashMap();
debugInfo.set(BOUNDS_FOR_KNOWNS, map);
}
map.put(type, typeValue);
}
@Override
public void done(ConstraintSystemSolution solution, Set<TypeParameterDescriptor> typeParameterDescriptors) {
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
debugInfo.set(SOLUTION, solution);
debugInfo.set(UNKNOWNS, typeParameterDescriptors);
}
@Override
public void log(Object message) {
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
StringBuilder stringBuilder = debugInfo.get(LOG);
if (stringBuilder == null) {
stringBuilder = new StringBuilder();
debugInfo.set(LOG, stringBuilder);
}
stringBuilder.append(message).append("\n");
}
@Override
public void error(Object message) {
if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return;
StringBuilder stringBuilder = debugInfo.get(ERRORS);
if (stringBuilder == null) {
stringBuilder = new StringBuilder();
debugInfo.set(ERRORS, stringBuilder);
}
stringBuilder.append(message).append("\n");
}
}
@@ -0,0 +1,55 @@
package org.jetbrains.jet.lang.resolve.calls.inference;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Set;
/**
* @author abreslav
*/
public class PrintingConstraintResolutionListener implements ConstraintResolutionListener {
@Override
public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue) {
println("Constraints for " + typeParameterDescriptor);
printTypeValue(typeValue);
}
@Override
public void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue) {
println("Constraints for " + type);
printTypeValue(typeValue);
}
@Override
public void done(ConstraintSystemSolution solution, Set<TypeParameterDescriptor> typeParameterDescriptors) {
println("==================================================");
println("");
println("");
}
@Override
public void log(Object message) {
println(message);
}
@Override
public void error(Object message) {
println(message);
}
private void printTypeValue(ConstraintSystemImpl.TypeValue typeValue) {
for (ConstraintSystemImpl.TypeValue bound : typeValue.getUpperBounds()) {
println(" :< " + bound);
}
for (ConstraintSystemImpl.TypeValue bound : typeValue.getLowerBounds()) {
println(" :> " + bound);
}
}
private static void println(Object message) {
ResolutionDebugInfo.println(message);
}
}
@@ -1,12 +1,37 @@
package org.jetbrains.jet.util.slicedmap;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
/**
* @author abreslav
*/
public interface SlicedMap extends Iterable<Map.Entry<SlicedMapKey<?, ?>, ?>> {
SlicedMap DO_NOTHING = new SlicedMap() {
@Override
public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
return slice.computeValue(this, key, null, true);
}
@Override
public <K, V> boolean containsKey(ReadOnlySlice<K, V> slice, K key) {
return false;
}
@Override
public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
return Collections.emptySet();
}
@Override
public Iterator<Map.Entry<SlicedMapKey<?, ?>, ?>> iterator() {
return Collections.<Map.Entry<SlicedMapKey<?, ?>, ?>>emptySet().iterator();
}
};
<K, V> V get(ReadOnlySlice<K, V> slice, K key);
<K, V> boolean containsKey(ReadOnlySlice<K, V> slice, K key);
@@ -21,27 +21,31 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.content.ContentFactory;
import com.intellij.util.Alarm;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetElement;
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.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.internal.codewindow.BytecodeToolwindow;
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
import org.jetbrains.jet.util.slicedmap.WritableSlice;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo.*;
/*
* @author abreslav
@@ -121,19 +125,20 @@ public class ResolveToolwindow extends JPanel {
PsiElement currentElement = elementAtOffset;
boolean callFound = false;
while (currentElement != null && !(currentElement instanceof PsiFile)) {
if (currentElement instanceof JetElement) {
JetElement atOffset = (JetElement) currentElement;
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(RESOLVED_CALL, (JetElement) atOffset);
if (resolvedCall != null) {
setText(renderCall(resolvedCall) + "\n===\n" + currentElement + ": " + currentElement.getText());
callFound = true;
break;
}
}
currentElement = currentElement.getParent();
PsiElement elementWithDebugInfo = findData(bindingContext, currentElement, RESOLUTION_DEBUG_INFO);
if (elementWithDebugInfo != null) {
callFound = true;
setText(renderDebugInfo(elementWithDebugInfo, bindingContext.get(RESOLUTION_DEBUG_INFO, elementWithDebugInfo), null));
}
else {
PsiElement elementWithResolvedCall = findData(bindingContext, currentElement, (WritableSlice) RESOLVED_CALL);
if (elementWithResolvedCall instanceof JetElement) {
callFound = true;
setText(renderDebugInfo(elementWithResolvedCall, null, bindingContext.get(RESOLVED_CALL, (JetElement) elementWithResolvedCall)));
}
}
if (!callFound) {
JetExpression parentExpression = (elementAtOffset instanceof JetExpression) ? (JetExpression) elementAtOffset
@@ -153,8 +158,70 @@ public class ResolveToolwindow extends JPanel {
}
}
private String renderCall(ResolvedCall<? extends CallableDescriptor> resolvedCall) {
StringBuilder builder = new StringBuilder();
@Nullable
private <D> PsiElement findData(BindingContext bindingContext, PsiElement currentElement, ReadOnlySlice<PsiElement, D> slice) {
while (currentElement != null && !(currentElement instanceof PsiFile)) {
if (currentElement instanceof JetElement) {
JetElement atOffset = (JetElement) currentElement;
D data = bindingContext.get(slice, atOffset);
if (data != null && data != NO_DEBUG_INFO) {
return currentElement;
}
}
currentElement = currentElement.getParent();
}
return null;
}
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);
}
StringBuilder log = debugInfo.get(LOG);
if (log != null) {
result.append("Log: \n").append(log).append(bar);
}
Map<JetType, ConstraintSystemImpl.TypeValue> knowns = debugInfo.get(BOUNDS_FOR_KNOWNS);
renderMap(knowns, result);
Map<TypeParameterDescriptor, ConstraintSystemImpl.TypeValue> unknowns = debugInfo.get(BOUNDS_FOR_UNKNOWNS);
renderMap(unknowns, result);
result.append(bar);
call = debugInfo.get(RESULT);
}
renderCall(result, call);
result.append(currentElement + ": " + currentElement.getText());
return result.toString();
}
private <K> void renderMap(Map<K, ConstraintSystemImpl.TypeValue> map, StringBuilder builder) {
if (map == null) return;
for (Map.Entry<K, ConstraintSystemImpl.TypeValue> entry : map.entrySet()) {
K key = entry.getKey();
ConstraintSystemImpl.TypeValue typeValue = entry.getValue();
builder.append("Bounds for ").append(key).append("\n");
for (ConstraintSystemImpl.TypeValue bound : typeValue.getLowerBounds()) {
builder.append(" >: ").append(bound).append("\n");
}
for (ConstraintSystemImpl.TypeValue bound : typeValue.getUpperBounds()) {
builder.append(" <: ").append(bound).append("\n");
}
}
}
private String renderCall(StringBuilder builder, ResolvedCall<? extends CallableDescriptor> resolvedCall) {
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
ReceiverDescriptor receiverArgument = resolvedCall.getReceiverArgument();