Allow assigning array to vararg in named form in annotations

See more in KT-20171
This commit is contained in:
Mikhail Zarechenskiy
2017-09-13 16:05:46 +03:00
parent f905d56b38
commit 68259f7939
26 changed files with 410 additions and 96 deletions
@@ -620,6 +620,8 @@ public interface Errors {
DiagnosticFactory1<KtExpression, KotlinType> MISSING_RECEIVER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<KtExpression> NO_RECEIVER_ALLOWED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM = DiagnosticFactory0.create(WARNING);
// Call resolution
DiagnosticFactory0<KtExpression> ILLEGAL_SELECTOR = DiagnosticFactory0.create(ERROR);
@@ -55,7 +55,7 @@ fun ResolutionContext<*>.reportTypeMismatchDueToTypeProjection(
is CallPosition.ValueArgumentPosition -> Pair(
callPosition.resolvedCall, {
f: CallableDescriptor ->
getEffectiveExpectedType(f.valueParameters[callPosition.valueParameter.index], callPosition.valueArgument)
getEffectiveExpectedType(f.valueParameters[callPosition.valueParameter.index], callPosition.valueArgument, this)
})
is CallPosition.ExtensionReceiverPosition -> Pair(
callPosition.resolvedCall, {
@@ -756,6 +756,7 @@ public class DefaultErrorMessages {
MAP.put(NO_VALUE_FOR_PARAMETER, "No value passed for parameter ''{0}''", NAME);
MAP.put(MISSING_RECEIVER, "A receiver of type {0} is required", RENDER_TYPE);
MAP.put(NO_RECEIVER_ALLOWED, "No receiver can be passed to this function or property");
MAP.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM, "Assigning single elements to varargs in named form is deprecated");
MAP.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class");
@@ -278,7 +278,7 @@ class CallCompleter(
val argumentMapping = getArgumentMapping(valueArgument!!)
val (expectedType, callPosition) = when (argumentMapping) {
is ArgumentMatch -> Pair(
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument),
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context),
CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument))
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
}
@@ -18,16 +18,21 @@ package org.jetbrains.kotlin.resolve.calls.callResolverUtil
import com.google.common.collect.Lists
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.*
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
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.getNestedTypeVariables
@@ -45,6 +50,7 @@ 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,
@@ -177,8 +183,12 @@ fun getSuperCallExpression(call: Call): KtSuperExpression? {
return (call.explicitReceiver as? ExpressionReceiver)?.expression as? KtSuperExpression
}
fun getEffectiveExpectedType(parameterDescriptor: ValueParameterDescriptor, argument: ValueArgument): KotlinType {
if (argument.getSpreadElement() != null) {
fun getEffectiveExpectedType(
parameterDescriptor: ValueParameterDescriptor,
argument: ValueArgument,
context: ResolutionContext<*>
): KotlinType {
if (argument.getSpreadElement() != null || shouldCheckAsArray(parameterDescriptor, argument, context)) {
if (parameterDescriptor.varargElementType == null) {
// Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper
return DONT_CARE
@@ -193,6 +203,31 @@ fun getEffectiveExpectedType(parameterDescriptor: ValueParameterDescriptor, argu
return parameterDescriptor.type
}
private fun shouldCheckAsArray(
parameterDescriptor: ValueParameterDescriptor,
argument: ValueArgument,
context: ResolutionContext<*>
): Boolean {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations)) return false
if (!isParameterOfAnnotation(parameterDescriptor)) return false
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
val type = context.trace.getType(argumentExpression) ?: return false
return KotlinBuiltIns.isArrayOrPrimitiveArray(type)
}
fun createResolutionCandidatesForConstructors(
lexicalScope: LexicalScope,
call: Call,
@@ -363,7 +363,7 @@ class CandidateResolver(
for (argument in resolvedArgument.arguments) {
val expression = argument.getArgumentExpression() ?: continue
val expectedType = getEffectiveExpectedType(parameterDescriptor, argument)
val expectedType = getEffectiveExpectedType(parameterDescriptor, argument, context)
val newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument)).replaceExpectedType(expectedType)
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(expression, newContext, resolveFunctionArgumentBodies)
@@ -174,7 +174,7 @@ class GenericCandidateResolver(
context: CallCandidateResolutionContext<*>,
resolveFunctionArgumentBodies: ResolveArgumentsMode
) {
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
val argumentExpression = valueArgument.getArgumentExpression()
val expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
@@ -336,7 +336,7 @@ class GenericCandidateResolver(
) {
val argumentExpression = valueArgument.getArgumentExpression() ?: return
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
if (isCoroutineCallWithAdditionalInference(valueParameterDescriptor, valueArgument)) {
coroutineInferenceSupport.analyzeCoroutine(functionLiteral, valueArgument, constraintSystem, context, effectiveExpectedType)
@@ -398,7 +398,7 @@ class GenericCandidateResolver(
constraintSystem: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<D>
) {
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
val expectedType = getExpectedTypeForCallableReference(callableReference, constraintSystem, context, effectiveExpectedType)
?: return
if (!ReflectionTypes.isCallableType(expectedType)) return
@@ -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.
@@ -203,7 +203,7 @@ class CoroutineInferenceSupport(
?: return@forceInferenceForArguments
with(NewKotlinTypeChecker) {
val parameterType = getEffectiveExpectedType(argumentMatch.valueParameter, valueArgument)
val parameterType = getEffectiveExpectedType(argumentMatch.valueParameter, valueArgument, context)
CoroutineTypeCheckerContext().isSubtypeOf(kotlinType.unwrap(), parameterType.unwrap())
}
}
@@ -176,7 +176,7 @@ class KotlinToResolvedCallTransformer(
val argumentMapping = resolvedCall.getArgumentMapping(valueArgument!!)
val (expectedType, callPosition) = when (argumentMapping) {
is ArgumentMatch -> Pair(
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument),
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context),
CallPosition.ValueArgumentPosition(resolvedCall, argumentMapping.valueParameter, valueArgument))
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
}
@@ -101,6 +101,8 @@ class ConstantExpressionEvaluator(
val constants = compileTimeConstants.map { it.toConstantValue(constantType) }
if (argumentsAsVararg) {
if (isArrayPassedInNamedForm(constants, resolvedArgument)) return constants.single()
if (parameterDescriptor.declaresDefaultValue() && compileTimeConstants.isEmpty()) return null
return constantValueFactory.createArrayValue(constants, parameterDescriptor.type)
@@ -111,6 +113,12 @@ class ConstantExpressionEvaluator(
}
}
private fun isArrayPassedInNamedForm(constants: List<ConstantValue<Any?>>, resolvedArgument: ResolvedValueArgument): Boolean {
val constant = constants.singleOrNull() ?: return false
val argument = resolvedArgument.arguments.singleOrNull() ?: return false
return KotlinBuiltIns.isArrayOrPrimitiveArray(constant.type) && argument.isNamed()
}
private fun checkCompileTimeConstant(
argumentExpression: KtExpression,
expectedType: KotlinType,