From 731efd07819d5a7d88622917aa1eb0d465069f61 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Thu, 26 Sep 2013 14:05:49 +0400 Subject: [PATCH] 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 --- .../jet/lang/diagnostics/Errors.java | 2 +- .../lang/diagnostics/rendering/Renderers.java | 46 +++-- .../lang/resolve/calls/CandidateResolver.java | 36 +--- .../resolve/calls/tasks/TracingStrategy.java | 6 - .../calls/tasks/TracingStrategyImpl.java | 9 +- .../ControlStructureTypingUtils.java | 7 - .../calls/inference/ConstraintPosition.java | 62 +++++- .../calls/inference/ConstraintSystemImpl.java | 113 ++++++++-- .../inference/ConstraintSystemStatus.java | 10 + .../calls/inference/TypeConstraints.java | 9 - .../calls/inference/TypeConstraintsImpl.java | 195 +++++++++--------- .../jet/plugin/highlighter/IdeRenderers.java | 6 +- .../diagnosticMessage/upperBoundViolated.kt | 23 ++- .../upperBoundViolated2.html | 32 +++ .../upperBoundViolated3.html | 34 +++ .../highlighter/DiagnosticMessageTest.java | 2 +- 16 files changed, 387 insertions(+), 205 deletions(-) create mode 100644 idea/testData/diagnosticMessage/upperBoundViolated2.html create mode 100644 idea/testData/diagnosticMessage/upperBoundViolated3.html diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index ac9709bc744..3707180d809 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -354,7 +354,7 @@ public interface Errors { DiagnosticFactory1 TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH = DiagnosticFactory1.create(ERROR); - DiagnosticFactory1 TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1 TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); // Callable references diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java index 918e743e8a6..0ec2114a188 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java @@ -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 TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER = - new Renderer() { + public static final Renderer TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER = + new Renderer() { @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 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; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index ef4196b3802..8a9885f7d19 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -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 boolean updateSystemCheckingBounds( - @NotNull ResolvedCallImpl 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 JetType reportInferenceError( @NotNull CallCandidateResolutionContext context ) { ResolvedCallImpl 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); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategy.java index 4e152fcc247..49a0dfc6717 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategy.java @@ -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) {} }; void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace 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); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java index 0ff64e4108d..9c254243b8a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java @@ -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)); - } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java index a2f7488699f..088253f51a1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java @@ -477,12 +477,5 @@ public class ControlStructureTypingUtils { ) { throwError(); } - - @Override - public void upperBoundViolated( - @NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData - ) { - throwError(); - } } } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintPosition.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintPosition.java index e36aa2d30b5..86aec6c47b9 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintPosition.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintPosition.java @@ -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 valueParameterPositions = Maps.newHashMap(); + private static final Map 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 positions; + + public CompoundConstraintPosition(Collection 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 positions, final boolean strong) { + return ContainerUtil.exists(positions, new Condition() { + @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 diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java index f9b3d689905..a30c386e7c7 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java @@ -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 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 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.identity(), true); + return replaceTypeVariables(Functions.identity(), + new Function() { + @Override + public TypeConstraintsImpl apply(TypeConstraintsImpl typeConstraints) { + return typeConstraints.copy(); + } + }, + Conditions.alwaysTrue()); } @NotNull public ConstraintSystem replaceTypeVariables(@NotNull Function typeVariablesMap) { - return replaceTypeVariables(typeVariablesMap, false); + return replaceTypeVariables(typeVariablesMap, + Functions.identity(), + Conditions.alwaysTrue()); + } + + @NotNull + public ConstraintSystem filterConstrains(@NotNull final Condition condition) { + return replaceTypeVariables(Functions.identity(), + new Function() { + @Override + public TypeConstraintsImpl apply(TypeConstraintsImpl typeConstraints) { + return typeConstraints.filter(condition); + } + }, + condition); + } + + @NotNull + public ConstraintSystem getSystemWithoutWeakConstraints() { + return filterConstrains(new Condition() { + @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 typeVariablesMap, - boolean recreateTypeConstraints + @NotNull Function typeConstraintsMap, + @NotNull Condition constraintPositionCondition + ) { ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl(); for (Map.Entry 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 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); + } } } } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemStatus.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemStatus.java index 76a0cc6df62..1c87cf69b02 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemStatus.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemStatus.java @@ -43,6 +43,16 @@ public interface ConstraintSystemStatus { */ boolean hasConflictingConstraints(); + /** + * Returns true if contradiction of type constraints comes from declared bounds for type parameters. + * + * For example, for
fun <R: Any> foo(r: R) {}
in invocation foo(null) + * upper bounds Any for type parameter R is violated.

