diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java index 66a58c21f17..c90c252e0b1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.renderer.DescriptorRenderer; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; +import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter; import org.jetbrains.kotlin.resolve.calls.inference.TypeVariableKt; @@ -39,7 +40,6 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory; import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.ScopeUtils; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; -import org.jetbrains.kotlin.resolve.validation.OperatorValidator; import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator; import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; @@ -263,7 +263,7 @@ public class DelegatedPropertyResolver { PsiElement byKeyword = delegate.getByKeywordNode().getPsi(); if (!resultingDescriptor.isOperator()) { - OperatorValidator.Companion.report(byKeyword, resultingDescriptor, trace); + OperatorCallChecker.Companion.report(byKeyword, resultingDescriptor, trace); } symbolUsageValidator.validateCall(resultingCall, resultingCall.getResultingDescriptor(), trace, byKeyword); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index c60bbf4ca35..e160b12d695 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -27,8 +27,6 @@ import org.jetbrains.kotlin.resolve.calls.checkers.* import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes import org.jetbrains.kotlin.resolve.validation.DeprecatedSymbolValidator -import org.jetbrains.kotlin.resolve.validation.InfixValidator -import org.jetbrains.kotlin.resolve.validation.OperatorValidator import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.DynamicTypesSettings @@ -66,12 +64,14 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( SuspendModifierChecker, CoroutineModifierChecker) -private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(), - SafeCallChecker(), InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(), - ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, CoroutineSuspendCallChecker, - BuilderFunctionsCallChecker) +private val DEFAULT_CALL_CHECKERS = listOf( + CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(), SafeCallChecker(), + InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(), InfixCallChecker(), OperatorCallChecker(), + ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, + CoroutineSuspendCallChecker, BuilderFunctionsCallChecker +) private val DEFAULT_TYPE_CHECKERS = emptyList() -private val DEFAULT_VALIDATORS = listOf(DeprecatedSymbolValidator(), OperatorValidator(), InfixValidator()) +private val DEFAULT_VALIDATORS = listOf(DeprecatedSymbolValidator()) abstract class PlatformConfigurator( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt index 0d142d27355..a1f611d6d5c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.BindingContext 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.checkers.InfixCallChecker 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 @@ -41,7 +42,6 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy -import org.jetbrains.kotlin.resolve.validation.InfixValidator import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE import org.jetbrains.kotlin.types.checker.KotlinTypeChecker @@ -136,7 +136,7 @@ fun isConventionCall(call: Call): Boolean { return calleeExpression.getNameForConventionalOperation() != null } -fun isInfixCall(call: Call): Boolean = InfixValidator.isInfixCall(call.calleeExpression) +fun isInfixCall(call: Call): Boolean = InfixCallChecker.isInfixCall(call.calleeExpression) fun getUnaryPlusOrMinusOperatorFunctionName(call: Call): Name? { if (call.callElement !is KtPrefixExpression) return null diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/InfixValidator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InfixCallChecker.kt similarity index 68% rename from compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/InfixValidator.kt rename to compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InfixCallChecker.kt index 533ebc0735a..c1d013b5736 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/InfixValidator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InfixCallChecker.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -14,34 +14,30 @@ * limitations under the License. */ -package org.jetbrains.kotlin.resolve.validation +package org.jetbrains.kotlin.resolve.calls.checkers import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.config.LanguageFeatureSettings import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtOperationReferenceExpression -import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.types.ErrorUtils -class InfixValidator : SymbolUsageValidator { - - override fun validateCall( - resolvedCall: ResolvedCall<*>?, - targetDescriptor: CallableDescriptor, - trace: BindingTrace, - element: PsiElement - ) { - val functionDescriptor = targetDescriptor as? FunctionDescriptor ?: return +class InfixCallChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext, languageFeatureSettings: LanguageFeatureSettings) { + val functionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return if (functionDescriptor.isDynamic() || ErrorUtils.isError(functionDescriptor)) return + val element = ((resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall ?: resolvedCall).call.calleeExpression if (isInfixCall(element) && !functionDescriptor.isInfix) { val operationRefExpression = element as? KtOperationReferenceExpression ?: return val containingDeclarationName = functionDescriptor.containingDeclaration.fqNameUnsafe.asString() - trace.report(Errors.INFIX_MODIFIER_REQUIRED.on(operationRefExpression, functionDescriptor, containingDeclarationName)) + context.trace.report(Errors.INFIX_MODIFIER_REQUIRED.on(operationRefExpression, functionDescriptor, containingDeclarationName)) } } @@ -52,4 +48,4 @@ class InfixValidator : SymbolUsageValidator { return binaryExpression.operationReference === operationRefExpression && !operationRefExpression.isPredefinedOperator() } } -} \ No newline at end of file +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/OperatorValidator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/OperatorCallChecker.kt similarity index 64% rename from compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/OperatorValidator.kt rename to compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/OperatorCallChecker.kt index 2bffb1c8b7d..9a4b8147d1b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/validation/OperatorValidator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/OperatorCallChecker.kt @@ -14,18 +14,17 @@ * limitations under the License. */ -package org.jetbrains.kotlin.resolve.validation +package org.jetbrains.kotlin.resolve.calls.checkers import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.config.LanguageFeatureSettings import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.calls.CallTransformer import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic @@ -36,51 +35,41 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.PLUS import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_MINUS import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_PLUS -class OperatorValidator : SymbolUsageValidator { - - override fun validateCall(resolvedCall: ResolvedCall<*>?, targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) { - val functionDescriptor = targetDescriptor as? FunctionDescriptor ?: return +class OperatorCallChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext, languageFeatureSettings: LanguageFeatureSettings) { + val functionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return if (!checkNotErrorOrDynamic(functionDescriptor)) return - val jetElement = element as? KtElement ?: return - val call = resolvedCall?.call ?: trace.bindingContext[BindingContext.CALL, jetElement] + val element = resolvedCall.call.calleeExpression ?: resolvedCall.call.callElement + val call = resolvedCall.call - fun isInvokeCall(): Boolean { - return call is CallTransformer.CallForImplicitInvoke - } + fun isInvokeCall(): Boolean = call is CallTransformer.CallForImplicitInvoke - fun isMultiDeclaration(): Boolean { - return (resolvedCall != null) && (call?.callElement is KtDestructuringDeclarationEntry) - } + fun isMultiDeclaration(): Boolean = call.callElement is KtDestructuringDeclarationEntry - fun isConventionOperator(): Boolean { - if (jetElement !is KtOperationReferenceExpression) return false - return jetElement.getNameForConventionalOperation() != null - } - - fun isArrayAccessExpression() = jetElement is KtArrayAccessExpression - - if (resolvedCall is VariableAsFunctionResolvedCall && call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) { + if (resolvedCall is VariableAsFunctionResolvedCall && + call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) { val outerCall = call.outerCall if (isConventionCall(outerCall)) { - throw AssertionError("Illegal resolved call to variable with invoke for $outerCall. Variable: ${resolvedCall.variableCall.resultingDescriptor}") + throw AssertionError("Illegal resolved call to variable with invoke for $outerCall. " + + "Variable: ${resolvedCall.variableCall.resultingDescriptor}") } } if (isMultiDeclaration() || isInvokeCall()) { - if (!functionDescriptor.isOperator && call != null) { - report(call.callElement, functionDescriptor, trace) + if (!functionDescriptor.isOperator) { + report(call.callElement, functionDescriptor, context.trace) } return } - val isConventionOperator = isConventionOperator() - if (isConventionOperator || isArrayAccessExpression()) { + val isConventionOperator = element is KtOperationReferenceExpression && element.getNameForConventionalOperation() != null + if (isConventionOperator || element is KtArrayAccessExpression) { if (!functionDescriptor.isOperator) { - report(jetElement, functionDescriptor, trace) + report(element, functionDescriptor, context.trace) } - if (isConventionOperator && call != null) { - checkDeprecatedUnaryConventions(call, functionDescriptor, trace) + if (isConventionOperator) { + checkDeprecatedUnaryConventions(call, functionDescriptor, context.trace) } } } @@ -108,4 +97,4 @@ class OperatorValidator : SymbolUsageValidator { return (!functionDescriptor.isDynamic() && !ErrorUtils.isError(functionDescriptor)) } } -} \ No newline at end of file +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index 0031cee29b1..4a28dcfbdc7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -869,22 +869,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { * @return {@code true} iff expression can be assigned to */ public boolean checkLValue( - @NotNull BindingTrace trace, - @NotNull ExpressionTypingContext context, - @NotNull KtExpression expression, - @Nullable KtExpression rightHandSide, - @NotNull KtOperationExpression operationExpression - ) { - return checkLValue(trace, context, expression, rightHandSide, operationExpression, false); - } - - private boolean checkLValue( @NotNull BindingTrace trace, @NotNull ExpressionTypingContext context, @NotNull KtExpression expressionWithParenthesis, @Nullable KtExpression rightHandSide, - @NotNull KtOperationExpression operationExpression, - boolean canBeThis + @NotNull KtOperationExpression operationExpression ) { KtExpression expression = KtPsiUtil.deparenthesize(expressionWithParenthesis); if (expression instanceof KtArrayAccessExpression) { @@ -901,17 +890,20 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { || operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) { ResolvedCall resolvedCall = ignoreReportsTrace.get(INDEXED_LVALUE_SET, expression); if (resolvedCall != null) { - CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); // Call must be validated with the actual, not temporary trace in order to report operator diagnostic // Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace - components.symbolUsageValidator.validateCall(resolvedCall, descriptor, trace, expression); + BasicCallResolutionContext callResolutionContext = BasicCallResolutionContext.create( + context.replaceBindingTrace(trace), resolvedCall.getCall(), CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS + ); + for (CallChecker checker : components.callCheckers) { + checker.check(resolvedCall, callResolutionContext, components.languageFeatureSettings); + } } } return info.getType() != null; } - if (canBeThis && expression instanceof KtThisExpression) return true; VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), expression, true); boolean result = true; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ForLoopConventionsChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ForLoopConventionsChecker.java index 31f215cee5b..a5f0eb8b19b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ForLoopConventionsChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ForLoopConventionsChecker.java @@ -27,11 +27,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticSink; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.psi.KtExpression; +import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver; -import org.jetbrains.kotlin.resolve.validation.OperatorValidator; import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator; import org.jetbrains.kotlin.types.DynamicTypesKt; import org.jetbrains.kotlin.types.ErrorUtils; @@ -99,7 +99,7 @@ public class ForLoopConventionsChecker { if ((extensionReceiverParameter != null) && (DynamicTypesKt.isDynamic(extensionReceiverParameter.getType()))) return; if (!descriptor.isOperator()) { - OperatorValidator.Companion.report(expression, descriptor, sink); + OperatorCallChecker.Companion.report(expression, descriptor, sink); } }