From 6fca46a452ea63e1dd8cab41a92454bba9b442e0 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 14 Nov 2016 14:17:39 +0300 Subject: [PATCH] Allow inferring property type from its getter #KT-550 Fixed --- .../kotlin/resolve/DeclarationsChecker.kt | 6 +- .../kotlin/resolve/DescriptorResolver.java | 34 +++++--- .../VariableTypeAndInitializerResolver.kt | 29 +++++-- .../box/properties/typeInferredFromGetter.kt | 7 ++ .../diagnostics/tests/RecursiveGetter.kt | 3 - .../ambiguousObjectExpressionType.kt | 4 +- .../ambiguousObjectExpressionType.txt | 2 +- .../inferenceFromGetters/blockBodyGetter.kt | 3 + .../inferenceFromGetters/blockBodyGetter.txt | 3 + .../inferenceFromGetters/cantBeInferred.kt | 5 ++ .../inferenceFromGetters/cantBeInferred.txt | 6 ++ .../explicitGetterType.kt | 18 ++++ .../explicitGetterType.txt | 9 ++ .../inferenceFromGetters/members.kt | 24 ++++++ .../inferenceFromGetters/members.txt | 18 ++++ .../inferenceFromGetters/nullAsNothing.kt | 8 ++ .../inferenceFromGetters/nullAsNothing.txt | 5 ++ .../inferenceFromGetters/objectExpression.kt | 35 ++++++++ .../objectExpression.txt} | 8 +- .../inferenceFromGetters/overrides.kt | 41 +++++++++ .../inferenceFromGetters/overrides.txt | 30 +++++++ .../inferenceFromGetters/recursiveGetter.kt | 18 ++++ .../inferenceFromGetters/recursiveGetter.txt | 18 ++++ .../inferenceFromGetters/topLevel.kt | 21 +++++ .../inferenceFromGetters/topLevel.txt | 11 +++ .../properties/inferenceFromGetters/vars.kt | 21 +++++ .../properties/inferenceFromGetters/vars.txt | 5 ++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 ++ .../checkers/DiagnosticsTestGenerated.java | 84 +++++++++++++++++-- .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++ .../propertyWithRecursiveGetter.kt | 4 +- .../semantics/JsCodegenBoxTestGenerated.java | 6 ++ 32 files changed, 460 insertions(+), 38 deletions(-) create mode 100644 compiler/testData/codegen/box/properties/typeInferredFromGetter.kt delete mode 100644 compiler/testData/diagnostics/tests/RecursiveGetter.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.txt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/cantBeInferred.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/cantBeInferred.txt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/explicitGetterType.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/explicitGetterType.txt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/members.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/members.txt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/nullAsNothing.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/nullAsNothing.txt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/objectExpression.kt rename compiler/testData/diagnostics/tests/{RecursiveGetter.txt => properties/inferenceFromGetters/objectExpression.txt} (56%) create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/overrides.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/overrides.txt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.txt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/topLevel.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/topLevel.txt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.kt create mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index ae214a72caf..e58187b8f8a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -678,7 +678,7 @@ class DeclarationsChecker( trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property)) } } - else if (property.typeReference == null) { + else if (noExplicitTypeOrGetterType(property)) { trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property)) } if (backingFieldRequired && !inTrait && propertyDescriptor.isLateInit && !isUninitialized) { @@ -690,6 +690,10 @@ class DeclarationsChecker( } } + private fun noExplicitTypeOrGetterType(property: KtProperty) = + property.typeReference == null + && (property.getter == null || (property.getter!!.hasBlockBody() && property.getter!!.returnTypeReference == null)) + fun checkFunction(function: KtNamedFunction, functionDescriptor: SimpleFunctionDescriptor) { val typeParameterList = function.typeParameterList val nameIdentifier = function.nameIdentifier diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 9f6dbb5325c..739583aed22 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -814,11 +814,18 @@ public class DescriptorResolver { DescriptorFactory.createExtensionReceiverParameterForCallable(propertyDescriptor, receiverType); LexicalScope scopeForInitializer = ScopeUtils.makeScopeForPropertyInitializer(scopeWithTypeParameters, propertyDescriptor); - KotlinType type = variableTypeAndInitializerResolver.resolveType( + KotlinType typeIfKnown = variableTypeAndInitializerResolver.resolveTypeNullable( propertyDescriptor, scopeForInitializer, property, dataFlowInfo, true, trace ); + PropertyGetterDescriptorImpl getter = resolvePropertyGetterDescriptor( + scopeWithTypeParameters, property, propertyDescriptor, annotationSplitter, trace, typeIfKnown); + + KotlinType type = typeIfKnown != null ? typeIfKnown : getter.getReturnType(); + + assert type != null : "At least getter type must be initialized via resolvePropertyGetterDescriptor"; + variableTypeAndInitializerResolver.setConstantForVariableIfNeeded( propertyDescriptor, scopeForInitializer, property, dataFlowInfo, type, trace ); @@ -826,8 +833,6 @@ public class DescriptorResolver { propertyDescriptor.setType(type, typeParameterDescriptors, getDispatchReceiverParameterIfNeeded(containingDeclaration), receiverDescriptor); - PropertyGetterDescriptorImpl getter = resolvePropertyGetterDescriptor( - scopeWithTypeParameters, property, propertyDescriptor, annotationSplitter, trace); PropertySetterDescriptor setter = resolvePropertySetterDescriptor( scopeWithTypeParameters, property, propertyDescriptor, annotationSplitter, trace); @@ -963,10 +968,12 @@ public class DescriptorResolver { @NotNull KtProperty property, @NotNull PropertyDescriptor propertyDescriptor, @NotNull AnnotationSplitter annotationSplitter, - BindingTrace trace + BindingTrace trace, + @Nullable KotlinType propertyTypeIfKnown ) { PropertyGetterDescriptorImpl getterDescriptor; KtPropertyAccessor getter = property.getGetter(); + KotlinType getterType; if (getter != null) { Annotations getterAnnotations = new CompositeAnnotations(CollectionsKt.listOf( annotationSplitter.getAnnotationsForTarget(PROPERTY_GETTER), @@ -980,33 +987,34 @@ public class DescriptorResolver { property.hasModifier(KtTokens.INLINE_KEYWORD) || getter.hasModifier(KtTokens.INLINE_KEYWORD), CallableMemberDescriptor.Kind.DECLARATION, null, KotlinSourceElementKt.toSourceElement(getter) ); - KotlinType returnType = - determineGetterReturnType(scopeWithTypeParameters, trace, getterDescriptor, getter, propertyDescriptor.getType()); - getterDescriptor.initialize(returnType); + getterType = determineGetterReturnType(scopeWithTypeParameters, trace, getterDescriptor, getter, propertyTypeIfKnown); trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor); } else { Annotations getterAnnotations = annotationSplitter.getAnnotationsForTarget(PROPERTY_GETTER); getterDescriptor = DescriptorFactory.createGetter(propertyDescriptor, getterAnnotations, !property.hasDelegate(), /* isExternal = */ false, property.hasModifier(KtTokens.INLINE_KEYWORD)); - getterDescriptor.initialize(propertyDescriptor.getType()); + getterType = propertyTypeIfKnown; } + + getterDescriptor.initialize(getterType != null ? getterType : VariableTypeAndInitializerResolver.STUB_FOR_PROPERTY_WITHOUT_TYPE); + return getterDescriptor; } - @NotNull + @Nullable private KotlinType determineGetterReturnType( @NotNull LexicalScope scope, @NotNull BindingTrace trace, @NotNull PropertyGetterDescriptor getterDescriptor, @NotNull KtPropertyAccessor getter, - @NotNull KotlinType propertyType + @Nullable KotlinType propertyTypeIfKnown ) { KtTypeReference returnTypeReference = getter.getReturnTypeReference(); if (returnTypeReference != null) { KotlinType explicitReturnType = typeResolver.resolveType(scope, returnTypeReference, trace, true); - if (!TypeUtils.equalTypes(explicitReturnType, propertyType)) { - trace.report(WRONG_GETTER_RETURN_TYPE.on(returnTypeReference, propertyType, explicitReturnType)); + if (propertyTypeIfKnown != null && !TypeUtils.equalTypes(explicitReturnType, propertyTypeIfKnown)) { + trace.report(WRONG_GETTER_RETURN_TYPE.on(returnTypeReference, propertyTypeIfKnown, explicitReturnType)); } return explicitReturnType; } @@ -1020,7 +1028,7 @@ public class DescriptorResolver { return inferReturnTypeFromExpressionBody(trace, scope, DataFlowInfoFactory.EMPTY, getter, getterDescriptor); } - return propertyType; + return propertyTypeIfKnown; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableTypeAndInitializerResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableTypeAndInitializerResolver.kt index 3b1b9e17202..1ea0c6026b2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableTypeAndInitializerResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableTypeAndInitializerResolver.kt @@ -43,6 +43,10 @@ class VariableTypeAndInitializerResolver( private val constantExpressionEvaluator: ConstantExpressionEvaluator, private val delegatedPropertyResolver: DelegatedPropertyResolver ) { + companion object { + @JvmField + val STUB_FOR_PROPERTY_WITHOUT_TYPE = ErrorUtils.createErrorType("No type, no body") + } fun resolveType( variableDescriptor: VariableDescriptorWithInitializerImpl, @@ -52,8 +56,24 @@ class VariableTypeAndInitializerResolver( notLocal: Boolean, trace: BindingTrace ): KotlinType { - val propertyTypeRef = variable.typeReference + resolveTypeNullable(variableDescriptor, scopeForInitializer, variable, dataFlowInfo, notLocal, trace)?.let { return it } + if (!notLocal) { + trace.report(VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.on(variable)) + } + + return STUB_FOR_PROPERTY_WITHOUT_TYPE + } + + fun resolveTypeNullable( + variableDescriptor: VariableDescriptorWithInitializerImpl, + scopeForInitializer: LexicalScope, + variable: KtVariableDeclaration, + dataFlowInfo: DataFlowInfo, + notLocal: Boolean, + trace: BindingTrace + ): KotlinType? { + val propertyTypeRef = variable.typeReference return when { propertyTypeRef != null -> typeResolver.resolveType(scopeForInitializer, propertyTypeRef, trace, true) @@ -74,12 +94,7 @@ class VariableTypeAndInitializerResolver( else -> resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace) } - else -> { - if (!notLocal) { - trace.report(VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.on(variable)) - } - ErrorUtils.createErrorType("No type, no body") - } + else -> null } } diff --git a/compiler/testData/codegen/box/properties/typeInferredFromGetter.kt b/compiler/testData/codegen/box/properties/typeInferredFromGetter.kt new file mode 100644 index 00000000000..f4f042888b1 --- /dev/null +++ b/compiler/testData/codegen/box/properties/typeInferredFromGetter.kt @@ -0,0 +1,7 @@ +val x get() = "O" + +class A { + val y get() = "K" +} + +fun box() = x + A().y diff --git a/compiler/testData/diagnostics/tests/RecursiveGetter.kt b/compiler/testData/diagnostics/tests/RecursiveGetter.kt deleted file mode 100644 index 4acf31b0295..00000000000 --- a/compiler/testData/diagnostics/tests/RecursiveGetter.kt +++ /dev/null @@ -1,3 +0,0 @@ -class A { - val a get() = a -} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/ambiguousObjectExpressionType.kt b/compiler/testData/diagnostics/tests/declarationChecks/ambiguousObjectExpressionType.kt index 34032f98091..7060e072d8e 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/ambiguousObjectExpressionType.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/ambiguousObjectExpressionType.kt @@ -24,7 +24,7 @@ class Foo { public val publicProperty = object : MyClass(), MyTrait {} - val propertyWithGetter + val propertyWithGetter get() = object: MyClass(), MyTrait {} @@ -117,4 +117,4 @@ fun fooPackage() { fun fooPackageLocal() = object : MyClass(), MyTrait {} fooPackageLocal().f1() fooPackageLocal().f2() -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/ambiguousObjectExpressionType.txt b/compiler/testData/diagnostics/tests/declarationChecks/ambiguousObjectExpressionType.txt index d2973089870..dd73bbc41bc 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/ambiguousObjectExpressionType.txt +++ b/compiler/testData/diagnostics/tests/declarationChecks/ambiguousObjectExpressionType.txt @@ -16,7 +16,7 @@ public final class Foo { internal final val internal2Property: Foo.internal2Property. public final val internalProperty: Foo.internalProperty. private final val privateProperty: Foo.privateProperty. - public final val propertyWithGetter: [ERROR : No type, no body] + public final val propertyWithGetter: Foo.. protected final val protectedProperty: Foo.protectedProperty. public final val publicProperty: Foo.publicProperty. public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.kt new file mode 100644 index 00000000000..38d500a9c42 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.kt @@ -0,0 +1,3 @@ +val x get() { + return 1 +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.txt new file mode 100644 index 00000000000..cc166f318d5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.txt @@ -0,0 +1,3 @@ +package + +public val x: [ERROR : No type, no body] diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/cantBeInferred.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/cantBeInferred.kt new file mode 100644 index 00000000000..804ac350ff3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/cantBeInferred.kt @@ -0,0 +1,5 @@ +val x get() = foo() +val y get() = bar() + +fun foo(): E = null!! +fun bar(): List = null!! diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/cantBeInferred.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/cantBeInferred.txt new file mode 100644 index 00000000000..74f05e17888 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/cantBeInferred.txt @@ -0,0 +1,6 @@ +package + +public val x: [ERROR : Error function type] +public val y: [ERROR : Error function type] +public fun bar(): kotlin.collections.List +public fun foo(): E diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/explicitGetterType.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/explicitGetterType.kt new file mode 100644 index 00000000000..9f83d3d8b3d --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/explicitGetterType.kt @@ -0,0 +1,18 @@ +// !CHECK_TYPE +val x get(): String = foo() +val y get(): List = bar() +val z get(): List { + return bar() +} + +val u get(): String = field + +fun foo(): E = null!! +fun bar(): List = null!! + + +fun baz() { + x checkType { _() } + y checkType { _>() } + z checkType { _>() } +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/explicitGetterType.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/explicitGetterType.txt new file mode 100644 index 00000000000..4e3883a4e3c --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/explicitGetterType.txt @@ -0,0 +1,9 @@ +package + +public val u: kotlin.String +public val x: kotlin.String +public val y: kotlin.collections.List +public val z: kotlin.collections.List +public fun bar(): kotlin.collections.List +public fun baz(): kotlin.Unit +public fun foo(): E diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/members.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/members.kt new file mode 100644 index 00000000000..9e0835f7777 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/members.kt @@ -0,0 +1,24 @@ +// !CHECK_TYPE +class A { + val x get() = 1 + val y get() = id(1) + val y2 get() = id(id(2)) + val z get() = l("") + val z2 get() = l(id(l(""))) + + val T.u get() = id(this) +} +fun id(x: E) = x +fun l(x: E): List = null!! + +fun foo(a: A) { + a.x checkType { _() } + a.y checkType { _() } + a.y2 checkType { _() } + a.z checkType { _>() } + a.z2 checkType { _>>() } + + with(a) { + 1.u checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/members.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/members.txt new file mode 100644 index 00000000000..a3eb98f7197 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/members.txt @@ -0,0 +1,18 @@ +package + +public fun foo(/*0*/ a: A): kotlin.Unit +public fun id(/*0*/ x: E): E +public fun l(/*0*/ x: E): kotlin.collections.List + +public final class A { + public constructor A() + public final val x: kotlin.Int + public final val y: kotlin.Int + public final val y2: kotlin.Int + public final val z: kotlin.collections.List + public final val z2: kotlin.collections.List> + public final val T.u: T + 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 +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/nullAsNothing.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/nullAsNothing.kt new file mode 100644 index 00000000000..c9c42e8cf62 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/nullAsNothing.kt @@ -0,0 +1,8 @@ +// !CHECK_TYPE +val x get() = null +val y get() = null!! + +fun foo() { + x checkType { _() } + y checkType { _() } +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/nullAsNothing.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/nullAsNothing.txt new file mode 100644 index 00000000000..3c43a1c0579 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/nullAsNothing.txt @@ -0,0 +1,5 @@ +package + +public val x: kotlin.Nothing? +public val y: kotlin.Nothing +public fun foo(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/objectExpression.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/objectExpression.kt new file mode 100644 index 00000000000..b34a14da86c --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/objectExpression.kt @@ -0,0 +1,35 @@ +// !CHECK_TYPE +object Outer { + private var x + get() = object : CharSequence { + override val length: Int + get() = 0 + + override fun get(index: Int): Char { + checkSubtype(x) + return ' ' + } + + override fun subSequence(startIndex: Int, endIndex: Int) = "" + + fun bar() { + } + } + set(q) { + checkSubtype(x) + y = q + x = q + } + + private var y = x + + fun foo() { + x = y + + checkSubtype(x) + checkSubtype(y) + + x.bar() + y.bar() + } +} diff --git a/compiler/testData/diagnostics/tests/RecursiveGetter.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/objectExpression.txt similarity index 56% rename from compiler/testData/diagnostics/tests/RecursiveGetter.txt rename to compiler/testData/diagnostics/tests/properties/inferenceFromGetters/objectExpression.txt index 0650ad60855..4b41acb8745 100644 --- a/compiler/testData/diagnostics/tests/RecursiveGetter.txt +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/objectExpression.txt @@ -1,9 +1,11 @@ package -public final class A { - public constructor A() - public final val a: [ERROR : No type, no body] +public object Outer { + private constructor Outer() + private final var x: Outer.. + private final var y: Outer.. public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/overrides.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/overrides.kt new file mode 100644 index 00000000000..d4a0aff75e7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/overrides.kt @@ -0,0 +1,41 @@ +// !CHECK_TYPE +interface A { + val x: Int + + val z: Comparable<*> +} + +open class B { + open var y = "" + + open val z: CharSequence = "" +} + +class C : B(), A { + override val x + get() = 1 + + override var y + get() = super.y + set(value) { + value checkType { _() } + } + + override var z + get() = "" + set(value) { + value checkType { _() } + } +} + +fun foo(c: C) { + c.x checkType { _() } + c.y checkType { _() } + c.z checkType { _() } + + c.y = "" + c.y = 1 + + c.z = "" + c.z = 1 +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/overrides.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/overrides.txt new file mode 100644 index 00000000000..69896cc8237 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/overrides.txt @@ -0,0 +1,30 @@ +package + +public fun foo(/*0*/ c: C): kotlin.Unit + +public interface A { + public abstract val x: kotlin.Int + public abstract val z: kotlin.Comparable<*> + 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 open class B { + public constructor B() + public open var y: kotlin.String + public open val z: kotlin.CharSequence + 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 class C : B, A { + public constructor C() + public open override /*1*/ val x: kotlin.Int + public open override /*1*/ var y: kotlin.String + public open override /*2*/ var z: kotlin.String + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.kt new file mode 100644 index 00000000000..e0887524739 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.kt @@ -0,0 +1,18 @@ +// !CHECK_TYPE + +val x get() = x + +class A { + val y get() = y + + val a get() = b + val b get() = a + + val z1 get() = id(z1) + val z2 get() = l(z2) + + val u get() = field +} + +fun id(x: E) = x +fun l(x: E): List = null!! diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.txt new file mode 100644 index 00000000000..83c24b9000a --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.txt @@ -0,0 +1,18 @@ +package + +public val x: [ERROR : Error function type] +public fun id(/*0*/ x: E): E +public fun l(/*0*/ x: E): kotlin.collections.List + +public final class A { + public constructor A() + public final val a: [ERROR : Error function type] + public final val b: [ERROR : Error function type] + public final val u: [ERROR : Error function type] + public final val y: [ERROR : Error function type] + public final val z1: [ERROR : Error function type] + public final val z2: [ERROR : Error function type] + 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 +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/topLevel.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/topLevel.kt new file mode 100644 index 00000000000..13f297ca5e9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/topLevel.kt @@ -0,0 +1,21 @@ +// !CHECK_TYPE +val x get() = 1 +val y get() = id(1) +val y2 get() = id(id(2)) +val z get() = l("") +val z2 get() = l(id(l(""))) + +val T.u get() = id(this) + +fun id(x: E) = x +fun l(x: E): List = null!! + +fun foo() { + x checkType { _() } + y checkType { _() } + y2 checkType { _() } + z checkType { _>() } + z2 checkType { _>>() } + + 1.u checkType { _() } +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/topLevel.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/topLevel.txt new file mode 100644 index 00000000000..fee87746152 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/topLevel.txt @@ -0,0 +1,11 @@ +package + +public val x: kotlin.Int +public val y: kotlin.Int +public val y2: kotlin.Int +public val z: kotlin.collections.List +public val z2: kotlin.collections.List> +public val T.u: T +public fun foo(): kotlin.Unit +public fun id(/*0*/ x: E): E +public fun l(/*0*/ x: E): kotlin.collections.List diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.kt new file mode 100644 index 00000000000..49849d2b13a --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.kt @@ -0,0 +1,21 @@ +// !CHECK_TYPE +var x + get() = 1 + set(q) { + q checkType { _() } + } + +var noSetter + get() = 1 + + +fun foo() { + x checkType { _() } + noSetter checkType { _() } + + x = 1 + x = "" + + noSetter = 2 + noSetter = "" +} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.txt new file mode 100644 index 00000000000..ceed4454ba8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.txt @@ -0,0 +1,5 @@ +package + +public var noSetter: kotlin.Int +public var x: kotlin.Int +public fun foo(): kotlin.Unit diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 1ad297b8180..8e11331da6f 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -11189,6 +11189,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("typeInferredFromGetter.kt") + public void testTypeInferredFromGetter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/typeInferredFromGetter.kt"); + doTest(fileName); + } + @TestMetadata("compiler/testData/codegen/box/properties/const") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 9c6d1ecec8b..86b6c3f5e0b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -572,12 +572,6 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } - @TestMetadata("RecursiveGetter.kt") - public void testRecursiveGetter() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/RecursiveGetter.kt"); - doTest(fileName); - } - @TestMetadata("RecursiveResolve.kt") public void testRecursiveResolve() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/RecursiveResolve.kt"); @@ -14525,6 +14519,84 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/properties") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Properties extends AbstractDiagnosticsTest { + public void testAllFilesPresentInProperties() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/properties"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InferenceFromGetters extends AbstractDiagnosticsTest { + public void testAllFilesPresentInInferenceFromGetters() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/properties/inferenceFromGetters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("blockBodyGetter.kt") + public void testBlockBodyGetter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.kt"); + doTest(fileName); + } + + @TestMetadata("cantBeInferred.kt") + public void testCantBeInferred() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/cantBeInferred.kt"); + doTest(fileName); + } + + @TestMetadata("explicitGetterType.kt") + public void testExplicitGetterType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/explicitGetterType.kt"); + doTest(fileName); + } + + @TestMetadata("members.kt") + public void testMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/members.kt"); + doTest(fileName); + } + + @TestMetadata("nullAsNothing.kt") + public void testNullAsNothing() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/nullAsNothing.kt"); + doTest(fileName); + } + + @TestMetadata("objectExpression.kt") + public void testObjectExpression() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/objectExpression.kt"); + doTest(fileName); + } + + @TestMetadata("overrides.kt") + public void testOverrides() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/overrides.kt"); + doTest(fileName); + } + + @TestMetadata("recursiveGetter.kt") + public void testRecursiveGetter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/recursiveGetter.kt"); + doTest(fileName); + } + + @TestMetadata("topLevel.kt") + public void testTopLevel() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/topLevel.kt"); + doTest(fileName); + } + + @TestMetadata("vars.kt") + public void testVars() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.kt"); + doTest(fileName); + } + } + } + @TestMetadata("compiler/testData/diagnostics/tests/qualifiedExpression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index c6090c342a4..d09903c16a3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -11189,6 +11189,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("typeInferredFromGetter.kt") + public void testTypeInferredFromGetter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/typeInferredFromGetter.kt"); + doTest(fileName); + } + @TestMetadata("compiler/testData/codegen/box/properties/const") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/testData/quickfix/typeAddition/propertyWithRecursiveGetter.kt b/idea/testData/quickfix/typeAddition/propertyWithRecursiveGetter.kt index a25bed2ec65..5a6172d61a3 100644 --- a/idea/testData/quickfix/typeAddition/propertyWithRecursiveGetter.kt +++ b/idea/testData/quickfix/typeAddition/propertyWithRecursiveGetter.kt @@ -1,5 +1,5 @@ // "Specify type explicitly" "false" -// ERROR: This property must either have a type annotation, be initialized or be delegated +// ERROR: Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly // ACTION: Convert member to extension // ACTION: Convert property to function // ACTION: Move to companion object @@ -7,4 +7,4 @@ class A { val a get() = a -} \ No newline at end of file +} diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 46e832cacbd..0f1937abc3a 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -13760,6 +13760,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("typeInferredFromGetter.kt") + public void testTypeInferredFromGetter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/typeInferredFromGetter.kt"); + doTest(fileName); + } + @TestMetadata("compiler/testData/codegen/box/properties/const") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)