Resolve invoke on any kind of expressions, not only on simple name expressions
This commit is contained in:
@@ -23,7 +23,6 @@ import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
@@ -38,8 +37,6 @@ import org.jetbrains.jet.lang.resolve.calls.results.ResolutionResultsHandler;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.JetFakeReference;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
@@ -48,7 +45,6 @@ import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
|
||||
import org.jetbrains.jet.lang.types.expressions.LabelResolver;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -57,7 +53,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLUTION_SCOPE;
|
||||
@@ -285,31 +280,20 @@ public class CallResolver {
|
||||
prioritizedTasks = Collections.singletonList(new ResolutionTask<CallableDescriptor, FunctionDescriptor>(candidates, functionReference, context)); // !! DataFlowInfo.EMPTY
|
||||
}
|
||||
else if (calleeExpression != null) {
|
||||
|
||||
// Here we handle the case where the callee expression must be something of type function, e.g. (foo.bar())(1, 2)
|
||||
JetType calleeType = expressionTypingServices.safeGetType(context.scope, calleeExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); // We are actually expecting a function, but there seems to be no easy way of expressing this
|
||||
ExpressionReceiver expressionReceiver = new ExpressionReceiver(calleeExpression, calleeType);
|
||||
|
||||
if (!KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(calleeType)) {
|
||||
// checkTypesWithNoCallee(trace, scope, call);
|
||||
if (!calleeType.isError()) {
|
||||
context.trace.report(CALLEE_NOT_A_FUNCTION.on(calleeExpression, calleeType));
|
||||
}
|
||||
return checkArgumentTypesAndFail(context);
|
||||
Call call = new CallTransformer.CallForImplicitInvoke(
|
||||
context.call.getExplicitReceiver(), expressionReceiver, context.call);
|
||||
TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke(calleeExpression, call);
|
||||
OverloadResolutionResults<FunctionDescriptor> invokeResults =
|
||||
resolveCallForInvoke(context.replaceCall(call), tracingForInvoke);
|
||||
if (invokeResults.isNothing() || invokeResults.getResultCode() == CANDIDATES_WITH_WRONG_RECEIVER) {
|
||||
context.trace.report(CALLEE_NOT_A_FUNCTION.on(calleeExpression, calleeType));
|
||||
}
|
||||
|
||||
FunctionDescriptorImpl functionDescriptor = new ExpressionAsFunctionDescriptor(context.scope.getContainingDeclaration(), Name.special("<for expression " + calleeExpression.getText() + ">"), calleeExpression);
|
||||
FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType, NO_RECEIVER_PARAMETER, Modality.FINAL,
|
||||
Visibilities.LOCAL);
|
||||
ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(functionDescriptor, JetPsiUtil.isSafeCall(context.call));
|
||||
resolutionCandidate.setReceiverArgument(context.call.getExplicitReceiver());
|
||||
resolutionCandidate.setExplicitReceiverKind(ExplicitReceiverKind.RECEIVER_ARGUMENT);
|
||||
|
||||
// strictly speaking, this is a hack:
|
||||
// we need to pass a reference, but there's no reference in the PSI,
|
||||
// so we wrap what we have into a fake reference and pass it on (unwrap on the other end)
|
||||
functionReference = new JetFakeReference(calleeExpression);
|
||||
|
||||
prioritizedTasks = Collections.singletonList(new ResolutionTask<CallableDescriptor, FunctionDescriptor>(
|
||||
Collections.singleton(resolutionCandidate), functionReference, context));
|
||||
return (OverloadResolutionResultsImpl<FunctionDescriptor>) invokeResults; //todo
|
||||
}
|
||||
else {
|
||||
// checkTypesWithNoCallee(trace, scope, call);
|
||||
@@ -486,7 +470,9 @@ public class CallResolver {
|
||||
@NotNull TracingStrategy tracing
|
||||
) {
|
||||
ResolutionDebugInfo.Data debugInfo = ResolutionDebugInfo.create();
|
||||
context.trace.record(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement(), debugInfo);
|
||||
if (context.call.getCallType() != Call.CallType.INVOKE) {
|
||||
context.trace.record(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement(), debugInfo);
|
||||
}
|
||||
context.trace.record(RESOLUTION_SCOPE, context.call.getCalleeExpression(), context.scope);
|
||||
|
||||
if (context.dataFlowInfo.hasTypeInfoConstraints()) {
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImp
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategyForInvoke;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
@@ -205,8 +206,9 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
functionCall, context.checkArguments, context.dataFlowInfoForArguments);
|
||||
|
||||
// 'invoke' call resolve
|
||||
TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke(calleeExpression, functionCall);
|
||||
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallForInvoke(
|
||||
basicCallResolutionContext, context.tracing); //todo context.tracing is incorrect
|
||||
basicCallResolutionContext, tracingForInvoke);
|
||||
Collection<ResolvedCallWithTrace<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
|
||||
|
||||
return Collections2.transform(calls, new Function<ResolvedCallWithTrace<FunctionDescriptor>, ResolvedCallWithTrace<FunctionDescriptor>>() {
|
||||
@@ -224,7 +226,7 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
final ExpressionReceiver calleeExpressionAsThisObject;
|
||||
final JetSimpleNameExpression fakeInvokeExpression;
|
||||
|
||||
private CallForImplicitInvoke(
|
||||
public CallForImplicitInvoke(
|
||||
@NotNull ReceiverValue explicitExtensionReceiver,
|
||||
@NotNull ExpressionReceiver calleeExpressionAsThisObject,
|
||||
@NotNull Call call
|
||||
@@ -256,14 +258,7 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getCallElement() {
|
||||
if (outerCall.getCallElement() instanceof JetCallElement) {
|
||||
//to report errors properly
|
||||
JetValueArgumentList list = ((JetCallElement)outerCall.getCallElement()).getValueArgumentList();
|
||||
if (list != null) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
return fakeInvokeExpression;
|
||||
return outerCall.getCallElement();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+5
@@ -90,4 +90,9 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
|
||||
return create(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
|
||||
labelResolver, dataFlowInfoForArguments, callResolverExtension, isAnnotationContext);
|
||||
}
|
||||
|
||||
public BasicCallResolutionContext replaceCall(@NotNull Call newCall) {
|
||||
return create(trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
|
||||
labelResolver, dataFlowInfoForArguments, callResolverExtension, isAnnotationContext);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ public class ResolutionResultsCacheImpl implements ResolutionResultsCache {
|
||||
@NotNull WritableSlice<CallKey, T> slice
|
||||
) {
|
||||
if (expression == null) return null;
|
||||
for (CallType callType : Lists.newArrayList(DEFAULT, ARRAY_GET_METHOD, ARRAY_SET_METHOD)) {
|
||||
for (CallType callType : Lists.newArrayList(DEFAULT, ARRAY_GET_METHOD, ARRAY_SET_METHOD, INVOKE)) {
|
||||
CallKey callKey = CallKey.create(callType, expression);
|
||||
T context = trace.get(slice, callKey);
|
||||
if (context != null) {
|
||||
|
||||
+1
-6
@@ -46,7 +46,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
|
||||
|
||||
public abstract class AbstractTracingStrategy implements TracingStrategy {
|
||||
private final JetExpression reference;
|
||||
protected final JetExpression reference;
|
||||
protected final Call call;
|
||||
|
||||
protected AbstractTracingStrategy(@NotNull JetExpression reference, @NotNull Call call) {
|
||||
@@ -63,11 +63,6 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
|
||||
trace.record(AMBIGUOUS_REFERENCE_TARGET, reference, descriptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates) {
|
||||
trace.report(UNRESOLVED_REFERENCE_WRONG_RECEIVER.on(reference, candidates));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) {
|
||||
JetElement reportOn;
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.calls.tasks;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.Call;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.CALL;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
|
||||
|
||||
public class TracingStrategyForInvoke extends AbstractTracingStrategy {
|
||||
public TracingStrategyForInvoke(
|
||||
@NotNull JetExpression reference,
|
||||
@NotNull Call call
|
||||
) {
|
||||
super(reference, call);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <D extends CallableDescriptor> void bindReference(
|
||||
@NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall
|
||||
) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <D extends CallableDescriptor> void bindResolvedCall(
|
||||
@NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall
|
||||
) {
|
||||
trace.record(RESOLVED_CALL, reference, resolvedCall);
|
||||
trace.record(CALL, reference, call);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unresolvedReference(@NotNull BindingTrace trace) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(
|
||||
@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates
|
||||
) {
|
||||
}
|
||||
}
|
||||
+8
@@ -26,7 +26,10 @@ import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.UNRESOLVED_REFERENCE;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
|
||||
public class TracingStrategyImpl extends AbstractTracingStrategy {
|
||||
@@ -64,4 +67,9 @@ public class TracingStrategyImpl extends AbstractTracingStrategy {
|
||||
public void unresolvedReference(@NotNull BindingTrace trace) {
|
||||
trace.report(UNRESOLVED_REFERENCE.on(reference, reference));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates) {
|
||||
trace.report(UNRESOLVED_REFERENCE_WRONG_RECEIVER.on(reference, candidates));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.calls.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class is used to wrap an expression that occurs in a reference position, such as a function literal, into a reference expression
|
||||
*/
|
||||
public class JetFakeReference extends JetReferenceExpression {
|
||||
private final JetElement actualElement;
|
||||
|
||||
public JetFakeReference(@NotNull JetElement actualElement) {
|
||||
super(actualElement.getNode());
|
||||
this.actualElement = actualElement;
|
||||
}
|
||||
|
||||
public JetElement getActualElement() {
|
||||
return actualElement;
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,11 @@ L0:
|
||||
r(11)
|
||||
call(array[11], get)
|
||||
r(3)
|
||||
call(array[11], <for expression array[11]>)
|
||||
call(array[11], invoke)
|
||||
L1:
|
||||
1 <END> NEXT:[<SINK>]
|
||||
1 <END> NEXT:[<SINK>]
|
||||
error:
|
||||
<ERROR> PREV:[]
|
||||
<ERROR> PREV:[]
|
||||
sink:
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
=====================
|
||||
|
||||
@@ -11,11 +11,11 @@ L0:
|
||||
mark((f)())
|
||||
mark((f))
|
||||
r(f)
|
||||
call((f), <for expression (f)>)
|
||||
call((f), invoke)
|
||||
L1:
|
||||
1 <END> NEXT:[<SINK>]
|
||||
1 <END> NEXT:[<SINK>]
|
||||
error:
|
||||
<ERROR> PREV:[]
|
||||
<ERROR> PREV:[]
|
||||
sink:
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
=====================
|
||||
|
||||
@@ -7,12 +7,11 @@ L0:
|
||||
1 <START>
|
||||
2 mark({ this() })
|
||||
mark(this())
|
||||
r(this)
|
||||
call(this, <for expression this>)
|
||||
call(this, invoke)
|
||||
L1:
|
||||
1 <END> NEXT:[<SINK>]
|
||||
1 <END> NEXT:[<SINK>]
|
||||
error:
|
||||
<ERROR> PREV:[]
|
||||
<ERROR> PREV:[]
|
||||
sink:
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
=====================
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
class A
|
||||
|
||||
class B {
|
||||
fun A.invoke() = "##"
|
||||
fun A.invoke(i: Int) = "#${i}"
|
||||
}
|
||||
|
||||
fun foo() = A()
|
||||
|
||||
fun B.test(): String {
|
||||
if (A()() != "##") return "fail1"
|
||||
if (A()(1) != "#1") return "fail2"
|
||||
if (foo()() != "##") return "fail3"
|
||||
if (foo()(42) != "#42") return "fail4"
|
||||
if ((foo())(42) != "#42") return "fail5"
|
||||
if ({() -> A()}()() != "##") return "fail6"
|
||||
if ({() -> A()}()(37) != "#37") return "fail7"
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun box(): String = B().test()
|
||||
@@ -0,0 +1,20 @@
|
||||
//KT-3217 Invoke convention after function invocation doesn't work
|
||||
//KT-2728 Can't compile A()()
|
||||
|
||||
class A {
|
||||
fun invoke() = "##"
|
||||
fun invoke(i: Int) = "#${i}"
|
||||
}
|
||||
|
||||
fun foo() = A()
|
||||
|
||||
fun box(): String {
|
||||
if (A()() != "##") return "fail1"
|
||||
if (A()(1) != "#1") return "fail2"
|
||||
if (foo()() != "##") return "fail3"
|
||||
if (foo()(42) != "#42") return "fail4"
|
||||
if ((foo())(42) != "#42") return "fail5"
|
||||
if ({() -> A()}()() != "##") return "fail6"
|
||||
if ({() -> A()}()(37) != "#37") return "fail7"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
//KT-3450 get and invoke are not parsed in one expression
|
||||
|
||||
public class A(val s: String) {
|
||||
|
||||
public fun get(i: Int) : A = A("$s + $i")
|
||||
|
||||
public fun invoke(builder : A.() -> String): String = builder()
|
||||
}
|
||||
fun x(y : String) : A = A(y)
|
||||
|
||||
fun foo() = x("aaa")[42] { "$s!!" }
|
||||
|
||||
fun box() = if (foo() == "aaa + 42!!") "OK" else "fail"
|
||||
@@ -0,0 +1,5 @@
|
||||
//KT-3631 String.invoke doesn't work with literals
|
||||
|
||||
fun String.invoke(i: Int) = "$this$i"
|
||||
|
||||
fun box() = if ("a"(12) == "a12") "OK" else "fail"
|
||||
@@ -0,0 +1,21 @@
|
||||
//KT-3772 Invoke and overload resolution ambiguity
|
||||
|
||||
open class A {
|
||||
fun invoke(f: A.() -> Unit) = 1
|
||||
}
|
||||
|
||||
class B {
|
||||
fun invoke(f: B.() -> Unit) = 2
|
||||
}
|
||||
|
||||
open class C
|
||||
val C.attr = A()
|
||||
|
||||
open class D: C()
|
||||
val D.attr = B()
|
||||
|
||||
|
||||
fun box(): String {
|
||||
val d = D()
|
||||
return if (d.attr {} == 2) "OK" else "fail"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
//KT-3821 Invoke convention doesn't work for `this`
|
||||
|
||||
class A() {
|
||||
fun invoke() = 42
|
||||
fun foo() = this() // Expecting a function type, but found A
|
||||
}
|
||||
|
||||
fun box() = if (A().foo() == 42) "OK" else "fail"
|
||||
@@ -0,0 +1,9 @@
|
||||
//KT-3822 Compiler crashes when use invoke convention with `this` in class which extends Function0<T>
|
||||
|
||||
class B() : Function0<Boolean> {
|
||||
override fun invoke() = true
|
||||
|
||||
fun foo() = this() // Exception
|
||||
}
|
||||
|
||||
fun box() = if (B().foo()) "OK" else "fail"
|
||||
@@ -7,4 +7,4 @@ class Z{
|
||||
}
|
||||
}
|
||||
|
||||
// 2 invoke \(LZ;I\)V
|
||||
// 1 invoke \(LZ;I\)V
|
||||
@@ -2,4 +2,4 @@ fun test() {
|
||||
1.{Int.() -> 2}()
|
||||
}
|
||||
|
||||
// 2 invoke \(I\)I
|
||||
// 1 invoke \(I\)I
|
||||
@@ -0,0 +1,23 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
public class A {
|
||||
public fun get(vararg attrs : Pair<String, String>) : A = this
|
||||
}
|
||||
fun String.plus() : A = A()
|
||||
fun A.div(s : String) : A = A()
|
||||
|
||||
fun test() {
|
||||
(+"node2" / "node3" / "zzz") ["attr" to "value", "a2" to "v2"]
|
||||
}
|
||||
|
||||
//---------
|
||||
class B {
|
||||
public fun get(s : String, q : String) : B = this
|
||||
public fun get(s : Pair<String, String>) : B = this
|
||||
public fun invoke(q : B.() -> Unit) : B = this
|
||||
}
|
||||
val x = B()["a", "v"]["a" to "b"] {} ["q" to "p"] // does not parses around {}
|
||||
|
||||
//from library
|
||||
data class Pair<out A, out B> (val first: A, val second: B)
|
||||
fun <A,B> A.to(that: B) = Pair(this, that)
|
||||
@@ -0,0 +1,10 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun Int.invoke(i: Int, a: Any) {}
|
||||
fun Int.invoke(a: Any, i: Int) {}
|
||||
|
||||
fun foo(i: Int) {
|
||||
<!OVERLOAD_RESOLUTION_AMBIGUITY!>i<!>(1, 1)
|
||||
|
||||
<!OVERLOAD_RESOLUTION_AMBIGUITY!>5<!>(1, 2)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class My {
|
||||
private fun Int.invoke(s: String) {}
|
||||
}
|
||||
|
||||
fun My.foo(i: Int) {
|
||||
<!INVISIBLE_MEMBER!>i<!>("")
|
||||
<!INVISIBLE_MEMBER!>1<!>("")
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class A<T>
|
||||
|
||||
fun <T> T.invoke(a: A<T>) {}
|
||||
|
||||
fun foo(s: String, ai: A<Int>) {
|
||||
1(ai)
|
||||
|
||||
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>s<!>(ai)
|
||||
|
||||
<!TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS!>""<!>(ai)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo(i: Int) {
|
||||
<!FUNCTION_EXPECTED!>i<!>()
|
||||
<!CALLEE_NOT_A_FUNCTION!>1<!>()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun String.invoke(i: Int) {}
|
||||
|
||||
fun foo(s: String?) {
|
||||
<!UNSAFE_CALL!>s<!>(1)
|
||||
|
||||
<!UNSAFE_CALL!>(s ?: null)<!>(1)
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun String.invoke(i: Int) {}
|
||||
|
||||
fun foo(i: Int) {
|
||||
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>i<!>(1)
|
||||
|
||||
<!CALLEE_NOT_A_FUNCTION!>1<!>(1)
|
||||
}
|
||||
@@ -5081,6 +5081,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt1028.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3450.kt")
|
||||
public void testKt3450() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/overload")
|
||||
@@ -6041,6 +6046,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/resolve/invoke")
|
||||
@InnerTestClasses({Invoke.Errors.class})
|
||||
public static class Invoke extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInInvoke() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/resolve/invoke"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -6091,6 +6097,50 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/resolve/invoke/valNamedInvoke.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/resolve/invoke/errors")
|
||||
public static class Errors extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInErrors() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/resolve/invoke/errors"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ambiguityForInvoke.kt")
|
||||
public void testAmbiguityForInvoke() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/resolve/invoke/errors/ambiguityForInvoke.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invisibleInvoke.kt")
|
||||
public void testInvisibleInvoke() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/resolve/invoke/errors/invisibleInvoke.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeInferenceErrorForInvoke.kt")
|
||||
public void testTypeInferenceErrorForInvoke() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/resolve/invoke/errors/typeInferenceErrorForInvoke.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unresolvedInvoke.kt")
|
||||
public void testUnresolvedInvoke() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/resolve/invoke/errors/unresolvedInvoke.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unsafeCallWithInvoke.kt")
|
||||
public void testUnsafeCallWithInvoke() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/resolve/invoke/errors/unsafeCallWithInvoke.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("wrongReceiverTypeForInvoke.kt")
|
||||
public void testWrongReceiverTypeForInvoke() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/resolve/invoke/errors/wrongReceiverTypeForInvoke.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("Invoke");
|
||||
suite.addTestSuite(Invoke.class);
|
||||
suite.addTestSuite(Errors.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/resolve/nestedCalls")
|
||||
@@ -6142,7 +6192,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("Resolve");
|
||||
suite.addTestSuite(Resolve.class);
|
||||
suite.addTestSuite(Invoke.class);
|
||||
suite.addTest(Invoke.innerSuite());
|
||||
suite.addTestSuite(NestedCalls.class);
|
||||
suite.addTestSuite(SpecialConstructions.class);
|
||||
return suite;
|
||||
|
||||
@@ -2878,11 +2878,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box/functions/invoke"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionInvokeOnExpr.kt")
|
||||
public void testExtensionInvokeOnExpr() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/extensionInvokeOnExpr.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invoke.kt")
|
||||
public void testInvoke() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/invoke.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokeOnExprByConvention.kt")
|
||||
public void testInvokeOnExprByConvention() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/invokeOnExprByConvention.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3189.kt")
|
||||
public void testKt3189() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/kt3189.kt");
|
||||
@@ -2898,6 +2908,31 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/kt3297.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3450getAndInvoke.kt")
|
||||
public void testKt3450getAndInvoke() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/kt3450getAndInvoke.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3631invokeOnString.kt")
|
||||
public void testKt3631invokeOnString() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/kt3631invokeOnString.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3772.kt")
|
||||
public void testKt3772() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/kt3772.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3821invokeOnThis.kt")
|
||||
public void testKt3821invokeOnThis() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/kt3821invokeOnThis.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3822invokeOnThis.kt")
|
||||
public void testKt3822invokeOnThis() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/functions/localFunctions")
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.io.File
|
||||
import java.util.Collections
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
|
||||
public abstract class AbstractResolvedCallsTest() : JetLiteFixture() {
|
||||
override fun createEnvironment(): JetCoreEnvironment = createEnvironmentWithMockJdk(ConfigurationKind.JDK_ONLY)
|
||||
@@ -72,12 +73,22 @@ public abstract class AbstractResolvedCallsTest() : JetLiteFixture() {
|
||||
|
||||
var callFound = false
|
||||
for ((element, resolvedCall) in analyzeFileAndGetResolvedCallEntries()) {
|
||||
if (callName.equals(element.getText())) {
|
||||
|
||||
fun tryCall(resolvedCall: ResolvedCall<*>, actualName: String? = element.getText()) {
|
||||
if (callName == null || callName != actualName) return
|
||||
callFound = true
|
||||
checkResolvedCall(resolvedCall, element)
|
||||
}
|
||||
|
||||
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||
tryCall(resolvedCall.getFunctionCall(), "invoke")
|
||||
tryCall(resolvedCall.getVariableCall())
|
||||
}
|
||||
else {
|
||||
tryCall(resolvedCall)
|
||||
}
|
||||
}
|
||||
assertTrue(callFound, "Resolved call for $callName was not found.")
|
||||
assertTrue(callFound, "Resolved call for $callName was not found")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
@@ -32,6 +33,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.CALL;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
|
||||
|
||||
class JetInvokeFunctionReference extends JetSimpleReference<JetCallExpression> implements MultiRangeReference {
|
||||
@@ -48,10 +50,15 @@ class JetInvokeFunctionReference extends JetSimpleReference<JetCallExpression> i
|
||||
@Override
|
||||
@NotNull
|
||||
protected Collection<DeclarationDescriptor> getTargetDescriptors(@NotNull BindingContext context) {
|
||||
ResolvedCall<?> resolvedCall = context.get(RESOLVED_CALL, getExpression().getCalleeExpression());
|
||||
JetExpression calleeExpression = getExpression().getCalleeExpression();
|
||||
ResolvedCall<?> resolvedCall = context.get(RESOLVED_CALL, calleeExpression);
|
||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||
return Collections.<DeclarationDescriptor>singleton(((VariableAsFunctionResolvedCall) resolvedCall).getCandidateDescriptor());
|
||||
}
|
||||
Call call = context.get(CALL, calleeExpression);
|
||||
if (call != null && resolvedCall != null && call.getCallType() == Call.CallType.INVOKE) {
|
||||
return Collections.<DeclarationDescriptor>singleton(resolvedCall.getCandidateDescriptor());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user