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_CONFLICTING_SUBSTITUTIONS = 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);
|
||||
|
||||
// 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.JetClassOrObject;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
|
||||
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.inference.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
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 =
|
||||
new Renderer<InferenceErrorData>() {
|
||||
public static final Renderer<ExtendedInferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER =
|
||||
new Renderer<ExtendedInferenceErrorData>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public String render(@NotNull InferenceErrorData inferenceErrorData) {
|
||||
public String render(@NotNull ExtendedInferenceErrorData inferenceErrorData) {
|
||||
return renderUpperBoundViolatedInferenceError(inferenceErrorData, TabledDescriptorRenderer.create()).toString();
|
||||
}
|
||||
};
|
||||
@@ -265,32 +262,47 @@ public class Renderers {
|
||||
.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;
|
||||
ConstraintSystemImpl constraintSystem = (ConstraintSystemImpl) inferenceErrorData.constraintSystem;
|
||||
assert constraintSystem.getStatus().hasViolatedUpperBound();
|
||||
|
||||
ConstraintSystem systemWithoutWeakConstraints = constraintSystem.getSystemWithoutWeakConstraints();
|
||||
for (TypeParameterDescriptor typeParameter : inferenceErrorData.descriptor.getTypeParameters()) {
|
||||
if (!ConstraintsUtil.checkUpperBoundIsSatisfied(inferenceErrorData.constraintSystem, typeParameter, true)) {
|
||||
if (!ConstraintsUtil.checkUpperBoundIsSatisfied(systemWithoutWeakConstraints, typeParameter, true)) {
|
||||
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 "))
|
||||
.table(newTable().
|
||||
descriptor(inferenceErrorData.descriptor));
|
||||
|
||||
JetType inferredValueForTypeParameter = inferenceErrorData.constraintSystem.getTypeConstraints(typeParameterDescriptor).getValue();
|
||||
assert inferredValueForTypeParameter != null;
|
||||
JetType upperBound = typeParameterDescriptor.getUpperBoundsAsType();
|
||||
JetType upperBoundWithSubstitutedInferredTypes = inferenceErrorData.constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT);
|
||||
assert upperBoundWithSubstitutedInferredTypes != null;
|
||||
JetType violatedUpperBound = null;
|
||||
for (JetType upperBound : typeParameterDescriptor.getUpperBounds()) {
|
||||
JetType upperBoundWithSubstitutedInferredTypes =
|
||||
systemWithoutWeakConstraints.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT);
|
||||
if (upperBoundWithSubstitutedInferredTypes != null &&
|
||||
!JetTypeChecker.INSTANCE.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) {
|
||||
violatedUpperBound = upperBoundWithSubstitutedInferredTypes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert violatedUpperBound != null : errorMessage;
|
||||
|
||||
Renderer<JetType> typeRenderer = result.getTypeRenderer();
|
||||
result.text(newText()
|
||||
.normal(" is not satisfied: inferred type ")
|
||||
.error(typeRenderer.render(inferredValueForTypeParameter))
|
||||
.normal(" is not a subtype of ")
|
||||
.strong(typeRenderer.render(upperBoundWithSubstitutedInferredTypes)));
|
||||
.strong(typeRenderer.render(violatedUpperBound)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -232,19 +232,13 @@ public class CandidateResolver {
|
||||
|
||||
updateSystemWithConstraintSystemCompleter(context, resolvedCall);
|
||||
|
||||
if (resolvedCall.getConstraintSystem().getStatus().hasContradiction()) {
|
||||
return reportInferenceError(context);
|
||||
}
|
||||
updateSystemIfExpectedTypeIsUnit(context, resolvedCall);
|
||||
|
||||
boolean boundsAreSatisfied = updateSystemCheckingBounds(resolvedCall);
|
||||
((ConstraintSystemImpl)resolvedCall.getConstraintSystem()).processDeclaredBoundConstraints();
|
||||
|
||||
if (!resolvedCall.getConstraintSystem().getStatus().isSuccessful()) {
|
||||
return reportInferenceError(context);
|
||||
}
|
||||
if (!boundsAreSatisfied) {
|
||||
context.tracing.upperBoundViolated(context.trace, InferenceErrorData.create(
|
||||
resolvedCall.getCandidateDescriptor(), resolvedCall.getConstraintSystem()));
|
||||
}
|
||||
resolvedCall.setResultingSubstitutor(resolvedCall.getConstraintSystem().getResultingSubstitutor());
|
||||
|
||||
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(
|
||||
@NotNull CallCandidateResolutionContext<D> context
|
||||
) {
|
||||
ResolvedCallImpl<D> resolvedCall = context.candidateCall;
|
||||
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
|
||||
assert constraintSystem != null;
|
||||
|
||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
||||
completeNestedCallsInference(context);
|
||||
@@ -471,7 +447,8 @@ public class CandidateResolver {
|
||||
if (expression == null) return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -617,9 +594,8 @@ public class CandidateResolver {
|
||||
|
||||
// Solution
|
||||
boolean hasContradiction = constraintSystem.getStatus().hasContradiction();
|
||||
boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/false);
|
||||
candidateCall.setHasUnknownTypeParameters(true);
|
||||
if (!hasContradiction && boundsAreSatisfied) {
|
||||
if (!hasContradiction) {
|
||||
return INCOMPLETE_TYPE_INFERENCE;
|
||||
}
|
||||
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.psi.JetExpression;
|
||||
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.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
@@ -95,9 +94,6 @@ public interface TracingStrategy {
|
||||
|
||||
@Override
|
||||
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);
|
||||
@@ -140,6 +136,4 @@ public interface TracingStrategy {
|
||||
void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor);
|
||||
|
||||
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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
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";
|
||||
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()) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
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;
|
||||
|
||||
public class ConstraintPosition {
|
||||
public static final ConstraintPosition RECEIVER_POSITION = new ConstraintPosition("RECEIVER_POSITION");
|
||||
public static final ConstraintPosition EXPECTED_TYPE_POSITION = new ConstraintPosition("EXPECTED_TYPE_POSITION");
|
||||
public static final ConstraintPosition BOUND_CONSTRAINT_POSITION = new ConstraintPosition("BOUND_CONSTRAINT_POSITION");
|
||||
public static final ConstraintPosition FROM_COMPLETER = new ConstraintPosition("FROM_COMPLETER");
|
||||
public static final ConstraintPosition SPECIAL = new ConstraintPosition("SPECIAL");
|
||||
public static final ConstraintPosition RECEIVER_POSITION = new ConstraintPosition("RECEIVER_POSITION", true);
|
||||
public static final ConstraintPosition EXPECTED_TYPE_POSITION = new ConstraintPosition("EXPECTED_TYPE_POSITION", true);
|
||||
public static final ConstraintPosition FROM_COMPLETER = new ConstraintPosition("FROM_COMPLETER", true);
|
||||
public static final ConstraintPosition SPECIAL = new ConstraintPosition("SPECIAL", true);
|
||||
|
||||
private static final Map<Integer, ConstraintPosition> valueParameterPositions = Maps.newHashMap();
|
||||
private static final Map<Integer, ConstraintPosition> typeBoundPositions = Maps.newHashMap();
|
||||
|
||||
public static ConstraintPosition getValueParameterPosition(int index) {
|
||||
ConstraintPosition position = valueParameterPositions.get(index);
|
||||
if (position == null) {
|
||||
position = new ConstraintPosition("VALUE_PARAMETER_POSITION(" + index + ")");
|
||||
position = new ConstraintPosition("VALUE_PARAMETER_POSITION(" + index + ")", true);
|
||||
valueParameterPositions.put(index, 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;
|
||||
this.isStrong = isStrong;
|
||||
}
|
||||
|
||||
public boolean isStrong() {
|
||||
return isStrong;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+92
-21
@@ -21,6 +21,9 @@ import com.google.common.base.Functions;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
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.Nullable;
|
||||
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.lang.KotlinBuiltIns;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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.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 {
|
||||
|
||||
@@ -67,10 +73,16 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
||||
return hasTypeConstructorMismatch() || hasConflictingConstraints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasViolatedUpperBound() {
|
||||
if (isSuccessful()) return false;
|
||||
ConstraintSystem systemWithoutWeakConstraints = getSystemWithoutWeakConstraints();
|
||||
return systemWithoutWeakConstraints.getStatus().isSuccessful();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConflictingConstraints() {
|
||||
for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
|
||||
TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
|
||||
for (TypeConstraintsImpl typeConstraints : typeParameterConstraints.values()) {
|
||||
if (typeConstraints.getValues().size() > 1) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -78,8 +90,8 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
||||
|
||||
@Override
|
||||
public boolean hasUnknownParameters() {
|
||||
for (TypeConstraintsImpl constraints : typeParameterConstraints.values()) {
|
||||
if (constraints.isEmpty()) {
|
||||
for (TypeConstraintsImpl typeConstraints : typeParameterConstraints.values()) {
|
||||
if (typeConstraints.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -167,25 +179,78 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
||||
for (Map.Entry<TypeParameterDescriptor, Variance> entry : typeVariables.entrySet()) {
|
||||
TypeParameterDescriptor typeVariable = entry.getKey();
|
||||
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
|
||||
@NotNull
|
||||
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
|
||||
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
|
||||
private ConstraintSystem replaceTypeVariables(
|
||||
@NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap,
|
||||
boolean recreateTypeConstraints
|
||||
@NotNull Function<TypeConstraintsImpl, TypeConstraintsImpl> typeConstraintsMap,
|
||||
@NotNull Condition<ConstraintPosition> constraintPositionCondition
|
||||
|
||||
) {
|
||||
ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl();
|
||||
for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
|
||||
@@ -194,9 +259,9 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
||||
|
||||
TypeParameterDescriptor newTypeParameter = typeVariablesMap.apply(typeParameter);
|
||||
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;
|
||||
return newConstraintSystem;
|
||||
}
|
||||
@@ -267,7 +332,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -308,7 +373,7 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
||||
// can be considered as extension function if one is expected
|
||||
// (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
|
||||
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:
|
||||
@@ -320,11 +385,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
// 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(
|
||||
@NotNull JetType parameterType,
|
||||
@NotNull JetType constrainingType,
|
||||
@NotNull BoundKind boundKind
|
||||
@NotNull BoundKind boundKind,
|
||||
@NotNull ConstraintPosition constraintPosition
|
||||
) {
|
||||
TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType);
|
||||
assert typeConstraints != null : "constraint should be generated only for type variables";
|
||||
|
||||
if (!parameterType.isNullable() || !constrainingType.isNullable()) {
|
||||
typeConstraints.addBound(boundKind, constrainingType);
|
||||
typeConstraints.addConstraint(boundKind, constrainingType, constraintPosition);
|
||||
return;
|
||||
}
|
||||
// For parameter type T:
|
||||
@@ -349,11 +415,11 @@ public class ConstraintSystemImpl implements ConstraintSystem {
|
||||
// constraint T? >: Int? should transform to T >: Int
|
||||
JetType notNullConstrainingType = TypeUtils.makeNotNullable(constrainingType);
|
||||
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?
|
||||
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();
|
||||
for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
|
||||
//todo order matters here
|
||||
for (JetType lowerOrExactBound : Sets.union(typeConstraints.getLowerBounds(), typeConstraints.getExactBounds())) {
|
||||
addSubtypeConstraint(lowerOrExactBound, declaredUpperBound, ConstraintPosition.BOUND_CONSTRAINT_POSITION);
|
||||
Collection<Constraint> constraints = Lists.newArrayList(typeConstraints.getConstraints());
|
||||
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();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
-9
@@ -25,15 +25,6 @@ import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
public interface TypeConstraints {
|
||||
@NotNull
|
||||
Set<JetType> getLowerBounds();
|
||||
|
||||
@NotNull
|
||||
Set<JetType> getUpperBounds();
|
||||
|
||||
@NotNull
|
||||
Set<JetType> getExactBounds();
|
||||
|
||||
@NotNull
|
||||
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.Sets;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
|
||||
@@ -30,14 +32,33 @@ import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
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 Set<JetType> upperBounds = Sets.newLinkedHashSet();
|
||||
private final Set<JetType> lowerBounds = Sets.newLinkedHashSet();
|
||||
private final Set<JetType> exactBounds = Sets.newLinkedHashSet();
|
||||
private final Set<Constraint> constraints = Sets.newLinkedHashSet();
|
||||
|
||||
private Collection<JetType> resultValues;
|
||||
|
||||
public TypeConstraintsImpl(Variance varianceOfPosition) {
|
||||
public TypeConstraintsImpl(
|
||||
@NotNull TypeParameterDescriptor typeVariable,
|
||||
@NotNull Variance varianceOfPosition
|
||||
) {
|
||||
this.typeVariable = typeVariable;
|
||||
this.varianceOfPosition = varianceOfPosition;
|
||||
}
|
||||
|
||||
@@ -47,67 +68,65 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
||||
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;
|
||||
switch (boundKind) {
|
||||
case LOWER_BOUND:
|
||||
lowerBounds.add(type);
|
||||
break;
|
||||
case UPPER_BOUND:
|
||||
upperBounds.add(type);
|
||||
break;
|
||||
case EXACT_BOUND:
|
||||
exactBounds.add(type);
|
||||
}
|
||||
constraints.add(new Constraint(type, boundKind, constraintPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return upperBounds.isEmpty() && lowerBounds.isEmpty() && exactBounds.isEmpty();
|
||||
return getValues().isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<JetType> getLowerBounds() {
|
||||
return lowerBounds;
|
||||
public Collection<Constraint> getConstraints() {
|
||||
return constraints;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<JetType> getUpperBounds() {
|
||||
return upperBounds;
|
||||
private static Set<JetType> filterBounds(
|
||||
@NotNull Collection<Constraint> constraints,
|
||||
@NotNull BoundKind boundKind
|
||||
) {
|
||||
return filterBounds(constraints, boundKind, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<JetType> getExactBounds() {
|
||||
return exactBounds;
|
||||
private static Set<JetType> filterBounds(
|
||||
@NotNull Collection<Constraint> constraints,
|
||||
@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() {
|
||||
TypeConstraintsImpl typeConstraints = new TypeConstraintsImpl(varianceOfPosition);
|
||||
typeConstraints.upperBounds.addAll(upperBounds);
|
||||
typeConstraints.lowerBounds.addAll(lowerBounds);
|
||||
typeConstraints.exactBounds.addAll(exactBounds);
|
||||
TypeConstraintsImpl typeConstraints = new TypeConstraintsImpl(typeVariable, varianceOfPosition);
|
||||
typeConstraints.constraints.addAll(constraints);
|
||||
typeConstraints.resultValues = resultValues;
|
||||
return typeConstraints;
|
||||
}
|
||||
|
||||
public static enum BoundKind {
|
||||
LOWER_BOUND, UPPER_BOUND, EXACT_BOUND
|
||||
}
|
||||
|
||||
private Collection<Pair<BoundKind, JetType>> getAllBounds() {
|
||||
Collection<Pair<BoundKind, JetType>> result = Lists.newArrayList();
|
||||
for (JetType exactBound : exactBounds) {
|
||||
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));
|
||||
}
|
||||
@NotNull
|
||||
public TypeConstraintsImpl filter(@NotNull final Condition<ConstraintPosition> condition) {
|
||||
TypeConstraintsImpl result = new TypeConstraintsImpl(typeVariable, varianceOfPosition);
|
||||
result.constraints.addAll(ContainerUtil.filter(constraints, new Condition<Constraint>() {
|
||||
@Override
|
||||
public boolean value(Constraint constraint) {
|
||||
return condition.value(constraint.constraintPosition);
|
||||
}
|
||||
}));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -119,47 +138,47 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
||||
return values.iterator().next();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JetType> getValues() {
|
||||
if (resultValues == null) {
|
||||
resultValues = computeValues();
|
||||
resultValues = computeValues(constraints);
|
||||
}
|
||||
return resultValues;
|
||||
}
|
||||
|
||||
private Collection<JetType> computeValues() {
|
||||
@NotNull
|
||||
private static Collection<JetType> computeValues(@NotNull Collection<Constraint> constraints) {
|
||||
Set<JetType> values = Sets.newLinkedHashSet();
|
||||
if (isEmpty()) {
|
||||
return values;
|
||||
if (constraints.isEmpty()) {
|
||||
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) {
|
||||
JetType exactBound = exactBounds.iterator().next();
|
||||
if (trySuggestion(exactBound)) {
|
||||
if (trySuggestion(exactBound, constraints)) {
|
||||
return Collections.singleton(exactBound);
|
||||
}
|
||||
}
|
||||
values.addAll(exactBounds);
|
||||
|
||||
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> numberLowerBounds = pair.getSecond();
|
||||
|
||||
JetType superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds);
|
||||
if (trySuggestion(superTypeOfLowerBounds)) {
|
||||
if (trySuggestion(superTypeOfLowerBounds, constraints)) {
|
||||
return Collections.singleton(superTypeOfLowerBounds);
|
||||
}
|
||||
ContainerUtil.addIfNotNull(superTypeOfLowerBounds, values);
|
||||
|
||||
Collection<JetType> upperBounds = withoutErrorTypes.getUpperBounds();
|
||||
Set<JetType> upperBounds = filterBounds(constraints, BoundKind.UPPER_BOUND, values);
|
||||
for (JetType upperBound : upperBounds) {
|
||||
if (trySuggestion(upperBound)) {
|
||||
if (trySuggestion(upperBound, constraints)) {
|
||||
return Collections.singleton(upperBound);
|
||||
}
|
||||
}
|
||||
@@ -167,10 +186,10 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
||||
//fun <T> foo(t: T, consumer: Consumer<T>): T
|
||||
//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);
|
||||
if (trySuggestion(superTypeOfNumberLowerBounds)) {
|
||||
if (trySuggestion(superTypeOfNumberLowerBounds, constraints)) {
|
||||
return Collections.singleton(superTypeOfNumberLowerBounds);
|
||||
}
|
||||
ContainerUtil.addIfNotNull(superTypeOfNumberLowerBounds, values);
|
||||
@@ -178,54 +197,42 @@ public class TypeConstraintsImpl implements TypeConstraints {
|
||||
if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) {
|
||||
JetType superTypeOfAllLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(
|
||||
Lists.newArrayList(superTypeOfLowerBounds, superTypeOfNumberLowerBounds));
|
||||
if (trySuggestion(superTypeOfAllLowerBounds)) {
|
||||
if (trySuggestion(superTypeOfAllLowerBounds, constraints)) {
|
||||
return Collections.singleton(superTypeOfAllLowerBounds);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private boolean trySuggestion(
|
||||
@Nullable JetType suggestion
|
||||
private static boolean trySuggestion(
|
||||
@Nullable JetType suggestion,
|
||||
@NotNull Collection<Constraint> constraints
|
||||
) {
|
||||
if (suggestion == null) 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()) {
|
||||
if (!JetTypeChecker.INSTANCE.equalTypes(exactBound, suggestion)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (JetType lowerBound : getLowerBounds()) {
|
||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(lowerBound, suggestion)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (JetType upperBound : getUpperBounds()) {
|
||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(suggestion, upperBound)) {
|
||||
return false;
|
||||
for (Constraint constraint : constraints) {
|
||||
switch (constraint.boundKind) {
|
||||
case LOWER_BOUND:
|
||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(constraint.type, suggestion)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case UPPER_BOUND:
|
||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(suggestion, constraint.type)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXACT_BOUND:
|
||||
if (!JetTypeChecker.INSTANCE.equalTypes(constraint.type, suggestion)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 =
|
||||
new Renderer<InferenceErrorData>() {
|
||||
public static final Renderer<ExtendedInferenceErrorData> HTML_TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER =
|
||||
new Renderer<ExtendedInferenceErrorData>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public String render(@NotNull InferenceErrorData inferenceErrorData) {
|
||||
public String render(@NotNull ExtendedInferenceErrorData inferenceErrorData) {
|
||||
return renderUpperBoundViolatedInferenceError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,5 +3,24 @@ package i
|
||||
fun foo<R, T: List<R>>(r: R, list: T) {}
|
||||
|
||||
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 {
|
||||
doTest("upperBoundViolated", 1, Errors.TYPE_INFERENCE_UPPER_BOUND_VIOLATED);
|
||||
doTest("upperBoundViolated", 3, Errors.TYPE_INFERENCE_UPPER_BOUND_VIOLATED);
|
||||
}
|
||||
|
||||
public void testTypeMismatchWithNothing() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user