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.PsiElement
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
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.context.TemporaryTraceAndCache
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl
|
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
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.CANDIDATES_WITH_WRONG_RECEIVER
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.NAME_NOT_FOUND
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.NAME_NOT_FOUND
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil
|
||||||
@@ -266,13 +264,7 @@ class CallExpressionResolver(
|
|||||||
private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) =
|
private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) =
|
||||||
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) {
|
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) {
|
||||||
nameExpression ->
|
nameExpression ->
|
||||||
val temporaryForVariable = TemporaryTraceAndCache.create(
|
val resolutionResult = resolveSimpleName(context, nameExpression)
|
||||||
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)
|
|
||||||
|
|
||||||
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
|
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
|
||||||
false
|
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(
|
private fun getUnsafeSelectorTypeInfo(
|
||||||
receiver: Receiver,
|
receiver: Receiver,
|
||||||
callOperationNode: ASTNode?,
|
callOperationNode: ASTNode?,
|
||||||
|
|||||||
+74
-1
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.descriptors.*;
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Severity;
|
||||||
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
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.callableReferences.CallableReferencesResolutionUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
|
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver;
|
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.checkers.CallChecker;
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
|
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
|
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.DataFlowInfoForArgumentsImpl;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl;
|
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.ResolutionCandidate;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
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.constants.*;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
||||||
@@ -711,10 +715,79 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return components.dataFlowAnalyzer.createCheckedTypeInfo(errorType, c, expression);
|
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);
|
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
|
@Override
|
||||||
public KotlinTypeInfo visitObjectLiteralExpression(
|
public KotlinTypeInfo visitObjectLiteralExpression(
|
||||||
@NotNull final KtObjectLiteralExpression expression,
|
@NotNull final KtObjectLiteralExpression expression,
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ public class DescriptorUtils {
|
|||||||
return isKindOf(descriptor, ClassKind.OBJECT) && !((ClassDescriptor) descriptor).isCompanionObject();
|
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);
|
return isKindOf(descriptor, ClassKind.OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user