Skip to content

Commit d8263eb

Browse files
committed
Assert that callable references cannot have expression on LHS
1 parent 92f3795 commit d8263eb

File tree

3 files changed

+89
-13
lines changed

3 files changed

+89
-13
lines changed

compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.kt

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ import com.intellij.lang.ASTNode
2020
import com.intellij.psi.PsiElement
2121
import com.intellij.psi.util.PsiTreeUtil
2222
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
23-
import org.jetbrains.kotlin.descriptors.ClassDescriptor
24-
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
25-
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
26-
import org.jetbrains.kotlin.descriptors.Modality
23+
import org.jetbrains.kotlin.descriptors.*
2724
import org.jetbrains.kotlin.diagnostics.Errors.*
2825
import org.jetbrains.kotlin.psi.*
2926
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
@@ -39,6 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
3936
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache
4037
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl
4138
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
39+
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
4240
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER
4341
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.NAME_NOT_FOUND
4442
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil
@@ -266,13 +264,7 @@ class CallExpressionResolver(
266264
private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) =
267265
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) {
268266
nameExpression ->
269-
val temporaryForVariable = TemporaryTraceAndCache.create(
270-
context, "trace to resolve as local variable or property", nameExpression)
271-
val call = CallMaker.makePropertyCall(null, null, nameExpression)
272-
val contextForVariable = BasicCallResolutionContext.create(
273-
context.replaceTraceAndCache(temporaryForVariable),
274-
call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS)
275-
val resolutionResult = callResolver.resolveSimpleProperty(contextForVariable)
267+
val resolutionResult = resolveSimpleName(context, nameExpression)
276268

277269
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
278270
false
@@ -283,6 +275,17 @@ class CallExpressionResolver(
283275
}
284276
}
285277

278+
fun resolveSimpleName(
279+
context: ExpressionTypingContext, expression: KtSimpleNameExpression
280+
): OverloadResolutionResults<VariableDescriptor> {
281+
val temporaryForVariable = TemporaryTraceAndCache.create(context, "trace to resolve as local variable or property", expression)
282+
val call = CallMaker.makePropertyCall(null, null, expression)
283+
val contextForVariable = BasicCallResolutionContext.create(
284+
context.replaceTraceAndCache(temporaryForVariable), call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
285+
)
286+
return callResolver.resolveSimpleProperty(contextForVariable)
287+
}
288+
286289
private fun getUnsafeSelectorTypeInfo(
287290
receiver: Receiver,
288291
callOperationNode: ASTNode?,

compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
3333
import org.jetbrains.kotlin.diagnostics.Diagnostic;
3434
import org.jetbrains.kotlin.diagnostics.Errors;
35+
import org.jetbrains.kotlin.diagnostics.Severity;
3536
import org.jetbrains.kotlin.lexer.KtKeywordToken;
3637
import org.jetbrains.kotlin.lexer.KtTokens;
3738
import org.jetbrains.kotlin.name.Name;
@@ -41,9 +42,11 @@
4142
import org.jetbrains.kotlin.resolve.callableReferences.CallableReferencesResolutionUtilsKt;
4243
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
4344
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver;
45+
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
4446
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
4547
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
4648
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
49+
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
4750
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl;
4851
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
4952
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl;
@@ -58,6 +61,7 @@
5861
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
5962
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
6063
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
64+
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
6165
import org.jetbrains.kotlin.resolve.constants.*;
6266
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
6367
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
@@ -711,10 +715,79 @@ public KotlinTypeInfo visitCallableReferenceExpression(@NotNull KtCallableRefere
711715
return components.dataFlowAnalyzer.createCheckedTypeInfo(errorType, c, expression);
712716
}
713717

714-
KotlinType result = getCallableReferenceType(expression, receiverType, c);
718+
TemporaryBindingTrace trace = TemporaryBindingTrace.create(c.trace, "Callable reference type");
719+
KotlinType result = getCallableReferenceType(expression, receiverType, c.replaceBindingTrace(trace));
720+
boolean hasErrors = hasErrors(trace); // Do not inline this local variable (execution order is important)
721+
trace.commit();
722+
if (!hasErrors && result != null) {
723+
checkNoExpressionOnLHS(expression, c);
724+
}
715725
return components.dataFlowAnalyzer.createCheckedTypeInfo(result, c, expression);
716726
}
717727

