From 23cfe88b7175efbf41ab25e3917be3920f99c9d0 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 17 Jul 2015 15:13:39 +0300 Subject: [PATCH] KT-8530 Synthetic properties doesn't work with smart casts #KT-8530 Fixed --- .../synthetic/JavaSyntheticExtensionsScope.kt | 36 ++++++++++----- .../kotlin/resolve/AllUnderImportsScope.kt | 8 ++-- .../tasks/CallableDescriptorCollectors.kt | 16 +++---- .../resolve/calls/tasks/TaskPrioritizer.kt | 45 ++++++++++++------- .../resolve/calls/tasks/dynamicCalls.kt | 4 +- .../kotlin/resolve/lazy/LazyImportScope.kt | 8 ++-- .../tests/syntheticExtensions/SmartCast.kt | 28 ++++++++++++ .../tests/syntheticExtensions/SmartCast.txt | 37 +++++++++++++++ .../SmartCastImplicitReceiver.kt | 23 ++++++++++ .../SmartCastImplicitReceiver.txt | 29 ++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 12 +++++ .../resolve/scopes/AbstractScopeAdapter.kt | 8 ++-- .../kotlin/resolve/scopes/ChainedScope.kt | 8 ++-- .../kotlin/resolve/scopes/FilteringScope.kt | 4 +- .../kotlin/resolve/scopes/JetScope.kt | 4 +- .../kotlin/resolve/scopes/JetScopeImpl.kt | 4 +- .../resolve/scopes/SubstitutingScope.kt | 4 +- .../jetbrains/kotlin/types/ErrorUtils.java | 8 ++-- .../codeInsight/ReferenceVariantsHelper.kt | 14 +++--- 19 files changed, 229 insertions(+), 71 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/syntheticExtensions/SmartCast.kt create mode 100644 compiler/testData/diagnostics/tests/syntheticExtensions/SmartCast.txt create mode 100644 compiler/testData/diagnostics/tests/syntheticExtensions/SmartCastImplicitReceiver.kt create mode 100644 compiler/testData/diagnostics/tests/syntheticExtensions/SmartCastImplicitReceiver.txt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticExtensionsScope.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticExtensionsScope.kt index 2b44ac22772..695dcfca9af 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticExtensionsScope.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticExtensionsScope.kt @@ -36,7 +36,7 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.utils.addIfNotNull import java.beans.Introspector -import java.util.ArrayList +import java.util.* interface SyntheticJavaPropertyDescriptor : PropertyDescriptor { val getMethod: FunctionDescriptor @@ -52,7 +52,7 @@ interface SyntheticJavaPropertyDescriptor : PropertyDescriptor { val owner = getterOrSetter.getContainingDeclaration() if (owner !is JavaClassDescriptor) return null - return resolutionScope.getSyntheticExtensionProperties(owner.getDefaultType()) + return resolutionScope.getSyntheticExtensionProperties(listOf(owner.getDefaultType())) .filterIsInstance() .firstOrNull { getterOrSetter == it.getMethod || getterOrSetter == it.setMethod } } @@ -136,11 +136,22 @@ class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by && descriptor.getVisibility() == Visibilities.PUBLIC } - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection { - return collectSyntheticPropertiesByName(null, receiverType.makeNotNullable(), name) ?: emptyList() + override fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection { + var result: SmartList? = null + val processedTypes: MutableSet? = if (receiverTypes.size() > 1) HashSet() else null + receiverTypes.forEach { + result = collectSyntheticPropertiesByName(result, it.makeNotNullable(), name, processedTypes) + } + return when { + result == null -> emptyList() + result!!.size() > 1 -> result!!.toSet() + else -> result!! + } } - private fun collectSyntheticPropertiesByName(result: SmartList?, type: JetType, name: Name): SmartList? { + private fun collectSyntheticPropertiesByName(result: SmartList?, type: JetType, name: Name, processedTypes: MutableSet?): SmartList? { + if (processedTypes != null && !processedTypes.add(type)) return result + @suppress("NAME_SHADOWING") var result = result @@ -150,18 +161,23 @@ class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by result = result.add(syntheticPropertyInClass(Triple(classifier, type, name))) } - typeConstructor.getSupertypes().forEach { result = collectSyntheticPropertiesByName(result, it, name) } + typeConstructor.getSupertypes().forEach { result = collectSyntheticPropertiesByName(result, it, name, processedTypes) } return result } - override fun getSyntheticExtensionProperties(receiverType: JetType): Collection { + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection { val result = ArrayList() - result.collectSyntheticProperties(receiverType.makeNotNullable()) + val processedTypes = HashSet() + receiverTypes.forEach { + result.collectSyntheticProperties(it.makeNotNullable(), processedTypes) + } return result } - private fun MutableList.collectSyntheticProperties(type: JetType) { + private fun MutableList.collectSyntheticProperties(type: JetType, processedTypes: MutableSet) { + if (!processedTypes.add(type)) return + val typeConstructor = type.getConstructor() val classifier = typeConstructor.getDeclarationDescriptor() if (classifier is JavaClassDescriptor) { @@ -173,7 +189,7 @@ class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by } } - typeConstructor.getSupertypes().forEach { collectSyntheticProperties(it) } + typeConstructor.getSupertypes().forEach { collectSyntheticProperties(it, processedTypes) } } private fun SmartList?.add(property: PropertyDescriptor?): SmartList? { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt index f4218d6fc5c..f80c038a654 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt @@ -53,12 +53,12 @@ class AllUnderImportsScope : JetScope { return scopes.flatMap { it.getFunctions(name) } } - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection { - return scopes.flatMap { it.getSyntheticExtensionProperties(receiverType, name) } + override fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection { + return scopes.flatMap { it.getSyntheticExtensionProperties(receiverTypes, name) } } - override fun getSyntheticExtensionProperties(receiverType: JetType): Collection { - return scopes.flatMap { it.getSyntheticExtensionProperties(receiverType) } + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection { + return scopes.flatMap { it.getSyntheticExtensionProperties(receiverTypes) } } override fun getPackage(name: Name): PackageViewDescriptor? = null // packages are not imported by all under imports diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt index 32555451aa8..2625c5d35de 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt @@ -39,7 +39,7 @@ public trait CallableDescriptorCollector { public fun getStaticMembersByName(receiver: JetType, name: Name, bindingTrace: BindingTrace): Collection - public fun getExtensionsByName(scope: JetScope, name: Name, receiver: JetType, bindingTrace: BindingTrace): Collection + public fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, bindingTrace: BindingTrace): Collection } private fun CallableDescriptorCollector.withDefaultFilter() = filtered { !LibrarySourceHacks.shouldSkip(it) } @@ -97,7 +97,7 @@ private object FunctionCollector : CallableDescriptorCollector { + override fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, bindingTrace: BindingTrace): Collection { val functions = scope.getFunctions(name) val (extensions, nonExtensions) = functions.partition { it.getExtensionReceiverParameter() != null } @@ -151,9 +151,9 @@ private object VariableCollector : CallableDescriptorCollector { + override fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, bindingTrace: BindingTrace): Collection { // property may have an extension function type, we check the applicability later to avoid an early computing of deferred types - return (listOf(scope.getLocalVariable(name)) + scope.getProperties(name) + scope.getSyntheticExtensionProperties(receiver, name)).filterNotNull() + return (listOf(scope.getLocalVariable(name)) + scope.getProperties(name) + scope.getSyntheticExtensionProperties(receiverTypes, name)).filterNotNull() } override fun toString() = "VARIABLES" @@ -175,8 +175,8 @@ private object PropertyCollector : CallableDescriptorCollector { - return filterProperties(VARIABLES_COLLECTOR.getExtensionsByName(scope, name, receiver, bindingTrace)) + override fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, bindingTrace: BindingTrace): Collection { + return filterProperties(VARIABLES_COLLECTOR.getExtensionsByName(scope, name, receiverTypes, bindingTrace)) } override fun toString() = "PROPERTIES" @@ -197,8 +197,8 @@ private fun CallableDescriptorCollector.filtered(fil return delegate.getStaticMembersByName(receiver, name, bindingTrace).filter(filter) } - override fun getExtensionsByName(scope: JetScope, name: Name, receiver: JetType, bindingTrace: BindingTrace): Collection { - return delegate.getExtensionsByName(scope, name, receiver, bindingTrace).filter(filter) + override fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, bindingTrace: BindingTrace): Collection { + return delegate.getExtensionsByName(scope, name, receiverTypes, bindingTrace).filter(filter) } override fun toString(): String { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt index e6b8ead5a3c..41ea2fbd7a8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt @@ -18,9 +18,9 @@ package org.jetbrains.kotlin.resolve.calls.tasks import com.google.common.collect.Lists import com.google.common.collect.Sets -import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.psi.Call import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized @@ -41,6 +41,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.ErrorUtils +import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.checker.JetTypeChecker import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.isDynamic @@ -119,8 +120,9 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { } val implicitReceivers = Sets.newLinkedHashSet(JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope)) if (receiver.exists()) { - addCandidatesForExplicitReceiver(receiver, implicitReceivers, c, isExplicit = true) - addMembers(receiver, c, staticMembers = true, isExplicit = true) + val receiverTypes = SmartCastUtils.getSmartCastVariants(receiver, c.context) + addCandidatesForExplicitReceiver(receiver, receiverTypes, implicitReceivers, c, isExplicit = true) + addMembers(receiver, receiverTypes, c, staticMembers = true, isExplicit = true) return } addCandidatesForNoReceiver(implicitReceivers, c) @@ -128,22 +130,24 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { private fun addCandidatesForExplicitReceiver( explicitReceiver: ReceiverValue, + explicitReceiverTypes: Collection, implicitReceivers: Collection, c: TaskPrioritizerContext, isExplicit: Boolean ) { - addMembers(explicitReceiver, c, staticMembers = false, isExplicit = isExplicit) + addMembers(explicitReceiver, explicitReceiverTypes, c, staticMembers = false, isExplicit = isExplicit) if (explicitReceiver.getType().isDynamic()) { - addCandidatesForDynamicReceiver(explicitReceiver, implicitReceivers, c, isExplicit) + addCandidatesForDynamicReceiver(explicitReceiver, explicitReceiverTypes, implicitReceivers, c, isExplicit) } else { - addExtensionCandidates(explicitReceiver, implicitReceivers, c, isExplicit) + addExtensionCandidates(explicitReceiver, explicitReceiverTypes, implicitReceivers, c, isExplicit) } } private fun addExtensionCandidates( explicitReceiver: ReceiverValue, + explicitReceiverTypes: Collection, implicitReceivers: Collection, c: TaskPrioritizerContext, isExplicit: Boolean @@ -154,6 +158,7 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { addMemberExtensionCandidates( implicitReceiver, explicitReceiver, + explicitReceiverTypes, callableDescriptorCollector, c, createKind(EXTENSION_RECEIVER, isExplicit) @@ -164,7 +169,7 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { convertWithImpliedThis( c.scope, explicitReceiver, - callableDescriptorCollector.getExtensionsByName(c.scope, c.name, explicitReceiver.getType(), c.context.trace), + callableDescriptorCollector.getExtensionsByName(c.scope, c.name, explicitReceiverTypes, c.context.trace), createKind(EXTENSION_RECEIVER, isExplicit), c.context.call ) @@ -174,15 +179,15 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { private fun addMembers( explicitReceiver: ReceiverValue, + explicitReceiverTypes: Collection, c: TaskPrioritizerContext, staticMembers: Boolean, isExplicit: Boolean ) { for (callableDescriptorCollector in c.callableDescriptorCollectors) { c.result.addCandidates { - val variantsForExplicitReceiver = SmartCastUtils.getSmartCastVariants(explicitReceiver, c.context) val members = Lists.newArrayList>() - for (type in variantsForExplicitReceiver) { + for (type in explicitReceiverTypes) { val membersForThisVariant = if (staticMembers) { callableDescriptorCollector.getStaticMembersByName(type, c.name, c.context.trace) } @@ -205,12 +210,13 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { private fun addCandidatesForDynamicReceiver( explicitReceiver: ReceiverValue, + explicitReceiverTypes: Collection, implicitReceivers: Collection, c: TaskPrioritizerContext, isExplicit: Boolean ) { val onlyDynamicReceivers = c.replaceCollectors(c.callableDescriptorCollectors.onlyDynamicReceivers()) - addExtensionCandidates(explicitReceiver, implicitReceivers, onlyDynamicReceivers, isExplicit) + addExtensionCandidates(explicitReceiver, explicitReceiverTypes, implicitReceivers, onlyDynamicReceivers, isExplicit) c.result.addCandidates { val dynamicScope = DynamicCallableDescriptors.createDynamicDescriptorScope(c.context.call, c.scope.getContainingDeclaration()) @@ -231,13 +237,14 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { private fun addMemberExtensionCandidates( dispatchReceiver: ReceiverValue, receiverParameter: ReceiverValue, + receiverParameterTypes: Collection, callableDescriptorCollector: CallableDescriptorCollector, c: TaskPrioritizerContext, receiverKind: ExplicitReceiverKind ) { c.result.addCandidates { val memberExtensions = - callableDescriptorCollector.getExtensionsByName(dispatchReceiver.getType().getMemberScope(), c.name, receiverParameter.getType(), c.context.trace) + callableDescriptorCollector.getExtensionsByName(dispatchReceiver.getType().getMemberScope(), c.name, receiverParameterTypes, c.context.trace) convertWithReceivers(memberExtensions, dispatchReceiver, receiverParameter, receiverKind, c.context.call) } } @@ -269,17 +276,19 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { //locals c.result.addCandidates(localsList) + val implicitReceiversWithTypes = implicitReceivers.map { it to SmartCastUtils.getSmartCastVariants(it, c.context) } + //try all implicit receivers as explicit - for (implicitReceiver in implicitReceivers) { - addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, isExplicit = false) + for ((implicitReceiver, implicitReceiverTypes) in implicitReceiversWithTypes) { + addCandidatesForExplicitReceiver(implicitReceiver, implicitReceiverTypes, implicitReceivers, c, isExplicit = false) } //nonlocals c.result.addCandidates(nonlocalsList) //static (only for better error reporting) - for (implicitReceiver in implicitReceivers) { - addMembers(implicitReceiver, c, staticMembers = true, isExplicit = false) + for ((implicitReceiver, implicitReceiverTypes) in implicitReceiversWithTypes) { + addMembers(implicitReceiver, implicitReceiverTypes, c, staticMembers = true, isExplicit = false) } } @@ -297,7 +306,8 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { // (1) a.foo + foo.invoke() if (!explicitReceiver.exists()) { - addCandidatesForExplicitReceiver(variableReceiver, implicitReceivers, c, isExplicit = true) + val variableReceiverTypes = SmartCastUtils.getSmartCastVariants(variableReceiver, c.context) + addCandidatesForExplicitReceiver(variableReceiver, variableReceiverTypes, implicitReceivers, c, isExplicit = true) } // (2) foo + a.invoke() @@ -323,8 +333,9 @@ public class TaskPrioritizer(private val storageManager: StorageManager) { c: TaskPrioritizerContext, receiverKind: ExplicitReceiverKind ) { + val receiverParameterTypes = SmartCastUtils.getSmartCastVariants(receiverParameter, c.context) for (callableDescriptorCollector in c.callableDescriptorCollectors) { - addMemberExtensionCandidates(dispatchReceiver, receiverParameter, callableDescriptorCollector, c, receiverKind) + addMemberExtensionCandidates(dispatchReceiver, receiverParameter, receiverParameterTypes, callableDescriptorCollector, c, receiverKind) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt index eb376226710..528cdb6eed2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/dynamicCalls.kt @@ -223,8 +223,8 @@ public fun DeclarationDescriptor.isDynamic(): Boolean { } class CollectorForDynamicReceivers(val delegate: CallableDescriptorCollector) : CallableDescriptorCollector by delegate { - override fun getExtensionsByName(scope: JetScope, name: Name, receiver: JetType, bindingTrace: BindingTrace): Collection { - return delegate.getExtensionsByName(scope, name, receiver, bindingTrace).filter { + override fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, bindingTrace: BindingTrace): Collection { + return delegate.getExtensionsByName(scope, name, receiverTypes, bindingTrace).filter { it.getExtensionReceiverParameter()?.getType()?.isDynamic() ?: false } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt index 272ee60ff50..8b2d59de4f0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt @@ -258,18 +258,18 @@ class LazyImportScope( return importResolver.collectFromImports(name, LookupMode.EVERYTHING) { scope, name -> scope.getFunctions(name) } } - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection { + override fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection { if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() - return importResolver.collectFromImports(name, LookupMode.EVERYTHING) { scope, name -> scope.getSyntheticExtensionProperties(receiverType, name) } + return importResolver.collectFromImports(name, LookupMode.EVERYTHING) { scope, name -> scope.getSyntheticExtensionProperties(receiverTypes, name) } } - override fun getSyntheticExtensionProperties(receiverType: JetType): Collection { + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection { // we do not perform any filtering by visibility here because all descriptors from both visible/invisible filter scopes are to be added anyway if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() return importResolver.storageManager.compute { importResolver.indexedImports.imports.flatMapTo(LinkedHashSet()) { import -> - importResolver.getImportScope(import, LookupMode.EVERYTHING).getSyntheticExtensionProperties(receiverType) + importResolver.getImportScope(import, LookupMode.EVERYTHING).getSyntheticExtensionProperties(receiverTypes) } } } diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCast.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCast.kt new file mode 100644 index 00000000000..6dff2b630a1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCast.kt @@ -0,0 +1,28 @@ +// FILE: KotlinFile.kt +fun foo(o: JavaInterface2): Int { + if (o is JavaClass) { + o.something++ + return o.x + o.something2 + } + return 0 +} + +// FILE: JavaClass.java +public abstract class JavaClass extends BaseClass implements JavaInterface { + public int getSomething() { return 1; } + public void setSomething(int value) { } +} + +// FILE: BaseClass.java +public abstract class BaseClass implements JavaInterface { +} + +// FILE: JavaInterface.java +public interface JavaInterface { + int getX(); +} + +// FILE: JavaInterface2.java +public interface JavaInterface2 { + int getSomething2(); +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCast.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCast.txt new file mode 100644 index 00000000000..7100c3e7725 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCast.txt @@ -0,0 +1,37 @@ +package + +public /*synthesized*/ fun JavaInterface(/*0*/ function: () -> kotlin.Int): JavaInterface +public /*synthesized*/ fun JavaInterface2(/*0*/ function: () -> kotlin.Int): JavaInterface2 +internal fun foo(/*0*/ o: JavaInterface2): kotlin.Int + +public abstract class BaseClass : JavaInterface { + public constructor BaseClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun getX(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class JavaClass : BaseClass, JavaInterface { + public constructor JavaClass() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething(): kotlin.Int + public abstract override /*2*/ /*fake_override*/ fun getX(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun setSomething(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getX(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getSomething2(): kotlin.Int + 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/syntheticExtensions/SmartCastImplicitReceiver.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCastImplicitReceiver.kt new file mode 100644 index 00000000000..7da8bd686ca --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCastImplicitReceiver.kt @@ -0,0 +1,23 @@ +// FILE: KotlinFile.kt +fun Any.foo(): Int { + if (this is JavaClass) { + something++ + return x + } + return 0 +} + +// FILE: JavaClass.java +public abstract class JavaClass extends BaseClass implements JavaInterface { + public int getSomething() { return 1; } + public void setSomething(int value) { } +} + +// FILE: BaseClass.java +public abstract class BaseClass implements JavaInterface { +} + +// FILE: JavaInterface.java +public interface JavaInterface { + int getX(); +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCastImplicitReceiver.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCastImplicitReceiver.txt new file mode 100644 index 00000000000..fb712c02c73 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/SmartCastImplicitReceiver.txt @@ -0,0 +1,29 @@ +package + +public /*synthesized*/ fun JavaInterface(/*0*/ function: () -> kotlin.Int): JavaInterface +internal fun kotlin.Any.foo(): kotlin.Int + +public abstract class BaseClass : JavaInterface { + public constructor BaseClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun getX(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class JavaClass : BaseClass, JavaInterface { + public constructor JavaClass() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething(): kotlin.Int + public abstract override /*2*/ /*fake_override*/ fun getX(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun setSomething(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getX(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 1563eeaba42..4de00ef2cf9 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -14093,6 +14093,18 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/SetterOnly.kt"); doTest(fileName); } + + @TestMetadata("SmartCast.kt") + public void testSmartCast() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/SmartCast.kt"); + doTest(fileName); + } + + @TestMetadata("SmartCastImplicitReceiver.kt") + public void testSmartCastImplicitReceiver() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/SmartCastImplicitReceiver.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/thisAndSuper") diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt index bd2484fe4fe..91712ae2867 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt @@ -47,12 +47,12 @@ public abstract class AbstractScopeAdapter : JetScope { return workerScope.getProperties(name) } - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection { - return workerScope.getSyntheticExtensionProperties(receiverType, name) + override fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection { + return workerScope.getSyntheticExtensionProperties(receiverTypes, name) } - override fun getSyntheticExtensionProperties(receiverType: JetType): Collection { - return workerScope.getSyntheticExtensionProperties(receiverType) + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection { + return workerScope.getSyntheticExtensionProperties(receiverTypes) } override fun getLocalVariable(name: Name): VariableDescriptor? { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt index 7ba44c9658b..276e6e68e57 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt @@ -65,11 +65,11 @@ public open class ChainedScope( override fun getFunctions(name: Name): Collection = getFromAllScopes { it.getFunctions(name) } - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection - = getFromAllScopes { it.getSyntheticExtensionProperties(receiverType, name) } + override fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection + = getFromAllScopes { it.getSyntheticExtensionProperties(receiverTypes, name) } - override fun getSyntheticExtensionProperties(receiverType: JetType): Collection - = getFromAllScopes { it.getSyntheticExtensionProperties(receiverType) } + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection + = getFromAllScopes { it.getSyntheticExtensionProperties(receiverTypes) } override fun getImplicitReceiversHierarchy(): List { if (implicitReceiverHierarchy == null) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt index 5dc3782cee5..9bfe6e2b90f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt @@ -37,9 +37,9 @@ public class FilteringScope(private val workerScope: JetScope, private val predi override fun getProperties(name: Name) = workerScope.getProperties(name).filter(predicate) - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection = workerScope.getSyntheticExtensionProperties(receiverType, name).filter(predicate) + override fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection = workerScope.getSyntheticExtensionProperties(receiverTypes, name).filter(predicate) - override fun getSyntheticExtensionProperties(receiverType: JetType): Collection = workerScope.getSyntheticExtensionProperties(receiverType).filter(predicate) + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection = workerScope.getSyntheticExtensionProperties(receiverTypes).filter(predicate) override fun getLocalVariable(name: Name) = filterDescriptor(workerScope.getLocalVariable(name)) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt index 6e117e28ff2..6735a8f95e0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt @@ -35,9 +35,9 @@ public trait JetScope { public fun getFunctions(name: Name): Collection - public fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection + public fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection - public fun getSyntheticExtensionProperties(receiverType: JetType): Collection + public fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection public fun getContainingDeclaration(): DeclarationDescriptor diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt index e55a691dffc..bb5905a005d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt @@ -32,9 +32,9 @@ public abstract class JetScopeImpl : JetScope { override fun getFunctions(name: Name): Collection = setOf() - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection = listOf() + override fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection = listOf() - override fun getSyntheticExtensionProperties(receiverType: JetType): Collection = listOf() + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection = listOf() override fun getDeclarationsByLabel(labelName: Name): Collection = listOf() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt index d1533271a52..25d9e79d4bb 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt @@ -70,9 +70,9 @@ public class SubstitutingScope(private val workerScope: JetScope, private val su override fun getFunctions(name: Name) = substitute(workerScope.getFunctions(name)) - override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection = substitute(workerScope.getSyntheticExtensionProperties(receiverType, name)) + override fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection = substitute(workerScope.getSyntheticExtensionProperties(receiverTypes, name)) - override fun getSyntheticExtensionProperties(receiverType: JetType): Collection = substitute(workerScope.getSyntheticExtensionProperties(receiverType)) + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection = substitute(workerScope.getSyntheticExtensionProperties(receiverTypes)) override fun getPackage(name: Name) = workerScope.getPackage(name) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java index 4c1299be7ec..86fc5e0d1f2 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java @@ -94,14 +94,14 @@ public class ErrorUtils { @NotNull @Override public Collection getSyntheticExtensionProperties( - @NotNull JetType receiverType, @NotNull Name name + @NotNull Collection receiverTypes, @NotNull Name name ) { return ERROR_PROPERTY_GROUP; } @NotNull @Override - public Collection getSyntheticExtensionProperties(@NotNull JetType receiverType) { + public Collection getSyntheticExtensionProperties(@NotNull Collection receiverTypes) { return ERROR_PROPERTY_GROUP; } @@ -210,14 +210,14 @@ public class ErrorUtils { @NotNull @Override public Collection getSyntheticExtensionProperties( - @NotNull JetType receiverType, @NotNull Name name + @NotNull Collection receiverTypes, @NotNull Name name ) { throw new IllegalStateException(); } @NotNull @Override - public Collection getSyntheticExtensionProperties(@NotNull JetType receiverType) { + public Collection getSyntheticExtensionProperties(@NotNull Collection receiverTypes) { throw new IllegalStateException(); } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index 2ec2d2d549b..f07eaa5c5b3 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -167,7 +167,9 @@ public class ReferenceVariantsHelper( val memberFilter = kindFilter exclude DescriptorKindExclude.Extensions val containingDeclaration = resolutionScope.getContainingDeclaration() - for (receiverType in SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo)) { + val receiverTypes = SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo) + + for (receiverType in receiverTypes) { val members = receiverType.getMemberScope().getDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter) // filter by kind later because of constructors for (member in members) { if (member is ClassDescriptor) { @@ -179,12 +181,12 @@ public class ReferenceVariantsHelper( this.add(member) } } + } - if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) { - for (extension in resolutionScope.getSyntheticExtensionProperties(receiverType)) { - if (nameFilter(extension.getName()) && kindFilter.accepts(extension)) { - addAll(extension.substituteExtensionIfCallable(receiverValue, callType, context, dataFlowInfo, containingDeclaration)) - } + if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) { + for (extension in resolutionScope.getSyntheticExtensionProperties(receiverTypes)) { + if (nameFilter(extension.getName()) && kindFilter.accepts(extension)) { + addAll(extension.substituteExtensionIfCallable(receiverValue, callType, context, dataFlowInfo, containingDeclaration)) } } }