[NI] Support assigning single array elements in named form to varargs

This commit is contained in:
Mikhail Zarechenskiy
2017-11-07 12:34:48 +03:00
parent fe2499b47f
commit 519e5c33d8
8 changed files with 46 additions and 16 deletions
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.psi.*
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.callUtil.getResolvedCall
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.tasks.ExplicitReceiverKind
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.SyntheticScopes
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.expressions.OperatorConventions
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
enum class ResolveArgumentsMode {
RESOLVE_FUNCTION_ARGUMENTS,
@@ -215,11 +214,6 @@ private fun shouldCheckAsArray(
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 {
val argumentExpression = argument.getArgumentExpression() ?: return false
if (argumentExpression is KtCollectionLiteralExpression) return true
@@ -23,10 +23,10 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.ValueArgument
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.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.isParameterOfAnnotation
class AssigningNamedArgumentToVarargChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.model.*
@@ -25,7 +26,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
// very initial state of component
// todo: handle all diagnostic inside DiagnosticReporterByTrackingStrategy
// move it to frontend module
class AdditionalDiagnosticReporter {
class AdditionalDiagnosticReporter(private val languageVersionSettings: LanguageVersionSettings) {
fun reportAdditionalDiagnostics(
candidate: ResolvedCallAtom,
@@ -79,7 +80,8 @@ class AdditionalDiagnosticReporter {
for (parameter in resultingDescriptor.valueParameters) {
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 {
it.argument == argument
@@ -16,9 +16,15 @@
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.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.model.CollectionLiteralKotlinCallArgument
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.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
@@ -42,8 +48,8 @@ internal val ReceiverValueWithSmartCastInfo.stableType: UnwrappedType
return intersectWrappedTypes(possibleTypes + receiverValue.type)
}
internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor) =
if (this.isSpread) {
internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor, languageVersionSettings: LanguageVersionSettings) =
if (this.isSpread || this.isArrayAssignedAsNamedArgumentInAnnotation(parameter, languageVersionSettings)) {
parameter.type.unwrap()
}
else {
@@ -51,3 +57,23 @@ internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor)
}
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)
}
@@ -225,7 +225,7 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument(
isReceiver: Boolean
) {
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))
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.calls.components.*
@@ -40,7 +41,8 @@ class KotlinCallComponents(
val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
val constraintInjector: ConstraintInjector,
val reflectionTypes: ReflectionTypes,
val builtIns: KotlinBuiltIns
val builtIns: KotlinBuiltIns,
val languageVersionSettings: LanguageVersionSettings
)
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");
* 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.utils.DFS
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun ClassDescriptor.getClassObjectReferenceTarget(): ClassDescriptor = companionObjectDescriptor ?: this
@@ -433,3 +434,8 @@ fun MemberDescriptor.isEffectivelyExternal(): Boolean {
val containingClass = getContainingClass(this)
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");
* you may not use this file except in compliance with the License.