+ * + * It's the special case of 'hasConflictingConstraints' case. + */ + boolean hasViolatedUpperBound(); + /** * Returns true if there is no information for some registered type variable. * diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraints.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraints.java index 5a9bbff7000..45d93aa348f 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraints.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraints.java @@ -25,15 +25,6 @@ import java.util.Collection; import java.util.Set; public interface TypeConstraints { - @NotNull - Set getLowerBounds(); - - @NotNull - Set getUpperBounds(); - - @NotNull - Set getExactBounds(); - @NotNull Variance getVarianceOfPosition(); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraintsImpl.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraintsImpl.java index fd8a1c27cc1..1c7c4421095 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraintsImpl.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeConstraintsImpl.java @@ -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 upperBounds = Sets.newLinkedHashSet(); - private final Set lowerBounds = Sets.newLinkedHashSet(); - private final Set exactBounds = Sets.newLinkedHashSet(); + private final Set constraints = Sets.newLinkedHashSet(); private Collection 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 getLowerBounds() { - return lowerBounds; + public Collection getConstraints() { + return constraints; } @NotNull - @Override - public Set getUpperBounds() { - return upperBounds; + private static Set filterBounds( + @NotNull Collection constraints, + @NotNull BoundKind boundKind + ) { + return filterBounds(constraints, boundKind, null); } @NotNull - @Override - public Set getExactBounds() { - return exactBounds; + private static Set filterBounds( + @NotNull Collection constraints, + @NotNull BoundKind boundKind, + @Nullable Collection errorValues + ) { + Set 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> getAllBounds() { - Collection> 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 condition) { + TypeConstraintsImpl result = new TypeConstraintsImpl(typeVariable, varianceOfPosition); + result.constraints.addAll(ContainerUtil.filter(constraints, new Condition() { + @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 getValues() { if (resultValues == null) { - resultValues = computeValues(); + resultValues = computeValues(constraints); } return resultValues; } - private Collection computeValues() { + @NotNull + private static Collection computeValues(@NotNull Collection constraints) { Set values = Sets.newLinkedHashSet(); - if (isEmpty()) { - return values; + if (constraints.isEmpty()) { + return Collections.emptyList(); } - TypeConstraints withoutErrorTypes = filterNotContainingErrorType(values); - Collection exactBounds = withoutErrorTypes.getExactBounds(); + + Set 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> pair = - TypeUtils.filterNumberTypes(withoutErrorTypes.getLowerBounds()); + TypeUtils.filterNumberTypes(filterBounds(constraints, BoundKind.LOWER_BOUND, values)); Collection generalLowerBounds = pair.getFirst(); Collection numberLowerBounds = pair.getSecond(); JetType superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds); - if (trySuggestion(superTypeOfLowerBounds)) { + if (trySuggestion(superTypeOfLowerBounds, constraints)) { return Collections.singleton(superTypeOfLowerBounds); } ContainerUtil.addIfNotNull(superTypeOfLowerBounds, values); - Collection upperBounds = withoutErrorTypes.getUpperBounds(); + Set 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 foo(t: T, consumer: Consumer): T //foo(1, c: Consumer) - 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 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 values - ) { - TypeConstraintsImpl typeConstraintsWithoutErrorType = new TypeConstraintsImpl(getVarianceOfPosition()); - Collection> allBounds = getAllBounds(); - for (Pair 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; - } } diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/IdeRenderers.java b/idea/src/org/jetbrains/jet/plugin/highlighter/IdeRenderers.java index 5fd65b7b40f..6aecf4fdf64 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/IdeRenderers.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/IdeRenderers.java @@ -201,11 +201,11 @@ public class IdeRenderers { } }; - public static final Renderer HTML_TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER = - new Renderer() { + public static final Renderer HTML_TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER = + new Renderer() { @NotNull @Override - public String render(@NotNull InferenceErrorData inferenceErrorData) { + public String render(@NotNull ExtendedInferenceErrorData inferenceErrorData) { return renderUpperBoundViolatedInferenceError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString(); } }; diff --git a/idea/testData/diagnosticMessage/upperBoundViolated.kt b/idea/testData/diagnosticMessage/upperBoundViolated.kt index 82991ee56c4..19393027042 100644 --- a/idea/testData/diagnosticMessage/upperBoundViolated.kt +++ b/idea/testData/diagnosticMessage/upperBoundViolated.kt @@ -3,5 +3,24 @@ package i fun foo>(r: R, list: T) {} fun test1(i: Int, collection: Collection) { - foo(i, collection) -} \ No newline at end of file + foo(i, collection) //error +} + +//-------------- +fun bar(v: V, u: MutableSet) = u + +fun test2(a: Any, s: MutableSet) { + bar(a, s) //error +} + +//-------------- +trait A +class B + +fun baz(t: T, r: R) where T: A { + +} + +fun test3(a: A, b: B) { + baz(a, b) //error +} diff --git a/idea/testData/diagnosticMessage/upperBoundViolated2.html b/idea/testData/diagnosticMessage/upperBoundViolated2.html new file mode 100644 index 00000000000..a410c813008 --- /dev/null +++ b/idea/testData/diagnosticMessage/upperBoundViolated2.html @@ -0,0 +1,32 @@ + + +Type parameter bound for +V + in + + + + + + + + + +
+ + +fun + <V : U, U> + bar +( +v: V, +u: jet.MutableSet<U> +) +: jet.MutableSet<U>
+ is not satisfied: inferred type + +jet.Any + + is not a subtype of +jet.String + diff --git a/idea/testData/diagnosticMessage/upperBoundViolated3.html b/idea/testData/diagnosticMessage/upperBoundViolated3.html new file mode 100644 index 00000000000..bff5b9b62b2 --- /dev/null +++ b/idea/testData/diagnosticMessage/upperBoundViolated3.html @@ -0,0 +1,34 @@ + + +Type parameter bound for +T + in + + + + + + + + + +
+ + +fun + <T : R, R : i.B> + baz +( +t: T, +r: R +) +: jet.Unit +where + T : i.A
+ is not satisfied: inferred type + +i.A + + is not a subtype of +i.B + diff --git a/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTest.java b/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTest.java index 3a330edeb1b..3ff6e5a79a8 100644 --- a/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTest.java @@ -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 {