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