diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java index 23a5e43777c..469fb9289ed 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java @@ -44,6 +44,8 @@ import java.util.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFQName; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getVarargParameterType; +import static org.jetbrains.jet.lang.resolve.java.TypeUsage.*; +import static org.jetbrains.jet.lang.types.Variance.INVARIANT; public class SignaturesPropagationData { private static final Logger LOG = Logger.getInstance(SignaturesPropagationData.class); @@ -108,7 +110,7 @@ public class SignaturesPropagationData { } }); - return modifyTypeAccordingToSuperMethods(autoType, typesFromSuperMethods); + return modifyTypeAccordingToSuperMethods(autoType, typesFromSuperMethods, MEMBER_SIGNATURE_COVARIANT); } private List modifyTypeParametersAccordingToSuperMethods(List autoTypeParameters) { @@ -128,10 +130,10 @@ public class SignaturesPropagationData { for (Iterator iterator : upperBoundFromSuperFunctionsIterators) { assert iterator.hasNext(); - upperBoundsFromSuperFunctions.add(new TypeAndVariance(iterator.next(), Variance.INVARIANT)); + upperBoundsFromSuperFunctions.add(new TypeAndVariance(iterator.next(), INVARIANT)); } - JetType modifiedUpperBound = modifyTypeAccordingToSuperMethods(autoUpperBound, upperBoundsFromSuperFunctions); + JetType modifiedUpperBound = modifyTypeAccordingToSuperMethods(autoUpperBound, upperBoundsFromSuperFunctions, UPPER_BOUND); modifiedTypeParameter.addUpperBound(modifiedUpperBound); } @@ -160,14 +162,14 @@ public class SignaturesPropagationData { new Function() { @Override public TypeAndVariance fun(FunctionDescriptor superFunction) { - return new TypeAndVariance(superFunction.getValueParameters().get(index).getType(), Variance.INVARIANT); + return new TypeAndVariance(superFunction.getValueParameters().get(index).getType(), INVARIANT); } }); VarargCheckResult varargCheckResult = checkVarargInSuperFunctions(originalParam); - JetType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType, typesFromSuperMethods); + JetType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType, typesFromSuperMethods, MEMBER_SIGNATURE_CONTRAVARIANT); resultParameters.add(new ValueParameterDescriptorImpl( originalParam.getContainingDeclaration(), @@ -184,7 +186,7 @@ public class SignaturesPropagationData { JetType originalReceiverType = parameters.getReceiverType(); if (originalReceiverType != null) { JetType substituted = SignaturesUtil.createSubstitutorForFunctionTypeParameters(autoTypeParameterToModified) - .substitute(originalReceiverType, Variance.INVARIANT); + .substitute(originalReceiverType, INVARIANT); assert substituted != null; return new JavaDescriptorResolver.ValueParameterDescriptors(substituted, resultParameters); } @@ -289,13 +291,14 @@ public class SignaturesPropagationData { @NotNull private JetType modifyTypeAccordingToSuperMethods( @NotNull JetType autoType, - @NotNull List typesFromSuper + @NotNull List typesFromSuper, + @NotNull TypeUsage howThisTypeIsUsed ) { if (ErrorUtils.isErrorType(autoType)) { return autoType; } - boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper); + boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, howThisTypeIsUsed); ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper); List resultArguments = getTypeArgsOfType(autoType, resultClassifier, typesFromSuper); JetScope resultScope; @@ -338,7 +341,7 @@ public class SignaturesPropagationData { List projectionsFromSuper = typeArgumentsFromSuper.get(parameter.getIndex()); List argTypesFromSuper = getTypes(projectionsFromSuper); - JetType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper); + JetType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, TYPE_ARGUMENT); Variance projectionKind = calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper); resultArguments.add(new TypeProjection(projectionKind, type)); @@ -361,7 +364,7 @@ public class SignaturesPropagationData { } else if (projectionKindsInSuper.size() == 1) { Variance projectionKindInSuper = projectionKindsInSuper.iterator().next(); - if (defaultProjectionKind == Variance.INVARIANT || defaultProjectionKind == projectionKindInSuper) { + if (defaultProjectionKind == INVARIANT || defaultProjectionKind == projectionKindInSuper) { return projectionKindInSuper; } else { @@ -380,11 +383,24 @@ public class SignaturesPropagationData { private static List getTypes(@NotNull List projections) { List types = Lists.newArrayList(); for (TypeProjectionAndVariance projection : projections) { - types.add(new TypeAndVariance(projection.typeProjection.getType(), projection.varianceOfParameter)); + types.add(new TypeAndVariance(projection.typeProjection.getType(), + merge(projection.varianceOfPosition, projection.typeProjection.getProjectionKind()))); } return types; } + private static Variance merge(Variance positionOfOuter, Variance projectionKind) { + // Inv>, X is in invariant position + if (positionOfOuter == INVARIANT) return INVARIANT; + // Out, X is in out-position + if (projectionKind == INVARIANT) return positionOfOuter; + // Out>, X is in out-position + // In>, X is in out-position + // Out>, X is in in-position + // In>, X is in in-position + return positionOfOuter.superpose(projectionKind); + } + // Returns list with type arguments info from supertypes // Example: // - Foo is a subtype of Bar>, Baz @@ -432,7 +448,8 @@ public class SignaturesPropagationData { // this condition is true for 1 and 4, false for 2 and 3 if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) { int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex(); - parameterToArgumentsFromSuper.get(parameterIndex).add(new TypeProjectionAndVariance(argument, parameter.getVariance())); + Variance effectiveVariance = parameter.getVariance().superpose(typeFromSuper.varianceOfPosition); + parameterToArgumentsFromSuper.get(parameterIndex).add(new TypeProjectionAndVariance(argument, effectiveVariance)); } } } @@ -442,36 +459,44 @@ public class SignaturesPropagationData { private boolean typeMustBeNullable( @NotNull JetType autoType, - @NotNull List typesFromSuper + @NotNull List typesFromSuper, + @NotNull TypeUsage howThisTypeIsUsed ) { boolean someSupersNotCovariantNullable = false; + boolean someSupersCovariantNullable = false; boolean someSupersNotNull = false; for (TypeAndVariance typeFromSuper : typesFromSuper) { - if (typeFromSuper.type.isNullable() && typeFromSuper.varianceOfParameter != Variance.OUT_VARIANCE) { - someSupersNotCovariantNullable = true; - } - else if (!typeFromSuper.type.isNullable()) { + if (!typeFromSuper.type.isNullable()) { someSupersNotNull = true; } + else { + if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) { + someSupersCovariantNullable = true; + } + else { + someSupersNotCovariantNullable = true; + } + } } - if (someSupersNotCovariantNullable == someSupersNotNull) { - if (someSupersNotCovariantNullable) { - reportError("Incompatible types in superclasses: " + typesFromSuper); - } + if (someSupersNotNull && someSupersNotCovariantNullable) { + reportError("Incompatible types in superclasses: " + typesFromSuper); return autoType.isNullable(); } - else { - if (someSupersNotCovariantNullable) { - if (!autoType.isNullable()) { - reportError("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + autoType); - } + else if (someSupersNotNull) { + return false; + } + else if (someSupersNotCovariantNullable || someSupersCovariantNullable) { + boolean annotatedAsNotNull = howThisTypeIsUsed != TYPE_ARGUMENT && !autoType.isNullable(); + + if (annotatedAsNotNull && someSupersNotCovariantNullable) { + reportError("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + autoType); return true; } - else { // someSupersNotNull is true here - return false; - } + + return !annotatedAsNotNull; } + return autoType.isNullable(); } @NotNull @@ -504,7 +529,7 @@ public class SignaturesPropagationData { someSupersMutable = true; } else if (collectionMapping.isReadOnlyCollection(classFromSuper)) { - if (typeFromSuper.varianceOfParameter == Variance.OUT_VARIANCE) { + if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) { someSupersCovariantReadOnly = true; } else { @@ -549,11 +574,11 @@ public class SignaturesPropagationData { private static class TypeProjectionAndVariance { public final TypeProjection typeProjection; - public final Variance varianceOfParameter; + public final Variance varianceOfPosition; - public TypeProjectionAndVariance(TypeProjection typeProjection, Variance varianceOfParameter) { + public TypeProjectionAndVariance(TypeProjection typeProjection, Variance varianceOfPosition) { this.typeProjection = typeProjection; - this.varianceOfParameter = varianceOfParameter; + this.varianceOfPosition = varianceOfPosition; } public String toString() { @@ -563,11 +588,11 @@ public class SignaturesPropagationData { private static class TypeAndVariance { public final JetType type; - public final Variance varianceOfParameter; + public final Variance varianceOfPosition; - public TypeAndVariance(JetType type, Variance varianceOfParameter) { + public TypeAndVariance(JetType type, Variance varianceOfPosition) { this.type = type; - this.varianceOfParameter = varianceOfParameter; + this.varianceOfPosition = varianceOfPosition; } public String toString() { diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.java b/compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.java new file mode 100644 index 00000000000..81c6a502f77 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.java @@ -0,0 +1,42 @@ +package test; + +import java.util.List; +import jet.runtime.typeinfo.KotlinSignature; + +public interface PropagateTypeArgumentNullable { + + public interface Super { + + @KotlinSignature("fun outS(p : List)") + void outS(List p); + + @KotlinSignature("fun invOutS(p : MutableList>)") + void invOutS(List> p); + + @KotlinSignature("fun outOutS(p : List>)") + void outOutS(List> p); + + @KotlinSignature("fun outR() : List") + List outR(); + + @KotlinSignature("fun invR() : MutableList") + List invR(); + + @KotlinSignature("fun invOutR() : MutableList>") + List> invOutR(); + } + + public interface Sub extends Super { + void outS(List p); + + void invOutS(List> p); + + void outOutS(List> p); + + List outR(); + + List invR(); + + List> invOutR(); + } +} diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.kt b/compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.kt new file mode 100644 index 00000000000..f0c7ebabe08 --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.kt @@ -0,0 +1,29 @@ +package test + +public trait PropagateTypeArgumentNullable: Object { + + public trait Super: Object { + public fun outS(p0: List) + + public fun invOutS(p0 : MutableList>) + + public fun outOutS(p0 : List>) + + public fun outR() : List + public fun invR() : MutableList + public fun invOutR() : MutableList> + + } + + public trait Sub: Super { + override fun outS(p0: List) + + override fun invOutS(p0 : MutableList>) + + override fun outOutS(p0 : List>) + + override fun outR() : List + override fun invR() : MutableList + override fun invOutR() : MutableList> + } +} diff --git a/compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.txt b/compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.txt new file mode 100644 index 00000000000..959b8462f4d --- /dev/null +++ b/compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.txt @@ -0,0 +1,20 @@ +namespace test + +public abstract trait test.PropagateTypeArgumentNullable : java.lang.Object { + public abstract trait test.PropagateTypeArgumentNullable.Sub : test.PropagateTypeArgumentNullable.Super { + public abstract override /*1*/ fun invOutR(): jet.MutableList> + public abstract override /*1*/ fun invOutS(/*0*/ p0: jet.MutableList>): jet.Tuple0 + public abstract override /*1*/ fun invR(): jet.MutableList + public abstract override /*1*/ fun outOutS(/*0*/ p0: jet.List>): jet.Tuple0 + public abstract override /*1*/ fun outR(): jet.List + public abstract override /*1*/ fun outS(/*0*/ p0: jet.List): jet.Tuple0 + } + public abstract trait test.PropagateTypeArgumentNullable.Super : java.lang.Object { + public abstract fun invOutR(): jet.MutableList> + public abstract fun invOutS(/*0*/ p0: jet.MutableList>): jet.Tuple0 + public abstract fun invR(): jet.MutableList + public abstract fun outOutS(/*0*/ p0: jet.List>): jet.Tuple0 + public abstract fun outR(): jet.List + public abstract fun outS(/*0*/ p0: jet.List): jet.Tuple0 + } +} diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java index ef696cc5ac0..8f30906d08e 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -15,16 +15,13 @@ */ package org.jetbrains.jet.jvm.compiler; -import junit.framework.Assert; import junit.framework.Test; import junit.framework.TestSuite; - -import java.io.File; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.test.InnerTestClasses; import org.jetbrains.jet.test.TestMetadata; -import org.jetbrains.jet.jvm.compiler.AbstractLoadJavaTest; +import java.io.File; /** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */ @TestMetadata("compiler/testData/loadJava") @@ -460,6 +457,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/loadJava/kotlinSignature/propagation"), "java", true); } + @TestMetadata("PropagateTypeArgumentNullable.java") + public void testPropagateTypeArgumentNullable() throws Exception { + doTest("compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.java"); + } + @TestMetadata("compiler/testData/loadJava/kotlinSignature/propagation/parameter") public static class Parameter extends AbstractLoadJavaTest { public void testAllFilesPresentInParameter() throws Exception { diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java index 8bee7694da7..b620662048a 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java @@ -1355,6 +1355,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/loadJava/kotlinSignature/propagation"), "kt", true); } + @TestMetadata("PropagateTypeArgumentNullable.kt") + public void testPropagateTypeArgumentNullable() throws Exception { + doTestSinglePackage("compiler/testData/loadJava/kotlinSignature/propagation/PropagateTypeArgumentNullable.kt"); + } + @TestMetadata("compiler/testData/loadJava/kotlinSignature/propagation/parameter") public static class Parameter extends AbstractLazyResolveNamespaceComparingTest { public void testAllFilesPresentInParameter() throws Exception {