'createDelegate' operator convention:
- resolution & inference - additional diagnostic for language feature support
This commit is contained in:
committed by
Stanislav Erokhin
parent
d3ab0f066e
commit
e2ba288323
@@ -141,6 +141,8 @@ public interface BindingContext {
|
||||
|
||||
WritableSlice<VariableAccessorDescriptor, ResolvedCall<FunctionDescriptor>> DELEGATED_PROPERTY_RESOLVED_CALL = Slices.createSimpleSlice();
|
||||
WritableSlice<VariableAccessorDescriptor, Call> DELEGATED_PROPERTY_CALL = Slices.createSimpleSlice();
|
||||
WritableSlice<VariableDescriptorWithAccessors, ResolvedCall<FunctionDescriptor>> CREATE_DELEGATE_RESOLVED_CALL = Slices.createSimpleSlice();
|
||||
WritableSlice<VariableDescriptorWithAccessors, Call> CREATE_DELEGATE_CALL = Slices.createSimpleSlice();
|
||||
|
||||
WritableSlice<VariableDescriptorWithAccessors, ResolvedCall<FunctionDescriptor>> DELEGATED_PROPERTY_PD_RESOLVED_CALL = Slices.createSimpleSlice();
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.resolve
|
||||
|
||||
import com.google.common.collect.Lists
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
||||
@@ -51,7 +53,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
class DelegatedPropertyResolver(
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val fakeCallResolver: FakeCallResolver,
|
||||
private val expressionTypingServices: ExpressionTypingServices
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
|
||||
fun resolvePropertyDelegate(
|
||||
@@ -81,31 +84,53 @@ class DelegatedPropertyResolver(
|
||||
delegateFunctionsScope = initializerScope
|
||||
}
|
||||
|
||||
val delegateType = resolveDelegateExpression(delegateExpression, property, variableDescriptor, initializerScope, trace, outerDataFlowInfo)
|
||||
resolveDelegatedPropertyGetMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo)
|
||||
val byExpressionType = resolveDelegateExpression(delegateExpression, property, variableDescriptor, initializerScope, trace, outerDataFlowInfo)
|
||||
|
||||
resolveCreateDelegateMethod(variableDescriptor, delegateExpression, byExpressionType, trace, delegateFunctionsScope, outerDataFlowInfo)
|
||||
val delegateType = getResolvedDelegateType(variableDescriptor, delegateExpression, byExpressionType, trace)
|
||||
|
||||
resolveGetValueMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo)
|
||||
if (property.isVar) {
|
||||
resolveDelegatedPropertySetMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo)
|
||||
resolveSetValueMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo)
|
||||
}
|
||||
|
||||
resolveDelegatedPropertyPDMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo)
|
||||
resolvePropertyDelegatedMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo)
|
||||
}
|
||||
|
||||
fun getDelegatedPropertyGetMethodReturnType(
|
||||
private fun getResolvedDelegateType(
|
||||
variableDescriptor: VariableDescriptorWithAccessors,
|
||||
delegateExpression: KtExpression,
|
||||
delegateType: KotlinType,
|
||||
byExpressionType: KotlinType,
|
||||
trace: BindingTrace
|
||||
): KotlinType {
|
||||
val createDelegateResolvedCall = trace.bindingContext.get(CREATE_DELEGATE_RESOLVED_CALL, variableDescriptor)
|
||||
if (createDelegateResolvedCall != null) {
|
||||
return createDelegateResolvedCall.resultingDescriptor.returnType
|
||||
?: throw AssertionError("No return type fore 'createDelegate' of ${delegateExpression.text}")
|
||||
}
|
||||
return byExpressionType
|
||||
}
|
||||
|
||||
fun getGetValueMethodReturnType(
|
||||
variableDescriptor: VariableDescriptorWithAccessors,
|
||||
delegateExpression: KtExpression,
|
||||
byExpressionType: KotlinType,
|
||||
trace: BindingTrace,
|
||||
delegateFunctionsScope: LexicalScope,
|
||||
dataFlowInfo: DataFlowInfo
|
||||
): KotlinType? {
|
||||
resolveDelegatedPropertyConventionMethod(
|
||||
variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, dataFlowInfo, true
|
||||
)
|
||||
resolveCreateDelegateMethod(variableDescriptor, delegateExpression, byExpressionType, trace, delegateFunctionsScope, dataFlowInfo)
|
||||
val delegateType = getResolvedDelegateType(variableDescriptor, delegateExpression, byExpressionType, trace)
|
||||
resolveGetSetValueMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, dataFlowInfo, true)
|
||||
|
||||
val resolvedCall = trace.bindingContext.get(DELEGATED_PROPERTY_RESOLVED_CALL, variableDescriptor.getter)
|
||||
return if (resolvedCall != null) resolvedCall.resultingDescriptor.returnType else null
|
||||
}
|
||||
|
||||
private fun resolveDelegatedPropertyGetMethod(
|
||||
private val isOperatorCreateDelegateSupported: Boolean
|
||||
get() = languageVersionSettings.supportsFeature(LanguageFeature.OperatorCreateDelegate)
|
||||
|
||||
private fun resolveGetValueMethod(
|
||||
variableDescriptor: VariableDescriptorWithAccessors,
|
||||
delegateExpression: KtExpression,
|
||||
delegateType: KotlinType,
|
||||
@@ -113,9 +138,7 @@ class DelegatedPropertyResolver(
|
||||
delegateFunctionsScope: LexicalScope,
|
||||
dataFlowInfo: DataFlowInfo
|
||||
) {
|
||||
val returnType = getDelegatedPropertyGetMethodReturnType(
|
||||
variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, dataFlowInfo
|
||||
)
|
||||
val returnType = getGetValueMethodReturnType(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, dataFlowInfo)
|
||||
val propertyType = variableDescriptor.type
|
||||
|
||||
/* Do not check return type of get() method of delegate for properties with DeferredType because property type is taken from it */
|
||||
@@ -127,7 +150,7 @@ class DelegatedPropertyResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveDelegatedPropertySetMethod(
|
||||
private fun resolveSetValueMethod(
|
||||
variableDescriptor: VariableDescriptorWithAccessors,
|
||||
delegateExpression: KtExpression,
|
||||
delegateType: KotlinType,
|
||||
@@ -135,15 +158,15 @@ class DelegatedPropertyResolver(
|
||||
delegateFunctionsScope: LexicalScope,
|
||||
dataFlowInfo: DataFlowInfo
|
||||
) {
|
||||
resolveDelegatedPropertyConventionMethod(variableDescriptor, delegateExpression, delegateType, trace,
|
||||
delegateFunctionsScope, dataFlowInfo, false)
|
||||
resolveGetSetValueMethod(variableDescriptor, delegateExpression, delegateType, trace,
|
||||
delegateFunctionsScope, dataFlowInfo, false)
|
||||
}
|
||||
|
||||
private fun createExpressionForProperty(psiFactory: KtPsiFactory): KtExpression {
|
||||
return psiFactory.createExpression("null as ${KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName().asString()}<*>")
|
||||
private fun KtPsiFactory.createExpressionForProperty(): KtExpression {
|
||||
return createExpression("null as ${KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName().asString()}<*>")
|
||||
}
|
||||
|
||||
private fun resolveDelegatedPropertyPDMethod(
|
||||
private fun resolvePropertyDelegatedMethod(
|
||||
variableDescriptor: VariableDescriptorWithAccessors,
|
||||
delegateExpression: KtExpression,
|
||||
delegateType: KotlinType,
|
||||
@@ -155,7 +178,7 @@ class DelegatedPropertyResolver(
|
||||
val context = ExpressionTypingContext.newContext(traceToResolvePDMethod, delegateFunctionsScope, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE)
|
||||
|
||||
val psiFactory = KtPsiFactory(delegateExpression)
|
||||
val arguments = listOf(createExpressionForProperty(psiFactory))
|
||||
val arguments = listOf(psiFactory.createExpressionForProperty())
|
||||
val receiver = ExpressionReceiver.create(delegateExpression, delegateType, trace.bindingContext)
|
||||
|
||||
val resolutionResult = fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments,
|
||||
@@ -180,7 +203,7 @@ class DelegatedPropertyResolver(
|
||||
}
|
||||
|
||||
/* Resolve getValue() or setValue() methods from delegate */
|
||||
private fun resolveDelegatedPropertyConventionMethod(
|
||||
private fun resolveGetSetValueMethod(
|
||||
propertyDescriptor: VariableDescriptorWithAccessors,
|
||||
delegateExpression: KtExpression,
|
||||
delegateType: KotlinType,
|
||||
@@ -194,34 +217,26 @@ class DelegatedPropertyResolver(
|
||||
|
||||
if (trace.bindingContext.get(DELEGATED_PROPERTY_CALL, accessor) != null) return
|
||||
|
||||
val functionResults = getDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace,
|
||||
delegateFunctionsScope, dataFlowInfo, isGet, true)
|
||||
val call = trace.bindingContext.get(DELEGATED_PROPERTY_CALL, accessor)
|
||||
?: throw AssertionError("'getDelegatedPropertyConventionMethod' didn't record a call")
|
||||
val functionResults = getGetSetValueMethod(
|
||||
propertyDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, dataFlowInfo,
|
||||
isGet = isGet, isComplete = true
|
||||
)
|
||||
|
||||
if (!functionResults.isSuccess) {
|
||||
val expectedFunction = renderCall(call, trace.bindingContext)
|
||||
when {
|
||||
functionResults.isSingleResult ||
|
||||
functionResults.isIncomplete ||
|
||||
functionResults.resultCode == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES ->
|
||||
trace.report(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE.on(delegateExpression, expectedFunction, functionResults.resultingCalls))
|
||||
functionResults.isAmbiguity ->
|
||||
trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY.on(delegateExpression, expectedFunction, functionResults.resultingCalls))
|
||||
else ->
|
||||
trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType))
|
||||
}
|
||||
val call = trace.bindingContext.get(DELEGATED_PROPERTY_CALL, accessor)
|
||||
?: throw AssertionError("'getDelegatedPropertyConventionMethod' didn't record a call")
|
||||
reportDelegateOperatorResolutionError(trace, call, functionResults, delegateExpression, delegateType)
|
||||
return
|
||||
}
|
||||
|
||||
val resultingDescriptor = functionResults.resultingDescriptor
|
||||
|
||||
val resultingCall = functionResults.resultingCall
|
||||
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor)
|
||||
if (declaration is KtProperty) {
|
||||
val delegate = declaration.delegate
|
||||
if (delegate != null) {
|
||||
if (!resultingDescriptor.isOperator) {
|
||||
|
||||
if (!resultingDescriptor.isOperator) {
|
||||
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor)
|
||||
if (declaration is KtProperty) {
|
||||
val delegate = declaration.delegate
|
||||
if (delegate != null) {
|
||||
val byKeyword = delegate.byKeywordNode.psi
|
||||
OperatorCallChecker.report(byKeyword, resultingDescriptor, trace)
|
||||
}
|
||||
@@ -231,8 +246,61 @@ class DelegatedPropertyResolver(
|
||||
trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, resultingCall)
|
||||
}
|
||||
|
||||
private fun reportDelegateOperatorResolutionError(
|
||||
trace: BindingTrace,
|
||||
delegateOperatorCall: Call,
|
||||
delegateOperatorResults: OverloadResolutionResults<FunctionDescriptor>,
|
||||
delegateExpression: KtExpression,
|
||||
delegateType: KotlinType,
|
||||
operatorRequired: Boolean = true
|
||||
) {
|
||||
val expectedFunction = renderCall(delegateOperatorCall, trace.bindingContext)
|
||||
|
||||
when {
|
||||
delegateOperatorResults.isSingleResult ||
|
||||
delegateOperatorResults.isIncomplete ||
|
||||
delegateOperatorResults.resultCode == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES ->
|
||||
trace.report(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE.on(delegateExpression, expectedFunction, delegateOperatorResults.resultingCalls))
|
||||
delegateOperatorResults.isAmbiguity ->
|
||||
trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY.on(delegateExpression, expectedFunction, delegateOperatorResults.resultingCalls))
|
||||
else ->
|
||||
if (operatorRequired) trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType))
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveCreateDelegateMethod(
|
||||
propertyDescriptor: VariableDescriptorWithAccessors,
|
||||
byExpression: KtExpression,
|
||||
byExpressionType: KotlinType,
|
||||
trace: BindingTrace,
|
||||
delegateFunctionsScope: LexicalScope,
|
||||
dataFlowInfo: DataFlowInfo
|
||||
) {
|
||||
if (!isOperatorCreateDelegateSupported) return
|
||||
if (trace.bindingContext.get(BindingContext.CREATE_DELEGATE_CALL, propertyDescriptor) != null) return
|
||||
|
||||
val createDelegateResults = getCreateDelegateMethod(propertyDescriptor, byExpression, byExpressionType,
|
||||
trace, delegateFunctionsScope, dataFlowInfo)
|
||||
if (!createDelegateResults.isSuccess) {
|
||||
val call = trace.bindingContext.get(BindingContext.CREATE_DELEGATE_CALL, propertyDescriptor)
|
||||
?: throw AssertionError("'getDelegatedPropertyConventionMethod' didn't record a call")
|
||||
reportDelegateOperatorResolutionError(trace, call, createDelegateResults, byExpression, byExpressionType,
|
||||
operatorRequired = false)
|
||||
return
|
||||
}
|
||||
|
||||
val resultingDescriptor = createDelegateResults.resultingDescriptor
|
||||
if (!resultingDescriptor.isOperator) {
|
||||
// TODO resolved 'createDelegate' function, which is not an operator - warning?
|
||||
return
|
||||
}
|
||||
|
||||
val resultingCall = createDelegateResults.resultingCall
|
||||
trace.record(CREATE_DELEGATE_RESOLVED_CALL, propertyDescriptor, resultingCall)
|
||||
}
|
||||
|
||||
/* Resolve getValue() or setValue() methods from delegate */
|
||||
private fun getDelegatedPropertyConventionMethod(
|
||||
private fun getGetSetValueMethod(
|
||||
propertyDescriptor: VariableDescriptorWithAccessors,
|
||||
delegateExpression: KtExpression,
|
||||
delegateType: KotlinType,
|
||||
@@ -257,7 +325,7 @@ class DelegatedPropertyResolver(
|
||||
val arguments = Lists.newArrayList<KtExpression>()
|
||||
val psiFactory = KtPsiFactory(delegateExpression)
|
||||
arguments.add(psiFactory.createExpression(if (hasThis) "this" else "null"))
|
||||
arguments.add(createExpressionForProperty(psiFactory))
|
||||
arguments.add(psiFactory.createExpressionForProperty())
|
||||
|
||||
if (!isGet) {
|
||||
val fakeArgument = createFakeExpressionOfType(delegateExpression.project, trace,
|
||||
@@ -277,6 +345,34 @@ class DelegatedPropertyResolver(
|
||||
return resolutionResult.second
|
||||
}
|
||||
|
||||
private fun getCreateDelegateMethod(
|
||||
propertyDescriptor: VariableDescriptorWithAccessors,
|
||||
delegateExpression: KtExpression,
|
||||
delegateExpressionType: KotlinType,
|
||||
trace: BindingTrace,
|
||||
delegateFunctionsScope: LexicalScope,
|
||||
dataFlowInfo: DataFlowInfo
|
||||
): OverloadResolutionResults<FunctionDescriptor> {
|
||||
val expectedType = TypeUtils.NO_EXPECTED_TYPE
|
||||
val context = ExpressionTypingContext.newContext(trace, delegateFunctionsScope, dataFlowInfo, expectedType)
|
||||
val propertyHasReceiver = propertyDescriptor.extensionReceiverParameter != null ||
|
||||
propertyDescriptor.dispatchReceiverParameter != null
|
||||
val arguments = KtPsiFactory(delegateExpression).run {
|
||||
listOf(
|
||||
createExpression(if (propertyHasReceiver) "this" else "null"),
|
||||
createExpressionForProperty()
|
||||
)
|
||||
}
|
||||
val functionName = OperatorNameConventions.CREATE_DELEGATE
|
||||
val receiver = ExpressionReceiver.create(delegateExpression, delegateExpressionType, trace.bindingContext)
|
||||
|
||||
val (createDelegateCall, createDelegateResolutionResult) =
|
||||
fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, functionName, delegateExpression)
|
||||
trace.record(BindingContext.CREATE_DELEGATE_CALL, propertyDescriptor, createDelegateCall)
|
||||
|
||||
return createDelegateResolutionResult
|
||||
}
|
||||
|
||||
//TODO: diagnostics rendering does not belong here
|
||||
private fun renderCall(call: Call, context: BindingContext): String {
|
||||
val calleeExpression = call.calleeExpression
|
||||
@@ -303,15 +399,16 @@ class DelegatedPropertyResolver(
|
||||
): KotlinType {
|
||||
val traceToResolveDelegatedProperty = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property")
|
||||
val calleeExpression = delegateExpression.getCalleeExpressionIfAny()
|
||||
val completer = createConstraintSystemCompleter(
|
||||
property, variableDescriptor, delegateExpression, scopeForDelegate, trace, dataFlowInfo
|
||||
)
|
||||
if (calleeExpression != null) {
|
||||
traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, calleeExpression, completer)
|
||||
val completer = createConstraintSystemCompleter(property, variableDescriptor, delegateExpression, scopeForDelegate, trace, dataFlowInfo)
|
||||
|
||||
calleeExpression?.let {
|
||||
traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, it, completer)
|
||||
}
|
||||
val delegateType = expressionTypingServices.safeGetType(scopeForDelegate, delegateExpression, NO_EXPECTED_TYPE,
|
||||
dataFlowInfo, traceToResolveDelegatedProperty)
|
||||
traceToResolveDelegatedProperty.commit({ slice, key -> slice !== CONSTRAINT_SYSTEM_COMPLETER }, true)
|
||||
|
||||
val delegateType = expressionTypingServices.safeGetType(scopeForDelegate, delegateExpression, NO_EXPECTED_TYPE, dataFlowInfo, traceToResolveDelegatedProperty)
|
||||
|
||||
traceToResolveDelegatedProperty.commit({ slice, _ -> slice !== CONSTRAINT_SYSTEM_COMPLETER }, true)
|
||||
|
||||
return delegateType
|
||||
}
|
||||
|
||||
@@ -334,21 +431,23 @@ class DelegatedPropertyResolver(
|
||||
?: throw AssertionError("No substitutor in the system for call: " + resolvedCall.call)
|
||||
|
||||
val traceToResolveConventionMethods = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods")
|
||||
val getMethodResults = getDelegatedPropertyConventionMethod(
|
||||
variableDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope,
|
||||
dataFlowInfo, true, false
|
||||
)
|
||||
|
||||
if (conventionMethodFound(getMethodResults)) {
|
||||
val descriptor = getMethodResults.resultingDescriptor
|
||||
val returnTypeOfGetMethod = descriptor.returnType
|
||||
if (returnTypeOfGetMethod != null && !TypeUtils.noExpectedType(expectedType)) {
|
||||
val returnTypeInSystem = typeVariableSubstitutor.substitute(returnTypeOfGetMethod, Variance.INVARIANT)
|
||||
val delegateType = getDelegateType(returnType, constraintSystem, typeVariableSubstitutor, traceToResolveConventionMethods)
|
||||
|
||||
val getValueResults = getGetSetValueMethod(
|
||||
variableDescriptor, delegateExpression, delegateType, traceToResolveConventionMethods, delegateFunctionsScope, dataFlowInfo,
|
||||
isGet = true, isComplete = false
|
||||
)
|
||||
if (conventionMethodFound(getValueResults)) {
|
||||
val getValueDescriptor = getValueResults.resultingDescriptor
|
||||
val getValueReturnType = getValueDescriptor.returnType
|
||||
if (getValueReturnType != null && !TypeUtils.noExpectedType(expectedType)) {
|
||||
val returnTypeInSystem = typeVariableSubstitutor.substitute(getValueReturnType, Variance.INVARIANT)
|
||||
if (returnTypeInSystem != null) {
|
||||
constraintSystem.addSubtypeConstraint(returnTypeInSystem, expectedType, FROM_COMPLETER.position())
|
||||
}
|
||||
}
|
||||
addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor)
|
||||
addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, getValueDescriptor)
|
||||
}
|
||||
if (!variableDescriptor.isVar) return
|
||||
|
||||
@@ -357,29 +456,49 @@ class DelegatedPropertyResolver(
|
||||
// But if the type isn't known yet, the constraint shouldn't be added (we try to infer the type of 'v' here as well).
|
||||
if (variableDescriptor.returnType is DeferredType) return
|
||||
|
||||
val setMethodResults = getDelegatedPropertyConventionMethod(
|
||||
variableDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope,
|
||||
dataFlowInfo, false, false
|
||||
val setValueResults = getGetSetValueMethod(
|
||||
variableDescriptor, delegateExpression, delegateType, traceToResolveConventionMethods, delegateFunctionsScope, dataFlowInfo,
|
||||
isGet = false, isComplete = false
|
||||
)
|
||||
|
||||
if (conventionMethodFound(setMethodResults)) {
|
||||
val descriptor = setMethodResults.resultingDescriptor
|
||||
val valueParameters = descriptor.valueParameters
|
||||
if (valueParameters.size == 3) {
|
||||
val valueParameterForThis = valueParameters[2]
|
||||
|
||||
if (conventionMethodFound(setValueResults)) {
|
||||
val setValueDescriptor = setValueResults.resultingDescriptor
|
||||
val setValueParameters = setValueDescriptor.valueParameters
|
||||
if (setValueParameters.size == 3) {
|
||||
if (!noExpectedType(expectedType)) {
|
||||
constraintSystem.addSubtypeConstraint(
|
||||
expectedType,
|
||||
typeVariableSubstitutor.substitute(valueParameterForThis.type, Variance.INVARIANT),
|
||||
FROM_COMPLETER.position()
|
||||
)
|
||||
val thisParameterType = setValueParameters[2].type
|
||||
val substitutedThisParameterType = typeVariableSubstitutor.substitute(thisParameterType, Variance.INVARIANT)
|
||||
constraintSystem.addSubtypeConstraint(expectedType, substitutedThisParameterType, FROM_COMPLETER.position())
|
||||
}
|
||||
addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor)
|
||||
addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, setValueDescriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDelegateType(
|
||||
byExpressionType: KotlinType,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
typeVariableSubstitutor: TypeSubstitutor,
|
||||
traceToResolveConventionMethods: TemporaryBindingTrace
|
||||
): KotlinType {
|
||||
if (isOperatorCreateDelegateSupported) {
|
||||
val createDelegateResults = getCreateDelegateMethod(
|
||||
variableDescriptor, delegateExpression, byExpressionType,
|
||||
traceToResolveConventionMethods, delegateFunctionsScope, dataFlowInfo
|
||||
)
|
||||
if (conventionMethodFound(createDelegateResults)) {
|
||||
val createDelegateDescriptor = createDelegateResults.resultingDescriptor
|
||||
val createDelegateReturnType = createDelegateDescriptor.returnType
|
||||
if (createDelegateDescriptor.isOperator) {
|
||||
addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, createDelegateDescriptor)
|
||||
return createDelegateReturnType
|
||||
?: throw AssertionError("No return type fore 'createDelegate' of ${delegateExpression.text}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return byExpressionType
|
||||
}
|
||||
|
||||
private fun conventionMethodFound(results: OverloadResolutionResults<FunctionDescriptor>): Boolean =
|
||||
results.isSuccess ||
|
||||
results.isSingleResult && results.resultCode == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
@@ -42,22 +43,17 @@ object OperatorModifierChecker {
|
||||
|
||||
val checkResult = OperatorChecks.check(functionDescriptor)
|
||||
if (checkResult.isSuccess) {
|
||||
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
|
||||
when (functionDescriptor.name) {
|
||||
in COROUTINE_OPERATOR_NAMES -> {
|
||||
if (!languageVersionSettings.supportsFeature(LanguageFeature.Coroutines)) {
|
||||
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(modifier, LanguageFeature.Coroutines))
|
||||
}
|
||||
}
|
||||
|
||||
in REM_TO_MOD_OPERATION_NAMES.keys -> {
|
||||
if (!shouldUseOperatorRem) {
|
||||
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(modifier, LanguageFeature.OperatorRem))
|
||||
}
|
||||
}
|
||||
in COROUTINE_OPERATOR_NAMES ->
|
||||
checkSupportsFeature(LanguageFeature.Coroutines, languageVersionSettings, diagnosticHolder, modifier)
|
||||
in REM_TO_MOD_OPERATION_NAMES.keys ->
|
||||
checkSupportsFeature(LanguageFeature.OperatorRem, languageVersionSettings, diagnosticHolder, modifier)
|
||||
OperatorNameConventions.CREATE_DELEGATE ->
|
||||
checkSupportsFeature(LanguageFeature.OperatorCreateDelegate, languageVersionSettings, diagnosticHolder, modifier)
|
||||
}
|
||||
|
||||
if (functionDescriptor.name in REM_TO_MOD_OPERATION_NAMES.values && shouldUseOperatorRem) {
|
||||
if (functionDescriptor.name in REM_TO_MOD_OPERATION_NAMES.values
|
||||
&& languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)) {
|
||||
val newNameConvention = REM_TO_MOD_OPERATION_NAMES.inverse()[functionDescriptor.name]
|
||||
diagnosticHolder.report(Errors.DEPRECATED_BINARY_MOD.on(modifier, functionDescriptor, newNameConvention!!.asString()))
|
||||
}
|
||||
@@ -69,6 +65,12 @@ object OperatorModifierChecker {
|
||||
|
||||
diagnosticHolder.report(Errors.INAPPLICABLE_OPERATOR_MODIFIER.on(modifier, errorDescription))
|
||||
}
|
||||
|
||||
private fun checkSupportsFeature(feature: LanguageFeature, languageVersionSettings: LanguageVersionSettings, diagnosticHolder: DiagnosticSink, modifier: PsiElement) {
|
||||
if (!languageVersionSettings.supportsFeature(feature)) {
|
||||
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(modifier, feature))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val COROUTINE_OPERATOR_NAMES =
|
||||
|
||||
+1
-1
@@ -140,7 +140,7 @@ class VariableTypeAndInitializerResolver(
|
||||
delegateExpression, property, variableDescriptor, scopeForInitializer, trace, dataFlowInfo)
|
||||
|
||||
val delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(scopeForInitializer, variableDescriptor)
|
||||
val getterReturnType = delegatedPropertyResolver.getDelegatedPropertyGetMethodReturnType(
|
||||
val getterReturnType = delegatedPropertyResolver.getGetValueMethodReturnType(
|
||||
variableDescriptor, delegateExpression, type, trace, delegateFunctionsScope, dataFlowInfo
|
||||
)
|
||||
|
||||
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class Cell<out V>(val value: V)
|
||||
|
||||
class GenericDelegate<V>(val value: V)
|
||||
|
||||
operator fun <T> T.createDelegate(a: Any?, p: Any?) = GenericDelegate(this)
|
||||
|
||||
operator fun <W> GenericDelegate<W>.getValue(a: Any?, p: Any?) = Cell(value)
|
||||
|
||||
val test1: Cell<String> by "OK"
|
||||
val test2: Cell<Any> by "OK"
|
||||
val test3 by "OK"
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
package
|
||||
|
||||
public val test1: Cell<kotlin.String>
|
||||
public val test2: Cell<kotlin.Any>
|
||||
public val test3: Cell<kotlin.String>
|
||||
public operator fun </*0*/ T> T.createDelegate(/*0*/ a: kotlin.Any?, /*1*/ p: kotlin.Any?): GenericDelegate<T>
|
||||
public operator fun </*0*/ W> GenericDelegate<W>.getValue(/*0*/ a: kotlin.Any?, /*1*/ p: kotlin.Any?): Cell<W>
|
||||
|
||||
public final class Cell</*0*/ out V> {
|
||||
public constructor Cell</*0*/ out V>(/*0*/ value: V)
|
||||
public final val value: V
|
||||
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 GenericDelegate</*0*/ V> {
|
||||
public constructor GenericDelegate</*0*/ V>(/*0*/ value: V)
|
||||
public final val value: V
|
||||
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
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class StringDelegate(val s: String) {
|
||||
operator fun getValue(a: Any?, p: KProperty<*>): Int = 42
|
||||
}
|
||||
|
||||
// NB no operator
|
||||
fun String.createDelegate(a: Any?, p: KProperty<*>) = StringDelegate(this)
|
||||
|
||||
operator fun String.getValue(a: Any?, p: KProperty<*>) = this
|
||||
|
||||
val test1: String by "OK"
|
||||
val test2: Int by <!DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH!>"OK"<!>
|
||||
val test3 by "OK"
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package
|
||||
|
||||
public val test1: kotlin.String
|
||||
public val test2: kotlin.Int
|
||||
public val test3: kotlin.String
|
||||
public fun kotlin.String.createDelegate(/*0*/ a: kotlin.Any?, /*1*/ p: kotlin.reflect.KProperty<*>): StringDelegate
|
||||
public operator fun kotlin.String.getValue(/*0*/ a: kotlin.Any?, /*1*/ p: kotlin.reflect.KProperty<*>): kotlin.String
|
||||
|
||||
public final class StringDelegate {
|
||||
public constructor StringDelegate(/*0*/ s: kotlin.String)
|
||||
public final val s: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final operator fun getValue(/*0*/ a: kotlin.Any?, /*1*/ p: kotlin.reflect.KProperty<*>): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
operator fun String.createDelegate(a: Any?, p: KProperty<*>) = this
|
||||
operator fun String.getValue(a: Any?, p: KProperty<*>) = this
|
||||
|
||||
val test1: String by "OK"
|
||||
|
||||
val test2 by "OK"
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
package
|
||||
|
||||
public val test1: kotlin.String
|
||||
public val test2: kotlin.String
|
||||
public operator fun kotlin.String.createDelegate(/*0*/ a: kotlin.Any?, /*1*/ p: kotlin.reflect.KProperty<*>): kotlin.String
|
||||
public operator fun kotlin.String.getValue(/*0*/ a: kotlin.Any?, /*1*/ p: kotlin.reflect.KProperty<*>): kotlin.String
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// !LANGUAGE: -OperatorCreateDelegate
|
||||
|
||||
class WrongDelegate(val x: Int) {
|
||||
operator fun getValue(thisRef: Any?, prop: Any): Int = x
|
||||
}
|
||||
|
||||
<!UNSUPPORTED_FEATURE(only available since Kotlin 1.1: operator createDelegate)!>operator<!> fun String.createDelegate(thisRef: Any?, prop: Any) = WrongDelegate(this.length)
|
||||
|
||||
operator fun String.getValue(thisRef: Any?, prop: Any) = this
|
||||
|
||||
val test1: String by "OK"
|
||||
val test2: Int by <!DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH!>"OK"<!>
|
||||
val test3 by "OK"
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package
|
||||
|
||||
public val test1: kotlin.String
|
||||
public val test2: kotlin.Int
|
||||
public val test3: kotlin.String
|
||||
public operator fun kotlin.String.createDelegate(/*0*/ thisRef: kotlin.Any?, /*1*/ prop: kotlin.Any): WrongDelegate
|
||||
public operator fun kotlin.String.getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ prop: kotlin.Any): kotlin.String
|
||||
|
||||
public final class WrongDelegate {
|
||||
public constructor WrongDelegate(/*0*/ x: kotlin.Int)
|
||||
public final val x: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ prop: kotlin.Any): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -5758,6 +5758,39 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/delegatedProperty/createDelegate")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class CreateDelegate extends AbstractDiagnosticsTest {
|
||||
public void testAllFilesPresentInCreateDelegate() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/createDelegate"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("genericCreateDelegate.kt")
|
||||
public void testGenericCreateDelegate() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/createDelegate/genericCreateDelegate.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noOperatorModifierOnCreateDelegate.kt")
|
||||
public void testNoOperatorModifierOnCreateDelegate() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/createDelegate/noOperatorModifierOnCreateDelegate.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleCreateDelegate.kt")
|
||||
public void testSimpleCreateDelegate() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/createDelegate/simpleCreateDelegate.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unsupportedOperatorCreateDelegate.kt")
|
||||
public void testUnsupportedOperatorCreateDelegate() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/createDelegate/unsupportedOperatorCreateDelegate.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/delegatedProperty/inference")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -36,6 +36,7 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion?) {
|
||||
DivisionByZeroInConstantExpressions(KOTLIN_1_1),
|
||||
InlineConstVals(KOTLIN_1_1),
|
||||
OperatorRem(KOTLIN_1_1),
|
||||
OperatorCreateDelegate(KOTLIN_1_1),
|
||||
|
||||
// Experimental features
|
||||
MultiPlatformProjects(null),
|
||||
|
||||
Reference in New Issue
Block a user