KT-1863 Wrong nullability for class derived from java classes.

#KT-1863 In progress
This commit is contained in:
Andrey Breslav
2012-04-28 23:13:41 +04:00
parent dcc2728f0a
commit 08de6d8d07
6 changed files with 116 additions and 21 deletions
@@ -959,7 +959,7 @@ public class JavaDescriptorResolver {
continue; continue;
} }
JetType transform = semanticServices.getTypeTransformer().transformToType(type, typeVariableResolver); JetType transform = semanticServices.getTypeTransformer().transformToType(type, JavaTypeTransformer.TypeUsage.SUPERTYPE, typeVariableResolver);
result.add(TypeUtils.makeNotNullable(transform)); result.add(TypeUtils.makeNotNullable(transform));
} }
@@ -33,11 +33,9 @@ import org.jetbrains.jet.lang.types.lang.PrimitiveType;
import org.jetbrains.jet.rt.signature.JetSignatureReader; import org.jetbrains.jet.rt.signature.JetSignatureReader;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Collections; import java.util.*;
import java.util.HashMap;
import java.util.List; import static org.jetbrains.jet.lang.resolve.java.JavaTypeTransformer.TypeUsage.*;
import java.util.Map;
import java.util.Set;
/** /**
* @author abreslav * @author abreslav
@@ -66,9 +64,11 @@ public class JavaTypeTransformer {
@NotNull @NotNull
public TypeProjection transformToTypeProjection(@NotNull final PsiType javaType, private TypeProjection transformToTypeProjection(@NotNull final PsiType javaType,
@NotNull final TypeParameterDescriptor typeParameterDescriptor, @NotNull final TypeParameterDescriptor typeParameterDescriptor,
@NotNull final TypeVariableResolver typeVariableByPsiResolver) { @NotNull final TypeVariableResolver typeVariableByPsiResolver,
@NotNull final TypeUsage howThisTypeIsUsed
) {
TypeProjection result = javaType.accept(new PsiTypeVisitor<TypeProjection>() { TypeProjection result = javaType.accept(new PsiTypeVisitor<TypeProjection>() {
@Override @Override
@@ -85,12 +85,12 @@ public class JavaTypeTransformer {
PsiType bound = wildcardType.getBound(); PsiType bound = wildcardType.getBound();
assert bound != null; assert bound != null;
return new TypeProjection(variance, transformToType(bound, TypeUsage.UPPER_BOUND, typeVariableByPsiResolver)); return new TypeProjection(variance, transformToType(bound, UPPER_BOUND, typeVariableByPsiResolver));
} }
@Override @Override
public TypeProjection visitType(PsiType type) { public TypeProjection visitType(PsiType type) {
return new TypeProjection(transformToType(type, TypeUsage.TYPE_ARGUMENT, typeVariableByPsiResolver)); return new TypeProjection(transformToType(type, howThisTypeIsUsed, typeVariableByPsiResolver));
} }
}); });
return result; return result;
@@ -136,7 +136,7 @@ public class JavaTypeTransformer {
if (psiMethod.isConstructor()) { if (psiMethod.isConstructor()) {
Set<JetType> supertypesJet = Sets.newHashSet(); Set<JetType> supertypesJet = Sets.newHashSet();
for (PsiClassType supertype : typeParameter.getExtendsListTypes()) { 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); return TypeUtils.intersect(JetTypeChecker.INSTANCE, supertypesJet);
} }
@@ -144,20 +144,24 @@ public class JavaTypeTransformer {
TypeParameterDescriptor typeParameterDescriptor = typeVariableResolver.getTypeVariable(typeParameter.getName()); TypeParameterDescriptor typeParameterDescriptor = typeVariableResolver.getTypeVariable(typeParameter.getName());
if (howThisTypeIsUsed == TypeUsage.TYPE_ARGUMENT || howThisTypeIsUsed == TypeUsage.UPPER_BOUND) { // In Java: ArrayList<T>
// In Java: ArrayList<T> // In Kotlin: ArrayList<T>, not ArrayList<T?>
// In Kotlin: ArrayList<T>, not ArrayList<T?> // nullability will be taken care of in individual member signatures
// nullability will be taken care of in individual member signatures boolean nullable = !EnumSet.of(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT).contains(howThisTypeIsUsed);
return typeParameterDescriptor.getDefaultType(); if (nullable) {
return TypeUtils.makeNullable(typeParameterDescriptor.getDefaultType());
} }
else { else {
return TypeUtils.makeNullable(typeParameterDescriptor.getDefaultType()); return typeParameterDescriptor.getDefaultType();
} }
} }
else { else {
// 'L extends List<T>' in Java is a List<T> in Kotlin, not a List<T?>
boolean nullable = !EnumSet.of(SUPERTYPE_ARGUMENT, SUPERTYPE).contains(howThisTypeIsUsed);
JetType jetAnalog = getKotlinAnalog(new FqName(psiClass.getQualifiedName())); JetType jetAnalog = getKotlinAnalog(new FqName(psiClass.getQualifiedName()));
if (jetAnalog != null) { if (jetAnalog != null) {
return jetAnalog; return TypeUtils.makeNullableAsSpecified(jetAnalog, nullable);
} }
final ClassDescriptor classData = final ClassDescriptor classData =
@@ -187,13 +191,15 @@ public class JavaTypeTransformer {
PsiType psiArgument = psiArguments[i]; PsiType psiArgument = psiArguments[i];
TypeParameterDescriptor typeParameterDescriptor = parameters.get(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( return new JetTypeImpl(
Collections.<AnnotationDescriptor>emptyList(), Collections.<AnnotationDescriptor>emptyList(),
classData.getTypeConstructor(), classData.getTypeConstructor(),
true, nullable,
arguments, arguments,
classData.getMemberScope(arguments)); classData.getMemberScope(arguments));
} }
@@ -291,6 +297,7 @@ public class JavaTypeTransformer {
MEMBER_SIGNATURE_COVARIANT, MEMBER_SIGNATURE_COVARIANT,
MEMBER_SIGNATURE_CONTRAVARIANT, MEMBER_SIGNATURE_CONTRAVARIANT,
MEMBER_SIGNATURE_INVARIANT, MEMBER_SIGNATURE_INVARIANT,
SUPERTYPE SUPERTYPE,
SUPERTYPE_ARGUMENT
} }
} }
@@ -0,0 +1,23 @@
// FILE: A.java
public class A {}
// FILE: X.java
import org.jetbrains.annotations.NotNull;
public class X<T> {
@NotNull T fooN() {return null;}
void barN(@NotNull T a) {}
}
// FILE: Y.java
public class Y extends X<String> {
}
// FILE: test.kt
fun main() {
Y().fooN() : Any
Y().barN(<!ERROR_COMPILE_TIME_VALUE!>null<!>);
}
@@ -0,0 +1,23 @@
// FILE: A.java
public class A {}
// FILE: X.java
import org.jetbrains.annotations.NotNull;
public class X<T> {
@NotNull T fooN() {return null;}
void barN(@NotNull T a) {}
}
// FILE: Y.java
public class Y extends X<A> {
}
// FILE: test.kt
fun main() {
Y().fooN() : Any
Y().barN(<!ERROR_COMPILE_TIME_VALUE!>null<!>);
}
@@ -0,0 +1,21 @@
// FILE: A.java
public class A {}
// FILE: X.java
public class X<T> {
T foo() {return null;}
void bar(T a) {}
}
// FILE: Y.java
public class Y extends X<String> {
}
// FILE: test.kt
fun main() {
Y().foo()<!UNSAFE_CALL!>.<!>length
Y().bar(null)
}
@@ -0,0 +1,21 @@
// FILE: A.java
public class A {}
// FILE: X.java
public class X<T> {
T foo() {return null;}
void bar(T a) {}
}
// FILE: Y.java
public class Y extends X<A> {
}
// FILE: test.kt
fun main() {
Y().foo()<!UNSAFE_CALL!>.<!>hashCode()
Y().bar(null)
}