Implement resolution of desctructuring declarations in lambdas
#KT-5828 In Progress
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+33
-15
@@ -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()
|
||||
}
|
||||
|
||||
+6
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user