Capture types only on the top level

This commit is contained in:
Svetlana Isakova
2014-09-26 17:45:39 +04:00
parent cd359a046c
commit 1fb713342b
30 changed files with 111 additions and 12 deletions
@@ -396,6 +396,7 @@ public interface Errors {
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CANNOT_CAPTURE_TYPES = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<JetExpression, JetType, JetType> TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
@@ -487,6 +487,7 @@ public class DefaultErrorMessages {
MAP.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class");
MAP.put(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, "Type inference failed: {0}", TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER);
MAP.put(TYPE_INFERENCE_CANNOT_CAPTURE_TYPES, "Type inference failed: {0}", TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER);
MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Type inference failed: {0}", TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER);
MAP.put(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH, "Type inference failed: {0}", TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH_RENDERER);
MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "{0}", TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER);
@@ -34,10 +34,7 @@ import org.jetbrains.jet.lang.resolve.calls.inference.*;
import org.jetbrains.jet.lang.resolve.calls.inference.constraintPosition.ConstraintPosition;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import org.jetbrains.jet.renderer.Renderer;
@@ -214,6 +211,15 @@ public class Renderers {
}
};
public static final Renderer<InferenceErrorData> TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return renderCannotCaptureTypeParameterError(inferenceErrorData, TabledDescriptorRenderer.create()).toString();
}
};
public static TabledDescriptorRenderer renderConflictingSubstitutionsInferenceError(InferenceErrorData inferenceErrorData,
TabledDescriptorRenderer result) {
LOG.assertTrue(inferenceErrorData.constraintSystem.getStatus().hasConflictingConstraints(), renderDebugMessage(
@@ -277,8 +283,11 @@ public class Renderers {
return result;
}
public static TabledDescriptorRenderer renderTypeConstructorMismatchError(final InferenceErrorData inferenceErrorData,
TabledDescriptorRenderer renderer) {
@NotNull
public static TabledDescriptorRenderer renderTypeConstructorMismatchError(
final @NotNull InferenceErrorData inferenceErrorData,
@NotNull TabledDescriptorRenderer renderer
) {
Predicate<ConstraintPosition> isErrorPosition = new Predicate<ConstraintPosition>() {
@Override
public boolean apply(ConstraintPosition constraintPosition) {
@@ -294,8 +303,11 @@ public class Renderers {
isErrorPosition));
}
public static TabledDescriptorRenderer renderNoInformationForParameterError(InferenceErrorData inferenceErrorData,
TabledDescriptorRenderer result) {
@NotNull
public static TabledDescriptorRenderer renderNoInformationForParameterError(
@NotNull InferenceErrorData inferenceErrorData,
@NotNull TabledDescriptorRenderer result
) {
TypeParameterDescriptor firstUnknownParameter = null;
for (TypeParameterDescriptor typeParameter : inferenceErrorData.constraintSystem.getTypeVariables()) {
if (inferenceErrorData.constraintSystem.getTypeBounds(typeParameter).isEmpty()) {
@@ -376,6 +388,37 @@ public class Renderers {
return result;
}
@NotNull
public static TabledDescriptorRenderer renderCannotCaptureTypeParameterError(
@NotNull InferenceErrorData inferenceErrorData,
@NotNull TabledDescriptorRenderer result
) {
ConstraintSystem constraintSystem = inferenceErrorData.constraintSystem;
TypeParameterDescriptor typeParameterWithCapturedConstraint = null;
CapturedTypeConstructor capturedTypeConstructor = null;
for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeVariables()) {
TypeBounds typeBounds = constraintSystem.getTypeBounds(typeParameter);
for (TypeBounds.Bound bound : typeBounds.getBounds()) {
TypeConstructor constructor = bound.getConstrainingType().getConstructor();
if (constructor instanceof CapturedTypeConstructor) {
typeParameterWithCapturedConstraint = typeParameter;
capturedTypeConstructor = (CapturedTypeConstructor) constructor;
}
}
}
if (capturedTypeConstructor == null) {
LOG.error(renderDebugMessage("There is no captured type in bounds, but there is an error 'cannot capture type parameter'",
inferenceErrorData));
return result;
}
result.text(newText().normal("'" + typeParameterWithCapturedConstraint.getName() + "'" +
" cannot capture " +
"'" + capturedTypeConstructor.getTypeProjection() + "'. " +
"Only top level type projections can be captured"));
return result;
}
public static final Renderer<Collection<ClassDescriptor>> CLASSES_OR_SEPARATED = new Renderer<Collection<ClassDescriptor>>() {
@NotNull
@Override
@@ -226,9 +226,9 @@ public abstract class AbstractTracingStrategy 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.hasConflictWithCapturedType()) {
// trace.report(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS.on(reference, data));
//}
else if (status.hasCannotCaptureTypesError()) {
trace.report(TYPE_INFERENCE_CANNOT_CAPTURE_TYPES.on(reference, data));
}
else if (status.hasViolatedUpperBound()) {
trace.report(TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, data));
}
@@ -6,6 +6,7 @@ SUPERTYPE T String
type parameter bounds:
T <: kotlin.Int(SPECIAL), >: kotlin.String(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: true
-hasContradiction: true
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUPERTYPE T Int
type parameter bounds:
T <: kotlin.Int(SPECIAL), >: kotlin.Int(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -5,6 +5,7 @@ SUBTYPE List<T> Int
type parameter bounds:
T
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: true
-hasErrorInConstrainingTypes: false
@@ -5,6 +5,7 @@ SUBTYPE Any Any
type parameter bounds:
T
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUBTYPE T String weak
type parameter bounds:
T <: kotlin.Int(SPECIAL), <: kotlin.String(TYPE_BOUND_POSITION(0))
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: true
-hasContradiction: true
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUPERTYPE T A
type parameter bounds:
T <: B(SPECIAL), >: A(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: true
-hasContradiction: true
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUBTYPE T B
type parameter bounds:
T <: A(SPECIAL), <: B(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUPERTYPE T C
type parameter bounds:
T <: A(SPECIAL), >: C(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -7,6 +7,7 @@ SUPERTYPE T C
type parameter bounds:
T <: A(SPECIAL), >: B(SPECIAL), >: C(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUBTYPE T Byte
type parameter bounds:
T >: IntegerValueType(1000)(SPECIAL), <: kotlin.Byte(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: true
-hasContradiction: true
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUPERTYPE T IntegerValueType(10000000000)
type parameter bounds:
T >: IntegerValueType(1)(SPECIAL), >: IntegerValueType(10000000000)(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUBTYPE T Any
type parameter bounds:
T >: IntegerValueType(1)(SPECIAL), <: kotlin.Any(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUPERTYPE T String
type parameter bounds:
T >: IntegerValueType(1)(SPECIAL), >: kotlin.String(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUPERTYPE T IntegerValueType(1000)
type parameter bounds:
T >: IntegerValueType(1)(SPECIAL), >: IntegerValueType(1000)(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUBTYPE T Byte
type parameter bounds:
T >: IntegerValueType(1)(SPECIAL), <: kotlin.Byte(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -5,6 +5,7 @@ SUPERTYPE T IntegerValueType(1)
type parameter bounds:
T >: IntegerValueType(1)(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ SUBTYPE T Short
type parameter bounds:
T >: IntegerValueType(1)(SPECIAL), <: kotlin.Short(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -6,6 +6,7 @@ type parameter bounds:
T <: kotlin.Int(SPECIAL)
P <: ???(TYPE_BOUND_POSITION(1)), <: kotlin.Int(COMPOUND_CONSTRAINT_POSITION(TYPE_BOUND_POSITION(1), SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -5,6 +5,7 @@ SUBTYPE Consumer<A> Consumer<T>
type parameter bounds:
T <: A(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -5,6 +5,7 @@ SUBTYPE My<T> My<A>
type parameter bounds:
T := A(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -5,6 +5,7 @@ SUBTYPE Producer<A> Producer<T>
type parameter bounds:
T >: A(SPECIAL)
status:
-hasCannotCaptureTypesError: false
-hasConflictingConstraints: false
-hasContradiction: false
-hasErrorInConstrainingTypes: false
@@ -0,0 +1,9 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
fun <T> foo(array: Array<Array<T>>): Array<Array<T>> = array
fun test(array: Array<Array<out Int>>) {
<!TYPE_INFERENCE_CANNOT_CAPTURE_TYPES!>foo<!>(array)
val f: Array<out Array<out Int>> = <!TYPE_INFERENCE_CANNOT_CAPTURE_TYPES!>foo<!>(array)
}
@@ -0,0 +1,4 @@
package
internal fun </*0*/ T> foo(/*0*/ array: kotlin.Array<kotlin.Array<T>>): kotlin.Array<kotlin.Array<T>>
internal fun test(/*0*/ array: kotlin.Array<kotlin.Array<out kotlin.Int>>): kotlin.Unit
@@ -5123,6 +5123,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/kt2872.kt");
doTest(fileName);
}
@TestMetadata("captureTypeOnlyOnTopLevel.kt")
public void testCaptureTypeOnlyOnTopLevel() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureTypeOnlyOnTopLevel.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/inference/constraints")
@@ -56,13 +56,14 @@ public class ConstraintSystemImpl : ConstraintSystem {
private val typeParameterBounds = LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>()
private val errorConstraintPositions = HashSet<ConstraintPosition>()
private var hasErrorInConstrainingTypes: Boolean = false
private var cannotCaptureTypesError: Boolean = false
private val constraintSystemStatus = object : ConstraintSystemStatus {
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters()
override fun hasContradiction() = hasTypeConstructorMismatch() || hasConflictingConstraints()
override fun hasContradiction() = hasTypeConstructorMismatch() || hasConflictingConstraints() || hasCannotCaptureTypesError()
override fun hasViolatedUpperBound(): Boolean {
if (isSuccessful()) return false
@@ -104,6 +105,8 @@ public class ConstraintSystemImpl : ConstraintSystem {
}
override fun hasErrorInConstrainingTypes() = hasErrorInConstrainingTypes
override fun hasCannotCaptureTypesError() = cannotCaptureTypesError
}
private fun getParameterToInferredValueMap(typeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>, getDefaultTypeProjection: Function1<TypeParameterDescriptor, TypeProjection>): Map<TypeParameterDescriptor, TypeProjection> {
@@ -195,6 +198,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
newSystem.errorConstraintPositions.addAll(errorConstraintPositions.filter(filterConstraintPosition))
//todo if 'filterConstraintPosition' is not trivial, it's incorrect to just copy 'hasErrorInConstrainingTypes'
newSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes
newSystem.cannotCaptureTypesError = cannotCaptureTypesError
return newSystem
}
@@ -210,7 +214,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
private fun addConstraint(constraintKind: ConstraintKind, subType: JetType?, superType: JetType?, constraintPosition: ConstraintPosition) {
val typeCheckingProcedure = TypeCheckingProcedure(object : TypingConstraints {
private var isTopLevel = true
override fun assertEqualTypes(a: JetType, b: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
isTopLevel = false
doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure)
return true
@@ -221,12 +228,16 @@ public class ConstraintSystemImpl : ConstraintSystem {
}
override fun assertSubtype(subtype: JetType, supertype: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
isTopLevel = false
doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure)
return true
}
override fun capture(typeVariable: JetType, typeProjection: TypeProjection): Boolean {
if (isMyTypeVariable(typeVariable) && constraintPosition.isCaptureAllowed()) {
if (!isTopLevel) {
cannotCaptureTypesError = true
}
generateTypeParameterCaptureConstraint(typeVariable, typeProjection, constraintPosition)
return true
}
@@ -85,4 +85,7 @@ public trait ConstraintSystemStatus {
* Is used not to generate type inference error if there was one in argument types.
*/
public fun hasErrorInConstrainingTypes(): Boolean
//todo comment
public fun hasCannotCaptureTypesError(): Boolean
}