From 24819a079bf95f885848ed3452df6caf16712190 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 9 Nov 2016 18:10:17 +0300 Subject: [PATCH] Change resolution scope for componentX in lambda parameters Component-functions are resolved in the same scope as the first statement of the lambda, but lambda receiver was not available #KT-14692 Fixed --- .../kotlin/resolve/DescriptorResolver.java | 33 ++++++++++++++----- .../kotlin/resolve/lazy/ForceResolveUtil.java | 10 ++++-- .../kotlin/resolve/scopes/utils/ScopeUtils.kt | 5 +++ .../extensionComponents.kt | 14 ++++---- .../impl/ValueParameterDescriptorImpl.kt | 11 +++++-- 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 63e06d1259d..983d446a9fa 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -263,9 +263,9 @@ public class DescriptorResolver { @NotNull public ValueParameterDescriptorImpl resolveValueParameterDescriptor( - @NotNull LexicalScope scope, @NotNull FunctionDescriptor owner, + @NotNull final LexicalScope scope, @NotNull final FunctionDescriptor owner, @NotNull KtParameter valueParameter, int index, - @NotNull KotlinType type, @NotNull BindingTrace trace + @NotNull final KotlinType type, @NotNull final BindingTrace trace ) { KotlinType varargElementType = null; KotlinType variableType = type; @@ -291,20 +291,35 @@ public class DescriptorResolver { } } - KtDestructuringDeclaration destructuringDeclaration = valueParameter.getDestructuringDeclaration(); + final KtDestructuringDeclaration destructuringDeclaration = valueParameter.getDestructuringDeclaration(); - List destructuringVariables; + Function0> destructuringVariables; if (destructuringDeclaration != null) { if (!languageVersionSettings.supportsFeature(LanguageFeature.DestructuringLambdaParameters)) { trace.report(Errors.UNSUPPORTED_FEATURE.on(valueParameter, LanguageFeature.DestructuringLambdaParameters)); } - destructuringVariables = destructuringDeclarationResolver.resolveLocalVariablesFromDestructuringDeclaration( - scope, destructuringDeclaration, new TransientReceiver(type), /* initializer = */ null, - ExpressionTypingContext.newContext(trace, scope, DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE) - ); + destructuringVariables = new Function0>() { + @Override + public List invoke() { + assert owner.getDispatchReceiverParameter() == null + : "Destructuring declarations are only be parsed for lambdas, and they must not have a dispatch receiver"; + LexicalScope scopeWithReceiver = + ScopeUtilsKt.addImplicitReceiver(scope, owner.getExtensionReceiverParameter()); - modifiersChecker.withTrace(trace).checkModifiersForDestructuringDeclaration(destructuringDeclaration); + List result = + destructuringDeclarationResolver.resolveLocalVariablesFromDestructuringDeclaration( + scope, + destructuringDeclaration, new TransientReceiver(type), /* initializer = */ null, + ExpressionTypingContext.newContext( + trace, scopeWithReceiver, DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE + ) + ); + + modifiersChecker.withTrace(trace).checkModifiersForDestructuringDeclaration(destructuringDeclaration); + return result; + } + }; } else { destructuringVariables = null; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ForceResolveUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ForceResolveUtil.java index 862e22d8421..d3c613e3d97 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ForceResolveUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/ForceResolveUtil.java @@ -22,10 +22,13 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget; import org.jetbrains.kotlin.descriptors.annotations.Annotations; +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.scopes.MemberScope; -import org.jetbrains.kotlin.serialization.ProtoBuf; -import org.jetbrains.kotlin.types.*; +import org.jetbrains.kotlin.types.FlexibleTypesKt; +import org.jetbrains.kotlin.types.KotlinType; +import org.jetbrains.kotlin.types.TypeConstructor; +import org.jetbrains.kotlin.types.TypeProjection; import java.util.Collection; @@ -71,6 +74,9 @@ public class ForceResolveUtil { LazyEntity lazyEntity = (LazyEntity) object; lazyEntity.forceResolveAllContents(); } + else if (object instanceof ValueParameterDescriptorImpl.WithDestructuringDeclaration) { + ((ValueParameterDescriptorImpl.WithDestructuringDeclaration) object).getDestructuringVariables(); + } else if (object instanceof CallableDescriptor) { CallableDescriptor callableDescriptor = (CallableDescriptor) object; ReceiverParameterDescriptor parameter = callableDescriptor.getExtensionReceiverParameter(); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt index 03027108ef4..82cf01b8417 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt @@ -201,6 +201,11 @@ fun LexicalScope.replaceImportingScopes(importingScopeChain: ImportingScope?): L return LexicalScopeWrapper(this, newImportingScopeChain) } +fun LexicalScope.addImplicitReceiver(newReceiver: ReceiverParameterDescriptor?): LexicalScope { + if (newReceiver == null) return this + return LexicalScopeImpl(parent, ownerDescriptor, isOwnerDescriptorAccessibleByLabel, newReceiver, kind) +} + private class LexicalScopeWrapper(val delegate: LexicalScope, val newImportingScopeChain: ImportingScope): LexicalScope by delegate { init { assert(delegate !is LexicalScopeWrapper) { diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt index dcd2b38fb2f..4eed101c9a8 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt @@ -30,15 +30,17 @@ fun bar() { b checkType { _() } } - // From KEEP: Component-functions are resolved in the scope that contains the lambda - foobaz { (a, b) -> + // From KEEP: Component-functions are resolved in the same scope as the first statement of the lambda + foobaz { (a, b) -> + a checkType { _() } + b checkType { _() } } - // From KEEP: Component-functions are resolved in the scope that contains the lambda - // So `component1`/`component2` for lambda parameters were resolved to the top-level extensions + // From KEEP: Component-functions are resolved in the same scope as the first statement of the lambda + // So `component1`/`component2` for lambda parameters were resolved to member extensions foobar { (a, b) -> - a checkType { _() } - b checkType { _() } + a checkType { _() } + b checkType { _() } } // the following code fails with exception, see KT-13873 diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt index fce84e0607a..d4143de299b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt @@ -53,7 +53,7 @@ open class ValueParameterDescriptorImpl( isCrossinline: Boolean, isNoinline: Boolean, isCoroutine: Boolean, varargElementType: KotlinType?, source: SourceElement, - destructuringVariables: List? + destructuringVariables: (() -> List)? ): ValueParameterDescriptorImpl = if (destructuringVariables == null) ValueParameterDescriptorImpl(containingDeclaration, original, index, annotations, name, outType, @@ -74,11 +74,16 @@ open class ValueParameterDescriptorImpl( isCrossinline: Boolean, isNoinline: Boolean, isCoroutine: Boolean, varargElementType: KotlinType?, source: SourceElement, - val destructuringVariables: List + destructuringVariables: () -> List ) : ValueParameterDescriptorImpl( containingDeclaration, original, index, annotations, name, outType, declaresDefaultValue, isCrossinline, isNoinline, isCoroutine, - varargElementType, source) + varargElementType, source) { + // It's forced to be lazy because its resolution depends on receiver of relevant lambda, that is being created at the same moment + // as value parameters. + // Must be forced via ForceResolveUtil.forceResolveAllContents() + val destructuringVariables by lazy(destructuringVariables) + } private val original: ValueParameterDescriptor = original ?: this