Assert that callable references cannot have expression on LHS
This commit is contained in:
+14
-11
@@ -20,10 +20,7 @@ import com.intellij.lang.ASTNode
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
@@ -39,6 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.NAME_NOT_FOUND
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil
|
||||
@@ -266,13 +264,7 @@ class CallExpressionResolver(
|
||||
private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) =
|
||||
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) {
|
||||
nameExpression ->
|
||||
val temporaryForVariable = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve as local variable or property", nameExpression)
|
||||
val call = CallMaker.makePropertyCall(null, null, nameExpression)
|
||||
val contextForVariable = BasicCallResolutionContext.create(
|
||||
context.replaceTraceAndCache(temporaryForVariable),
|
||||
call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS)
|
||||
val resolutionResult = callResolver.resolveSimpleProperty(contextForVariable)
|
||||
val resolutionResult = resolveSimpleName(context, nameExpression)
|
||||
|
||||
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
|
||||
false
|
||||
@@ -283,6 +275,17 @@ class CallExpressionResolver(
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveSimpleName(
|
||||
context: ExpressionTypingContext, expression: KtSimpleNameExpression
|
||||
): OverloadResolutionResults<VariableDescriptor> {
|
||||
val temporaryForVariable = TemporaryTraceAndCache.create(context, "trace to resolve as local variable or property", expression)
|
||||
val call = CallMaker.makePropertyCall(null, null, expression)
|
||||
val contextForVariable = BasicCallResolutionContext.create(
|
||||
context.replaceTraceAndCache(temporaryForVariable), call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
|
||||
)
|
||||
return callResolver.resolveSimpleProperty(contextForVariable)
|
||||
}
|
||||
|
||||
private fun getUnsafeSelectorTypeInfo(
|
||||
receiver: Receiver,
|
||||
callOperationNode: ASTNode?,
|
||||
|
||||
+74
-1
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.diagnostics.Severity;
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
@@ -41,9 +42,11 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.callableReferences.CallableReferencesResolutionUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
|
||||
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl;
|
||||
@@ -58,6 +61,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
|
||||
import org.jetbrains.kotlin.resolve.constants.*;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
||||
@@ -711,10 +715,79 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
return components.dataFlowAnalyzer.createCheckedTypeInfo(errorType, c, expression);
|
||||
}
|
||||
|
||||
KotlinType result = getCallableReferenceType(expression, receiverType, c);
|
||||
TemporaryBindingTrace trace = TemporaryBindingTrace.create(c.trace, "Callable reference type");
|
||||
KotlinType result = getCallableReferenceType(expression, receiverType, c.replaceBindingTrace(trace));
|
||||
boolean hasErrors = hasErrors(trace); // Do not inline this local variable (execution order is important)
|
||||
trace.commit();
|
||||
if (!hasErrors && result != null) {
|
||||
checkNoExpressionOnLHS(expression, c);
|
||||
}
|
||||
return components.dataFlowAnalyzer.createCheckedTypeInfo(result, c, expression);
|
||||
}
|
||||
|
||||
private static boolean hasErrors(TemporaryBindingTrace trace) {
|
||||
for (Diagnostic diagnostic : trace.getBindingContext().getDiagnostics().all()) {
|
||||
if (diagnostic.getSeverity() == Severity.ERROR) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkNoExpressionOnLHS(@NotNull KtCallableReferenceExpression expression, @NotNull ExpressionTypingContext c) {
|
||||
KtTypeReference typeReference = expression.getTypeReference();
|
||||
if (typeReference == null) return;
|
||||
KtTypeElement typeElement = typeReference.getTypeElement();
|
||||
if (!(typeElement instanceof KtUserType)) return;
|
||||
|
||||
KtUserType userType = (KtUserType) typeElement;
|
||||
while (true) {
|
||||
if (userType.getTypeArgumentList() != null) return;
|
||||
KtUserType qualifier = userType.getQualifier();
|
||||
if (qualifier == null) break;
|
||||
userType = qualifier;
|
||||
}
|
||||
|
||||
KtSimpleNameExpression simpleNameExpression = userType.getReferenceExpression();
|
||||
if (simpleNameExpression == null) return;
|
||||
|
||||
TemporaryTraceAndCache traceAndCache =
|
||||
TemporaryTraceAndCache.create(c, "Resolve expression on LHS of callable reference", simpleNameExpression);
|
||||
OverloadResolutionResults<VariableDescriptor> resolutionResult =
|
||||
components.callExpressionResolver.resolveSimpleName(c.replaceTraceAndCache(traceAndCache), simpleNameExpression);
|
||||
|
||||
Collection<? extends ResolvedCall<VariableDescriptor>> resultingCalls =
|
||||
CollectionsKt.filter(resolutionResult.getResultingCalls(), new Function1<ResolvedCall<VariableDescriptor>, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(ResolvedCall<VariableDescriptor> call) {
|
||||
return call.getStatus().possibleTransformToSuccess();
|
||||
}
|
||||
});
|
||||
|
||||
if (resultingCalls.isEmpty()) return;
|
||||
|
||||
if (resultingCalls.size() == 1 &&
|
||||
resultingCalls.iterator().next().getResultingDescriptor() instanceof FakeCallableDescriptorForObject) return;
|
||||
|
||||
ResolvedCall<?> originalResolvedCall = CallUtilKt.getResolvedCall(expression.getCallableReference(), c.trace.getBindingContext());
|
||||
CallableDescriptor originalResult = originalResolvedCall == null ? null : originalResolvedCall.getResultingDescriptor();
|
||||
|
||||
throw new AssertionError(String.format(
|
||||
"Expressions on left-hand side of callable reference are not supported yet.\n" +
|
||||
"Resolution result: %s\n" +
|
||||
"Original result: %s",
|
||||
CollectionsKt.map(
|
||||
resultingCalls, new Function1<ResolvedCall<VariableDescriptor>, VariableDescriptor>() {
|
||||
@Override
|
||||
public VariableDescriptor invoke(ResolvedCall<VariableDescriptor> call) {
|
||||
return call.getResultingDescriptor();
|
||||
}
|
||||
}
|
||||
),
|
||||
originalResult
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public KotlinTypeInfo visitObjectLiteralExpression(
|
||||
@NotNull final KtObjectLiteralExpression expression,
|
||||
|
||||
@@ -284,7 +284,7 @@ public class DescriptorUtils {
|
||||
return isKindOf(descriptor, ClassKind.OBJECT) && !((ClassDescriptor) descriptor).isCompanionObject();
|
||||
}
|
||||
|
||||
public static boolean isObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
public static boolean isObject(@Nullable DeclarationDescriptor descriptor) {
|
||||
return isKindOf(descriptor, ClassKind.OBJECT);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user