728+
private static boolean hasErrors(TemporaryBindingTrace trace) {
729+
for (Diagnostic diagnostic : trace.getBindingContext().getDiagnostics().all()) {
730+
if (diagnostic.getSeverity() == Severity.ERROR) {
731+
return true;
732+
}
733+
}
734+
return false;
735+
}
736+
737+
private void checkNoExpressionOnLHS(@NotNull KtCallableReferenceExpression expression, @NotNull ExpressionTypingContext c) {
738+
KtTypeReference typeReference = expression.getTypeReference();
739+
if (typeReference == null) return;
740+
KtTypeElement typeElement = typeReference.getTypeElement();
741+
if (!(typeElement instanceof KtUserType)) return;
742+
743+
KtUserType userType = (KtUserType) typeElement;
744+
while (true) {
745+
if (userType.getTypeArgumentList() != null) return;
746+
KtUserType qualifier = userType.getQualifier();
747+
if (qualifier == null) break;
748+
userType = qualifier;
749+
}
750+
751+
KtSimpleNameExpression simpleNameExpression = userType.getReferenceExpression();
752+
if (simpleNameExpression == null) return;
753+
754+
TemporaryTraceAndCache traceAndCache =
755+
TemporaryTraceAndCache.create(c, "Resolve expression on LHS of callable reference", simpleNameExpression);
756+
OverloadResolutionResults<VariableDescriptor> resolutionResult =
757+
components.callExpressionResolver.resolveSimpleName(c.replaceTraceAndCache(traceAndCache), simpleNameExpression);
758+
759+
Collection<? extends ResolvedCall<VariableDescriptor>> resultingCalls =
760+
CollectionsKt.filter(resolutionResult.getResultingCalls(), new Function1<ResolvedCall<VariableDescriptor>, Boolean>() {
761+
@Override
762+
public Boolean invoke(ResolvedCall<VariableDescriptor> call) {
763+
return call.getStatus().possibleTransformToSuccess();
764+
}
765+
});
766+
767+
if (resultingCalls.isEmpty()) return;
768+
769+
if (resultingCalls.size() == 1 &&
770+
resultingCalls.iterator().next().getResultingDescriptor() instanceof FakeCallableDescriptorForObject) return;
771+
772+
ResolvedCall<?> originalResolvedCall = CallUtilKt.getResolvedCall(expression.getCallableReference(), c.trace.getBindingContext());
773+
CallableDescriptor originalResult = originalResolvedCall == null ? null : originalResolvedCall.getResultingDescriptor();
774+
775+
throw new AssertionError(String.format(
776+
"Expressions on left-hand side of callable reference are not supported yet.\n" +
777+
"Resolution result: %s\n" +
778+
"Original result: %s",
779+
CollectionsKt.map(
780+
resultingCalls, new Function1<ResolvedCall<VariableDescriptor>, VariableDescriptor>() {
781+
@Override
782+
public VariableDescriptor invoke(ResolvedCall<VariableDescriptor> call) {
783+
return call.getResultingDescriptor();
784+
}
785+
}
786+
),
787+
originalResult
788+
));
789+
}
790+
718791
@Override
719792
public KotlinTypeInfo visitObjectLiteralExpression(
720793
@NotNull final KtObjectLiteralExpression expression,

core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ public static boolean isNonCompanionObject(@NotNull DeclarationDescriptor descri
284284
return isKindOf(descriptor, ClassKind.OBJECT) && !((ClassDescriptor) descriptor).isCompanionObject();
285285
}
286286

287-
public static boolean isObject(@NotNull DeclarationDescriptor descriptor) {
287+
public static boolean isObject(@Nullable DeclarationDescriptor descriptor) {
288288
return isKindOf(descriptor, ClassKind.OBJECT);
289289
}
290290

0 commit comments

Comments
 (0)