[NI] Support assigning single array elements in named form to varargs
This commit is contained in:
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
|||||||
import org.jetbrains.kotlin.lexer.KtToken
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentForExpression
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentForExpression
|
||||||
@@ -39,6 +38,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.getNestedTypeVariables
|
|||||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
|
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isParameterOfAnnotation
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||||
import org.jetbrains.kotlin.resolve.scopes.collectSyntheticConstructors
|
import org.jetbrains.kotlin.resolve.scopes.collectSyntheticConstructors
|
||||||
@@ -50,7 +50,6 @@ import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
|||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|
||||||
|
|
||||||
enum class ResolveArgumentsMode {
|
enum class ResolveArgumentsMode {
|
||||||
RESOLVE_FUNCTION_ARGUMENTS,
|
RESOLVE_FUNCTION_ARGUMENTS,
|
||||||
@@ -215,11 +214,6 @@ private fun shouldCheckAsArray(
|
|||||||
return argument.isNamed() && parameterDescriptor.isVararg && isArrayOrArrayLiteral(argument, context)
|
return argument.isNamed() && parameterDescriptor.isVararg && isArrayOrArrayLiteral(argument, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isParameterOfAnnotation(parameterDescriptor: ValueParameterDescriptor): Boolean {
|
|
||||||
val constructedClass = parameterDescriptor.containingDeclaration.safeAs<ConstructorDescriptor>()?.constructedClass
|
|
||||||
return DescriptorUtils.isAnnotationClass(constructedClass)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isArrayOrArrayLiteral(argument: ValueArgument, context: ResolutionContext<*>): Boolean {
|
fun isArrayOrArrayLiteral(argument: ValueArgument, context: ResolutionContext<*>): Boolean {
|
||||||
val argumentExpression = argument.getArgumentExpression() ?: return false
|
val argumentExpression = argument.getArgumentExpression() ?: return false
|
||||||
if (argumentExpression is KtCollectionLiteralExpression) return true
|
if (argumentExpression is KtCollectionLiteralExpression) return true
|
||||||
|
|||||||
+1
-1
@@ -23,10 +23,10 @@ import org.jetbrains.kotlin.diagnostics.Errors
|
|||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument
|
import org.jetbrains.kotlin.psi.ValueArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isArrayOrArrayLiteral
|
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isArrayOrArrayLiteral
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isParameterOfAnnotation
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isParameterOfAnnotation
|
||||||
|
|
||||||
class AssigningNamedArgumentToVarargChecker : CallChecker {
|
class AssigningNamedArgumentToVarargChecker : CallChecker {
|
||||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
|
|||||||
+4
-2
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.components
|
package org.jetbrains.kotlin.resolve.calls.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
@@ -25,7 +26,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
|||||||
// very initial state of component
|
// very initial state of component
|
||||||
// todo: handle all diagnostic inside DiagnosticReporterByTrackingStrategy
|
// todo: handle all diagnostic inside DiagnosticReporterByTrackingStrategy
|
||||||
// move it to frontend module
|
// move it to frontend module
|
||||||
class AdditionalDiagnosticReporter {
|
class AdditionalDiagnosticReporter(private val languageVersionSettings: LanguageVersionSettings) {
|
||||||
|
|
||||||
fun reportAdditionalDiagnostics(
|
fun reportAdditionalDiagnostics(
|
||||||
candidate: ResolvedCallAtom,
|
candidate: ResolvedCallAtom,
|
||||||
@@ -79,7 +80,8 @@ class AdditionalDiagnosticReporter {
|
|||||||
|
|
||||||
for (parameter in resultingDescriptor.valueParameters) {
|
for (parameter in resultingDescriptor.valueParameters) {
|
||||||
for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) {
|
for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) {
|
||||||
val smartCastDiagnostic = createSmartCastDiagnostic(candidate, argument, argument.getExpectedType(parameter)) ?: continue
|
val effectiveExpectedType = argument.getExpectedType(parameter, languageVersionSettings)
|
||||||
|
val smartCastDiagnostic = createSmartCastDiagnostic(candidate, argument, effectiveExpectedType) ?: continue
|
||||||
|
|
||||||
val thereIsUnstableSmartCastError = candidate.diagnostics.filterIsInstance<UnstableSmartCast>().any {
|
val thereIsUnstableSmartCastError = candidate.diagnostics.filterIsInstance<UnstableSmartCast>().any {
|
||||||
it.argument == argument
|
it.argument == argument
|
||||||
|
|||||||
+28
-2
@@ -16,9 +16,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.components
|
package org.jetbrains.kotlin.resolve.calls.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.CollectionLiteralKotlinCallArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isParameterOfAnnotation
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
||||||
@@ -42,8 +48,8 @@ internal val ReceiverValueWithSmartCastInfo.stableType: UnwrappedType
|
|||||||
return intersectWrappedTypes(possibleTypes + receiverValue.type)
|
return intersectWrappedTypes(possibleTypes + receiverValue.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor) =
|
internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor, languageVersionSettings: LanguageVersionSettings) =
|
||||||
if (this.isSpread) {
|
if (this.isSpread || this.isArrayAssignedAsNamedArgumentInAnnotation(parameter, languageVersionSettings)) {
|
||||||
parameter.type.unwrap()
|
parameter.type.unwrap()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -51,3 +57,23 @@ internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null
|
val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null
|
||||||
|
val ParameterDescriptor.isVararg: Boolean get() = this.safeAs<ValueParameterDescriptor>()?.isVararg ?: false
|
||||||
|
|
||||||
|
private fun KotlinCallArgument.isArrayAssignedAsNamedArgumentInAnnotation(
|
||||||
|
parameter: ParameterDescriptor,
|
||||||
|
languageVersionSettings: LanguageVersionSettings
|
||||||
|
): Boolean {
|
||||||
|
if (!languageVersionSettings.supportsFeature(LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations)) return false
|
||||||
|
|
||||||
|
if (this.argumentName == null || !parameter.isVararg) return false
|
||||||
|
|
||||||
|
return isParameterOfAnnotation(parameter) && this.isArrayOrArrayLiteral()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinCallArgument.isArrayOrArrayLiteral(): Boolean {
|
||||||
|
if (this is CollectionLiteralKotlinCallArgument) return true
|
||||||
|
if (this !is SimpleKotlinCallArgument) return false
|
||||||
|
|
||||||
|
val type = this.receiver.receiverValue.type
|
||||||
|
return KotlinBuiltIns.isArrayOrPrimitiveArray(type)
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -225,7 +225,7 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument(
|
|||||||
isReceiver: Boolean
|
isReceiver: Boolean
|
||||||
) {
|
) {
|
||||||
val expectedType = candidateParameter?.let {
|
val expectedType = candidateParameter?.let {
|
||||||
resolvedCall.substitutor.substituteKeepAnnotations(argument.getExpectedType(candidateParameter))
|
resolvedCall.substitutor.substituteKeepAnnotations(argument.getExpectedType(candidateParameter, callComponents.languageVersionSettings))
|
||||||
}
|
}
|
||||||
addResolvedKtPrimitive(resolveKtPrimitive(csBuilder, argument, expectedType, this, isReceiver))
|
addResolvedKtPrimitive(resolveKtPrimitive(csBuilder, argument, expectedType, this, isReceiver))
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls.model
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.*
|
import org.jetbrains.kotlin.resolve.calls.components.*
|
||||||
@@ -40,7 +41,8 @@ class KotlinCallComponents(
|
|||||||
val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
|
val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
|
||||||
val constraintInjector: ConstraintInjector,
|
val constraintInjector: ConstraintInjector,
|
||||||
val reflectionTypes: ReflectionTypes,
|
val reflectionTypes: ReflectionTypes,
|
||||||
val builtIns: KotlinBuiltIns
|
val builtIns: KotlinBuiltIns,
|
||||||
|
val languageVersionSettings: LanguageVersionSettings
|
||||||
)
|
)
|
||||||
|
|
||||||
class SimpleCandidateFactory(
|
class SimpleCandidateFactory(
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
import org.jetbrains.kotlin.utils.DFS
|
import org.jetbrains.kotlin.utils.DFS
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
fun ClassDescriptor.getClassObjectReferenceTarget(): ClassDescriptor = companionObjectDescriptor ?: this
|
fun ClassDescriptor.getClassObjectReferenceTarget(): ClassDescriptor = companionObjectDescriptor ?: this
|
||||||
|
|
||||||
@@ -433,3 +434,8 @@ fun MemberDescriptor.isEffectivelyExternal(): Boolean {
|
|||||||
val containingClass = getContainingClass(this)
|
val containingClass = getContainingClass(this)
|
||||||
return containingClass != null && containingClass.isEffectivelyExternal()
|
return containingClass != null && containingClass.isEffectivelyExternal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isParameterOfAnnotation(parameterDescriptor: ParameterDescriptor): Boolean {
|
||||||
|
val constructedClass = parameterDescriptor.containingDeclaration.safeAs<ConstructorDescriptor>()?.constructedClass
|
||||||
|
return DescriptorUtils.isAnnotationClass(constructedClass)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
Reference in New Issue
Block a user