From 400ecd5e1347fadc4562bbb3bc8f0073c908da14 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Wed, 24 May 2017 16:32:33 +0300 Subject: [PATCH] Support destructuring declarations in scripts and REPL #KT-5620 In Progress #KT-15810 In Progress --- ...elegatePackageMemberDeclarationProvider.kt | 6 +- .../SyntheticClassOrObjectDescriptor.kt | 3 +- .../kotlin/resolve/BodiesResolveContext.java | 4 +- .../kotlin/resolve/DeclarationsChecker.kt | 10 ++ .../kotlin/resolve/DescriptorResolver.java | 132 ++++++++++++++---- .../kotlin/resolve/LazyTopDownAnalyzer.kt | 24 +++- .../resolve/TopDownAnalysisContext.java | 8 +- .../kotlin/resolve/VariableAsPropertyInfo.kt | 39 ++++++ .../resolve/lazy/LazyDeclarationResolver.java | 13 +- .../AbstractPsiBasedDeclarationProvider.kt | 13 +- ...ombinedPackageMemberDeclarationProvider.kt | 7 +- .../lazy/declarations/DeclarationProvider.kt | 11 +- .../descriptors/AbstractLazyMemberScope.kt | 13 +- .../DestructuringDeclarationResolver.kt | 15 +- .../destructuringDeclarationsScript.kts | 16 +++ .../destructuringDeclarationsScript.txt | 18 +++ ...tializerOfDestructuringDeclarationOnce.kts | 7 + ...tializerOfDestructuringDeclarationOnce.txt | 20 +++ .../checkers/DiagnosticsTestGenerated.java | 12 ++ .../idea/project/ResolveElementCache.kt | 2 + ...ubBasedPackageMemberDeclarationProvider.kt | 6 +- 21 files changed, 333 insertions(+), 46 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableAsPropertyInfo.kt create mode 100644 compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.kts create mode 100644 compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.txt create mode 100644 compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.kts create mode 100644 compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.txt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt index 22d3614d676..a32b50bb5e6 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.cli.jvm.repl import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry import org.jetbrains.kotlin.resolve.lazy.declarations.PackageMemberDeclarationProvider import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter @@ -34,6 +35,9 @@ open class DelegatePackageMemberDeclarationProvider(var delegate: PackageMemberD override fun getPropertyDeclarations(name: Name) = delegate.getPropertyDeclarations(name) + override fun getDestructuringDeclarationsEntries(name: Name): Collection = + delegate.getDestructuringDeclarationsEntries(name) + override fun getClassOrObjectDeclarations(name: Name) = delegate.getClassOrObjectDeclarations(name) override fun getTypeAliasDeclarations(name: Name) = delegate.getTypeAliasDeclarations(name) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt index 6f5973d2b8f..986a3ee1029 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/synthetics/SyntheticClassOrObjectDescriptor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -126,6 +126,7 @@ class SyntheticClassOrObjectDescriptor( override fun getDeclarations(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List = emptyList() override fun getFunctionDeclarations(name: Name): Collection = emptyList() override fun getPropertyDeclarations(name: Name): Collection = emptyList() + override fun getDestructuringDeclarationsEntries(name: Name): Collection = emptyList() override fun getClassOrObjectDeclarations(name: Name): Collection = emptyList() override fun getTypeAliasDeclarations(name: Name): Collection = emptyList() } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodiesResolveContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodiesResolveContext.java index aa53c730737..4286cc5fada 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodiesResolveContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodiesResolveContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,6 +48,8 @@ public interface BodiesResolveContext { Map getFunctions(); @Mutable Map getTypeAliases(); + @Mutable + Map getDestructuringDeclarationEntries(); @Nullable LexicalScope getDeclaringScope(@NotNull KtDeclaration declaration); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index a0e42bf83ef..00d05374773 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -110,6 +110,16 @@ class DeclarationsChecker( identifierChecker.checkDeclaration(property, trace) } + val destructuringDeclarations = bodiesResolveContext.destructuringDeclarationEntries.entries + .map { (entry, _) -> entry.parent } + .filterIsInstance() + .distinct() + + for (multiDeclaration in destructuringDeclarations) { + modifiersChecker.checkModifiersForDestructuringDeclaration(multiDeclaration) + identifierChecker.checkDeclaration(multiDeclaration, trace) + } + for ((declaration, constructorDescriptor) in bodiesResolveContext.secondaryConstructors.entries) { checkConstructorDeclaration(constructorDescriptor, declaration) exposedChecker.checkFunction(declaration, constructorDescriptor) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 849dc20afbe..df86762db8e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -51,6 +51,7 @@ import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension; import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil; import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor; import org.jetbrains.kotlin.resolve.scopes.*; +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt; import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt; @@ -777,6 +778,50 @@ public class DescriptorResolver { } } + @NotNull + public PropertyDescriptor resolveDestructuringDeclarationEntryAsProperty( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull LexicalScope scopeForDeclarationResolution, + @NotNull LexicalScope scopeForInitializerResolution, + @NotNull KtDestructuringDeclarationEntry entry, + @NotNull BindingTrace trace, + @NotNull DataFlowInfo dataFlowInfo + ) { + KtDestructuringDeclaration destructuringDeclaration = (KtDestructuringDeclaration) entry.getParent(); + KtExpression initializer = destructuringDeclaration.getInitializer(); + + ExpressionTypingContext context = ExpressionTypingContext.newContext( + trace, scopeForDeclarationResolution, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE + ); + + ExpressionReceiver receiver = createReceiverForDestructuringDeclaration(destructuringDeclaration, context); + + int componentIndex = destructuringDeclaration.getEntries().indexOf(entry); + KotlinType componentType = destructuringDeclarationResolver.resolveInitializer(entry, receiver, initializer, context, componentIndex); + + return resolveAsPropertyDescriptor( + containingDeclaration, + scopeForDeclarationResolution, + scopeForInitializerResolution, + entry, + trace, + dataFlowInfo, + VariableAsPropertyInfo.Companion.createFromDestructuringDeclarationEntry(componentType)); + } + + private ExpressionReceiver createReceiverForDestructuringDeclaration( + @NotNull KtDestructuringDeclaration destructuringDeclaration, + @NotNull ExpressionTypingContext context + ) { + KtExpression initializer = destructuringDeclaration.getInitializer(); + if (initializer == null) return null; + + KotlinType initializerType = expressionTypingServices.getTypeInfo(initializer, context).getType(); + if (initializerType == null) return null; + + return ExpressionReceiver.Companion.create(initializer, initializerType, context.trace.getBindingContext()); + } + @NotNull public PropertyDescriptor resolvePropertyDescriptor( @NotNull DeclarationDescriptor containingDeclaration, @@ -786,16 +831,37 @@ public class DescriptorResolver { @NotNull BindingTrace trace, @NotNull DataFlowInfo dataFlowInfo ) { - KtModifierList modifierList = property.getModifierList(); - boolean isVar = property.isVar(); + return resolveAsPropertyDescriptor( + containingDeclaration, + scopeForDeclarationResolution, + scopeForInitializerResolution, + property, + trace, + dataFlowInfo, + VariableAsPropertyInfo.Companion.createFromProperty(property)); + } - Visibility visibility = resolveVisibilityFromModifiers(property, getDefaultVisibility(property, containingDeclaration)); + @NotNull + private PropertyDescriptor resolveAsPropertyDescriptor( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull LexicalScope scopeForDeclarationResolution, + @NotNull LexicalScope scopeForInitializerResolution, + @NotNull KtVariableDeclaration variableDeclaration, + @NotNull BindingTrace trace, + @NotNull DataFlowInfo dataFlowInfo, + @NotNull VariableAsPropertyInfo propertyInfo + ) { + KtModifierList modifierList = variableDeclaration.getModifierList(); + boolean isVar = variableDeclaration.isVar(); + + Visibility visibility = resolveVisibilityFromModifiers(variableDeclaration, getDefaultVisibility(variableDeclaration, containingDeclaration)); Modality modality = containingDeclaration instanceof ClassDescriptor - ? resolveMemberModalityFromModifiers(property, getDefaultModality(containingDeclaration, visibility, property.hasBody()), + ? resolveMemberModalityFromModifiers(variableDeclaration, + getDefaultModality(containingDeclaration, visibility, propertyInfo.getHasBody()), trace.getBindingContext(), containingDeclaration) : Modality.FINAL; - AnnotationSplitter.PropertyWrapper wrapper = new AnnotationSplitter.PropertyWrapper(property); + AnnotationSplitter.PropertyWrapper wrapper = new AnnotationSplitter.PropertyWrapper(variableDeclaration); Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scopeForDeclarationResolution, modifierList, trace); AnnotationSplitter annotationSplitter = @@ -812,16 +878,16 @@ public class DescriptorResolver { modality, visibility, isVar, - KtPsiUtil.safeName(property.getName()), + KtPsiUtil.safeName(variableDeclaration.getName()), CallableMemberDescriptor.Kind.DECLARATION, - KotlinSourceElementKt.toSourceElement(property), + KotlinSourceElementKt.toSourceElement(variableDeclaration), modifierList != null && modifierList.hasModifier(KtTokens.LATEINIT_KEYWORD), modifierList != null && modifierList.hasModifier(KtTokens.CONST_KEYWORD), modifierList != null && modifierList.hasModifier(KtTokens.HEADER_KEYWORD) || containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).isHeader(), modifierList != null && modifierList.hasModifier(KtTokens.IMPL_KEYWORD), modifierList != null && modifierList.hasModifier(KtTokens.EXTERNAL_KEYWORD), - property.hasDelegate() + propertyInfo.getHasDelegate() ); wrapper.setDescriptor(propertyDescriptor); @@ -831,7 +897,7 @@ public class DescriptorResolver { KotlinType receiverType = null; { - List typeParameters = property.getTypeParameters(); + List typeParameters = variableDeclaration.getTypeParameters(); if (typeParameters.isEmpty()) { scopeForDeclarationResolutionWithTypeParameters = scopeForDeclarationResolution; scopeForInitializerResolutionWithTypeParameters = scopeForInitializerResolution; @@ -853,12 +919,12 @@ public class DescriptorResolver { } writableScopeForDeclarationResolution.freeze(); writableScopeForInitializerResolution.freeze(); - resolveGenericBounds(property, propertyDescriptor, writableScopeForDeclarationResolution, typeParameterDescriptors, trace); + resolveGenericBounds(variableDeclaration, propertyDescriptor, writableScopeForDeclarationResolution, typeParameterDescriptors, trace); scopeForDeclarationResolutionWithTypeParameters = writableScopeForDeclarationResolution; scopeForInitializerResolutionWithTypeParameters = writableScopeForInitializerResolution; } - KtTypeReference receiverTypeRef = property.getReceiverTypeReference(); + KtTypeReference receiverTypeRef = variableDeclaration.getReceiverTypeReference(); if (receiverTypeRef != null) { receiverType = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, receiverTypeRef, trace, true); } @@ -868,31 +934,45 @@ public class DescriptorResolver { DescriptorFactory.createExtensionReceiverParameterForCallable(propertyDescriptor, receiverType); LexicalScope scopeForInitializer = ScopeUtils.makeScopeForPropertyInitializer(scopeForInitializerResolutionWithTypeParameters, propertyDescriptor); - KotlinType typeIfKnown = variableTypeAndInitializerResolver.resolveTypeNullable( + KotlinType propertyType = propertyInfo.getVariableType(); + KotlinType typeIfKnown = propertyType != null ? propertyType : variableTypeAndInitializerResolver.resolveTypeNullable( propertyDescriptor, scopeForInitializer, - property, dataFlowInfo, /* local = */ trace, false + variableDeclaration, dataFlowInfo, /* local = */ trace, false ); PropertyGetterDescriptorImpl getter = resolvePropertyGetterDescriptor( - scopeForDeclarationResolutionWithTypeParameters, property, propertyDescriptor, annotationSplitter, trace, typeIfKnown); + scopeForDeclarationResolutionWithTypeParameters, + variableDeclaration, + propertyDescriptor, + annotationSplitter, + trace, + typeIfKnown, + propertyInfo.getPropertyGetter(), + propertyInfo.getHasDelegate()); 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 + propertyDescriptor, scopeForInitializer, variableDeclaration, dataFlowInfo, type, trace ); propertyDescriptor.setType(type, typeParameterDescriptors, getDispatchReceiverParameterIfNeeded(containingDeclaration), receiverDescriptor); PropertySetterDescriptor setter = resolvePropertySetterDescriptor( - scopeForDeclarationResolutionWithTypeParameters, property, propertyDescriptor, annotationSplitter, trace); + scopeForDeclarationResolutionWithTypeParameters, + variableDeclaration, + propertyDescriptor, + annotationSplitter, + trace, + propertyInfo.getPropertySetter(), + propertyInfo.getHasDelegate()); propertyDescriptor.initialize(getter, setter); - trace.record(BindingContext.VARIABLE, property, propertyDescriptor); + trace.record(BindingContext.VARIABLE, variableDeclaration, propertyDescriptor); return propertyDescriptor; } @@ -924,12 +1004,13 @@ public class DescriptorResolver { @Nullable private PropertySetterDescriptor resolvePropertySetterDescriptor( @NotNull LexicalScope scopeWithTypeParameters, - @NotNull KtProperty property, + @NotNull KtVariableDeclaration property, @NotNull PropertyDescriptor propertyDescriptor, @NotNull AnnotationSplitter annotationSplitter, - @NotNull BindingTrace trace + @NotNull BindingTrace trace, + @Nullable KtPropertyAccessor setter, + boolean hasDelegate ) { - KtPropertyAccessor setter = property.getSetter(); PropertySetterDescriptorImpl setterDescriptor = null; if (setter != null) { Annotations annotations = new CompositeAnnotations(CollectionsKt.listOf( @@ -986,7 +1067,7 @@ public class DescriptorResolver { } else if (property.isVar()) { Annotations setterAnnotations = annotationSplitter.getAnnotationsForTarget(PROPERTY_SETTER); - setterDescriptor = DescriptorFactory.createSetter(propertyDescriptor, setterAnnotations, !property.hasDelegate(), + setterDescriptor = DescriptorFactory.createSetter(propertyDescriptor, setterAnnotations, !hasDelegate, /* isExternal = */ false, property.hasModifier(KtTokens.INLINE_KEYWORD), propertyDescriptor.getSource()); } @@ -1003,14 +1084,15 @@ public class DescriptorResolver { @NotNull private PropertyGetterDescriptorImpl resolvePropertyGetterDescriptor( @NotNull LexicalScope scopeForDeclarationResolution, - @NotNull KtProperty property, + @NotNull KtVariableDeclaration property, @NotNull PropertyDescriptor propertyDescriptor, @NotNull AnnotationSplitter annotationSplitter, @NotNull BindingTrace trace, - @Nullable KotlinType propertyTypeIfKnown + @Nullable KotlinType propertyTypeIfKnown, + @Nullable KtPropertyAccessor getter, + boolean hasDelegate ) { PropertyGetterDescriptorImpl getterDescriptor; - KtPropertyAccessor getter = property.getGetter(); KotlinType getterType; if (getter != null) { Annotations getterAnnotations = new CompositeAnnotations(CollectionsKt.listOf( @@ -1031,7 +1113,7 @@ public class DescriptorResolver { } else { Annotations getterAnnotations = annotationSplitter.getAnnotationsForTarget(PROPERTY_GETTER); - getterDescriptor = DescriptorFactory.createGetter(propertyDescriptor, getterAnnotations, !property.hasDelegate(), + getterDescriptor = DescriptorFactory.createGetter(propertyDescriptor, getterAnnotations, !hasDelegate, /* isExternal = */ false, property.hasModifier(KtTokens.INLINE_KEYWORD)); getterType = propertyTypeIfKnown; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt index 34e08581a02..2262577985e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,6 +62,7 @@ class LazyTopDownAnalyzer( val properties = ArrayList() val functions = ArrayList() val typeAliases = ArrayList() + val destructuringDeclarations = ArrayList() // fill in the context for (declaration in declarations) { @@ -168,7 +169,9 @@ class LazyTopDownAnalyzer( } override fun visitDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) { - // Ignore: multi-declarations are only allowed locally + if (destructuringDeclaration.containingKtFile.isScript) { + destructuringDeclarations.add(destructuringDeclaration) + } } override fun visitNamedFunction(function: KtNamedFunction) { @@ -191,6 +194,8 @@ class LazyTopDownAnalyzer( createPropertyDescriptors(c, topLevelFqNames, properties) + createPropertiesFromDestructuringDeclarations(c, topLevelFqNames, destructuringDeclarations) + createTypeAliasDescriptors(c, topLevelFqNames, typeAliases) resolveAllHeadersInClasses(c) @@ -258,6 +263,21 @@ class LazyTopDownAnalyzer( } } + private fun createPropertiesFromDestructuringDeclarations( + c: TopDownAnalysisContext, + topLevelFqNames: Multimap, + destructuringDeclarations: List) { + for (destructuringDeclaration in destructuringDeclarations) { + for (entry in destructuringDeclaration.entries) { + val descriptor = lazyDeclarationResolver.resolveToDescriptor(entry) as PropertyDescriptor + + c.destructuringDeclarationEntries[entry] = descriptor + ForceResolveUtil.forceResolveAllContents(descriptor.annotations) + registerTopLevelFqName(topLevelFqNames, entry, descriptor) + } + } + } + private fun registerTopLevelFqName(topLevelFqNames: Multimap, declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor) { if (DescriptorUtils.isTopLevelDeclaration(descriptor)) { val fqName = declaration.fqName diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TopDownAnalysisContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TopDownAnalysisContext.java index 504c6792278..eef5f7419be 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TopDownAnalysisContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TopDownAnalysisContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,6 +46,7 @@ public class TopDownAnalysisContext implements BodiesResolveContext { private final Map properties = Maps.newLinkedHashMap(); private final Map primaryConstructorParameterProperties = Maps.newHashMap(); private final Map typeAliases = Maps.newLinkedHashMap(); + private final Map destructuringDeclarationEntries = Maps.newLinkedHashMap(); private Map members = null; private final Map scripts = Maps.newLinkedHashMap(); @@ -145,6 +146,11 @@ public class TopDownAnalysisContext implements BodiesResolveContext { return typeAliases; } + @Override + public Map getDestructuringDeclarationEntries() { + return destructuringDeclarationEntries; + } + @NotNull public Map getMembers() { if (members == null) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableAsPropertyInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableAsPropertyInfo.kt new file mode 100644 index 00000000000..dd8fa9ab6de --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableAsPropertyInfo.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve + +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.KtPropertyAccessor +import org.jetbrains.kotlin.types.KotlinType + +class VariableAsPropertyInfo( + val propertyGetter: KtPropertyAccessor?, + val propertySetter: KtPropertyAccessor?, + val variableType: KotlinType?, + val hasBody: Boolean, + val hasDelegate: Boolean +) { + companion object { + fun createFromDestructuringDeclarationEntry(type: KotlinType): VariableAsPropertyInfo { + return VariableAsPropertyInfo(null, null, type, false, false) + } + + fun createFromProperty(property: KtProperty): VariableAsPropertyInfo { + return VariableAsPropertyInfo(property.getter, property.setter, null, property.hasBody(), property.hasDelegate()) + } + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java index af84ad89469..5f2d027bbd2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -224,6 +224,17 @@ public class LazyDeclarationResolver { return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property); } + @Override + public DeclarationDescriptor visitDestructuringDeclarationEntry( + @NotNull KtDestructuringDeclarationEntry destructuringDeclarationEntry, Void data + ) { + LookupLocation location = lookupLocationFor(destructuringDeclarationEntry, false); + KtDestructuringDeclaration destructuringDeclaration = ((KtDestructuringDeclaration) destructuringDeclarationEntry.getParent()); + MemberScope scopeForDeclaration = getMemberScopeDeclaredIn(destructuringDeclaration, location); + scopeForDeclaration.getContributedVariables(destructuringDeclarationEntry.getNameAsSafeName(), location); + return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, destructuringDeclarationEntry); + } + @Override public DeclarationDescriptor visitTypeAlias(@NotNull KtTypeAlias typeAlias, Void data) { LookupLocation location = lookupLocationFor(typeAlias, typeAlias.isTopLevel()); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt index 2881eb2722d..91272d1c79a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ abstract class AbstractPsiBasedDeclarationProvider(storageManager: StorageManage val properties = ArrayListMultimap.create() val classesAndObjects = ArrayListMultimap.create() // order matters here val typeAliases = ArrayListMultimap.create() + val destructuringDeclarationsEntries = ArrayListMultimap.create() fun putToIndex(declaration: KtDeclaration) { if (declaration is KtAnonymousInitializer || declaration is KtSecondaryConstructor) return @@ -55,7 +56,12 @@ abstract class AbstractPsiBasedDeclarationProvider(storageManager: StorageManage val scriptInfo = KtScriptInfo(declaration) classesAndObjects.put(scriptInfo.script.nameAsName, scriptInfo) } - is KtParameter, is KtDestructuringDeclaration -> { + is KtDestructuringDeclaration -> { + for (entry in declaration.entries) { + destructuringDeclarationsEntries.put(safeNameForLazyResolve(entry.nameAsName), entry) + } + } + is KtParameter -> { // Do nothing, just put it into allDeclarations is enough } else -> throw IllegalArgumentException("Unknown declaration: " + declaration) @@ -80,6 +86,9 @@ abstract class AbstractPsiBasedDeclarationProvider(storageManager: StorageManage override fun getPropertyDeclarations(name: Name): List = index().properties[ResolveSessionUtils.safeNameForLazyResolve(name)].toList() + override fun getDestructuringDeclarationsEntries(name: Name): Collection + = index().destructuringDeclarationsEntries[ResolveSessionUtils.safeNameForLazyResolve(name)].toList() + override fun getClassOrObjectDeclarations(name: Name): Collection = index().classesAndObjects[ResolveSessionUtils.safeNameForLazyResolve(name)] diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt index daae17a2155..76f72fd58ef 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.resolve.lazy.declarations import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter class CombinedPackageMemberDeclarationProvider(val providers: Collection) : PackageMemberDeclarationProvider { @@ -31,6 +32,10 @@ class CombinedPackageMemberDeclarationProvider(val providers: Collection { + return providers.flatMap { it.getDestructuringDeclarationsEntries(name) } + } + override fun getClassOrObjectDeclarations(name: Name) = providers.flatMap { it.getClassOrObjectDeclarations(name) } override fun getTypeAliasDeclarations(name: Name) = providers.flatMap { it.getTypeAliasDeclarations(name) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/DeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/DeclarationProvider.kt index 30987a377f7..4957527f3ed 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/DeclarationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/DeclarationProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,9 @@ package org.jetbrains.kotlin.resolve.lazy.declarations -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.psi.KtProperty -import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtTypeAlias +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter interface DeclarationProvider { @@ -31,6 +28,8 @@ interface DeclarationProvider { fun getPropertyDeclarations(name: Name): Collection + fun getDestructuringDeclarationsEntries(name: Name): Collection + fun getClassOrObjectDeclarations(name: Name): Collection fun getTypeAliasDeclarations(name: Name): Collection diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt index fcf786e8137..ab8e5937721 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -128,6 +128,17 @@ protected constructor( result.add(propertyDescriptor) } + for (entry in declarationProvider.getDestructuringDeclarationsEntries(name)) { + val propertyDescriptor = c.descriptorResolver.resolveDestructuringDeclarationEntryAsProperty( + thisDescriptor, + getScopeForMemberDeclarationResolution(entry), + getScopeForInitializerResolution(entry), + entry, + trace, + c.declarationScopeProvider.getOuterDataFlowInfoForDeclaration(entry)) + result.add(propertyDescriptor) + } + getNonDeclaredProperties(name, result) return result.toList() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DestructuringDeclarationResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DestructuringDeclarationResolver.kt index 0adffe26652..bbaa839e67c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DestructuringDeclarationResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DestructuringDeclarationResolver.kt @@ -49,9 +49,7 @@ class DestructuringDeclarationResolver( ): List { val result = arrayListOf() for ((componentIndex, entry) in destructuringDeclaration.entries.withIndex()) { - val componentName = DataClassDescriptorResolver.createComponentName(componentIndex + 1) - - val componentType = resolveComponentFunctionAndGetType(componentName, context, entry, receiver, initializer) + val componentType = resolveInitializer(entry, receiver, initializer, context, componentIndex) val variableDescriptor = localVariableResolver.resolveLocalVariableDescriptorWithType(scope, entry, componentType, context.trace) result.add(variableDescriptor) @@ -73,6 +71,17 @@ class DestructuringDeclarationResolver( writableScope.addVariableDescriptor(it) } + fun resolveInitializer( + entry: KtDestructuringDeclarationEntry, + receiver: ReceiverValue?, + initializer: KtExpression?, + context: ExpressionTypingContext, + componentIndex: Int + ): KotlinType { + val componentName = DataClassDescriptorResolver.createComponentName(componentIndex + 1) + return resolveComponentFunctionAndGetType(componentName, context, entry, receiver, initializer) + } + private fun resolveComponentFunctionAndGetType( componentName: Name, context: ExpressionTypingContext, diff --git a/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.kts b/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.kts new file mode 100644 index 00000000000..21595c19e53 --- /dev/null +++ b/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.kts @@ -0,0 +1,16 @@ +val (a1, a2) = A() +val (b1: Int, b2: Int) = A() +val (c1) = unresolved + +private val (d1) = A() + +val (e1, _) = A() + +a1 +a2 +e1 + +class A { + operator fun component1() = 1 + operator fun component2() = "" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.txt b/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.txt new file mode 100644 index 00000000000..bf24a3bd364 --- /dev/null +++ b/compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.txt @@ -0,0 +1,18 @@ +package + +public final class DestructuringDeclarationsScript : kotlin.script.templates.standard.ScriptTemplateWithArgs { + public constructor DestructuringDeclarationsScript(/*0*/ args: kotlin.Array) + public final override /*1*/ /*fake_override*/ val args: kotlin.Array + 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 A { + public constructor A() + public final operator fun component1(): kotlin.Int + public final operator fun component2(): kotlin.String + 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/script/resolveInitializerOfDestructuringDeclarationOnce.kts b/compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.kts new file mode 100644 index 00000000000..6e34f6b76b0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.kts @@ -0,0 +1,7 @@ +val (a, b, c) = A() + +class A(val a: Int) { + operator fun component1() {} + operator fun component2() {} + operator fun component3() {} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.txt b/compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.txt new file mode 100644 index 00000000000..2f226e6b53a --- /dev/null +++ b/compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.txt @@ -0,0 +1,20 @@ +package + +public final class ResolveInitializerOfDestructuringDeclarationOnce : kotlin.script.templates.standard.ScriptTemplateWithArgs { + public constructor ResolveInitializerOfDestructuringDeclarationOnce(/*0*/ args: kotlin.Array) + public final override /*1*/ /*fake_override*/ val args: kotlin.Array + 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 A { + public constructor A(/*0*/ a: kotlin.Int) + public final val a: kotlin.Int + public final operator fun component1(): kotlin.Unit + public final operator fun component2(): kotlin.Unit + public final operator fun component3(): kotlin.Unit + 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/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index a2fa5d3869b..d631430ee94 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -23576,6 +23576,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("destructuringDeclarationsScript.kts") + public void testDestructuringDeclarationsScript() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/script/destructuringDeclarationsScript.kts"); + doTest(fileName); + } + @TestMetadata("imports.kts") public void testImports() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/script/imports.kts"); @@ -23588,6 +23594,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("resolveInitializerOfDestructuringDeclarationOnce.kts") + public void testResolveInitializerOfDestructuringDeclarationOnce() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/script/resolveInitializerOfDestructuringDeclarationOnce.kts"); + doTest(fileName); + } + @TestMetadata("SimpleScript.kts") public void testSimpleScript() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/script/SimpleScript.kts"); diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt index 31bf7856e8f..36fbcd4f91e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt @@ -617,6 +617,8 @@ class ResolveElementCache( override fun getTypeAliases(): MutableMap = hashMapOf() + override fun getDestructuringDeclarationEntries(): MutableMap = hashMapOf() + override fun getDeclaringScope(declaration: KtDeclaration): LexicalScope? = declaringScopes(declaration) override fun getScripts(): MutableMap = hashMapOf() diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/resolve/StubBasedPackageMemberDeclarationProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/resolve/StubBasedPackageMemberDeclarationProvider.kt index 12019cbb111..f2e8ecfc168 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/resolve/StubBasedPackageMemberDeclarationProvider.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/resolve/StubBasedPackageMemberDeclarationProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -85,6 +85,10 @@ class StubBasedPackageMemberDeclarationProvider( } } + override fun getDestructuringDeclarationsEntries(name: Name): Collection { + return emptyList() + } + override fun getAllDeclaredSubPackages(nameFilter: (Name) -> Boolean): Collection { return PackageIndexUtil.getSubPackageFqNames(fqName, searchScope, project, nameFilter) }