added declared bound constraints directly to constraint system
added status 'hasViolatedUpperBound' class TypeConstraintsImpl now stores constraint position for each constraint, so we can filter out bound constraints and find out if the system is successful without them
This commit is contained in:
@@ -354,7 +354,7 @@ public interface Errors {
|
|||||||
DiagnosticFactory1<PsiElement, ExtendedInferenceErrorData> TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<PsiElement, ExtendedInferenceErrorData> TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory1<PsiElement, ExtendedInferenceErrorData> TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<PsiElement, ExtendedInferenceErrorData> TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory1<PsiElement, ExtendedInferenceErrorData> TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<PsiElement, ExtendedInferenceErrorData> TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<PsiElement, ExtendedInferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory2<JetExpression, JetType, JetType> TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
|
DiagnosticFactory2<JetExpression, JetType, JetType> TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
|
||||||
|
|
||||||
// Callable references
|
// Callable references
|
||||||
|
|||||||
@@ -28,10 +28,7 @@ import org.jetbrains.jet.lang.descriptors.*;
|
|||||||
import org.jetbrains.jet.lang.psi.JetClass;
|
import org.jetbrains.jet.lang.psi.JetClass;
|
||||||
import org.jetbrains.jet.lang.psi.JetClassOrObject;
|
import org.jetbrains.jet.lang.psi.JetClassOrObject;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
|
import org.jetbrains.jet.lang.resolve.calls.inference.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil;
|
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
|
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraints;
|
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||||
@@ -159,11 +156,11 @@ public class Renderers {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Renderer<InferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER =
|
public static final Renderer<ExtendedInferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER =
|
||||||
new Renderer<InferenceErrorData>() {
|
new Renderer<ExtendedInferenceErrorData>() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public String render(@NotNull InferenceErrorData inferenceErrorData) {
|
public String render(@NotNull ExtendedInferenceErrorData inferenceErrorData) {
|
||||||
return renderUpperBoundViolatedInferenceError(inferenceErrorData, TabledDescriptorRenderer.create()).toString();
|
return renderUpperBoundViolatedInferenceError(inferenceErrorData, TabledDescriptorRenderer.create()).toString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -265,32 +262,47 @@ public class Renderers {
|
|||||||
.text("Please specify it explicitly."));
|
.text("Please specify it explicitly."));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TabledDescriptorRenderer renderUpperBoundViolatedInferenceError(InferenceErrorData inferenceErrorData, TabledDescriptorRenderer result) {
|
@NotNull
|
||||||
|
public static TabledDescriptorRenderer renderUpperBoundViolatedInferenceError(ExtendedInferenceErrorData inferenceErrorData, TabledDescriptorRenderer result) {
|
||||||
|
String errorMessage = "Rendering 'upper bound violated' error for " + inferenceErrorData.descriptor;
|
||||||
|
|
||||||
TypeParameterDescriptor typeParameterDescriptor = null;
|
TypeParameterDescriptor typeParameterDescriptor = null;
|
||||||
|
ConstraintSystemImpl constraintSystem = (ConstraintSystemImpl) inferenceErrorData.constraintSystem;
|
||||||
|
assert constraintSystem.getStatus().hasViolatedUpperBound();
|
||||||
|
|
||||||
|
ConstraintSystem systemWithoutWeakConstraints = constraintSystem.getSystemWithoutWeakConstraints();
|
||||||
for (TypeParameterDescriptor typeParameter : inferenceErrorData.descriptor.getTypeParameters()) {
|
for (TypeParameterDescriptor typeParameter : inferenceErrorData.descriptor.getTypeParameters()) {
|
||||||
if (!ConstraintsUtil.checkUpperBoundIsSatisfied(inferenceErrorData.constraintSystem, typeParameter, true)) {
|
if (!ConstraintsUtil.checkUpperBoundIsSatisfied(systemWithoutWeakConstraints, typeParameter, true)) {
|
||||||
typeParameterDescriptor = typeParameter;
|
typeParameterDescriptor = typeParameter;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert typeParameterDescriptor != null;
|
assert typeParameterDescriptor != null : errorMessage;
|
||||||
|
|
||||||
|
JetType inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeConstraints(typeParameterDescriptor).getValue();
|
||||||
|
assert inferredValueForTypeParameter != null : errorMessage;
|
||||||
|
|
||||||
result.text(newText().normal("Type parameter bound for ").strong(typeParameterDescriptor.getName()).normal(" in "))
|
result.text(newText().normal("Type parameter bound for ").strong(typeParameterDescriptor.getName()).normal(" in "))
|
||||||
.table(newTable().
|
.table(newTable().
|
||||||
descriptor(inferenceErrorData.descriptor));
|
descriptor(inferenceErrorData.descriptor));
|
||||||
|
|
||||||
JetType inferredValueForTypeParameter = inferenceErrorData.constraintSystem.getTypeConstraints(typeParameterDescriptor).getValue();
|
JetType violatedUpperBound = null;
|
||||||
assert inferredValueForTypeParameter != null;
|
for (JetType upperBound : typeParameterDescriptor.getUpperBounds()) {
|
||||||
JetType upperBound = typeParameterDescriptor.getUpperBoundsAsType();
|
JetType upperBoundWithSubstitutedInferredTypes =
|
||||||
JetType upperBoundWithSubstitutedInferredTypes = inferenceErrorData.constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT);
|
systemWithoutWeakConstraints.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT);
|
||||||
assert upperBoundWithSubstitutedInferredTypes != null;
|
if (upperBoundWithSubstitutedInferredTypes != null &&
|
||||||
|
!JetTypeChecker.INSTANCE.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) {
|
||||||
|
violatedUpperBound = upperBoundWithSubstitutedInferredTypes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert violatedUpperBound != null : errorMessage;
|
||||||
|
|
||||||
Renderer<JetType> typeRenderer = result.getTypeRenderer();
|
Renderer<JetType> typeRenderer = result.getTypeRenderer();
|
||||||
result.text(newText()
|
result.text(newText()
|
||||||
.normal(" is not satisfied: inferred type ")
|
.normal(" is not satisfied: inferred type ")
|
||||||
.error(typeRenderer.render(inferredValueForTypeParameter))
|
.error(typeRenderer.render(inferredValueForTypeParameter))
|
||||||
.normal(" is not a subtype of ")
|
.normal(" is not a subtype of ")
|
||||||
.strong(typeRenderer.render(upperBoundWithSubstitutedInferredTypes)));
|
.strong(typeRenderer.render(violatedUpperBound)));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -232,19 +232,13 @@ public class CandidateResolver {
|
|||||||
|
|
||||||
updateSystemWithConstraintSystemCompleter(context, resolvedCall);
|
updateSystemWithConstraintSystemCompleter(context, resolvedCall);
|
||||||
|
|
||||||
if (resolvedCall.getConstraintSystem().getStatus().hasContradiction()) {
|
|
||||||
return reportInferenceError(context);
|
|
||||||
}
|
|
||||||
updateSystemIfExpectedTypeIsUnit(context, resolvedCall);
|
updateSystemIfExpectedTypeIsUnit(context, resolvedCall);
|
||||||
|
|
||||||
boolean boundsAreSatisfied = updateSystemCheckingBounds(resolvedCall);
|
((ConstraintSystemImpl)resolvedCall.getConstraintSystem()).processDeclaredBoundConstraints();
|
||||||
|
|
||||||
if (!resolvedCall.getConstraintSystem().getStatus().isSuccessful()) {
|
if (!resolvedCall.getConstraintSystem().getStatus().isSuccessful()) {
|
||||||
return reportInferenceError(context);
|
return reportInferenceError(context);
|
||||||
}
|
}
|
||||||
if (!boundsAreSatisfied) {
|
|
||||||
context.tracing.upperBoundViolated(context.trace, InferenceErrorData.create(
|
|
||||||
resolvedCall.getCandidateDescriptor(), resolvedCall.getConstraintSystem()));
|
|
||||||
}
|
|
||||||
resolvedCall.setResultingSubstitutor(resolvedCall.getConstraintSystem().getResultingSubstitutor());
|
resolvedCall.setResultingSubstitutor(resolvedCall.getConstraintSystem().getResultingSubstitutor());
|
||||||
|
|
||||||
completeNestedCallsInference(context);
|
completeNestedCallsInference(context);
|
||||||
@@ -307,30 +301,12 @@ public class CandidateResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <D extends CallableDescriptor> boolean updateSystemCheckingBounds(
|
|
||||||
@NotNull ResolvedCallImpl<D> resolvedCall
|
|
||||||
) {
|
|
||||||
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
|
|
||||||
assert constraintSystem != null;
|
|
||||||
|
|
||||||
if (ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/true)
|
|
||||||
&& !constraintSystem.getStatus().hasUnknownParameters()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ConstraintSystemImpl copy = (ConstraintSystemImpl) constraintSystem.copy();
|
|
||||||
copy.processDeclaredBoundConstraints();
|
|
||||||
if (copy.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(copy, /*substituteOtherTypeParametersInBounds=*/true)) {
|
|
||||||
resolvedCall.setConstraintSystem(copy);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private <D extends CallableDescriptor> JetType reportInferenceError(
|
private <D extends CallableDescriptor> JetType reportInferenceError(
|
||||||
@NotNull CallCandidateResolutionContext<D> context
|
@NotNull CallCandidateResolutionContext<D> context
|
||||||
) {
|
) {
|
||||||
ResolvedCallImpl<D> resolvedCall = context.candidateCall;
|
ResolvedCallImpl<D> resolvedCall = context.candidateCall;
|
||||||
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
|
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
|
||||||
|
assert constraintSystem != null;
|
||||||
|
|
||||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
||||||
completeNestedCallsInference(context);
|
completeNestedCallsInference(context);
|
||||||
@@ -471,7 +447,8 @@ public class CandidateResolver {
|
|||||||
if (expression == null) return;
|
if (expression == null) return;
|
||||||
|
|
||||||
DataFlowInfo dataFlowInfoForValueArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(argument);
|
DataFlowInfo dataFlowInfoForValueArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(argument);
|
||||||
ResolutionContext<?> newContext = context.replaceExpectedType(context.expectedType).replaceDataFlowInfo(dataFlowInfoForValueArgument);
|
ResolutionContext<?> newContext = context.replaceExpectedType(context.expectedType).replaceDataFlowInfo(
|
||||||
|
dataFlowInfoForValueArgument);
|
||||||
DataFlowUtils.checkType(type, expression, newContext);
|
DataFlowUtils.checkType(type, expression, newContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,9 +594,8 @@ public class CandidateResolver {
|
|||||||
|
|
||||||
// Solution
|
// Solution
|
||||||
boolean hasContradiction = constraintSystem.getStatus().hasContradiction();
|
boolean hasContradiction = constraintSystem.getStatus().hasContradiction();
|
||||||
boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/false);
|
|
||||||
candidateCall.setHasUnknownTypeParameters(true);
|
candidateCall.setHasUnknownTypeParameters(true);
|
||||||
if (!hasContradiction && boundsAreSatisfied) {
|
if (!hasContradiction) {
|
||||||
return INCOMPLETE_TYPE_INFERENCE;
|
return INCOMPLETE_TYPE_INFERENCE;
|
||||||
}
|
}
|
||||||
ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS);
|
ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS);
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
|||||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
|
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
@@ -95,9 +94,6 @@ public interface TracingStrategy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull ExtendedInferenceErrorData inferenceErrorData) {}
|
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull ExtendedInferenceErrorData inferenceErrorData) {}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
<D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall);
|
<D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall);
|
||||||
@@ -140,6 +136,4 @@ public interface TracingStrategy {
|
|||||||
void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor);
|
void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor);
|
||||||
|
|
||||||
void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull ExtendedInferenceErrorData inferenceErrorData);
|
void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull ExtendedInferenceErrorData inferenceErrorData);
|
||||||
|
|
||||||
void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-6
@@ -21,7 +21,6 @@ import com.intellij.lang.ASTNode;
|
|||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
|
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
|
||||||
@@ -233,6 +232,9 @@ public class TracingStrategyImpl implements TracingStrategy {
|
|||||||
assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error";
|
assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error";
|
||||||
trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, data.expectedType, substitutedReturnType));
|
trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, data.expectedType, substitutedReturnType));
|
||||||
}
|
}
|
||||||
|
else if (status.hasViolatedUpperBound()) {
|
||||||
|
trace.report(TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, data));
|
||||||
|
}
|
||||||
else if (status.hasTypeConstructorMismatch()) {
|
else if (status.hasTypeConstructorMismatch()) {
|
||||||
trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data));
|
trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data));
|
||||||
}
|
}
|
||||||
@@ -244,9 +246,4 @@ public class TracingStrategyImpl implements TracingStrategy {
|
|||||||
trace.report(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data));
|
trace.report(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {
|
|
||||||
trace.report(Errors.TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, inferenceErrorData));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
-7
@@ -477,12 +477,5 @@ public class ControlStructureTypingUtils {
|
|||||||
) {
|
) {
|
||||||
throwError();
|
throwError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void upperBoundViolated(
|
|
||||||
@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData
|
|
||||||
) {
|
|
||||||
throwError();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+54
-8
@@ -16,32 +16,78 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.resolve.calls.inference;
|
package org.jetbrains.jet.lang.resolve.calls.inference;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
import com.intellij.openapi.util.Condition;
|
||||||
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ConstraintPosition {
|
public class ConstraintPosition {
|
||||||
public static final ConstraintPosition RECEIVER_POSITION = new ConstraintPosition("RECEIVER_POSITION");
|
public static final ConstraintPosition RECEIVER_POSITION = new ConstraintPosition("RECEIVER_POSITION", true);
|
||||||
public static final ConstraintPosition EXPECTED_TYPE_POSITION = new ConstraintPosition("EXPECTED_TYPE_POSITION");
|
public static final ConstraintPosition EXPECTED_TYPE_POSITION = new ConstraintPosition("EXPECTED_TYPE_POSITION", true);
|
||||||
public static final ConstraintPosition BOUND_CONSTRAINT_POSITION = new ConstraintPosition("BOUND_CONSTRAINT_POSITION");
|
public static final ConstraintPosition FROM_COMPLETER = new ConstraintPosition("FROM_COMPLETER", true);
|
||||||
public static final ConstraintPosition FROM_COMPLETER = new ConstraintPosition("FROM_COMPLETER");
|
public static final ConstraintPosition SPECIAL = new ConstraintPosition("SPECIAL", true);
|
||||||
public static final ConstraintPosition SPECIAL = new ConstraintPosition("SPECIAL");
|
|
||||||
|
|
||||||
private static final Map<Integer, ConstraintPosition> valueParameterPositions = Maps.newHashMap();
|
private static final Map<Integer, ConstraintPosition> valueParameterPositions = Maps.newHashMap();
|
||||||
|
private static final Map<Integer, ConstraintPosition> typeBoundPositions = Maps.newHashMap();
|
||||||
|
|
||||||
public static ConstraintPosition getValueParameterPosition(int index) {
|
public static ConstraintPosition getValueParameterPosition(int index) {
|
||||||
ConstraintPosition position = valueParameterPositions.get(index);
|
ConstraintPosition position = valueParameterPositions.get(index);
|
||||||
if (position == null) {
|
if (position == null) {
|
||||||
position = new ConstraintPosition("VALUE_PARAMETER_POSITION(" + index + ")");
|
position = new ConstraintPosition("VALUE_PARAMETER_POSITION(" + index + ")", true);
|
||||||
valueParameterPositions.put(index, position);
|
valueParameterPositions.put(index, position);
|
||||||
}
|
}
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String debugName;
|
public static ConstraintPosition getTypeBoundPosition(int index) {
|
||||||
|
ConstraintPosition position = typeBoundPositions.get(index);
|
||||||
|
if (position == null) {
|
||||||
|
position = new ConstraintPosition("TYPE_BOUND_POSITION(" + index + ")", false);
|
||||||
|
typeBoundPositions.put(index, position);
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
private ConstraintPosition(String name) {
|
public static class CompoundConstraintPosition extends ConstraintPosition {
|
||||||
|
private final Collection<ConstraintPosition> positions;
|
||||||
|
|
||||||
|
public CompoundConstraintPosition(Collection<ConstraintPosition> positions) {
|
||||||
|
super("COMPOUND_CONSTRAINT_POSITION", hasConstraint(positions, /*strong=*/true));
|
||||||
|
this.positions = positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean consistsOfOnlyStrongConstraints() {
|
||||||
|
return !hasConstraint(positions, /*strong=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasConstraint(@NotNull Collection<ConstraintPosition> positions, final boolean strong) {
|
||||||
|
return ContainerUtil.exists(positions, new Condition<ConstraintPosition>() {
|
||||||
|
@Override
|
||||||
|
public boolean value(ConstraintPosition constraintPosition) {
|
||||||
|
return constraintPosition.isStrong() == strong;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConstraintPosition getCompoundConstraintPosition(ConstraintPosition... positions) {
|
||||||
|
return new CompoundConstraintPosition(Lists.newArrayList(positions));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String debugName;
|
||||||
|
private final boolean isStrong;
|
||||||
|
|
||||||
|
private ConstraintPosition(String name, boolean isStrong) {
|
||||||
debugName = name;
|
debugName = name;
|
||||||
|
this.isStrong = isStrong;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStrong() {
|
||||||
|
return isStrong;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+92
-21
@@ -21,6 +21,9 @@ import com.google.common.base.Functions;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import com.intellij.openapi.util.Condition;
|
||||||
|
import com.intellij.openapi.util.Conditions;
|
||||||
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
||||||
@@ -31,6 +34,7 @@ import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
|
|||||||
import org.jetbrains.jet.lang.types.checker.TypingConstraints;
|
import org.jetbrains.jet.lang.types.checker.TypingConstraints;
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -39,7 +43,9 @@ import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImp
|
|||||||
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE;
|
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE;
|
||||||
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind;
|
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind;
|
||||||
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind.*;
|
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind.*;
|
||||||
import static org.jetbrains.jet.lang.types.TypeUtils.*;
|
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.Constraint;
|
||||||
|
import static org.jetbrains.jet.lang.types.TypeUtils.CANT_INFER_TYPE_PARAMETER;
|
||||||
|
import static org.jetbrains.jet.lang.types.TypeUtils.DONT_CARE;
|
||||||
|
|
||||||
public class ConstraintSystemImpl implements ConstraintSystem {
|
public class ConstraintSystemImpl implements ConstraintSystem {
|
||||||
|
|
||||||
@@ -67,10 +73,16 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
return hasTypeConstructorMismatch() || hasConflictingConstraints();
|
return hasTypeConstructorMismatch() || hasConflictingConstraints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasViolatedUpperBound() {
|
||||||
|
if (isSuccessful()) return false;
|
||||||
|
ConstraintSystem systemWithoutWeakConstraints = getSystemWithoutWeakConstraints();
|
||||||
|
return systemWithoutWeakConstraints.getStatus().isSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasConflictingConstraints() {
|
public boolean hasConflictingConstraints() {
|
||||||
for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
|
for (TypeConstraintsImpl typeConstraints : typeParameterConstraints.values()) {
|
||||||
TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
|
|
||||||
if (typeConstraints.getValues().size() > 1) return true;
|
if (typeConstraints.getValues().size() > 1) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -78,8 +90,8 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasUnknownParameters() {
|
public boolean hasUnknownParameters() {
|
||||||
for (TypeConstraintsImpl constraints : typeParameterConstraints.values()) {
|
for (TypeConstraintsImpl typeConstraints : typeParameterConstraints.values()) {
|
||||||
if (constraints.isEmpty()) {
|
if (typeConstraints.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,25 +179,78 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
for (Map.Entry<TypeParameterDescriptor, Variance> entry : typeVariables.entrySet()) {
|
for (Map.Entry<TypeParameterDescriptor, Variance> entry : typeVariables.entrySet()) {
|
||||||
TypeParameterDescriptor typeVariable = entry.getKey();
|
TypeParameterDescriptor typeVariable = entry.getKey();
|
||||||
Variance positionVariance = entry.getValue();
|
Variance positionVariance = entry.getValue();
|
||||||
typeParameterConstraints.put(typeVariable, new TypeConstraintsImpl(positionVariance));
|
typeParameterConstraints.put(typeVariable, new TypeConstraintsImpl(typeVariable, positionVariance));
|
||||||
|
}
|
||||||
|
TypeSubstitutor constantSubstitutor = TypeUtils.makeConstantSubstitutor(typeParameterConstraints.keySet(), DONT_CARE);
|
||||||
|
for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
|
||||||
|
TypeParameterDescriptor typeVariable = entry.getKey();
|
||||||
|
TypeConstraintsImpl typeConstraints = entry.getValue();
|
||||||
|
|
||||||
|
for (JetType declaredUpperBound : typeVariable.getUpperBounds()) {
|
||||||
|
if (KotlinBuiltIns.getInstance().getNullableAnyType().equals(declaredUpperBound)) continue; //todo remove this line (?)
|
||||||
|
JetType substitutedBound = constantSubstitutor.substitute(declaredUpperBound, Variance.INVARIANT);
|
||||||
|
if (substitutedBound != null) {
|
||||||
|
typeConstraints.addConstraint(UPPER_BOUND, substitutedBound, ConstraintPosition.getTypeBoundPosition(typeVariable.getIndex()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public ConstraintSystem copy() {
|
public ConstraintSystem copy() {
|
||||||
return replaceTypeVariables(Functions.<TypeParameterDescriptor>identity(), true);
|
return replaceTypeVariables(Functions.<TypeParameterDescriptor>identity(),
|
||||||
|
new Function<TypeConstraintsImpl, TypeConstraintsImpl>() {
|
||||||
|
@Override
|
||||||
|
public TypeConstraintsImpl apply(TypeConstraintsImpl typeConstraints) {
|
||||||
|
return typeConstraints.copy();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Conditions.<ConstraintPosition>alwaysTrue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ConstraintSystem replaceTypeVariables(@NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap) {
|
public ConstraintSystem replaceTypeVariables(@NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap) {
|
||||||
return replaceTypeVariables(typeVariablesMap, false);
|
return replaceTypeVariables(typeVariablesMap,
|
||||||
|
Functions.<TypeConstraintsImpl>identity(),
|
||||||
|
Conditions.<ConstraintPosition>alwaysTrue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public ConstraintSystem filterConstrains(@NotNull final Condition<ConstraintPosition> condition) {
|
||||||
|
return replaceTypeVariables(Functions.<TypeParameterDescriptor>identity(),
|
||||||
|
new Function<TypeConstraintsImpl, TypeConstraintsImpl>() {
|
||||||
|
@Override
|
||||||
|
public TypeConstraintsImpl apply(TypeConstraintsImpl typeConstraints) {
|
||||||
|
return typeConstraints.filter(condition);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public ConstraintSystem getSystemWithoutWeakConstraints() {
|
||||||
|
return filterConstrains(new Condition<ConstraintPosition>() {
|
||||||
|
@Override
|
||||||
|
public boolean value(ConstraintPosition constraintPosition) {
|
||||||
|
// 'isStrong' for compound means 'has some strong constraints'
|
||||||
|
// but for testing absence of weak constraints we need 'has only strong constraints' here
|
||||||
|
if (constraintPosition instanceof ConstraintPosition.CompoundConstraintPosition) {
|
||||||
|
ConstraintPosition.CompoundConstraintPosition position =
|
||||||
|
(ConstraintPosition.CompoundConstraintPosition) constraintPosition;
|
||||||
|
return position.consistsOfOnlyStrongConstraints();
|
||||||
|
}
|
||||||
|
return constraintPosition.isStrong();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private ConstraintSystem replaceTypeVariables(
|
private ConstraintSystem replaceTypeVariables(
|
||||||
@NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap,
|
@NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap,
|
||||||
boolean recreateTypeConstraints
|
@NotNull Function<TypeConstraintsImpl, TypeConstraintsImpl> typeConstraintsMap,
|
||||||
|
@NotNull Condition<ConstraintPosition> constraintPositionCondition
|
||||||
|
|
||||||
) {
|
) {
|
||||||
ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl();
|
ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl();
|
||||||
for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
|
for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
|
||||||
@@ -194,9 +259,9 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
|
|
||||||
TypeParameterDescriptor newTypeParameter = typeVariablesMap.apply(typeParameter);
|
TypeParameterDescriptor newTypeParameter = typeVariablesMap.apply(typeParameter);
|
||||||
assert newTypeParameter != null;
|
assert newTypeParameter != null;
|
||||||
newConstraintSystem.typeParameterConstraints.put(newTypeParameter, recreateTypeConstraints ? typeConstraints.copy() : typeConstraints);
|
newConstraintSystem.typeParameterConstraints.put(newTypeParameter, typeConstraintsMap.apply(typeConstraints));
|
||||||
}
|
}
|
||||||
newConstraintSystem.errorConstraintPositions.addAll(errorConstraintPositions);
|
newConstraintSystem.errorConstraintPositions.addAll(ContainerUtil.filter(errorConstraintPositions, constraintPositionCondition));
|
||||||
newConstraintSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes;
|
newConstraintSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes;
|
||||||
return newConstraintSystem;
|
return newConstraintSystem;
|
||||||
}
|
}
|
||||||
@@ -267,7 +332,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isErrorOrSpecialType(@Nullable JetType type) {
|
private boolean isErrorOrSpecialType(@Nullable JetType type) {
|
||||||
if (type == TypeUtils.DONT_CARE || type == TypeUtils.CANT_INFER_TYPE_PARAMETER) {
|
if (type == DONT_CARE || type == CANT_INFER_TYPE_PARAMETER) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +373,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
// can be considered as extension function if one is expected
|
// can be considered as extension function if one is expected
|
||||||
// (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
|
// (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
|
||||||
if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(subType) && kotlinBuiltIns.isExtensionFunctionType(superType)) {
|
if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(subType) && kotlinBuiltIns.isExtensionFunctionType(superType)) {
|
||||||
subType = createCorrespondingExtensionFunctionType(subType, TypeUtils.DONT_CARE);
|
subType = createCorrespondingExtensionFunctionType(subType, DONT_CARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// can be equal for the recursive invocations:
|
// can be equal for the recursive invocations:
|
||||||
@@ -320,11 +385,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
|
|
||||||
|
|
||||||
if (isMyTypeVariable(subType)) {
|
if (isMyTypeVariable(subType)) {
|
||||||
generateTypeParameterConstraint(subType, superType, constraintKind == SUB_TYPE ? UPPER_BOUND : EXACT_BOUND);
|
generateTypeParameterConstraint(subType, superType, constraintKind == SUB_TYPE ? UPPER_BOUND : EXACT_BOUND, constraintPosition);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isMyTypeVariable(superType)) {
|
if (isMyTypeVariable(superType)) {
|
||||||
generateTypeParameterConstraint(superType, subType, constraintKind == SUB_TYPE ? LOWER_BOUND : EXACT_BOUND);
|
generateTypeParameterConstraint(superType, subType, constraintKind == SUB_TYPE ? LOWER_BOUND : EXACT_BOUND, constraintPosition);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if superType is nullable and subType is not nullable, unsafe call error will be generated later,
|
// if superType is nullable and subType is not nullable, unsafe call error will be generated later,
|
||||||
@@ -335,13 +400,14 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
private void generateTypeParameterConstraint(
|
private void generateTypeParameterConstraint(
|
||||||
@NotNull JetType parameterType,
|
@NotNull JetType parameterType,
|
||||||
@NotNull JetType constrainingType,
|
@NotNull JetType constrainingType,
|
||||||
@NotNull BoundKind boundKind
|
@NotNull BoundKind boundKind,
|
||||||
|
@NotNull ConstraintPosition constraintPosition
|
||||||
) {
|
) {
|
||||||
TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType);
|
TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType);
|
||||||
assert typeConstraints != null : "constraint should be generated only for type variables";
|
assert typeConstraints != null : "constraint should be generated only for type variables";
|
||||||
|
|
||||||
if (!parameterType.isNullable() || !constrainingType.isNullable()) {
|
if (!parameterType.isNullable() || !constrainingType.isNullable()) {
|
||||||
typeConstraints.addBound(boundKind, constrainingType);
|
typeConstraints.addConstraint(boundKind, constrainingType, constraintPosition);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// For parameter type T:
|
// For parameter type T:
|
||||||
@@ -349,11 +415,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
// constraint T? >: Int? should transform to T >: Int
|
// constraint T? >: Int? should transform to T >: Int
|
||||||
JetType notNullConstrainingType = TypeUtils.makeNotNullable(constrainingType);
|
JetType notNullConstrainingType = TypeUtils.makeNotNullable(constrainingType);
|
||||||
if (boundKind == EXACT_BOUND || boundKind == LOWER_BOUND) {
|
if (boundKind == EXACT_BOUND || boundKind == LOWER_BOUND) {
|
||||||
typeConstraints.addBound(LOWER_BOUND, notNullConstrainingType);
|
typeConstraints.addConstraint(LOWER_BOUND, notNullConstrainingType, constraintPosition);
|
||||||
}
|
}
|
||||||
// constraint T? <: Int? should transform to T <: Int?
|
// constraint T? <: Int? should transform to T <: Int?
|
||||||
if (boundKind == EXACT_BOUND || boundKind == UPPER_BOUND) {
|
if (boundKind == EXACT_BOUND || boundKind == UPPER_BOUND) {
|
||||||
typeConstraints.addBound(UPPER_BOUND, constrainingType);
|
typeConstraints.addConstraint(UPPER_BOUND, constrainingType, constraintPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,8 +429,13 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
|||||||
TypeConstraintsImpl typeConstraints = entry.getValue();
|
TypeConstraintsImpl typeConstraints = entry.getValue();
|
||||||
for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
|
for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
|
||||||
//todo order matters here
|
//todo order matters here
|
||||||
for (JetType lowerOrExactBound : Sets.union(typeConstraints.getLowerBounds(), typeConstraints.getExactBounds())) {
|
Collection<Constraint> constraints = Lists.newArrayList(typeConstraints.getConstraints());
|
||||||
addSubtypeConstraint(lowerOrExactBound, declaredUpperBound, ConstraintPosition.BOUND_CONSTRAINT_POSITION);
|
for (Constraint constraint : constraints) {
|
||||||
|
if (constraint.boundKind == LOWER_BOUND || constraint.boundKind == EXACT_BOUND) {
|
||||||
|
ConstraintPosition position = ConstraintPosition.getCompoundConstraintPosition(
|
||||||
|
ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), constraint.constraintPosition);
|
||||||
|
addSubtypeConstraint(constraint.type, declaredUpperBound, position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -43,6 +43,16 @@ public interface ConstraintSystemStatus {
|
|||||||
*/
|
*/
|
||||||
boolean hasConflictingConstraints();
|
boolean hasConflictingConstraints();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <tt>true</tt> if contradiction of type constraints comes from declared bounds for type parameters.
|
||||||
|
*
|
||||||
|
* For example, for <pre>fun <R: Any> foo(r: R) {}</pre> in invocation <tt>foo(null)</tt>
|
||||||
|
* upper bounds <tt>Any</tt> for type parameter <tt>R</tt> is violated. <p/>
|
||||||
|
*
|
||||||
|
* It's the special case of 'hasConflictingConstraints' case.
|
||||||
|
*/
|
||||||
|
boolean hasViolatedUpperBound();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <tt>true</tt> if there is no information for some registered type variable.
|
* Returns <tt>true</tt> if there is no information for some registered type variable.
|
||||||
*
|
*
|
||||||
|
|||||||
-9
@@ -25,15 +25,6 @@ import java.util.Collection;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public interface TypeConstraints {
|
public interface TypeConstraints {
|
||||||
@NotNull
|
|
||||||
Set<JetType> getLowerBounds();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
Set<JetType> getUpperBounds();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
Set<JetType> getExactBounds();
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
Variance getVarianceOfPosition();
|
Variance getVarianceOfPosition();
|
||||||
|
|
||||||
|
|||||||
+101
-94
@@ -18,10 +18,12 @@ package org.jetbrains.jet.lang.resolve.calls.inference;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import com.intellij.openapi.util.Condition;
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
|
|
||||||
@@ -30,14 +32,33 @@ import java.util.Collections;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class TypeConstraintsImpl implements TypeConstraints {
|
public class TypeConstraintsImpl implements TypeConstraints {
|
||||||
|
public static enum BoundKind {
|
||||||
|
LOWER_BOUND, UPPER_BOUND, EXACT_BOUND
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Constraint {
|
||||||
|
public final JetType type;
|
||||||
|
public final BoundKind boundKind;
|
||||||
|
public final ConstraintPosition constraintPosition;
|
||||||
|
|
||||||
|
public Constraint(@NotNull JetType type, @NotNull BoundKind boundKind, @NotNull ConstraintPosition constraintPosition) {
|
||||||
|
this.type = type;
|
||||||
|
this.boundKind = boundKind;
|
||||||
|
this.constraintPosition = constraintPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final TypeParameterDescriptor typeVariable;
|
||||||
private final Variance varianceOfPosition;
|
private final Variance varianceOfPosition;
|
||||||
private final Set<JetType> upperBounds = Sets.newLinkedHashSet();
|
private final Set<Constraint> constraints = Sets.newLinkedHashSet();
|
||||||
private final Set<JetType> lowerBounds = Sets.newLinkedHashSet();
|
|
||||||
private final Set<JetType> exactBounds = Sets.newLinkedHashSet();
|
|
||||||
|
|
||||||
private Collection<JetType> resultValues;
|
private Collection<JetType> resultValues;
|
||||||
|
|
||||||
public TypeConstraintsImpl(Variance varianceOfPosition) {
|
public TypeConstraintsImpl(
|
||||||
|
@NotNull TypeParameterDescriptor typeVariable,
|
||||||
|
@NotNull Variance varianceOfPosition
|
||||||
|
) {
|
||||||
|
this.typeVariable = typeVariable;
|
||||||
this.varianceOfPosition = varianceOfPosition;
|
this.varianceOfPosition = varianceOfPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,67 +68,65 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
|||||||
return varianceOfPosition;
|
return varianceOfPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addBound(@NotNull BoundKind boundKind, @NotNull JetType type) {
|
public void addConstraint(@NotNull BoundKind boundKind, @NotNull JetType type, @NotNull ConstraintPosition constraintPosition) {
|
||||||
resultValues = null;
|
resultValues = null;
|
||||||
switch (boundKind) {
|
constraints.add(new Constraint(type, boundKind, constraintPosition));
|
||||||
case LOWER_BOUND:
|
|
||||||
lowerBounds.add(type);
|
|
||||||
break;
|
|
||||||
case UPPER_BOUND:
|
|
||||||
upperBounds.add(type);
|
|
||||||
break;
|
|
||||||
case EXACT_BOUND:
|
|
||||||
exactBounds.add(type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return upperBounds.isEmpty() && lowerBounds.isEmpty() && exactBounds.isEmpty();
|
return getValues().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
public Collection<Constraint> getConstraints() {
|
||||||
public Set<JetType> getLowerBounds() {
|
return constraints;
|
||||||
return lowerBounds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
private static Set<JetType> filterBounds(
|
||||||
public Set<JetType> getUpperBounds() {
|
@NotNull Collection<Constraint> constraints,
|
||||||
return upperBounds;
|
@NotNull BoundKind boundKind
|
||||||
|
) {
|
||||||
|
return filterBounds(constraints, boundKind, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
private static Set<JetType> filterBounds(
|
||||||
public Set<JetType> getExactBounds() {
|
@NotNull Collection<Constraint> constraints,
|
||||||
return exactBounds;
|
@NotNull BoundKind boundKind,
|
||||||
|
@Nullable Collection<JetType> errorValues
|
||||||
|
) {
|
||||||
|
Set<JetType> result = Sets.newLinkedHashSet();
|
||||||
|
for (Constraint constraint : constraints) {
|
||||||
|
if (constraint.boundKind == boundKind) {
|
||||||
|
if (!ErrorUtils.containsErrorType(constraint.type)) {
|
||||||
|
result.add(constraint.type);
|
||||||
|
}
|
||||||
|
else if (errorValues != null) {
|
||||||
|
errorValues.add(constraint.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ TypeConstraintsImpl copy() {
|
/*package*/ TypeConstraintsImpl copy() {
|
||||||
TypeConstraintsImpl typeConstraints = new TypeConstraintsImpl(varianceOfPosition);
|
TypeConstraintsImpl typeConstraints = new TypeConstraintsImpl(typeVariable, varianceOfPosition);
|
||||||
typeConstraints.upperBounds.addAll(upperBounds);
|
typeConstraints.constraints.addAll(constraints);
|
||||||
typeConstraints.lowerBounds.addAll(lowerBounds);
|
|
||||||
typeConstraints.exactBounds.addAll(exactBounds);
|
|
||||||
typeConstraints.resultValues = resultValues;
|
typeConstraints.resultValues = resultValues;
|
||||||
return typeConstraints;
|
return typeConstraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static enum BoundKind {
|
@NotNull
|
||||||
LOWER_BOUND, UPPER_BOUND, EXACT_BOUND
|
public TypeConstraintsImpl filter(@NotNull final Condition<ConstraintPosition> condition) {
|
||||||
}
|
TypeConstraintsImpl result = new TypeConstraintsImpl(typeVariable, varianceOfPosition);
|
||||||
|
result.constraints.addAll(ContainerUtil.filter(constraints, new Condition<Constraint>() {
|
||||||
private Collection<Pair<BoundKind, JetType>> getAllBounds() {
|
@Override
|
||||||
Collection<Pair<BoundKind, JetType>> result = Lists.newArrayList();
|
public boolean value(Constraint constraint) {
|
||||||
for (JetType exactBound : exactBounds) {
|
return condition.value(constraint.constraintPosition);
|
||||||
result.add(Pair.create(BoundKind.EXACT_BOUND, exactBound));
|
}
|
||||||
}
|
}));
|
||||||
for (JetType exactBound : upperBounds) {
|
|
||||||
result.add(Pair.create(BoundKind.UPPER_BOUND, exactBound));
|
|
||||||
}
|
|
||||||
for (JetType exactBound : lowerBounds) {
|
|
||||||
result.add(Pair.create(BoundKind.LOWER_BOUND, exactBound));
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,47 +138,47 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
|||||||
return values.iterator().next();
|
return values.iterator().next();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Collection<JetType> getValues() {
|
public Collection<JetType> getValues() {
|
||||||
if (resultValues == null) {
|
if (resultValues == null) {
|
||||||
resultValues = computeValues();
|
resultValues = computeValues(constraints);
|
||||||
}
|
}
|
||||||
return resultValues;
|
return resultValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<JetType> computeValues() {
|
@NotNull
|
||||||
|
private static Collection<JetType> computeValues(@NotNull Collection<Constraint> constraints) {
|
||||||
Set<JetType> values = Sets.newLinkedHashSet();
|
Set<JetType> values = Sets.newLinkedHashSet();
|
||||||
if (isEmpty()) {
|
if (constraints.isEmpty()) {
|
||||||
return values;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
TypeConstraints withoutErrorTypes = filterNotContainingErrorType(values);
|
|
||||||
Collection<JetType> exactBounds = withoutErrorTypes.getExactBounds();
|
Set<JetType> exactBounds = filterBounds(constraints, BoundKind.EXACT_BOUND, values);
|
||||||
if (exactBounds.size() == 1) {
|
if (exactBounds.size() == 1) {
|
||||||
JetType exactBound = exactBounds.iterator().next();
|
JetType exactBound = exactBounds.iterator().next();
|
||||||
if (trySuggestion(exactBound)) {
|
if (trySuggestion(exactBound, constraints)) {
|
||||||
return Collections.singleton(exactBound);
|
return Collections.singleton(exactBound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
values.addAll(exactBounds);
|
values.addAll(exactBounds);
|
||||||
|
|
||||||
Pair<Collection<JetType>, Collection<JetType>> pair =
|
Pair<Collection<JetType>, Collection<JetType>> pair =
|
||||||
TypeUtils.filterNumberTypes(withoutErrorTypes.getLowerBounds());
|
TypeUtils.filterNumberTypes(filterBounds(constraints, BoundKind.LOWER_BOUND, values));
|
||||||
Collection<JetType> generalLowerBounds = pair.getFirst();
|
Collection<JetType> generalLowerBounds = pair.getFirst();
|
||||||
Collection<JetType> numberLowerBounds = pair.getSecond();
|
Collection<JetType> numberLowerBounds = pair.getSecond();
|
||||||
|
|
||||||
JetType superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds);
|
JetType superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds);
|
||||||
if (trySuggestion(superTypeOfLowerBounds)) {
|
if (trySuggestion(superTypeOfLowerBounds, constraints)) {
|
||||||
return Collections.singleton(superTypeOfLowerBounds);
|
return Collections.singleton(superTypeOfLowerBounds);
|
||||||
}
|
}
|
||||||
ContainerUtil.addIfNotNull(superTypeOfLowerBounds, values);
|
ContainerUtil.addIfNotNull(superTypeOfLowerBounds, values);
|
||||||
|
|
||||||
Collection<JetType> upperBounds = withoutErrorTypes.getUpperBounds();
|
Set<JetType> upperBounds = filterBounds(constraints, BoundKind.UPPER_BOUND, values);
|
||||||
for (JetType upperBound : upperBounds) {
|
for (JetType upperBound : upperBounds) {
|
||||||
if (trySuggestion(upperBound)) {
|
if (trySuggestion(upperBound, constraints)) {
|
||||||
return Collections.singleton(upperBound);
|
return Collections.singleton(upperBound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,10 +186,10 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
|||||||
//fun <T> foo(t: T, consumer: Consumer<T>): T
|
//fun <T> foo(t: T, consumer: Consumer<T>): T
|
||||||
//foo(1, c: Consumer<Any>) - infer Int, not Any here
|
//foo(1, c: Consumer<Any>) - infer Int, not Any here
|
||||||
|
|
||||||
values.addAll(withoutErrorTypes.getUpperBounds());
|
values.addAll(filterBounds(constraints, BoundKind.UPPER_BOUND));
|
||||||
|
|
||||||
JetType superTypeOfNumberLowerBounds = TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds);
|
JetType superTypeOfNumberLowerBounds = TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds);
|
||||||
if (trySuggestion(superTypeOfNumberLowerBounds)) {
|
if (trySuggestion(superTypeOfNumberLowerBounds, constraints)) {
|
||||||
return Collections.singleton(superTypeOfNumberLowerBounds);
|
return Collections.singleton(superTypeOfNumberLowerBounds);
|
||||||
}
|
}
|
||||||
ContainerUtil.addIfNotNull(superTypeOfNumberLowerBounds, values);
|
ContainerUtil.addIfNotNull(superTypeOfNumberLowerBounds, values);
|
||||||
@@ -178,54 +197,42 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
|||||||
if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) {
|
if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) {
|
||||||
JetType superTypeOfAllLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(
|
JetType superTypeOfAllLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(
|
||||||
Lists.newArrayList(superTypeOfLowerBounds, superTypeOfNumberLowerBounds));
|
Lists.newArrayList(superTypeOfLowerBounds, superTypeOfNumberLowerBounds));
|
||||||
if (trySuggestion(superTypeOfAllLowerBounds)) {
|
if (trySuggestion(superTypeOfAllLowerBounds, constraints)) {
|
||||||
return Collections.singleton(superTypeOfAllLowerBounds);
|
return Collections.singleton(superTypeOfAllLowerBounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean trySuggestion(
|
private static boolean trySuggestion(
|
||||||
@Nullable JetType suggestion
|
@Nullable JetType suggestion,
|
||||||
|
@NotNull Collection<Constraint> constraints
|
||||||
) {
|
) {
|
||||||
if (suggestion == null) return false;
|
if (suggestion == null) return false;
|
||||||
if (!suggestion.getConstructor().isDenotable()) return false;
|
if (!suggestion.getConstructor().isDenotable()) return false;
|
||||||
if (getExactBounds().size() > 1) return false;
|
if (filterBounds(constraints, BoundKind.EXACT_BOUND).size() > 1) return false;
|
||||||
|
|
||||||
for (JetType exactBound : getExactBounds()) {
|
for (Constraint constraint : constraints) {
|
||||||
if (!JetTypeChecker.INSTANCE.equalTypes(exactBound, suggestion)) {
|
switch (constraint.boundKind) {
|
||||||
return false;
|
case LOWER_BOUND:
|
||||||
}
|
if (!JetTypeChecker.INSTANCE.isSubtypeOf(constraint.type, suggestion)) {
|
||||||
}
|
return false;
|
||||||
for (JetType lowerBound : getLowerBounds()) {
|
}
|
||||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(lowerBound, suggestion)) {
|
break;
|
||||||
return false;
|
|
||||||
}
|
case UPPER_BOUND:
|
||||||
}
|
if (!JetTypeChecker.INSTANCE.isSubtypeOf(suggestion, constraint.type)) {
|
||||||
for (JetType upperBound : getUpperBounds()) {
|
return false;
|
||||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(suggestion, upperBound)) {
|
}
|
||||||
return false;
|
break;
|
||||||
|
|
||||||
|
case EXACT_BOUND:
|
||||||
|
if (!JetTypeChecker.INSTANCE.equalTypes(constraint.type, suggestion)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private TypeConstraints filterNotContainingErrorType(
|
|
||||||
@NotNull Collection<JetType> values
|
|
||||||
) {
|
|
||||||
TypeConstraintsImpl typeConstraintsWithoutErrorType = new TypeConstraintsImpl(getVarianceOfPosition());
|
|
||||||
Collection<Pair<TypeConstraintsImpl.BoundKind, JetType>> allBounds = getAllBounds();
|
|
||||||
for (Pair<TypeConstraintsImpl.BoundKind, JetType> pair : allBounds) {
|
|
||||||
TypeConstraintsImpl.BoundKind boundKind = pair.getFirst();
|
|
||||||
JetType type = pair.getSecond();
|
|
||||||
if (ErrorUtils.containsErrorType(type)) {
|
|
||||||
values.add(type);
|
|
||||||
}
|
|
||||||
else if (type != null) {
|
|
||||||
typeConstraintsWithoutErrorType.addBound(boundKind, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return typeConstraintsWithoutErrorType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,11 +201,11 @@ public class IdeRenderers {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Renderer<InferenceErrorData> HTML_TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER =
|
public static final Renderer<ExtendedInferenceErrorData> HTML_TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER =
|
||||||
new Renderer<InferenceErrorData>() {
|
new Renderer<ExtendedInferenceErrorData>() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public String render(@NotNull InferenceErrorData inferenceErrorData) {
|
public String render(@NotNull ExtendedInferenceErrorData inferenceErrorData) {
|
||||||
return renderUpperBoundViolatedInferenceError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
|
return renderUpperBoundViolatedInferenceError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,5 +3,24 @@ package i
|
|||||||
fun foo<R, T: List<R>>(r: R, list: T) {}
|
fun foo<R, T: List<R>>(r: R, list: T) {}
|
||||||
|
|
||||||
fun test1(i: Int, collection: Collection<Int>) {
|
fun test1(i: Int, collection: Collection<Int>) {
|
||||||
foo(i, collection)
|
foo(i, collection) //error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------
|
||||||
|
fun bar<V : U, U>(v: V, u: MutableSet<U>) = u
|
||||||
|
|
||||||
|
fun test2(a: Any, s: MutableSet<String>) {
|
||||||
|
bar(a, s) //error
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------
|
||||||
|
trait A
|
||||||
|
class B
|
||||||
|
|
||||||
|
fun baz<T: R, R: B>(t: T, r: R) where T: A {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test3(a: A, b: B) {
|
||||||
|
baz(a, b) //error
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<!-- upperBoundViolated2 -->
|
||||||
|
<html>
|
||||||
|
Type parameter bound for <b>
|
||||||
|
V</b>
|
||||||
|
in <table>
|
||||||
|
<tr>
|
||||||
|
<td width="10%">
|
||||||
|
</td>
|
||||||
|
<td align="right" colspan="2" style="white-space:nowrap;font-weight:bold;">
|
||||||
|
<b>
|
||||||
|
fun</b>
|
||||||
|
<V : U, U>
|
||||||
|
bar</td>
|
||||||
|
<td style="white-space:nowrap;font-weight:bold;">
|
||||||
|
(</td>
|
||||||
|
<td align="right" style="white-space:nowrap;font-weight:bold;">
|
||||||
|
v: V,</td>
|
||||||
|
<td align="right" style="white-space:nowrap;font-weight:bold;">
|
||||||
|
u: jet.MutableSet<U></td>
|
||||||
|
<td style="white-space:nowrap;font-weight:bold;">
|
||||||
|
)</td>
|
||||||
|
<td style="white-space:nowrap;font-weight:bold;">
|
||||||
|
: jet.MutableSet<U></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
is not satisfied: inferred type <font color=red>
|
||||||
|
<b>
|
||||||
|
jet.Any</b>
|
||||||
|
</font>
|
||||||
|
is not a subtype of <b>
|
||||||
|
jet.String</b>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<!-- upperBoundViolated3 -->
|
||||||
|
<html>
|
||||||
|
Type parameter bound for <b>
|
||||||
|
T</b>
|
||||||
|
in <table>
|
||||||
|
<tr>
|
||||||
|
<td width="10%">
|
||||||
|
</td>
|
||||||
|
<td align="right" colspan="2" style="white-space:nowrap;font-weight:bold;">
|
||||||
|
<b>
|
||||||
|
fun</b>
|
||||||
|
<T : R, R : i.B>
|
||||||
|
baz</td>
|
||||||
|
<td style="white-space:nowrap;font-weight:bold;">
|
||||||
|
(</td>
|
||||||
|
<td align="right" style="white-space:nowrap;font-weight:bold;">
|
||||||
|
t: T,</td>
|
||||||
|
<td align="right" style="white-space:nowrap;font-weight:bold;">
|
||||||
|
r: R</td>
|
||||||
|
<td style="white-space:nowrap;font-weight:bold;">
|
||||||
|
)</td>
|
||||||
|
<td style="white-space:nowrap;font-weight:bold;">
|
||||||
|
: jet.Unit <b>
|
||||||
|
where</b>
|
||||||
|
T : i.A</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
is not satisfied: inferred type <font color=red>
|
||||||
|
<b>
|
||||||
|
i.A</b>
|
||||||
|
</font>
|
||||||
|
is not a subtype of <b>
|
||||||
|
i.B</b>
|
||||||
|
</html>
|
||||||
@@ -103,7 +103,7 @@ public class DiagnosticMessageTest extends JetLiteFixture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testUpperBoundViolated() throws Exception {
|
public void testUpperBoundViolated() throws Exception {
|
||||||
doTest("upperBoundViolated", 1, Errors.TYPE_INFERENCE_UPPER_BOUND_VIOLATED);
|
doTest("upperBoundViolated", 3, Errors.TYPE_INFERENCE_UPPER_BOUND_VIOLATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testTypeMismatchWithNothing() throws Exception {
|
public void testTypeMismatchWithNothing() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user