diff --git a/compiler/testData/loadJava/sourceJava/ErrorTypes.txt b/compiler/testData/loadJava/sourceJava/ErrorTypes.txt index 1e90a206970..35b48d0334b 100644 --- a/compiler/testData/loadJava/sourceJava/ErrorTypes.txt +++ b/compiler/testData/loadJava/sourceJava/ErrorTypes.txt @@ -5,11 +5,11 @@ public trait ErrorTypes : java.lang.Object { public trait Sub : test.ErrorTypes.Super { public abstract fun errorTypeInParameter(/*0*/ list: jet.List?>?): jet.Unit public abstract override /*1*/ /*fake_override*/ fun errorTypeInParameter(/*0*/ list: jet.List?>?): jet.Unit - public abstract override /*1*/ fun returnErrorType(): [ERROR : Unresolved java classifier: T] + public abstract override /*1*/ fun returnErrorType(): [ERROR : Unresolved java classifier: T]? } public trait Super : java.lang.Object { public abstract fun errorTypeInParameter(/*0*/ list: jet.List?>?): jet.Unit - public abstract fun returnErrorType(): [ERROR : Unresolved java classifier: T] + public abstract fun returnErrorType(): [ERROR : Unresolved java classifier: T]? } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt index f283c393f12..85cfa5378f1 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt @@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage.* import org.jetbrains.jet.lang.resolve.java.resolver.* import org.jetbrains.jet.lang.types.Variance.* import org.jetbrains.jet.lang.types.* +import com.intellij.openapi.diagnostic.Logger import org.jetbrains.kotlin.util.iif import org.jetbrains.kotlin.util.eq import org.jetbrains.jet.lang.resolve.java.structure.JavaPrimitiveType @@ -43,6 +44,8 @@ import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod import java.util.HashSet import org.jetbrains.jet.lang.types.checker.JetTypeChecker +private val LOG = Logger.getInstance(javaClass()) + class LazyJavaTypeResolver( private val c: LazyJavaResolverContext, private val typeParameterResolver: TypeParameterResolver @@ -234,14 +237,18 @@ class LazyJavaTypeResolver( // 'L extends List' in Java is a List in Kotlin, not a List // nullability will be taken care of in individual member signatures when (classifier()) { - is JavaClass -> attr.howThisTypeIsUsed !in setOf(TYPE_ARGUMENT, SUPERTYPE_ARGUMENT, SUPERTYPE) is JavaTypeParameter -> { if (isConstructorTypeParameter()) getConstructorTypeParameterSubstitute().isNullable() else attr.howThisTypeIsUsed !in setOf(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT, SUPERTYPE) } - else -> true + is JavaClass, + null -> attr.howThisTypeIsUsed !in setOf(TYPE_ARGUMENT, SUPERTYPE_ARGUMENT, SUPERTYPE) + else -> { + LOG.error("Unknown classifier: ${classifier()}") + true + } } } override fun isNullable(): Boolean = _nullable() diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaTypeTransformer.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaTypeTransformer.java index 87a511fcdbf..c8043d90c40 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaTypeTransformer.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaTypeTransformer.java @@ -78,11 +78,7 @@ public class JavaTypeTransformer { ) { if (type instanceof JavaClassifierType) { JavaClassifierType classifierType = (JavaClassifierType) type; - JetType jetType = transformClassifierType(classifierType, howThisTypeIsUsed, typeVariableResolver); - if (jetType == null) { - return ErrorUtils.createErrorType("Unresolved java classifier: " + classifierType.getPresentableText()); - } - return jetType; + return transformClassifierType(classifierType, howThisTypeIsUsed, typeVariableResolver); } else if (type instanceof JavaPrimitiveType) { String canonicalText = ((JavaPrimitiveType) type).getCanonicalText(); @@ -98,58 +94,55 @@ public class JavaTypeTransformer { } } - @Nullable + @NotNull private JetType transformClassifierType( @NotNull JavaClassifierType classifierType, @NotNull TypeUsage howThisTypeIsUsed, @NotNull TypeVariableResolver typeVariableResolver ) { JavaClassifier javaClassifier = classifierType.getClassifier(); - if (javaClassifier == null) { - return null; - } if (javaClassifier instanceof JavaTypeParameter) { - return transformTypeParameter((JavaTypeParameter) javaClassifier, howThisTypeIsUsed, typeVariableResolver); - } - else if (javaClassifier instanceof JavaClass) { - FqName fqName = ((JavaClass) javaClassifier).getFqName(); - assert fqName != null : "Class type should have a FQ name: " + javaClassifier; - return transformClassType(fqName, classifierType, howThisTypeIsUsed, typeVariableResolver); + return transformTypeParameter((JavaTypeParameter) javaClassifier, classifierType, howThisTypeIsUsed, typeVariableResolver); } else { - throw new UnsupportedOperationException("Unsupported classifier: " + javaClassifier); + return transformClassType(javaClassifier, classifierType, howThisTypeIsUsed, typeVariableResolver); } } - @Nullable + @NotNull private JetType transformTypeParameter( @NotNull JavaTypeParameter typeParameter, + @NotNull JavaClassifierType classifierType, @NotNull TypeUsage howThisTypeIsUsed, @NotNull TypeVariableResolver typeVariableResolver ) { + // 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); + JavaTypeParameterListOwner owner = typeParameter.getOwner(); if (owner instanceof JavaMethod && ((JavaMethod) owner).isConstructor()) { Set supertypesJet = new HashSet(); for (JavaClassifierType supertype : typeParameter.getUpperBounds()) { supertypesJet.add(transformToType(supertype, UPPER_BOUND, typeVariableResolver)); } - return TypeUtils.intersect(JetTypeChecker.INSTANCE, supertypesJet); + JetType intersection = TypeUtils.intersect(JetTypeChecker.INSTANCE, supertypesJet); + if (intersection == null) { + return createErrorClassifierType(classifierType, nullable); + } + return intersection; } TypeParameterDescriptor descriptor = typeVariableResolver.getTypeVariable(typeParameter.getName()); - if (descriptor == null) return null; - - // 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 (descriptor == null) return createErrorClassifierType(classifierType, nullable); return TypeUtils.makeNullableIfNeeded(descriptor.getDefaultType(), nullable); } - @Nullable + @NotNull private JetType transformClassType( - @NotNull FqName fqName, + @Nullable JavaClassifier javaClassifier, @NotNull JavaClassifierType classifierType, @NotNull TypeUsage howThisTypeIsUsed, @NotNull TypeVariableResolver typeVariableResolver @@ -157,13 +150,18 @@ public class JavaTypeTransformer { // 'L extends List' in Java is a List in Kotlin, not a List boolean nullable = !EnumSet.of(TYPE_ARGUMENT, SUPERTYPE_ARGUMENT, SUPERTYPE).contains(howThisTypeIsUsed); + if (javaClassifier == null) return createErrorClassifierType(classifierType, nullable); + + FqName fqName = ((JavaClass) javaClassifier).getFqName(); + assert fqName != null : "Class type should have a FQ name: " + javaClassifier; + ClassDescriptor classData = JavaToKotlinClassMap.getInstance().mapKotlinClass(fqName, howThisTypeIsUsed); if (classData == null) { classData = classResolver.resolveClass(fqName, INCLUDE_KOTLIN_SOURCES); } if (classData == null) { - return null; + return createErrorClassifierType(classifierType, nullable); } List arguments = new ArrayList(); @@ -221,6 +219,14 @@ public class JavaTypeTransformer { classData.getMemberScope(arguments)); } + @NotNull + private static JetType createErrorClassifierType(JavaClassifierType classifierType, boolean nullable) { + return TypeUtils.makeNullableAsSpecified( + ErrorUtils.createErrorType("Unresolved java classifier: " + classifierType.getPresentableText()), + nullable + ); + } + @NotNull private JetType transformArrayType( @NotNull JavaArrayType arrayType, diff --git a/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererImpl.java b/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererImpl.java index a0ef3f07dd3..86b156b01be 100644 --- a/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererImpl.java +++ b/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererImpl.java @@ -218,7 +218,7 @@ public class DescriptorRendererImpl implements DescriptorRenderer { return "???"; } if (type.isError()) { - return type.toString(); + return renderDefaultType(type); } if (KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type)) { return renderFunctionType(type); @@ -230,7 +230,12 @@ public class DescriptorRendererImpl implements DescriptorRenderer { private String renderDefaultType(@NotNull JetType type) { StringBuilder sb = new StringBuilder(); - sb.append(renderTypeName(type.getConstructor())); + if (type.isError()) { + sb.append(type.getConstructor().toString()); // Debug name of an error type is more informative + } + else { + sb.append(renderTypeName(type.getConstructor())); + } if (!type.getArguments().isEmpty()) { sb.append("<"); appendTypeProjections(type.getArguments(), sb);