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.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
|
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.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.JetScope;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
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 org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -241,6 +238,12 @@ public class CallResolver {
|
|||||||
@NotNull JetType expectedType,
|
@NotNull JetType expectedType,
|
||||||
@NotNull final List<ResolutionTask<D>> prioritizedTasks, // high to low priority
|
@NotNull final List<ResolutionTask<D>> prioritizedTasks, // high to low priority
|
||||||
@NotNull final JetReferenceExpression reference) {
|
@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() {
|
TracingStrategy tracing = new TracingStrategy() {
|
||||||
@Override
|
@Override
|
||||||
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl<D> resolvedCall) {
|
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);
|
OverloadResolutionResults<D> results = performResolution(temporaryTrace, scope, expectedType, task, tracing);
|
||||||
if (results.isSuccess()) {
|
if (results.isSuccess()) {
|
||||||
temporaryTrace.commit();
|
temporaryTrace.commit();
|
||||||
|
|
||||||
|
debugInfo.set(ResolutionDebugInfo.RESULT, results.getResult());
|
||||||
|
|
||||||
return results.getResult();
|
return results.getResult();
|
||||||
}
|
}
|
||||||
if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty()) {
|
if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty()) {
|
||||||
@@ -381,6 +387,9 @@ public class CallResolver {
|
|||||||
if (traceForFirstNonemptyCandidateSet != null) {
|
if (traceForFirstNonemptyCandidateSet != null) {
|
||||||
traceForFirstNonemptyCandidateSet.commit();
|
traceForFirstNonemptyCandidateSet.commit();
|
||||||
if (resultsForFirstNonemptyCandidateSet.singleDescriptor()) {
|
if (resultsForFirstNonemptyCandidateSet.singleDescriptor()) {
|
||||||
|
|
||||||
|
debugInfo.set(ResolutionDebugInfo.RESULT, resultsForFirstNonemptyCandidateSet.getResult());
|
||||||
|
|
||||||
return resultsForFirstNonemptyCandidateSet.getResult();
|
return resultsForFirstNonemptyCandidateSet.getResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,7 +429,10 @@ public class CallResolver {
|
|||||||
if (!candidate.getTypeParameters().isEmpty()) {
|
if (!candidate.getTypeParameters().isEmpty()) {
|
||||||
// Type argument inference
|
// 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()) {
|
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
|
||||||
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
|
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 {
|
private static class LoopInTypeVariableConstraintsException extends RuntimeException {
|
||||||
public LoopInTypeVariableConstraintsException() {}
|
public LoopInTypeVariableConstraintsException() {}
|
||||||
}
|
}
|
||||||
@@ -80,6 +79,8 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
public abstract boolean equate(TypeValue other);
|
public abstract boolean equate(TypeValue other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================================================================================================
|
||||||
|
|
||||||
private class UnknownType extends TypeValue {
|
private class UnknownType extends TypeValue {
|
||||||
|
|
||||||
private final TypeParameterDescriptor typeParameterDescriptor;
|
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);
|
value = new KnownType(commonSupertype);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -238,16 +239,18 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
|
|
||||||
private static final class TypeConstraintBuilderAdapter implements TypingConstraints {
|
private static final class TypeConstraintBuilderAdapter implements TypingConstraints {
|
||||||
private final TypingConstraints delegate;
|
private final TypingConstraints delegate;
|
||||||
|
private final ConstraintResolutionListener listener;
|
||||||
|
|
||||||
private TypeConstraintBuilderAdapter(TypingConstraints delegate) {
|
private TypeConstraintBuilderAdapter(TypingConstraints delegate, ConstraintResolutionListener listener) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) {
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
boolean result = delegate.assertEqualTypes(a, b, typeCheckingProcedure);
|
boolean result = delegate.assertEqualTypes(a, b, typeCheckingProcedure);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
println("-- Failed to equate " + a + " and " + b);
|
listener.error("-- Failed to equate " + a + " and " + b);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -256,7 +259,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
||||||
boolean result = delegate.assertEqualTypeConstructors(a, b);
|
boolean result = delegate.assertEqualTypeConstructors(a, b);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
println("-- Type constructors are not equal: " + a + " and " + b);
|
listener.error("-- Type constructors are not equal: " + a + " and " + b);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -265,7 +268,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) {
|
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
boolean result = delegate.assertSubtype(subtype, supertype, typeCheckingProcedure);
|
boolean result = delegate.assertSubtype(subtype, supertype, typeCheckingProcedure);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
println("-- " + subtype + " can't be a subtype of " + supertype);
|
listener.error("-- " + subtype + " can't be a subtype of " + supertype);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -274,60 +277,67 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
boolean result = delegate.noCorrespondingSupertype(subtype, supertype);
|
boolean result = delegate.noCorrespondingSupertype(subtype, supertype);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
println("-- " + subtype + " has no supertype corresponding to " + supertype);
|
listener.error("-- " + subtype + " has no supertype corresponding to " + supertype);
|
||||||
}
|
}
|
||||||
return result;
|
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 ConstraintSystemImpl(ConstraintResolutionListener listener) {
|
||||||
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
this.listener = listener;
|
||||||
return a.equals(b)
|
this.constraintExpander = createConstraintExpander();
|
||||||
|| unknownTypes.containsKey(a.getDeclarationDescriptor())
|
}
|
||||||
|| unknownTypes.containsKey(b.getDeclarationDescriptor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private TypeCheckingProcedure createConstraintExpander() {
|
||||||
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) {
|
return new TypeCheckingProcedure(new TypeConstraintBuilderAdapter(new TypingConstraints() {
|
||||||
TypeValue subtypeValue = getTypeValueFor(subtype);
|
@Override
|
||||||
TypeValue supertypeValue = getTypeValueFor(supertype);
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) {
|
||||||
|
TypeValue aValue = getTypeValueFor(a);
|
||||||
|
TypeValue bValue = getTypeValueFor(b);
|
||||||
|
|
||||||
if (someUnknown(subtypeValue, supertypeValue)) {
|
return aValue.equate(bValue);
|
||||||
addSubtypingConstraintOnTypeValues(subtypeValue, supertypeValue);
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
||||||
// If some of the types is an unknown, the constraint must be generated, and we should carry on
|
return a.equals(b)
|
||||||
// otherwise there can be no solution, and we should fail
|
|| unknownTypes.containsKey(a.getDeclarationDescriptor())
|
||||||
TypeValue subTypeValue = getTypeValueFor(subtype);
|
|| unknownTypes.containsKey(b.getDeclarationDescriptor());
|
||||||
TypeValue superTypeValue = getTypeValueFor(supertype);
|
|
||||||
boolean someUnknown = someUnknown(subTypeValue, superTypeValue);
|
|
||||||
if (someUnknown) {
|
|
||||||
addSubtypingConstraintOnTypeValues(subTypeValue, superTypeValue);
|
|
||||||
}
|
}
|
||||||
return someUnknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) {
|
@Override
|
||||||
return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType;
|
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
|
@NotNull
|
||||||
private TypeValue getTypeValueFor(@NotNull JetType type) {
|
private TypeValue getTypeValueFor(@NotNull JetType type) {
|
||||||
@@ -368,7 +378,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void mergeUnknowns(@NotNull UnknownType a, @NotNull UnknownType b) {
|
private void mergeUnknowns(@NotNull UnknownType a, @NotNull UnknownType b) {
|
||||||
System.err.println("!!!mergeUnknowns() is not implemented!!!");
|
listener.error("!!!mergeUnknowns() is not implemented!!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -379,7 +389,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) {
|
private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) {
|
||||||
println(typeValueForLower + " :< " + typeValueForUpper);
|
listener.log("Constraint added: " + typeValueForLower + " :< " + typeValueForUpper);
|
||||||
if (typeValueForLower != typeValueForUpper) {
|
if (typeValueForLower != typeValueForUpper) {
|
||||||
typeValueForLower.addUpperBound(typeValueForUpper);
|
typeValueForLower.addUpperBound(typeValueForUpper);
|
||||||
typeValueForUpper.addLowerBound(typeValueForLower);
|
typeValueForUpper.addLowerBound(typeValueForLower);
|
||||||
@@ -424,13 +434,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (UnknownType unknownType : unknownTypes.values()) {
|
for (UnknownType unknownType : unknownTypes.values()) {
|
||||||
println("Constraints for " + unknownType.getTypeParameterDescriptor());
|
listener.constraintsForUnknown(unknownType.getTypeParameterDescriptor(), unknownType);
|
||||||
printTypeValue(unknownType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (KnownType knownType : knownTypes.values()) {
|
for (KnownType knownType : knownTypes.values()) {
|
||||||
println("Constraints for " + knownType.getType());
|
listener.constraintsForKnownType(knownType.getType(), knownType);
|
||||||
printTypeValue(knownType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find inconsistencies
|
// Find inconsistencies
|
||||||
@@ -447,22 +455,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
// we have set some of them from equality constraints with known types
|
// 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
|
// and thus the bounds may be violated if some of the constraints conflict
|
||||||
|
|
||||||
println("====================================");
|
listener.done(solution, unknownTypes.keySet());
|
||||||
println("");
|
|
||||||
println("");
|
|
||||||
|
|
||||||
return solution;
|
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) {
|
private void check(TypeValue typeValue, Solution solution) {
|
||||||
try {
|
try {
|
||||||
KnownType resultingValue = typeValue.getValue();
|
KnownType resultingValue = typeValue.getValue();
|
||||||
@@ -471,33 +468,20 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT);
|
JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT);
|
||||||
if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO
|
if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO
|
||||||
solution.registerError("Constraint violation: " + type + " is not a subtype of " + boundingType);
|
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()) {
|
for (TypeValue lowerBound : typeValue.getLowerBounds()) {
|
||||||
JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT);
|
JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT);
|
||||||
if (!typeChecker.isSubtypeOf(boundingType, type)) {
|
if (!typeChecker.isSubtypeOf(boundingType, type)) {
|
||||||
solution.registerError("Constraint violation: " + boundingType + " is not a subtype of " + 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) {
|
catch (LoopInTypeVariableConstraintsException e) {
|
||||||
println("-------------------------------------------------------------------");
|
listener.error("Loop detected");
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
solution.registerError("[TODO] Loop in constraints");
|
solution.registerError("[TODO] Loop in constraints");
|
||||||
// e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,9 +528,14 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
|
DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
|
||||||
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
||||||
TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
|
TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
|
||||||
|
|
||||||
if (!unknownTypes.containsKey(descriptor)) return null;
|
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;
|
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;
|
package org.jetbrains.jet.util.slicedmap;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public interface SlicedMap extends Iterable<Map.Entry<SlicedMapKey<?, ?>, ?>> {
|
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> V get(ReadOnlySlice<K, V> slice, K key);
|
||||||
|
|
||||||
<K, V> boolean containsKey(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.psi.util.PsiUtilCore;
|
||||||
import com.intellij.ui.content.ContentFactory;
|
import com.intellij.ui.content.ContentFactory;
|
||||||
import com.intellij.util.Alarm;
|
import com.intellij.util.Alarm;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetFile;
|
import org.jetbrains.jet.lang.psi.JetFile;
|
||||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
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.ResolvedCall;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
|
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.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.plugin.JetFileType;
|
import org.jetbrains.jet.plugin.JetFileType;
|
||||||
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
|
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
|
||||||
import org.jetbrains.jet.plugin.internal.codewindow.BytecodeToolwindow;
|
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 javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE;
|
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
import static org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo.*;
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -121,19 +125,20 @@ public class ResolveToolwindow extends JPanel {
|
|||||||
PsiElement currentElement = elementAtOffset;
|
PsiElement currentElement = elementAtOffset;
|
||||||
|
|
||||||
boolean callFound = false;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
PsiElement elementWithDebugInfo = findData(bindingContext, currentElement, RESOLUTION_DEBUG_INFO);
|
||||||
currentElement = currentElement.getParent();
|
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) {
|
if (!callFound) {
|
||||||
|
|
||||||
JetExpression parentExpression = (elementAtOffset instanceof JetExpression) ? (JetExpression) elementAtOffset
|
JetExpression parentExpression = (elementAtOffset instanceof JetExpression) ? (JetExpression) elementAtOffset
|
||||||
@@ -153,8 +158,70 @@ public class ResolveToolwindow extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String renderCall(ResolvedCall<? extends CallableDescriptor> resolvedCall) {
|
@Nullable
|
||||||
StringBuilder builder = new StringBuilder();
|
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();
|
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
|
||||||
ReceiverDescriptor receiverArgument = resolvedCall.getReceiverArgument();
|
ReceiverDescriptor receiverArgument = resolvedCall.getReceiverArgument();
|
||||||
|
|||||||
Reference in New Issue
Block a user