Debug info for overload resolution/type inference
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -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);
|
||||
}
|
||||
+71
-85
@@ -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);
|
||||
}
|
||||
}
|
||||
+75
@@ -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");
|
||||
}
|
||||
}
|
||||
+55
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user