KT-1863 Wrong nullability for class derived from java classes.
#KT-1863 In progress
This commit is contained in:
+1
-1
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-20
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
@@ -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<!>);
|
||||||
|
}
|
||||||
|
|
||||||
+23
@@ -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<!>);
|
||||||
|
}
|
||||||
|
|
||||||
+21
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user