diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtParameter.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtParameter.java index aee460b15b5..1e9e18e35b4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtParameter.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtParameter.java @@ -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 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 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index ddf219bf800..13026154cac 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -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 resolveSupertypes( @@ -285,19 +287,35 @@ public class DescriptorResolver { } } - ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl( + KtDestructuringDeclaration destructuringDeclaration = valueParameter.getDestructuringDeclaration(); + + List 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(""), 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); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorUtil.java index 9f4e06f11f8..370537abe0c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorUtil.java @@ -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 entries = + ((ValueParameterDescriptorImpl.WithDestructuringDeclaration) valueParameterDescriptor) + .getDestructuringVariables(); + for (VariableDescriptor entry : entries) { + handler.addVariableDescriptor(entry); + } + } + else { + handler.addVariableDescriptor(valueParameterDescriptor); + } } return Unit.INSTANCE; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java index 7575fc66543..51f69f6acd3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -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); 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 61a52ddde4f..dda39fc69e0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DestructuringDeclarationResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DestructuringDeclarationResolver.kt @@ -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 { + 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 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() } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingUtils.java index 18a60e57545..bc0105b423a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingUtils.java @@ -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())); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java index 0ecfb9e8c35..6e0dbea8f5a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java @@ -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); diff --git a/compiler/testData/diagnostics/tests/declarationChecks/RedeclarationsInMultiDecl.kt b/compiler/testData/diagnostics/tests/declarationChecks/RedeclarationsInMultiDecl.kt index f0350b365dd..a23f77ad672 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/RedeclarationsInMultiDecl.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/RedeclarationsInMultiDecl.kt @@ -12,4 +12,4 @@ fun a() { } -fun use(a: Any): Any = a \ No newline at end of file +fun use(a: Any): Any = a diff --git a/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/RedeclarationInForLoop.kt b/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/RedeclarationInForLoop.kt index 4973697a161..2d273316d4a 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/RedeclarationInForLoop.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/RedeclarationInForLoop.kt @@ -11,4 +11,4 @@ fun test() { for ((x, x) in C()) { } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt index 87a8f14192e..257f11a149b 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt @@ -4,13 +4,13 @@ val receiverWithParameter = { Int.(a val receiverAndReturnType = { Int.(): Int -> 5 } val receiverAndReturnTypeWithParameter = { Int.(a: Int): Int -> 5 } -val returnType = { (): Int -> 5 } -val returnTypeWithParameter = { (b: Int): Int -> 5 } +val returnType = { (): Int -> 5 } +val returnTypeWithParameter = { (b: Int): Int -> 5 } val receiverWithFunctionType = { ((Int) -> Int).() -> } -val parenthesizedParameters = { (a: Int) -> } -val parenthesizedParameters2 = { (b) -> } +val parenthesizedParameters = { (a: Int) -> } +val parenthesizedParameters2 = { (b) -> } val none = { -> } @@ -21,4 +21,4 @@ val newSyntax = { a: Int -> } val newSyntax1 = { a, b -> } val newSyntax2 = { a: Int, b: Int -> } val newSyntax3 = { a, b: Int -> } -val newSyntax4 = { a: Int, b -> } \ No newline at end of file +val newSyntax4 = { a: Int, b -> } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.txt b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.txt index a798ef6b699..b0974b42778 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.txt +++ b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.txt @@ -7,12 +7,12 @@ public val newSyntax3: (???, kotlin.Int) -> kotlin.Unit public val newSyntax4: (kotlin.Int, ???) -> kotlin.Unit public val none: () -> kotlin.Unit public val parameterWithFunctionType: (((kotlin.Int) -> kotlin.Int) -> [ERROR : No type element]) -> kotlin.Unit -public val parenthesizedParameters: () -> ??? -public val parenthesizedParameters2: () -> ??? +public val parenthesizedParameters: (???) -> kotlin.Unit +public val parenthesizedParameters2: (???) -> kotlin.Unit public val receiver: () -> ??? public val receiverAndReturnType: () -> ??? public val receiverAndReturnTypeWithParameter: () -> ??? public val receiverWithFunctionType: () -> kotlin.Int.Companion public val receiverWithParameter: () -> ??? -public val returnType: () -> ??? -public val returnTypeWithParameter: () -> ??? +public val returnType: (kotlin.Int) -> kotlin.Int +public val returnTypeWithParameter: (kotlin.Int) -> kotlin.Int diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/complexInference.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/complexInference.kt new file mode 100644 index 00000000000..1370410d3f4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/complexInference.kt @@ -0,0 +1,47 @@ +// !CHECK_TYPE +// !DIAGNOSTICS: -UNUSED_PARAMETER +data class A(val x: Int, val y: String) +data class B(val u: Double, val w: Short) + +// first parameter of the functional type of 'x' can only be inferred from a lambda parameter explicit type specification +fun foo(y: Y, x: (X, Y) -> Unit) {} + +fun bar(aInstance: A, bInstance: B) { + foo("") { + (a, b): A, c -> + a checkType { _() } + b checkType { _() } + c checkType { _() } + } + + foo(aInstance) { + a: String, (b, c) -> + a checkType { _() } + b checkType { _() } + c checkType { _() } + } + + foo(bInstance) { + (a, b): A, (c, d) -> + a checkType { _() } + b checkType { _() } + c checkType { _() } + d checkType { _() } + } + + foo(bInstance) { + (a, b), (c, d) -> + a checkType { _() } + b checkType { _() } + c checkType { _() } + d checkType { _() } + } + + foo(bInstance) { + (a, b), (c, d) -> + a checkType { _() } + b checkType { _() } + c checkType { _() } + d checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/complexInference.txt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/complexInference.txt new file mode 100644 index 00000000000..b2f6ce0e009 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/complexInference.txt @@ -0,0 +1,28 @@ +package + +public fun bar(/*0*/ aInstance: A, /*1*/ bInstance: B): kotlin.Unit +public fun foo(/*0*/ y: Y, /*1*/ x: (X, Y) -> kotlin.Unit): kotlin.Unit + +public final data class A { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String) + public final val x: kotlin.Int + public final val y: kotlin.String + public final operator /*synthesized*/ fun component1(): kotlin.Int + public final operator /*synthesized*/ fun component2(): kotlin.String + public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.String = ...): A + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public final data class B { + public constructor B(/*0*/ u: kotlin.Double, /*1*/ w: kotlin.Short) + public final val u: kotlin.Double + public final val w: kotlin.Short + public final operator /*synthesized*/ fun component1(): kotlin.Double + public final operator /*synthesized*/ fun component2(): kotlin.Short + public final /*synthesized*/ fun copy(/*0*/ u: kotlin.Double = ..., /*1*/ w: kotlin.Short = ...): B + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt new file mode 100644 index 00000000000..3b42ee8c72e --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt @@ -0,0 +1,51 @@ +// !CHECK_TYPE +// !DIAGNOSTICS: -UNUSED_PARAMETER +class A + +operator fun A.component1() = 1 +operator fun A.component2() = "" + +class B + +class D { + operator fun A.component1() = 1.0 + operator fun A.component2() = ' ' + + operator fun B.component1() = 1.0 + operator fun B.component2() = ' ' +} + +fun foo(block: (A) -> Unit) { } +fun foobaz(block: D.(B) -> Unit) { } +fun foobar(block: D.(A) -> Unit) { } + +fun bar() { + foo { (a, b) -> + a checkType { _() } + b checkType { _() } + } + + foo { (a: Int, b: String) -> + a checkType { _() } + 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 scope that contains the lambda + // So `component1`/`component2` for lambda parameters were resolved to the top-level extensions + foobar { (a, b) -> + a checkType { _() } + b checkType { _() } + } + + // the following code fails with exception, see KT-13873 +// foobarbaz { +// component1: B.() -> Int, +// component2: B.() -> String, +// (a, b): B -> +// +// } +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.txt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.txt new file mode 100644 index 00000000000..b2ed2e85196 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.txt @@ -0,0 +1,33 @@ +package + +public fun bar(): kotlin.Unit +public fun foo(/*0*/ block: (A) -> kotlin.Unit): kotlin.Unit +public fun foobar(/*0*/ block: D.(A) -> kotlin.Unit): kotlin.Unit +public fun foobaz(/*0*/ block: D.(B) -> kotlin.Unit): kotlin.Unit +public operator fun A.component1(): kotlin.Int +public operator fun A.component2(): kotlin.String + +public final class A { + public constructor A() + 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 B { + public constructor B() + 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 D { + public constructor D() + 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 operator fun A.component1(): kotlin.Double + public final operator fun B.component1(): kotlin.Double + public final operator fun A.component2(): kotlin.Char + public final operator fun B.component2(): kotlin.Char +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/inferredFunctionalType.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/inferredFunctionalType.kt new file mode 100644 index 00000000000..a4ef09e64d3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/inferredFunctionalType.kt @@ -0,0 +1,33 @@ +// !CHECK_TYPE +// !DIAGNOSTICS: -UNUSED_PARAMETER +data class A(val x: Int, val y: String) +data class B(val u: Double, val w: Short) + +fun Iterable.foo(x: (T) -> Unit) {} + +fun bar(aList: List) { + aList.foo { (a, b) -> + a checkType { _() } + b checkType { _() } + } + + aList.foo { (a: Int, b: String) -> + a checkType { _() } + b checkType { _() } + } + + aList.foo { (a, b): A -> + a checkType { _() } + b checkType { _() } + } + + aList.foo { (a: String, b) -> + a checkType { _() } + b checkType { _() } + } + + aList.foo { (a, b): B -> + b checkType { _() } + a checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/inferredFunctionalType.txt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/inferredFunctionalType.txt new file mode 100644 index 00000000000..f1140b4acea --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/inferredFunctionalType.txt @@ -0,0 +1,28 @@ +package + +public fun bar(/*0*/ aList: kotlin.collections.List): kotlin.Unit +public fun kotlin.collections.Iterable.foo(/*0*/ x: (T) -> kotlin.Unit): kotlin.Unit + +public final data class A { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String) + public final val x: kotlin.Int + public final val y: kotlin.String + public final operator /*synthesized*/ fun component1(): kotlin.Int + public final operator /*synthesized*/ fun component2(): kotlin.String + public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.String = ...): A + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public final data class B { + public constructor B(/*0*/ u: kotlin.Double, /*1*/ w: kotlin.Short) + public final val u: kotlin.Double + public final val w: kotlin.Short + public final operator /*synthesized*/ fun component1(): kotlin.Double + public final operator /*synthesized*/ fun component2(): kotlin.Short + public final /*synthesized*/ fun copy(/*0*/ u: kotlin.Double = ..., /*1*/ w: kotlin.Short = ...): B + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/noExpectedType.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/noExpectedType.kt new file mode 100644 index 00000000000..2ecb86601d6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/noExpectedType.kt @@ -0,0 +1,31 @@ +// !CHECK_TYPE +// !DIAGNOSTICS: -UNUSED_VARIABLE +data class A(val x: Int, val y: String) + +fun bar() { + val x = { (a, b): A -> + a checkType { _() } + b checkType { _() } + } + + x checkType { _<(A) -> Unit>() } + + val y = { (a: Int, b): A -> + a checkType { _() } + b checkType { _() } + } + + y checkType { _<(A) -> Unit>() } + + val y2 = { (a: Number, b): A -> + a checkType { _() } + b checkType { _() } + } + + y2 checkType { _<(A) -> Unit>() } + + val z = { (a: Int, b: String) -> + a checkType { _() } + b checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/noExpectedType.txt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/noExpectedType.txt new file mode 100644 index 00000000000..f27c316b562 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/noExpectedType.txt @@ -0,0 +1,15 @@ +package + +public fun bar(): kotlin.Unit + +public final data class A { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String) + public final val x: kotlin.Int + public final val y: kotlin.String + public final operator /*synthesized*/ fun component1(): kotlin.Int + public final operator /*synthesized*/ fun component2(): kotlin.String + public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.String = ...): A + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.kt new file mode 100644 index 00000000000..f345b30d975 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.kt @@ -0,0 +1,29 @@ +// !CHECK_TYPE +// !DIAGNOSTICS: -UNUSED_PARAMETER +data class A(val x: Int, val y: String) +data class B(val u: Double, val w: Short) + +fun foo(block: (A, B) -> Unit) { } + +fun bar() { + foo { (a, a), b -> + a checkType { _() } + b checkType { _() } + } + + foo { (a, b), a -> + a checkType { _() } + b checkType { _() } + } + + foo { a, (a, b) -> + a checkType { _() } + b checkType { _() } + } + + foo { (a, b), (c, b) -> + a checkType { _() } + b checkType { _() } + c checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.txt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.txt new file mode 100644 index 00000000000..39971336b55 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.txt @@ -0,0 +1,28 @@ +package + +public fun bar(): kotlin.Unit +public fun foo(/*0*/ block: (A, B) -> kotlin.Unit): kotlin.Unit + +public final data class A { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String) + public final val x: kotlin.Int + public final val y: kotlin.String + public final operator /*synthesized*/ fun component1(): kotlin.Int + public final operator /*synthesized*/ fun component2(): kotlin.String + public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.String = ...): A + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public final data class B { + public constructor B(/*0*/ u: kotlin.Double, /*1*/ w: kotlin.Short) + public final val u: kotlin.Double + public final val w: kotlin.Short + public final operator /*synthesized*/ fun component1(): kotlin.Double + public final operator /*synthesized*/ fun component2(): kotlin.Short + public final /*synthesized*/ fun copy(/*0*/ u: kotlin.Double = ..., /*1*/ w: kotlin.Short = ...): B + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/shadowing.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/shadowing.kt new file mode 100644 index 00000000000..5554968db9f --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/shadowing.kt @@ -0,0 +1,25 @@ +// !CHECK_TYPE +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE +data class A(val x: Int, val y: String) + +fun foo(block: (A) -> Unit) { } + +fun bar(a: Double) { + val b = 1.toShort() + // Do not report NAME_SHADOWING on lambda destructured parameter, the same way as for common parameters + foo { (a, b) -> + a checkType { _() } + b checkType { _() } + } + + foo { (c, d) -> + c checkType { _() } + d checkType { _() } + + foo { (a, c) -> + a checkType { _() } + c checkType { _() } + d checkType { _() } + } + } +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/shadowing.txt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/shadowing.txt new file mode 100644 index 00000000000..91636ba6dc4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/shadowing.txt @@ -0,0 +1,16 @@ +package + +public fun bar(/*0*/ a: kotlin.Double): kotlin.Unit +public fun foo(/*0*/ block: (A) -> kotlin.Unit): kotlin.Unit + +public final data class A { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String) + public final val x: kotlin.Int + public final val y: kotlin.String + public final operator /*synthesized*/ fun component1(): kotlin.Int + public final operator /*synthesized*/ fun component2(): kotlin.String + public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.String = ...): A + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.kt new file mode 100644 index 00000000000..fa9444c5edb --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.kt @@ -0,0 +1,53 @@ +// !CHECK_TYPE +// !DIAGNOSTICS: -UNUSED_PARAMETER +data class A(val x: Int, val y: String) +data class B(val u: Double, val w: Short) + +fun foo(block: (A) -> Unit) { } +fun foobar(block: (A, B) -> Unit) { } + +fun bar() { + foo { (a, b) -> + a checkType { _() } + b checkType { _() } + } + + foo { (a: Int, b: String) -> + a checkType { _() } + b checkType { _() } + } + + foo { (a, b): A -> + a checkType { _() } + b checkType { _() } + } + + foobar { (a, b), c -> + a checkType { _() } + b checkType { _() } + c checkType { _() } + } + + foobar { a, (b, c) -> + a checkType { _() } + b checkType { _() } + c checkType { _() } + } + + foobar { (a, b), (c, d) -> + a checkType { _() } + b checkType { _() } + c checkType { _() } + d checkType { _() } + } + + foo { (a: String, b) -> + a checkType { _() } + b checkType { _() } + } + + foo { (a, b): B -> + a checkType { _() } + b checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.txt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.txt new file mode 100644 index 00000000000..71b3784c537 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.txt @@ -0,0 +1,29 @@ +package + +public fun bar(): kotlin.Unit +public fun foo(/*0*/ block: (A) -> kotlin.Unit): kotlin.Unit +public fun foobar(/*0*/ block: (A, B) -> kotlin.Unit): kotlin.Unit + +public final data class A { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String) + public final val x: kotlin.Int + public final val y: kotlin.String + public final operator /*synthesized*/ fun component1(): kotlin.Int + public final operator /*synthesized*/ fun component2(): kotlin.String + public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.String = ...): A + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public final data class B { + public constructor B(/*0*/ u: kotlin.Double, /*1*/ w: kotlin.Short) + public final val u: kotlin.Double + public final val w: kotlin.Short + public final operator /*synthesized*/ fun component1(): kotlin.Double + public final operator /*synthesized*/ fun component2(): kotlin.Short + public final /*synthesized*/ fun copy(/*0*/ u: kotlin.Double = ..., /*1*/ w: kotlin.Short = ...): B + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ 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 07b1a2ad1c9..35c3988e518 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -7470,6 +7470,57 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DestructuringInLambdas extends AbstractDiagnosticsTest { + public void testAllFilesPresentInDestructuringInLambdas() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("complexInference.kt") + public void testComplexInference() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/complexInference.kt"); + doTest(fileName); + } + + @TestMetadata("extensionComponents.kt") + public void testExtensionComponents() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt"); + doTest(fileName); + } + + @TestMetadata("inferredFunctionalType.kt") + public void testInferredFunctionalType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/inferredFunctionalType.kt"); + doTest(fileName); + } + + @TestMetadata("noExpectedType.kt") + public void testNoExpectedType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/noExpectedType.kt"); + doTest(fileName); + } + + @TestMetadata("redeclaration.kt") + public void testRedeclaration() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.kt"); + doTest(fileName); + } + + @TestMetadata("shadowing.kt") + public void testShadowing() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/shadowing.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/simple.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/functionLiterals/return") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) 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 ea27d0f16bf..fce84e0607a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ValueParameterDescriptorImpl.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeSubstitutor -class ValueParameterDescriptorImpl( +open class ValueParameterDescriptorImpl( containingDeclaration: CallableDescriptor, original: ValueParameterDescriptor?, override val index: Int, @@ -36,6 +36,50 @@ class ValueParameterDescriptorImpl( override val varargElementType: KotlinType?, source: SourceElement ) : VariableDescriptorImpl(containingDeclaration, annotations, name, outType, source), ValueParameterDescriptor { + + companion object { + @JvmStatic + fun getDestructuringVariablesOrNull(valueParameterDescriptor: ValueParameterDescriptor) = + (valueParameterDescriptor as? ValueParameterDescriptorImpl.WithDestructuringDeclaration)?.destructuringVariables + + @JvmStatic + fun createWithDestructuringDeclarations(containingDeclaration: CallableDescriptor, + original: ValueParameterDescriptor?, + index: Int, + annotations: Annotations, + name: Name, + outType: KotlinType, + declaresDefaultValue: Boolean, + isCrossinline: Boolean, + isNoinline: Boolean, isCoroutine: Boolean, varargElementType: KotlinType?, + source: SourceElement, + destructuringVariables: List? + ): ValueParameterDescriptorImpl = + if (destructuringVariables == null) + ValueParameterDescriptorImpl(containingDeclaration, original, index, annotations, name, outType, + declaresDefaultValue, isCrossinline, isNoinline, isCoroutine, varargElementType, source) + else + WithDestructuringDeclaration(containingDeclaration, original, index, annotations, name, outType, + declaresDefaultValue, isCrossinline, isNoinline, isCoroutine, varargElementType, source, + destructuringVariables) + } + + class WithDestructuringDeclaration internal constructor( + containingDeclaration: CallableDescriptor, + original: ValueParameterDescriptor?, + index: Int, + annotations: Annotations, name: Name, + outType: KotlinType, + declaresDefaultValue: Boolean, + isCrossinline: Boolean, + isNoinline: Boolean, isCoroutine: Boolean, varargElementType: KotlinType?, + source: SourceElement, + val destructuringVariables: List + ) : ValueParameterDescriptorImpl( + containingDeclaration, original, index, annotations, name, outType, declaresDefaultValue, + isCrossinline, isNoinline, isCoroutine, + varargElementType, source) + private val original: ValueParameterDescriptor = original ?: this override fun getContainingDeclaration() = super.getContainingDeclaration() as CallableDescriptor