Capture types only on the top level
This commit is contained in:
@@ -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);
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+9
@@ -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)
|
||||
}
|
||||
+4
@@ -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")
|
||||
|
||||
+12
-1
@@ -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
|
||||
}
|
||||
|
||||
+3
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user