KT-14641: Nested type alias reference via an instance is an error.

This commit is contained in:
Dmitry Petrov
2016-11-09 11:57:26 +03:00
parent a662d777e8
commit 94d7bd7a6b
13 changed files with 70 additions and 28 deletions
@@ -813,7 +813,7 @@ public interface Errors {
DiagnosticFactory1<KtSimpleNameExpression, ClassifierDescriptor> NO_COMPANION_OBJECT = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtSimpleNameExpression, ClassifierDescriptor> NO_COMPANION_OBJECT = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtSimpleNameExpression, TypeParameterDescriptor> TYPE_PARAMETER_IS_NOT_AN_EXPRESSION = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtSimpleNameExpression, TypeParameterDescriptor> TYPE_PARAMETER_IS_NOT_AN_EXPRESSION = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtSimpleNameExpression, TypeParameterDescriptor> TYPE_PARAMETER_ON_LHS_OF_DOT = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtSimpleNameExpression, TypeParameterDescriptor> TYPE_PARAMETER_ON_LHS_OF_DOT = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtExpression, ClassDescriptor> NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtExpression, ClassifierDescriptorWithTypeParameters> NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<KtExpression, ClassDescriptor, String> NESTED_CLASS_SHOULD_BE_QUALIFIED = DiagnosticFactory2.create(ERROR); DiagnosticFactory2<KtExpression, ClassDescriptor, String> NESTED_CLASS_SHOULD_BE_QUALIFIED = DiagnosticFactory2.create(ERROR);
DiagnosticFactory1<PsiElement, ClassDescriptor> INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, ClassDescriptor> INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR);
@@ -17,12 +17,13 @@
package org.jetbrains.kotlin.diagnostics.rendering package org.jetbrains.kotlin.diagnostics.rendering
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any
= renderer?.render(parameter, context) ?: parameter = renderer?.render(parameter, context) ?: parameter
fun ClassDescriptor.renderKindWithName(): String = DescriptorRenderer.getClassKindPrefix(this) + " '" + name + "'" fun ClassifierDescriptorWithTypeParameters.renderKindWithName(): String = DescriptorRenderer.getClassifierKindPrefix(this) + " '" + name + "'"
fun ClassDescriptor.renderKind(): String = DescriptorRenderer.getClassKindPrefix(this) fun ClassDescriptor.renderKind(): String = DescriptorRenderer.getClassifierKindPrefix(this)
@@ -38,10 +38,10 @@ import org.jetbrains.kotlin.resolve.calls.inference.*
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.Bound import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.Bound
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.UPPER_BOUND import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.UPPER_BOUND
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ValidityConstraintForConstituentType
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.* import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.getValidityConstraintForConstituentType import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.getValidityConstraintForConstituentType
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -53,7 +53,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.io.PrintWriter import java.io.PrintWriter
import java.io.StringWriter import java.io.StringWriter
import java.lang.AssertionError import java.lang.AssertionError
import java.util.*
object Renderers { object Renderers {
@@ -119,7 +118,7 @@ object Renderers {
if (classOrObject is KtClass) "Class" + name else "Object" + name if (classOrObject is KtClass) "Class" + name else "Object" + name
} }
@JvmField val RENDER_CLASS_OR_OBJECT_NAME = Renderer<ClassDescriptor> { it.renderKindWithName() } @JvmField val RENDER_CLASS_OR_OBJECT_NAME = Renderer<ClassifierDescriptorWithTypeParameters> { it.renderKindWithName() }
@JvmField val RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.FQ_NAMES_IN_TYPES.withOptions { parameterNamesInFunctionalTypes = false }) @JvmField val RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.FQ_NAMES_IN_TYPES.withOptions { parameterNamesInFunctionalTypes = false })
@@ -501,10 +501,9 @@ class CallExpressionResolver(
val receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.receiverExpression) val receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.receiverExpression)
if (receiverQualifier == null && expressionQualifier != null) { if (receiverQualifier == null && expressionQualifier != null) {
assert(expressionQualifier is ClassQualifier) { "Only class can (package cannot) be accessed by instance reference: " + expressionQualifier } assert(expressionQualifier is ClassifierQualifier) { "Only class can (package cannot) be accessed by instance reference: " + expressionQualifier }
context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on( val descriptor = (expressionQualifier as ClassifierQualifier).descriptor
selectorExpression, context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on(selectorExpression, descriptor))
(expressionQualifier as ClassQualifier).descriptor))
} }
} }
} }
@@ -0,0 +1,9 @@
class A {
public inner class B { }
public typealias BAlias = B
}
fun f() {
val a = A()
a.<!NO_COMPANION_OBJECT, NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>BAlias<!>
}
@@ -0,0 +1,18 @@
package
public fun f(): kotlin.Unit
public final class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final inner class B {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public typealias BAlias = A.B
}
@@ -20878,6 +20878,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("kt14641.kt")
public void testKt14641() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/kt14641.kt");
doTest(fileName);
}
@TestMetadata("localTypeAlias.kt") @TestMetadata("localTypeAlias.kt")
public void testLocalTypeAlias() throws Exception { public void testLocalTypeAlias() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/localTypeAlias.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/localTypeAlias.kt");
@@ -144,19 +144,25 @@ abstract class DescriptorRenderer {
modifiers = DescriptorRendererModifier.ALL modifiers = DescriptorRendererModifier.ALL
} }
fun getClassKindPrefix(klass: ClassDescriptor): String { fun getClassifierKindPrefix(classifier: ClassifierDescriptorWithTypeParameters): String =
if (klass.isCompanionObject) { when (classifier) {
return "companion object" is TypeAliasDescriptor ->
} "typealias"
return when (klass.kind) { is ClassDescriptor ->
ClassKind.CLASS -> "class" if (classifier.isCompanionObject) {
ClassKind.INTERFACE -> "interface" "companion object"
ClassKind.ENUM_CLASS -> "enum class" }
ClassKind.OBJECT -> "object" else when (classifier.kind) {
ClassKind.ANNOTATION_CLASS -> "annotation class" ClassKind.CLASS -> "class"
ClassKind.ENUM_ENTRY -> "enum entry" ClassKind.INTERFACE -> "interface"
} ClassKind.ENUM_CLASS -> "enum class"
} ClassKind.OBJECT -> "object"
ClassKind.ANNOTATION_CLASS -> "annotation class"
ClassKind.ENUM_ENTRY -> "enum entry"
}
else ->
throw AssertionError("Unexpected classifier: $classifier")
}
} }
} }
@@ -931,7 +931,7 @@ internal class DescriptorRendererImpl(
} }
private fun renderClassKindPrefix(klass: ClassDescriptor, builder: StringBuilder) { private fun renderClassKindPrefix(klass: ClassDescriptor, builder: StringBuilder) {
builder.append(renderKeyword(DescriptorRenderer.getClassKindPrefix(klass))) builder.append(renderKeyword(DescriptorRenderer.getClassifierKindPrefix(klass)))
} }
@@ -78,7 +78,7 @@ private val CALLABLE_RENDERER = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_I
fun DeclarationDescriptor.renderForConflicts(): String { fun DeclarationDescriptor.renderForConflicts(): String {
return when (this) { return when (this) {
is ClassDescriptor -> "${DescriptorRenderer.getClassKindPrefix(this)} ${IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(this)}" is ClassDescriptor -> "${DescriptorRenderer.getClassifierKindPrefix(this)} ${IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(this)}"
is FunctionDescriptor -> "function '${CALLABLE_RENDERER.render(this)}'" is FunctionDescriptor -> "function '${CALLABLE_RENDERER.render(this)}'"
is PropertyDescriptor -> "property '${CALLABLE_RENDERER.render(this)}'" is PropertyDescriptor -> "property '${CALLABLE_RENDERER.render(this)}'"
else -> "" else -> ""
@@ -1,4 +1,4 @@
// !DIAGNOSTICS_NUMBER: 3 // !DIAGNOSTICS_NUMBER: 4
// !DIAGNOSTICS: NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE // !DIAGNOSTICS: NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE
class A { class A {
@@ -6,11 +6,13 @@ class A {
class NestedWithClassObject { companion object } class NestedWithClassObject { companion object }
enum class NestedEnum { A } enum class NestedEnum { A }
object NestedObj { fun invoke() = 1 } object NestedObj { fun invoke() = 1 }
typealias NestedAlias = Nested
} }
fun test(a: A) { fun test(a: A) {
a.NestedWithClassObject a.NestedWithClassObject
a.NestedEnum a.NestedEnum
a.NestedObj a.NestedObj
a.NestedAlias
a.Nested() // TODO: report "nested class accessed via instance reference" here as well a.Nested() // TODO: report "nested class accessed via instance reference" here as well
} }
@@ -1,2 +1,2 @@
<!-- nestedClassAcessedViaInstanceReference4 --> <!-- nestedClassAcessedViaInstanceReference4 -->
Nested class 'Nested' accessed via instance reference Nested typealias 'NestedAlias' accessed via instance reference
@@ -0,0 +1,2 @@
<!-- nestedClassAcessedViaInstanceReference5 -->
Nested class 'Nested' accessed via instance reference