From 845e3323f9fca6a90a54d4e46ca44d6503939a71 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 8 May 2014 22:02:11 +0400 Subject: [PATCH] Create error type if reflection class isn't found Introduce a new diagnostic fired when reflection types aren't found in the classpath --- .../jetbrains/jet/lang/diagnostics/Errors.java | 4 +++- .../rendering/DefaultErrorMessages.java | 2 ++ .../psi/JetCallableReferenceExpression.java | 13 +++++++++---- .../jet/lang/reflect/ReflectionTypes.kt | 18 +++++++++++------- .../BasicExpressionTypingVisitor.java | 5 +++++ .../tests/ReflectionTypesNotLoaded.kt | 8 ++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 +++++ .../jetbrains/jet/lang/types/ErrorUtils.java | 2 +- .../lang/types/error/ErrorClassDescriptor.java | 12 ++++++------ 9 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/ReflectionTypesNotLoaded.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 95d8ebc6191..4d51dd1c33d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -367,7 +367,9 @@ public interface Errors { DiagnosticFactory1 TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); - // Callable references + // Reflection + + DiagnosticFactory0 REFLECTION_TYPES_NOT_LOADED = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 CALLABLE_REFERENCE_LHS_NOT_A_CLASS = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index d75ffb02754..5edc371a331 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -471,6 +471,8 @@ public class DefaultErrorMessages { MAP.put(AMBIGUOUS_ANONYMOUS_TYPE_INFERRED, "Right-hand side has anonymous type. Please specify type explicitly", TO_STRING); + MAP.put(REFLECTION_TYPES_NOT_LOADED, "Reflection types can't be loaded. Please ensure that you have Kotlin Runtime in your classpath"); + MAP.put(EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED, "''{0}'' is a member and an extension at the same time. References to such elements are not allowed", NAME); MAP.put(CALLABLE_REFERENCE_LHS_NOT_A_CLASS, "Callable reference left-hand side cannot be a type parameter"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallableReferenceExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallableReferenceExpression.java index a157ae176fa..e4cd9381e1c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallableReferenceExpression.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallableReferenceExpression.java @@ -33,15 +33,20 @@ public class JetCallableReferenceExpression extends JetExpressionImpl { return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); } + @NotNull + public PsiElement getDoubleColonTokenReference() { + //noinspection ConstantConditions + return findChildByType(JetTokens.COLONCOLON); + } + @NotNull public JetSimpleNameExpression getCallableReference() { - ASTNode node = getNode().findChildByType(JetTokens.COLONCOLON); - while (node != null) { - PsiElement psi = node.getPsi(); + PsiElement psi = getDoubleColonTokenReference(); + while (psi != null) { if (psi instanceof JetSimpleNameExpression) { return (JetSimpleNameExpression) psi; } - node = node.getTreeNext(); + psi = psi.getNextSibling(); } throw new IllegalStateException("Callable reference simple name shouldn't be parsed to null"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt b/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt index 1fb06a91b18..8f008d131f0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/reflect/ReflectionTypes.kt @@ -25,18 +25,19 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns import org.jetbrains.jet.lang.descriptors.annotations.Annotations import org.jetbrains.jet.lang.types.JetType import org.jetbrains.jet.lang.types.JetTypeImpl +import org.jetbrains.jet.lang.types.error.ErrorClassDescriptor + +private val KOTLIN_REFLECT_FQ_NAME = FqName("kotlin.reflect") public class ReflectionTypes(private val module: ModuleDescriptor) { - private val kotlinReflect: JetScope by Delegates.lazy { - // TODO: handle errors gracefully (error types) - val kotlin = module.getPackage(FqName("kotlin")) ?: error("Package kotlin not found in $module") - val reflect = kotlin.getMemberScope().getPackage(Name.identifier("reflect")) ?: error("Package reflect not found in $kotlin") - reflect.getMemberScope() + private val kotlinReflectScope: JetScope? by Delegates.lazy { + module.getPackage(KOTLIN_REFLECT_FQ_NAME)?.getMemberScope() } fun find(className: String): ClassDescriptor { val name = Name.identifier(className) - return kotlinReflect.getClassifier(name) as? ClassDescriptor ?: error("Reflection class not found: $name") + return kotlinReflectScope?.getClassifier(name) as? ClassDescriptor + ?: ErrorClassDescriptor(KOTLIN_REFLECT_FQ_NAME.child(name).asString()) } public fun getKFunction(n: Int): ClassDescriptor = find("KFunction$n") @@ -53,7 +54,10 @@ public class ReflectionTypes(private val module: ModuleDescriptor) { val arguments = KotlinBuiltIns.getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType) val classDescriptor = correspondingKFunctionClass(receiverType, extensionFunction, parameterTypes.size) - return JetTypeImpl(annotations, classDescriptor.getTypeConstructor(), false, arguments, classDescriptor.getMemberScope(arguments)) + return if (classDescriptor is ErrorClassDescriptor) + classDescriptor.getDefaultType() + else + JetTypeImpl(annotations, classDescriptor.getTypeConstructor(), false, arguments, classDescriptor.getMemberScope(arguments)) } private fun correspondingKFunctionClass( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 8a13f327825..738bc11d776 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -503,6 +503,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { receiverParameter != null ); + if (type.isError()) { + context.trace.report(REFLECTION_TYPES_NOT_LOADED.on(expression.getDoubleColonTokenReference())); + return null; + } + AnonymousFunctionDescriptor functionDescriptor = new AnonymousFunctionDescriptor( context.scope.getContainingDeclaration(), Annotations.EMPTY, diff --git a/compiler/testData/diagnostics/tests/ReflectionTypesNotLoaded.kt b/compiler/testData/diagnostics/tests/ReflectionTypesNotLoaded.kt new file mode 100644 index 00000000000..b91603d14ea --- /dev/null +++ b/compiler/testData/diagnostics/tests/ReflectionTypesNotLoaded.kt @@ -0,0 +1,8 @@ +fun foo() {} + +class A { + fun baz() {} +} + +val bar = ::foo +val quux = A::baz diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index e5c84174ed6..9ca4a95b530 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -374,6 +374,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt"); } + @TestMetadata("ReflectionTypesNotLoaded.kt") + public void testReflectionTypesNotLoaded() throws Exception { + doTest("compiler/testData/diagnostics/tests/ReflectionTypesNotLoaded.kt"); + } + @TestMetadata("ResolveOfJavaGenerics.kt") public void testResolveOfJavaGenerics() throws Exception { doTest("compiler/testData/diagnostics/tests/ResolveOfJavaGenerics.kt"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/types/ErrorUtils.java index 314bedf57c7..2d84488db70 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -227,7 +227,7 @@ public class ErrorUtils { } } - private static final ErrorClassDescriptor ERROR_CLASS = new ErrorClassDescriptor(""); + private static final ErrorClassDescriptor ERROR_CLASS = new ErrorClassDescriptor(null); @NotNull public static JetScope createErrorScope(@NotNull String debugMessage) { diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/error/ErrorClassDescriptor.java b/core/descriptors/src/org/jetbrains/jet/lang/types/error/ErrorClassDescriptor.java index e84b54bd84e..1cbede08cc7 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/error/ErrorClassDescriptor.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/error/ErrorClassDescriptor.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.types.error; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.Annotations; import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl; @@ -32,13 +33,12 @@ import java.util.List; import static org.jetbrains.jet.lang.types.ErrorUtils.*; -public final class ErrorClassDescriptor extends ClassDescriptorImpl { - public ErrorClassDescriptor(@NotNull String debugMessage) { - super(getErrorModule(), Name.special(""), Modality.OPEN, Collections.emptyList()); - - ConstructorDescriptorImpl errorConstructor = - ConstructorDescriptorImpl.create(this, Annotations.EMPTY, true); +public class ErrorClassDescriptor extends ClassDescriptorImpl { + public ErrorClassDescriptor(@Nullable String name) { + super(getErrorModule(), Name.special(name == null ? "" : ""), + Modality.OPEN, Collections.emptyList()); + ConstructorDescriptorImpl errorConstructor = ConstructorDescriptorImpl.create(this, Annotations.EMPTY, true); errorConstructor.initialize(Collections.emptyList(), Collections.emptyList(), Visibilities.INTERNAL, false); errorConstructor.setReturnType(createErrorType(""));