Implement resolution of desctructuring declarations in lambdas

#KT-5828 In Progress
This commit is contained in:
Denis Zharkov
2016-09-15 17:56:59 +03:00
parent ace3655824
commit e975d32196
27 changed files with 640 additions and 37 deletions
@@ -26,6 +26,7 @@ import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.KtNodeTypes;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.stubs.KotlinParameterStub;
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
@@ -120,6 +121,14 @@ public class KtParameter extends KtNamedDeclarationStub<KotlinParameterStub> imp
return findChildByType(VAL_VAR_TOKEN_SET);
}
@Nullable
public KtDestructuringDeclaration getDestructuringDeclaration() {
// No destructuring declaration in stubs
if (getStub() != null) return null;
return findChildByType(KtNodeTypes.DESTRUCTURING_DECLARATION);
}
private static final TokenSet VAL_VAR_TOKEN_SET = TokenSet.create(KtTokens.VAL_KEYWORD, KtTokens.VAR_KEYWORD);
@Override
@@ -49,14 +49,13 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
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.TransientReceiver;
import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
import org.jetbrains.kotlin.storage.StorageManager;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
import org.jetbrains.kotlin.types.expressions.FunctionsTypingVisitor;
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor;
import org.jetbrains.kotlin.types.expressions.*;
import java.util.*;
@@ -79,6 +78,7 @@ public class DescriptorResolver {
private final OverloadChecker overloadChecker;
private final LanguageVersionSettings languageVersionSettings;
private final FunctionsTypingVisitor functionsTypingVisitor;
private final DestructuringDeclarationResolver destructuringDeclarationResolver;
public DescriptorResolver(
@NotNull AnnotationResolver annotationResolver,
@@ -90,7 +90,8 @@ public class DescriptorResolver {
@NotNull ExpressionTypingServices expressionTypingServices,
@NotNull OverloadChecker overloadChecker,
@NotNull LanguageVersionSettings languageVersionSettings,
@NotNull FunctionsTypingVisitor functionsTypingVisitor
@NotNull FunctionsTypingVisitor functionsTypingVisitor,
@NotNull DestructuringDeclarationResolver destructuringDeclarationResolver
) {
this.annotationResolver = annotationResolver;
this.builtIns = builtIns;
@@ -102,6 +103,7 @@ public class DescriptorResolver {
this.overloadChecker = overloadChecker;
this.languageVersionSettings = languageVersionSettings;
this.functionsTypingVisitor = functionsTypingVisitor;
this.destructuringDeclarationResolver = destructuringDeclarationResolver;
}
public List<KotlinType> resolveSupertypes(
@@ -285,19 +287,35 @@ public class DescriptorResolver {
}
}
ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(
KtDestructuringDeclaration destructuringDeclaration = valueParameter.getDestructuringDeclaration();
List<VariableDescriptor> destructuringVariables;
if (destructuringDeclaration != null) {
destructuringVariables = destructuringDeclarationResolver.resolveLocalVariablesFromDestructuringDeclaration(
scope, destructuringDeclaration, new TransientReceiver(type), /* initializer = */ null,
ExpressionTypingContext.newContext(trace, scope, DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE)
);
}
else {
destructuringVariables = null;
}
ValueParameterDescriptorImpl valueParameterDescriptor = ValueParameterDescriptorImpl.createWithDestructuringDeclarations(
owner,
null,
index,
valueParameterAnnotations,
KtPsiUtil.safeName(valueParameter.getName()),
destructuringVariables == null
? KtPsiUtil.safeName(valueParameter.getName())
: Name.special("<name for destructuring parameter " + index + ">"),
variableType,
valueParameter.hasDefaultValue(),
valueParameter.hasModifier(CROSSINLINE_KEYWORD),
valueParameter.hasModifier(NOINLINE_KEYWORD),
valueParameter.hasModifier(COROUTINE_KEYWORD),
varargElementType,
KotlinSourceElementKt.toSourceElement(valueParameter)
KotlinSourceElementKt.toSourceElement(valueParameter),
destructuringVariables
);
trace.record(BindingContext.VALUE_PARAMETER, valueParameter, valueParameterDescriptor);
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
import org.jetbrains.kotlin.resolve.coroutine.CoroutineReceiverValue;
import org.jetbrains.kotlin.resolve.scopes.*;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
@@ -89,7 +90,17 @@ public class FunctionDescriptorUtil {
handler.addClassifierDescriptor(typeParameter);
}
for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
handler.addVariableDescriptor(valueParameterDescriptor);
if (valueParameterDescriptor instanceof ValueParameterDescriptorImpl.WithDestructuringDeclaration) {
List<VariableDescriptor> entries =
((ValueParameterDescriptorImpl.WithDestructuringDeclaration) valueParameterDescriptor)
.getDestructuringVariables();
for (VariableDescriptor entry : entries) {
handler.addVariableDescriptor(entry);
}
}
else {
handler.addVariableDescriptor(valueParameterDescriptor);
}
}
return Unit.INSTANCE;
}
@@ -412,7 +412,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
KotlinType elementType = expectedParameterType == null ? ErrorUtils.createErrorType("Loop range has no type") : expectedParameterType;
TransientReceiver iteratorNextAsReceiver = new TransientReceiver(elementType);
components.annotationResolver.resolveAnnotationsWithArguments(loopScope, multiParameter.getModifierList(), context.trace);
components.destructuringDeclarationResolver.defineLocalVariablesFromMultiDeclaration(
components.destructuringDeclarationResolver.defineLocalVariablesFromDestructuringDeclaration(
loopScope, multiParameter, iteratorNextAsReceiver, loopRange, context
);
components.modifiersChecker.withTrace(context.trace).checkModifiersForDestructuringDeclaration(multiParameter);
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.types.expressions
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
import org.jetbrains.kotlin.resolve.LocalVariableResolver
import org.jetbrains.kotlin.resolve.TypeResolver
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.ErrorUtils
@@ -37,23 +39,37 @@ class DestructuringDeclarationResolver(
private val localVariableResolver: LocalVariableResolver,
private val typeResolver: TypeResolver
) {
fun defineLocalVariablesFromMultiDeclaration(
fun resolveLocalVariablesFromDestructuringDeclaration(
scope: LexicalScope,
destructuringDeclaration: KtDestructuringDeclaration,
receiver: ReceiverValue?,
initializer: KtExpression?,
context: ExpressionTypingContext
): List<VariableDescriptor> {
val result = arrayListOf<VariableDescriptor>()
for ((componentIndex, entry) in destructuringDeclaration.entries.withIndex()) {
val componentName = DataClassDescriptorResolver.createComponentName(componentIndex + 1)
val componentType = resolveComponentFunctionAndGetType(componentName, context, entry, receiver, initializer)
val variableDescriptor = localVariableResolver.resolveLocalVariableDescriptorWithType(scope, entry, componentType, context.trace)
result.add(variableDescriptor)
}
return result
}
fun defineLocalVariablesFromDestructuringDeclaration(
writableScope: LexicalWritableScope,
destructuringDeclaration: KtDestructuringDeclaration,
receiver: ReceiverValue?,
initializer: KtExpression?,
context: ExpressionTypingContext
) {
for ((componentIndex, entry) in destructuringDeclaration.entries.withIndex()) {
val componentName = DataClassDescriptorResolver.createComponentName(componentIndex + 1)
val componentType = resolveComponentFunctionAndGetType(componentName, context, entry, receiver, initializer)
val variableDescriptor = localVariableResolver.resolveLocalVariableDescriptorWithType(writableScope, entry, componentType, context.trace)
ExpressionTypingUtils.checkVariableShadowing(writableScope, context.trace, variableDescriptor)
writableScope.addVariableDescriptor(variableDescriptor)
}
) = resolveLocalVariablesFromDestructuringDeclaration(
writableScope, destructuringDeclaration, receiver, initializer, context
).forEach {
ExpressionTypingUtils.checkVariableShadowing(writableScope, context.trace, it)
writableScope.addVariableDescriptor(it)
}
private fun resolveComponentFunctionAndGetType(
@@ -65,12 +81,12 @@ class DestructuringDeclarationResolver(
): KotlinType {
fun errorType() = ErrorUtils.createErrorType("$componentName() return type")
if (receiver == null || initializer == null) return errorType()
if (receiver == null) return errorType()
val expectedType = getExpectedTypeForComponent(context, entry)
val results = fakeCallResolver.resolveFakeCall(
context.replaceExpectedType(expectedType), receiver, componentName,
entry, initializer, FakeCallKind.COMPONENT, emptyList()
entry, initializer ?: entry, FakeCallKind.COMPONENT, emptyList()
)
if (!results.isSuccess) {
@@ -82,7 +98,9 @@ class DestructuringDeclarationResolver(
val functionReturnType = results.resultingDescriptor.returnType
if (functionReturnType != null && !TypeUtils.noExpectedType(expectedType)
&& !KotlinTypeChecker.DEFAULT.isSubtypeOf(functionReturnType, expectedType) ) {
context.trace.report(Errors.COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH.on(initializer, componentName, functionReturnType, expectedType))
context.trace.report(
Errors.COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH.on(
initializer ?: entry, componentName, functionReturnType, expectedType))
}
return functionReturnType ?: errorType()
}
@@ -112,6 +112,12 @@ public class ExpressionTypingUtils {
if (oldDescriptor != null && isLocal(variableDescriptor.getContainingDeclaration(), oldDescriptor)) {
PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor);
if (declaration != null) {
if (declaration instanceof KtDestructuringDeclarationEntry && declaration.getParent().getParent() instanceof KtParameter) {
// foo { a, (a, b) -> } -- do not report NAME_SHADOWING on the second 'a', because REDECLARATION must be reported here
PsiElement oldElement = DescriptorToSourceUtils.descriptorToDeclaration(oldDescriptor);
if (oldElement != null && oldElement.getParent().equals(declaration.getParent().getParent().getParent())) return;
}
trace.report(Errors.NAME_SHADOWING.on(declaration, variableDescriptor.getName().asString()));
}
}
@@ -134,7 +134,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)) : null;
components.destructuringDeclarationResolver
.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
.defineLocalVariablesFromDestructuringDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
components.modifiersChecker.withTrace(context.trace).checkModifiersForDestructuringDeclaration(multiDeclaration);
components.identifierChecker.checkDeclaration(multiDeclaration, context.trace);