From 08de6d8d0730201dfb845d1144a5e5b7c2297960 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sat, 28 Apr 2012 23:13:41 +0400 Subject: [PATCH] KT-1863 Wrong nullability for class derived from java classes. #KT-1863 In progress --- .../resolve/java/JavaDescriptorResolver.java | 2 +- .../resolve/java/JavaTypeTransformer.java | 47 +++++++++++-------- ...umentsNullability-NotNull-SpecialTypes.jet | 23 +++++++++ ...ArgumentsNullability-NotNull-UserTypes.jet | 23 +++++++++ ...rtypeArgumentsNullability-SpecialTypes.jet | 21 +++++++++ ...upertypeArgumentsNullability-UserTypes.jet | 21 +++++++++ 6 files changed, 116 insertions(+), 21 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-NotNull-SpecialTypes.jet create mode 100644 compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-NotNull-UserTypes.jet create mode 100644 compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-SpecialTypes.jet create mode 100644 compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-UserTypes.jet diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index c47411575c4..8ce7e33559e 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -959,7 +959,7 @@ public class JavaDescriptorResolver { continue; } - JetType transform = semanticServices.getTypeTransformer().transformToType(type, typeVariableResolver); + JetType transform = semanticServices.getTypeTransformer().transformToType(type, JavaTypeTransformer.TypeUsage.SUPERTYPE, typeVariableResolver); result.add(TypeUtils.makeNotNullable(transform)); } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java index 0da95ba01fc..8b853b146f9 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java @@ -33,11 +33,9 @@ import org.jetbrains.jet.lang.types.lang.PrimitiveType; import org.jetbrains.jet.rt.signature.JetSignatureReader; import javax.inject.Inject; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; + +import static org.jetbrains.jet.lang.resolve.java.JavaTypeTransformer.TypeUsage.*; /** * @author abreslav @@ -66,9 +64,11 @@ public class JavaTypeTransformer { @NotNull - public TypeProjection transformToTypeProjection(@NotNull final PsiType javaType, + private TypeProjection transformToTypeProjection(@NotNull final PsiType javaType, @NotNull final TypeParameterDescriptor typeParameterDescriptor, - @NotNull final TypeVariableResolver typeVariableByPsiResolver) { + @NotNull final TypeVariableResolver typeVariableByPsiResolver, + @NotNull final TypeUsage howThisTypeIsUsed + ) { TypeProjection result = javaType.accept(new PsiTypeVisitor() { @Override @@ -85,12 +85,12 @@ public class JavaTypeTransformer { PsiType bound = wildcardType.getBound(); assert bound != null; - return new TypeProjection(variance, transformToType(bound, TypeUsage.UPPER_BOUND, typeVariableByPsiResolver)); + return new TypeProjection(variance, transformToType(bound, UPPER_BOUND, typeVariableByPsiResolver)); } @Override public TypeProjection visitType(PsiType type) { - return new TypeProjection(transformToType(type, TypeUsage.TYPE_ARGUMENT, typeVariableByPsiResolver)); + return new TypeProjection(transformToType(type, howThisTypeIsUsed, typeVariableByPsiResolver)); } }); return result; @@ -136,7 +136,7 @@ public class JavaTypeTransformer { if (psiMethod.isConstructor()) { Set supertypesJet = Sets.newHashSet(); for (PsiClassType supertype : typeParameter.getExtendsListTypes()) { - supertypesJet.add(transformToType(supertype, TypeUsage.UPPER_BOUND, typeVariableResolver)); + supertypesJet.add(transformToType(supertype, UPPER_BOUND, typeVariableResolver)); } return TypeUtils.intersect(JetTypeChecker.INSTANCE, supertypesJet); } @@ -144,20 +144,24 @@ public class JavaTypeTransformer { TypeParameterDescriptor typeParameterDescriptor = typeVariableResolver.getTypeVariable(typeParameter.getName()); - if (howThisTypeIsUsed == TypeUsage.TYPE_ARGUMENT || howThisTypeIsUsed == TypeUsage.UPPER_BOUND) { - // In Java: ArrayList - // In Kotlin: ArrayList, not ArrayList - // nullability will be taken care of in individual member signatures - return typeParameterDescriptor.getDefaultType(); + // In Java: ArrayList + // In Kotlin: ArrayList, not ArrayList + // nullability will be taken care of in individual member signatures + boolean nullable = !EnumSet.of(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT).contains(howThisTypeIsUsed); + if (nullable) { + return TypeUtils.makeNullable(typeParameterDescriptor.getDefaultType()); } else { - return TypeUtils.makeNullable(typeParameterDescriptor.getDefaultType()); + return typeParameterDescriptor.getDefaultType(); } } else { + // 'L extends List' in Java is a List in Kotlin, not a List + boolean nullable = !EnumSet.of(SUPERTYPE_ARGUMENT, SUPERTYPE).contains(howThisTypeIsUsed); + JetType jetAnalog = getKotlinAnalog(new FqName(psiClass.getQualifiedName())); if (jetAnalog != null) { - return jetAnalog; + return TypeUtils.makeNullableAsSpecified(jetAnalog, nullable); } final ClassDescriptor classData = @@ -187,13 +191,15 @@ public class JavaTypeTransformer { PsiType psiArgument = psiArguments[i]; TypeParameterDescriptor typeParameterDescriptor = parameters.get(i); - arguments.add(transformToTypeProjection(psiArgument, typeParameterDescriptor, typeVariableResolver)); + TypeUsage howTheProjectionIsUsed = howThisTypeIsUsed == SUPERTYPE ? SUPERTYPE_ARGUMENT : TYPE_ARGUMENT; + arguments.add(transformToTypeProjection(psiArgument, typeParameterDescriptor, typeVariableResolver, howTheProjectionIsUsed)); } } + return new JetTypeImpl( Collections.emptyList(), classData.getTypeConstructor(), - true, + nullable, arguments, classData.getMemberScope(arguments)); } @@ -291,6 +297,7 @@ public class JavaTypeTransformer { MEMBER_SIGNATURE_COVARIANT, MEMBER_SIGNATURE_CONTRAVARIANT, MEMBER_SIGNATURE_INVARIANT, - SUPERTYPE + SUPERTYPE, + SUPERTYPE_ARGUMENT } } diff --git a/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-NotNull-SpecialTypes.jet b/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-NotNull-SpecialTypes.jet new file mode 100644 index 00000000000..e40bc8873a3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-NotNull-SpecialTypes.jet @@ -0,0 +1,23 @@ +// FILE: A.java +public class A {} + +// FILE: X.java +import org.jetbrains.annotations.NotNull; + +public class X { + @NotNull T fooN() {return null;} + void barN(@NotNull T a) {} +} + +// FILE: Y.java +public class Y extends X { + +} + +// FILE: test.kt + +fun main() { + Y().fooN() : Any + Y().barN(null); +} + diff --git a/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-NotNull-UserTypes.jet b/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-NotNull-UserTypes.jet new file mode 100644 index 00000000000..f44ffeaf690 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-NotNull-UserTypes.jet @@ -0,0 +1,23 @@ +// FILE: A.java +public class A {} + +// FILE: X.java +import org.jetbrains.annotations.NotNull; + +public class X { + @NotNull T fooN() {return null;} + void barN(@NotNull T a) {} +} + +// FILE: Y.java +public class Y extends X { + +} + +// FILE: test.kt + +fun main() { + Y().fooN() : Any + Y().barN(null); +} + diff --git a/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-SpecialTypes.jet b/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-SpecialTypes.jet new file mode 100644 index 00000000000..32114bfd2cf --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-SpecialTypes.jet @@ -0,0 +1,21 @@ +// FILE: A.java +public class A {} + +// FILE: X.java +public class X { + T foo() {return null;} + void bar(T a) {} +} + +// FILE: Y.java +public class Y extends X { + +} + +// FILE: test.kt + +fun main() { + Y().foo().length + Y().bar(null) +} + diff --git a/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-UserTypes.jet b/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-UserTypes.jet new file mode 100644 index 00000000000..2d86a647a05 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/SupertypeArgumentsNullability-UserTypes.jet @@ -0,0 +1,21 @@ +// FILE: A.java +public class A {} + +// FILE: X.java +public class X { + T foo() {return null;} + void bar(T a) {} +} + +// FILE: Y.java +public class Y extends X { + +} + +// FILE: test.kt + +fun main() { + Y().foo().hashCode() + Y().bar(null) +} +