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());
|
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?
|
// SCRIPT: is declaration in script?
|
||||||
public static boolean isScriptDeclaration(@NotNull JetDeclaration namedDeclaration) {
|
public static boolean isScriptDeclaration(@NotNull JetDeclaration namedDeclaration) {
|
||||||
return getScript(namedDeclaration) != null;
|
return getScript(namedDeclaration) != null;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
|||||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils
|
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils
|
||||||
import com.intellij.psi.PsiWhiteSpace
|
import com.intellij.psi.PsiWhiteSpace
|
||||||
import com.intellij.psi.PsiComment
|
import com.intellij.psi.PsiComment
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.CallTransformer.CallForImplicitInvoke
|
||||||
|
|
||||||
public fun JetCallElement.getCallNameExpression(): JetSimpleNameExpression? {
|
public fun JetCallElement.getCallNameExpression(): JetSimpleNameExpression? {
|
||||||
val calleeExpression = getCalleeExpression()
|
val calleeExpression = getCalleeExpression()
|
||||||
@@ -377,4 +378,16 @@ public fun PsiElement.nextLeafSkipWhitespacesAndComments(): PsiElement? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun JetExpression.isDotReceiver(): Boolean =
|
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));
|
context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
|
||||||
return checkArgumentTypesAndFail(context);
|
return checkArgumentTypesAndFail(context);
|
||||||
}
|
}
|
||||||
List<ResolutionCandidate<CallableDescriptor>> candidates = ResolutionCandidate.<CallableDescriptor>convertCollection(
|
List<ResolutionCandidate<CallableDescriptor>> candidates =
|
||||||
context.call, constructors, JetPsiUtil.isSafeCall(context.call));
|
ResolutionCandidate.<CallableDescriptor>convertCollection(context.call, constructors);
|
||||||
prioritizedTasks = Collections.singletonList(new ResolutionTask<CallableDescriptor, FunctionDescriptor>(candidates, functionReference, context)); // !! DataFlowInfo.EMPTY
|
prioritizedTasks = Collections.singletonList(new ResolutionTask<CallableDescriptor, FunctionDescriptor>(candidates, functionReference, context)); // !! DataFlowInfo.EMPTY
|
||||||
}
|
}
|
||||||
else if (calleeExpression != null) {
|
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.base.Function;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.intellij.lang.ASTNode;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
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();
|
boolean hasReceiver = candidate.getExtensionReceiver().exists();
|
||||||
Call variableCall = stripCallArguments(task.call);
|
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) {
|
if (!hasReceiver) {
|
||||||
CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
|
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);
|
return Collections.singleton(context);
|
||||||
}
|
}
|
||||||
CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
|
CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
|
||||||
@@ -116,11 +125,11 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
|||||||
|
|
||||||
Call variableCallWithoutReceiver = stripReceiver(variableCall);
|
Call variableCallWithoutReceiver = stripReceiver(variableCall);
|
||||||
ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
|
ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
|
||||||
variableCandidate.getCall(),
|
variableCallWithoutReceiver,
|
||||||
variableCandidate.getDescriptor(),
|
candidate.getDescriptor(),
|
||||||
variableCandidate.getDispatchReceiver(),
|
candidate.getDispatchReceiver(),
|
||||||
ReceiverValue.NO_RECEIVER,
|
ReceiverValue.NO_RECEIVER,
|
||||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false);
|
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
|
||||||
|
|
||||||
CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
|
CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
|
||||||
candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver());
|
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);
|
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) {
|
private Call stripCallArguments(@NotNull Call call) {
|
||||||
return new DelegatingCall(call) {
|
return new DelegatingCall(call) {
|
||||||
@Override
|
@Override
|
||||||
@@ -194,6 +189,12 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
|||||||
|
|
||||||
private Call stripReceiver(@NotNull Call variableCall) {
|
private Call stripReceiver(@NotNull Call variableCall) {
|
||||||
return new DelegatingCall(variableCall) {
|
return new DelegatingCall(variableCall) {
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public ASTNode getCallOperationNode() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public ReceiverValue getExplicitReceiver() {
|
public ReceiverValue getExplicitReceiver() {
|
||||||
@@ -250,10 +251,10 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static class CallForImplicitInvoke extends DelegatingCall {
|
public static class CallForImplicitInvoke extends DelegatingCall {
|
||||||
final Call outerCall;
|
private final Call outerCall;
|
||||||
final ReceiverValue explicitExtensionReceiver;
|
private final ReceiverValue explicitExtensionReceiver;
|
||||||
final ExpressionReceiver calleeExpressionAsDispatchReceiver;
|
private final ExpressionReceiver calleeExpressionAsDispatchReceiver;
|
||||||
final JetSimpleNameExpression fakeInvokeExpression;
|
private final JetSimpleNameExpression fakeInvokeExpression;
|
||||||
|
|
||||||
public CallForImplicitInvoke(
|
public CallForImplicitInvoke(
|
||||||
@NotNull ReceiverValue explicitExtensionReceiver,
|
@NotNull ReceiverValue explicitExtensionReceiver,
|
||||||
@@ -267,6 +268,15 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
|||||||
this.fakeInvokeExpression = (JetSimpleNameExpression) JetPsiFactory(call.getCallElement()).createExpression( "invoke");
|
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
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public ReceiverValue getExplicitReceiver() {
|
public ReceiverValue getExplicitReceiver() {
|
||||||
@@ -284,12 +294,6 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
|||||||
return fakeInvokeExpression;
|
return fakeInvokeExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public JetElement getCallElement() {
|
|
||||||
return outerCall.getCallElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public CallType getCallType() {
|
public CallType getCallType() {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
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.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.context.*;
|
import org.jetbrains.jet.lang.resolve.calls.context.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
|
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
|
||||||
@@ -583,7 +584,7 @@ public class CandidateResolver {
|
|||||||
D candidateDescriptor = candidateCall.getCandidateDescriptor();
|
D candidateDescriptor = candidateCall.getCandidateDescriptor();
|
||||||
if (TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters())) return SUCCESS;
|
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(
|
boolean isSubtypeBySmartCast = SmartCastUtils.isSubTypeBySmartCastIgnoringNullability(
|
||||||
receiverArgument, receiverParameter.getType(), context);
|
receiverArgument, receiverParameter.getType(), context);
|
||||||
if (!isSubtypeBySmartCast) {
|
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.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.Call;
|
import org.jetbrains.jet.lang.psi.Call;
|
||||||
import org.jetbrains.jet.lang.psi.ValueArgument;
|
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.DelegatingBindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
|
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
|
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.TypeProjection;
|
||||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
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.INCOMPLETE_TYPE_INFERENCE;
|
||||||
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.UNKNOWN_STATUS;
|
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 dispatchReceiver; // receiver object of a method
|
||||||
private final ReceiverValue extensionReceiver; // receiver of an extension function
|
private final ReceiverValue extensionReceiver; // receiver of an extension function
|
||||||
private final ExplicitReceiverKind explicitReceiverKind;
|
private final ExplicitReceiverKind explicitReceiverKind;
|
||||||
private final boolean isSafeCall;
|
|
||||||
|
|
||||||
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
|
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
|
||||||
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = 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.dispatchReceiver = candidate.getDispatchReceiver();
|
||||||
this.extensionReceiver = candidate.getExtensionReceiver();
|
this.extensionReceiver = candidate.getExtensionReceiver();
|
||||||
this.explicitReceiverKind = candidate.getExplicitReceiverKind();
|
this.explicitReceiverKind = candidate.getExplicitReceiverKind();
|
||||||
this.isSafeCall = candidate.isSafeCall();
|
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
this.tracing = tracing;
|
this.tracing = tracing;
|
||||||
this.dataFlowInfoForArguments = dataFlowInfoForArguments;
|
this.dataFlowInfoForArguments = dataFlowInfoForArguments;
|
||||||
@@ -285,7 +286,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSafeCall() {
|
public boolean isSafeCall() {
|
||||||
return isSafeCall;
|
return PsiUtilPackage.isSafeCall(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+7
-25
@@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve.calls.tasks;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.Call;
|
import org.jetbrains.jet.lang.psi.Call;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
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 dispatchReceiver; // receiver object of a method
|
||||||
private ReceiverValue extensionReceiver; // receiver of an extension function
|
private ReceiverValue extensionReceiver; // receiver of an extension function
|
||||||
private ExplicitReceiverKind explicitReceiverKind;
|
private ExplicitReceiverKind explicitReceiverKind;
|
||||||
private Boolean isSafeCall;
|
|
||||||
|
|
||||||
private ResolutionCandidate(
|
private ResolutionCandidate(
|
||||||
@NotNull Call call, @NotNull D descriptor, @NotNull ReceiverValue dispatchReceiver,
|
@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.call = call;
|
||||||
this.candidateDescriptor = descriptor;
|
this.candidateDescriptor = descriptor;
|
||||||
this.dispatchReceiver = dispatchReceiver;
|
this.dispatchReceiver = dispatchReceiver;
|
||||||
this.extensionReceiver = extensionReceiver;
|
this.extensionReceiver = extensionReceiver;
|
||||||
this.explicitReceiverKind = explicitReceiverKind;
|
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(
|
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(
|
public static <D extends CallableDescriptor> ResolutionCandidate<D> create(
|
||||||
@NotNull Call call, @NotNull D descriptor, @NotNull ReceiverValue dispatchReceiver,
|
@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) {
|
public void setDispatchReceiver(@NotNull ReceiverValue dispatchReceiver) {
|
||||||
@@ -105,25 +97,15 @@ public class ResolutionCandidate<D extends CallableDescriptor> {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static <D extends CallableDescriptor> List<ResolutionCandidate<D>> convertCollection(
|
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();
|
List<ResolutionCandidate<D>> result = Lists.newArrayList();
|
||||||
for (D descriptor : descriptors) {
|
for (D descriptor : descriptors) {
|
||||||
result.add(create(call, descriptor, isSafeCall));
|
result.add(create(call, descriptor));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSafeCall(boolean safeCall) {
|
|
||||||
assert isSafeCall == null;
|
|
||||||
isSafeCall = safeCall;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSafeCall() {
|
|
||||||
assert isSafeCall != null;
|
|
||||||
return isSafeCall;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return candidateDescriptor.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 priorityProvider: ResolutionTaskHolder.PriorityProvider<ResolutionCandidate<D>>,
|
||||||
private val tracing: TracingStrategy
|
private val tracing: TracingStrategy
|
||||||
) {
|
) {
|
||||||
private val isSafeCall = JetPsiUtil.isSafeCall(basicCallResolutionContext.call)
|
|
||||||
|
|
||||||
private val candidatesList = ArrayList<() -> Collection<ResolutionCandidate<D>>>()
|
private val candidatesList = ArrayList<() -> Collection<ResolutionCandidate<D>>>()
|
||||||
private var internalTasks: List<ResolutionTask<D, F>>? = null
|
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>>) {
|
public fun addCandidates(lazyCandidates: () -> Collection<ResolutionCandidate<D>>) {
|
||||||
assertNotFinished()
|
assertNotFinished()
|
||||||
candidatesList.add(storageManager.createLazyValue {
|
candidatesList.add(storageManager.createLazyValue { lazyCandidates().toReadOnlyList() })
|
||||||
setIsSafeCall(lazyCandidates()).toReadOnlyList()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun addCandidates(candidatesList: List<Collection<ResolutionCandidate<D>>>) {
|
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());
|
Call call = CallMaker.makeCall(expression, NO_RECEIVER, null, expression, Collections.<ValueArgument>emptyList());
|
||||||
ResolutionCandidate<ReceiverParameterDescriptor> resolutionCandidate =
|
ResolutionCandidate<ReceiverParameterDescriptor> resolutionCandidate =
|
||||||
ResolutionCandidate.create(
|
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<ReceiverParameterDescriptor> resolvedCall =
|
||||||
ResolvedCallImpl.create(resolutionCandidate,
|
ResolvedCallImpl.create(resolutionCandidate,
|
||||||
|
|||||||
+1
-1
@@ -72,7 +72,7 @@ public class ControlStructureTypingUtils {
|
|||||||
SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
|
SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
|
||||||
constructionName.toUpperCase(), argumentNames, isArgumentNullable);
|
constructionName.toUpperCase(), argumentNames, isArgumentNullable);
|
||||||
TracingStrategy tracing = createTracingForSpecialConstruction(call, constructionName);
|
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();
|
CallResolver callResolver = expressionTypingServices.getCallResolver();
|
||||||
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
|
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
|
||||||
call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
|
call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
class A {
|
||||||
|
val b = B()
|
||||||
|
}
|
||||||
|
class B
|
||||||
|
fun B.invoke(i: Int) = i
|
||||||
|
|
||||||
|
fun foo(i: Int) = i
|
||||||
|
|
||||||
|
fun test(a: A?) {
|
||||||
|
a?.b(1) //should be no warning
|
||||||
|
foo(<!TYPE_MISMATCH!>a?.b(1)<!>) //no warning, only error
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
DescriptorResolver@0 {
|
||||||
|
<name not found> = JetTypeImpl@1['Int']
|
||||||
|
<name not found> = JetTypeImpl@2['Int']
|
||||||
|
<name not found> = MutableClassDescriptor$1@3
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyJavaPackageFragmentProvider@4 {
|
||||||
|
packageFragments('<root>': FqName@5) = LazyJavaPackageFragment@6['<root>']
|
||||||
|
packageFragments('A': FqName@7) = null
|
||||||
|
packageFragments('B': FqName@8) = null
|
||||||
|
packageFragments('Int': FqName@9) = null
|
||||||
|
packageFragments('java': FqName@10) = LazyJavaPackageFragment@11['java']
|
||||||
|
packageFragments('java.lang': FqName@12) = LazyJavaPackageFragment@13['lang']
|
||||||
|
packageFragments('java.lang.A': FqName@14) = null
|
||||||
|
packageFragments('java.lang.B': FqName@15) = null
|
||||||
|
packageFragments('java.lang.Int': FqName@16) = null
|
||||||
|
packageFragments('kotlin': FqName@17) = null
|
||||||
|
packageFragments('kotlin.A': FqName@18) = null
|
||||||
|
packageFragments('kotlin.B': FqName@19) = null
|
||||||
|
packageFragments('kotlin.Int': FqName@20) = null
|
||||||
|
packageFragments('kotlin.io': FqName@21) = null
|
||||||
|
packageFragments('kotlin.jvm': FqName@22) = null
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyJavaPackageFragment@6['<root>'] {
|
||||||
|
classes('B': Name@23) = null // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
classes('Int': Name@25) = null // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
classes('b': Name@26) = null // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
classes('foo': Name@27) = null // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
classes('invoke': Name@28) = null // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
deserializedPackageScope = Empty@29 // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
functions('B': Name@23) = EmptyList@30[empty] // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
functions('b': Name@26) = EmptyList@30[empty] // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
functions('foo': Name@27) = EmptyList@30[empty] // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
functions('invoke': Name@28) = EmptyList@30[empty] // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
memberIndex = computeMemberIndex$1@31 // through LazyPackageFragmentScopeForJavaPackage@24
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyJavaPackageFragment@11['java'] {
|
||||||
|
classes('lang': Name@32) = null // through LazyPackageFragmentScopeForJavaPackage@33
|
||||||
|
deserializedPackageScope = Empty@29 // through LazyPackageFragmentScopeForJavaPackage@33
|
||||||
|
functions('lang': Name@34) = EmptyList@30[empty] // through LazyPackageFragmentScopeForJavaPackage@33
|
||||||
|
memberIndex = computeMemberIndex$1@35 // through LazyPackageFragmentScopeForJavaPackage@33
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyJavaPackageFragment@13['lang'] {
|
||||||
|
classes('B': Name@23) = null // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
classes('b': Name@26) = null // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
classes('foo': Name@27) = null // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
classes('invoke': Name@28) = null // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
deserializedPackageScope = Empty@29 // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
functions('B': Name@23) = EmptyList@30[empty] // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
functions('b': Name@26) = EmptyList@30[empty] // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
functions('foo': Name@27) = EmptyList@30[empty] // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
functions('invoke': Name@28) = EmptyList@30[empty] // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
memberIndex = computeMemberIndex$1@37 // through LazyPackageFragmentScopeForJavaPackage@36
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
internal fun foo(/*0*/ i: kotlin.Int): kotlin.Int
|
||||||
|
internal fun test(/*0*/ a: A?): kotlin.Unit
|
||||||
|
internal fun B.invoke(/*0*/ i: kotlin.Int): kotlin.Int
|
||||||
|
|
||||||
|
internal final class A {
|
||||||
|
public constructor A()
|
||||||
|
internal final val b: B
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
internal final class B {
|
||||||
|
public constructor B()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -7124,6 +7124,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("safeCallWithInvoke.kt")
|
||||||
|
public void testSafeCallWithInvoke() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/nullableTypes/safeCallWithInvoke.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("uselessElvis.kt")
|
@TestMetadata("uselessElvis.kt")
|
||||||
public void testUselessElvis() throws Exception {
|
public void testUselessElvis() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/nullableTypes/uselessElvis.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/nullableTypes/uselessElvis.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user