Set the right call operation node for implicit invoke
Make a call for implicit invoke safe if an outer call is safe
This commit is contained in:
@@ -336,11 +336,6 @@ public class JetPsiUtil {
|
||||
return KotlinBuiltIns.getInstance().getUnit().getName().asString().equals(typeReference.getText());
|
||||
}
|
||||
|
||||
public static boolean isSafeCall(@NotNull Call call) {
|
||||
ASTNode callOperationNode = call.getCallOperationNode();
|
||||
return callOperationNode != null && callOperationNode.getElementType() == JetTokens.SAFE_ACCESS;
|
||||
}
|
||||
|
||||
// SCRIPT: is declaration in script?
|
||||
public static boolean isScriptDeclaration(@NotNull JetDeclaration namedDeclaration) {
|
||||
return getScript(namedDeclaration) != null;
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.psi.PsiComment
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallTransformer.CallForImplicitInvoke
|
||||
|
||||
public fun JetCallElement.getCallNameExpression(): JetSimpleNameExpression? {
|
||||
val calleeExpression = getCalleeExpression()
|
||||
@@ -377,4 +378,16 @@ public fun PsiElement.nextLeafSkipWhitespacesAndComments(): PsiElement? {
|
||||
}
|
||||
|
||||
public fun JetExpression.isDotReceiver(): Boolean =
|
||||
(getParent() as? JetDotQualifiedExpression)?.getReceiverExpression() == this
|
||||
(getParent() as? JetDotQualifiedExpression)?.getReceiverExpression() == this
|
||||
|
||||
public fun Call.isSafeCall(): Boolean {
|
||||
if (this is CallForImplicitInvoke) {
|
||||
//implicit safe 'invoke'
|
||||
if (getOuterCall().isExplicitSafeCall()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return isExplicitSafeCall()
|
||||
}
|
||||
|
||||
public fun Call.isExplicitSafeCall(): Boolean = getCallOperationNode()?.getElementType() == JetTokens.SAFE_ACCESS
|
||||
|
||||
@@ -287,8 +287,8 @@ public class CallResolver {
|
||||
context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
|
||||
return checkArgumentTypesAndFail(context);
|
||||
}
|
||||
List<ResolutionCandidate<CallableDescriptor>> candidates = ResolutionCandidate.<CallableDescriptor>convertCollection(
|
||||
context.call, constructors, JetPsiUtil.isSafeCall(context.call));
|
||||
List<ResolutionCandidate<CallableDescriptor>> candidates =
|
||||
ResolutionCandidate.<CallableDescriptor>convertCollection(context.call, constructors);
|
||||
prioritizedTasks = Collections.singletonList(new ResolutionTask<CallableDescriptor, FunctionDescriptor>(candidates, functionReference, context)); // !! DataFlowInfo.EMPTY
|
||||
}
|
||||
else if (calleeExpression != null) {
|
||||
|
||||
@@ -19,7 +19,9 @@ package org.jetbrains.jet.lang.resolve.calls;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
@@ -105,10 +107,17 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
|
||||
boolean hasReceiver = candidate.getExtensionReceiver().exists();
|
||||
Call variableCall = stripCallArguments(task.call);
|
||||
ResolutionCandidate<CallableDescriptor> variableCandidate = getVariableCallCandidate(candidate, variableCall);
|
||||
ResolutionCandidate<CallableDescriptor> variableCandidate = ResolutionCandidate.create(
|
||||
variableCall,
|
||||
candidate.getDescriptor(),
|
||||
candidate.getDispatchReceiver(),
|
||||
candidate.getExtensionReceiver(),
|
||||
candidate.getExplicitReceiverKind()
|
||||
);
|
||||
if (!hasReceiver) {
|
||||
CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
|
||||
ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments), task, candidateTrace, task.tracing, variableCall);
|
||||
ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments),
|
||||
task, candidateTrace, task.tracing, variableCall);
|
||||
return Collections.singleton(context);
|
||||
}
|
||||
CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
|
||||
@@ -116,11 +125,11 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
|
||||
Call variableCallWithoutReceiver = stripReceiver(variableCall);
|
||||
ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
|
||||
variableCandidate.getCall(),
|
||||
variableCandidate.getDescriptor(),
|
||||
variableCandidate.getDispatchReceiver(),
|
||||
variableCallWithoutReceiver,
|
||||
candidate.getDescriptor(),
|
||||
candidate.getDispatchReceiver(),
|
||||
ReceiverValue.NO_RECEIVER,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false);
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
|
||||
|
||||
CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
|
||||
candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver());
|
||||
@@ -137,20 +146,6 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ResolutionCandidate<CallableDescriptor> getVariableCallCandidate(
|
||||
@NotNull ResolutionCandidate<CallableDescriptor> candidate,
|
||||
@NotNull Call variableCall
|
||||
) {
|
||||
return ResolutionCandidate.create(
|
||||
variableCall,
|
||||
candidate.getDescriptor(),
|
||||
candidate.getDispatchReceiver(),
|
||||
candidate.getExtensionReceiver(),
|
||||
candidate.getExplicitReceiverKind(),
|
||||
candidate.isSafeCall());
|
||||
}
|
||||
|
||||
private Call stripCallArguments(@NotNull Call call) {
|
||||
return new DelegatingCall(call) {
|
||||
@Override
|
||||
@@ -194,6 +189,12 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
|
||||
private Call stripReceiver(@NotNull Call variableCall) {
|
||||
return new DelegatingCall(variableCall) {
|
||||
@Nullable
|
||||
@Override
|
||||
public ASTNode getCallOperationNode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ReceiverValue getExplicitReceiver() {
|
||||
@@ -250,10 +251,10 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
};
|
||||
|
||||
public static class CallForImplicitInvoke extends DelegatingCall {
|
||||
final Call outerCall;
|
||||
final ReceiverValue explicitExtensionReceiver;
|
||||
final ExpressionReceiver calleeExpressionAsDispatchReceiver;
|
||||
final JetSimpleNameExpression fakeInvokeExpression;
|
||||
private final Call outerCall;
|
||||
private final ReceiverValue explicitExtensionReceiver;
|
||||
private final ExpressionReceiver calleeExpressionAsDispatchReceiver;
|
||||
private final JetSimpleNameExpression fakeInvokeExpression;
|
||||
|
||||
public CallForImplicitInvoke(
|
||||
@NotNull ReceiverValue explicitExtensionReceiver,
|
||||
@@ -267,6 +268,15 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
this.fakeInvokeExpression = (JetSimpleNameExpression) JetPsiFactory(call.getCallElement()).createExpression( "invoke");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ASTNode getCallOperationNode() {
|
||||
// if an explicit receiver corresponds to the implicit invoke, there is a corresponding call operation node:
|
||||
// a.b() or a?.b() (where b has an extension function type);
|
||||
// otherwise it's implicit
|
||||
return explicitExtensionReceiver.exists() ? super.getCallOperationNode() : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ReceiverValue getExplicitReceiver() {
|
||||
@@ -284,12 +294,6 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
return fakeInvokeExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetElement getCallElement() {
|
||||
return outerCall.getCallElement();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CallType getCallType() {
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
|
||||
@@ -583,7 +584,7 @@ public class CandidateResolver {
|
||||
D candidateDescriptor = candidateCall.getCandidateDescriptor();
|
||||
if (TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters())) return SUCCESS;
|
||||
|
||||
boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall();
|
||||
boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && PsiUtilPackage.isExplicitSafeCall(candidateCall.getCall());
|
||||
boolean isSubtypeBySmartCast = SmartCastUtils.isSubTypeBySmartCastIgnoringNullability(
|
||||
receiverArgument, receiverParameter.getType(), context);
|
||||
if (!isSubtypeBySmartCast) {
|
||||
|
||||
+5
-4
@@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.Call;
|
||||
import org.jetbrains.jet.lang.psi.ValueArgument;
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
|
||||
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
|
||||
@@ -37,7 +38,9 @@ import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.UNKNOWN_STATUS;
|
||||
@@ -74,7 +77,6 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
||||
private final ReceiverValue dispatchReceiver; // receiver object of a method
|
||||
private final ReceiverValue extensionReceiver; // receiver of an extension function
|
||||
private final ExplicitReceiverKind explicitReceiverKind;
|
||||
private final boolean isSafeCall;
|
||||
|
||||
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
|
||||
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newLinkedHashMap();
|
||||
@@ -99,7 +101,6 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
||||
this.dispatchReceiver = candidate.getDispatchReceiver();
|
||||
this.extensionReceiver = candidate.getExtensionReceiver();
|
||||
this.explicitReceiverKind = candidate.getExplicitReceiverKind();
|
||||
this.isSafeCall = candidate.isSafeCall();
|
||||
this.trace = trace;
|
||||
this.tracing = tracing;
|
||||
this.dataFlowInfoForArguments = dataFlowInfoForArguments;
|
||||
@@ -285,7 +286,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
||||
|
||||
@Override
|
||||
public boolean isSafeCall() {
|
||||
return isSafeCall;
|
||||
return PsiUtilPackage.isSafeCall(call);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+7
-25
@@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve.calls.tasks;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.Call;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
@@ -34,36 +33,29 @@ public class ResolutionCandidate<D extends CallableDescriptor> {
|
||||
private ReceiverValue dispatchReceiver; // receiver object of a method
|
||||
private ReceiverValue extensionReceiver; // receiver of an extension function
|
||||
private ExplicitReceiverKind explicitReceiverKind;
|
||||
private Boolean isSafeCall;
|
||||
|
||||
private ResolutionCandidate(
|
||||
@NotNull Call call, @NotNull D descriptor, @NotNull ReceiverValue dispatchReceiver,
|
||||
@NotNull ReceiverValue extensionReceiver, @NotNull ExplicitReceiverKind explicitReceiverKind, @Nullable Boolean isSafeCall
|
||||
@NotNull ReceiverValue extensionReceiver, @NotNull ExplicitReceiverKind explicitReceiverKind
|
||||
) {
|
||||
this.call = call;
|
||||
this.candidateDescriptor = descriptor;
|
||||
this.dispatchReceiver = dispatchReceiver;
|
||||
this.extensionReceiver = extensionReceiver;
|
||||
this.explicitReceiverKind = explicitReceiverKind;
|
||||
this.isSafeCall = isSafeCall;
|
||||
}
|
||||
|
||||
/*package*/ static <D extends CallableDescriptor> ResolutionCandidate<D> create(@NotNull Call call, @NotNull D descriptor) {
|
||||
return new ResolutionCandidate<D>(call, descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
|
||||
}
|
||||
|
||||
/* 'null' for isSafeCall parameter if it should be set later (with 'setSafeCall') */
|
||||
public static <D extends CallableDescriptor> ResolutionCandidate<D> create(
|
||||
@NotNull Call call, @NotNull D descriptor, @Nullable Boolean isSafeCall
|
||||
@NotNull Call call, @NotNull D descriptor
|
||||
) {
|
||||
return new ResolutionCandidate<D>(call, descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, isSafeCall);
|
||||
return new ResolutionCandidate<D>(call, descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
|
||||
}
|
||||
|
||||
public static <D extends CallableDescriptor> ResolutionCandidate<D> create(
|
||||
@NotNull Call call, @NotNull D descriptor, @NotNull ReceiverValue dispatchReceiver,
|
||||
@NotNull ReceiverValue receiverArgument, @NotNull ExplicitReceiverKind explicitReceiverKind, boolean isSafeCall
|
||||
@NotNull ReceiverValue receiverArgument, @NotNull ExplicitReceiverKind explicitReceiverKind
|
||||
) {
|
||||
return new ResolutionCandidate<D>(call, descriptor, dispatchReceiver, receiverArgument, explicitReceiverKind, isSafeCall);
|
||||
return new ResolutionCandidate<D>(call, descriptor, dispatchReceiver, receiverArgument, explicitReceiverKind);
|
||||
}
|
||||
|
||||
public void setDispatchReceiver(@NotNull ReceiverValue dispatchReceiver) {
|
||||
@@ -105,25 +97,15 @@ public class ResolutionCandidate<D extends CallableDescriptor> {
|
||||
|
||||
@NotNull
|
||||
public static <D extends CallableDescriptor> List<ResolutionCandidate<D>> convertCollection(
|
||||
@NotNull Call call, @NotNull Collection<? extends D> descriptors, boolean isSafeCall
|
||||
@NotNull Call call, @NotNull Collection<? extends D> descriptors
|
||||
) {
|
||||
List<ResolutionCandidate<D>> result = Lists.newArrayList();
|
||||
for (D descriptor : descriptors) {
|
||||
result.add(create(call, descriptor, isSafeCall));
|
||||
result.add(create(call, descriptor));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setSafeCall(boolean safeCall) {
|
||||
assert isSafeCall == null;
|
||||
isSafeCall = safeCall;
|
||||
}
|
||||
|
||||
public boolean isSafeCall() {
|
||||
assert isSafeCall != null;
|
||||
return isSafeCall;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return candidateDescriptor.toString();
|
||||
|
||||
+1
-12
@@ -29,23 +29,12 @@ public class ResolutionTaskHolder<D : CallableDescriptor, F : D>(
|
||||
private val priorityProvider: ResolutionTaskHolder.PriorityProvider<ResolutionCandidate<D>>,
|
||||
private val tracing: TracingStrategy
|
||||
) {
|
||||
private val isSafeCall = JetPsiUtil.isSafeCall(basicCallResolutionContext.call)
|
||||
|
||||
private val candidatesList = ArrayList<() -> Collection<ResolutionCandidate<D>>>()
|
||||
private var internalTasks: List<ResolutionTask<D, F>>? = null
|
||||
|
||||
public fun setIsSafeCall(candidates: Collection<ResolutionCandidate<D>>): Collection<ResolutionCandidate<D>> {
|
||||
for (candidate in candidates) {
|
||||
candidate.setSafeCall(isSafeCall)
|
||||
}
|
||||
return candidates
|
||||
}
|
||||
|
||||
public fun addCandidates(lazyCandidates: () -> Collection<ResolutionCandidate<D>>) {
|
||||
assertNotFinished()
|
||||
candidatesList.add(storageManager.createLazyValue {
|
||||
setIsSafeCall(lazyCandidates()).toReadOnlyList()
|
||||
})
|
||||
candidatesList.add(storageManager.createLazyValue { lazyCandidates().toReadOnlyList() })
|
||||
}
|
||||
|
||||
public fun addCandidates(candidatesList: List<Collection<ResolutionCandidate<D>>>) {
|
||||
|
||||
+1
-1
@@ -420,7 +420,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
Call call = CallMaker.makeCall(expression, NO_RECEIVER, null, expression, Collections.<ValueArgument>emptyList());
|
||||
ResolutionCandidate<ReceiverParameterDescriptor> resolutionCandidate =
|
||||
ResolutionCandidate.create(
|
||||
call, descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false);
|
||||
call, descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
|
||||
|
||||
ResolvedCallImpl<ReceiverParameterDescriptor> resolvedCall =
|
||||
ResolvedCallImpl.create(resolutionCandidate,
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ public class ControlStructureTypingUtils {
|
||||
SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
|
||||
constructionName.toUpperCase(), argumentNames, isArgumentNullable);
|
||||
TracingStrategy tracing = createTracingForSpecialConstruction(call, constructionName);
|
||||
ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(call, function, null);
|
||||
ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(call, function);
|
||||
CallResolver callResolver = expressionTypingServices.getCallResolver();
|
||||
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
|
||||
call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
|
||||
|
||||
Reference in New Issue
Block a user