diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 96b9ad1d740..559facf430b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -204,7 +204,8 @@ public class CallResolver { context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(context); } - Collection> candidates = TaskPrioritizer.convertWithImpliedThis(context.scope, Collections.singletonList(NO_RECEIVER), constructors); + Collection> candidates = + TaskPrioritizer.convertWithImpliedThisAndNoReceiver(context.scope, constructors); prioritizedTasks = TaskPrioritizer.computePrioritizedTasksFromCandidates( context, functionReference, candidates, null); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java index b913cab0c04..6b7708f9ab9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java @@ -45,6 +45,7 @@ import java.util.List; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject; import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.isOrOverridesSynthesized; +import static org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind.*; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; public class TaskPrioritizer { @@ -121,7 +122,7 @@ public class TaskPrioritizer { } List implicitReceivers = JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope); if (receiver.exists()) { - addCandidatesForExplicitReceiver(receiver, implicitReceivers, c, /*resolveInvoke=*/false); + addCandidatesForExplicitReceiver(receiver, implicitReceivers, c, /*isExplicit=*/true); return; } addCandidatesForNoReceiver(implicitReceivers, c); @@ -131,7 +132,7 @@ public class TaskPrioritizer { @NotNull ReceiverValue receiver, @NotNull List implicitReceivers, @NotNull TaskPrioritizerContext c, - boolean resolveInvoke + boolean isExplicit ) { List variantsForExplicitReceiver = AutoCastUtils.getAutoCastVariants(receiver, c.context); @@ -143,7 +144,7 @@ public class TaskPrioritizer { Collection membersForThisVariant = callableDescriptorCollector.getMembersByName(variant.getType(), c.name, c.context.trace); convertWithReceivers(membersForThisVariant, Collections.singletonList(variant), - Collections.singletonList(NO_RECEIVER), members, resolveInvoke); + Collections.singletonList(NO_RECEIVER), members, createKind(THIS_OBJECT, isExplicit)); } c.result.addCandidates(members); } @@ -152,26 +153,32 @@ public class TaskPrioritizer { //member extensions for (ReceiverValue implicitReceiver : implicitReceivers) { addMemberExtensionCandidates(implicitReceiver, variantsForExplicitReceiver, - callableDescriptorCollector, c, resolveInvoke); + callableDescriptorCollector, c, createKind(RECEIVER_ARGUMENT, isExplicit)); } //extensions Collection> extensions = convertWithImpliedThis( - c.scope, variantsForExplicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name, c.context.trace)); + c.scope, variantsForExplicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name, c.context.trace), + createKind(RECEIVER_ARGUMENT, isExplicit)); c.result.addCandidates(extensions); } } + private static ExplicitReceiverKind createKind(ExplicitReceiverKind kind, boolean isExplicit) { + if (isExplicit) return kind; + return ExplicitReceiverKind.NO_EXPLICIT_RECEIVER; + } + private static void addMemberExtensionCandidates( - @NotNull ReceiverValue implicitReceiver, - @NotNull List variantsForExplicitReceiver, + @NotNull ReceiverValue thisObject, + @NotNull List receiverParameters, @NotNull CallableDescriptorCollector callableDescriptorCollector, TaskPrioritizerContext c, - boolean resolveInvoke + @NotNull ExplicitReceiverKind receiverKind ) { Collection memberExtensions = callableDescriptorCollector.getNonMembersByName( - implicitReceiver.getType().getMemberScope(), c.name, c.context.trace); - List variantsForImplicitReceiver = AutoCastUtils.getAutoCastVariants(implicitReceiver, c.context); - c.result.addCandidates(convertWithReceivers(memberExtensions, variantsForImplicitReceiver, - variantsForExplicitReceiver, resolveInvoke)); + thisObject.getType().getMemberScope(), c.name, c.context.trace); + List thisObjects = AutoCastUtils.getAutoCastVariants(thisObject, c.context); + c.result.addCandidates(convertWithReceivers( + memberExtensions, thisObjects, receiverParameters, receiverKind)); } private static void addCandidatesForNoReceiver( @@ -182,9 +189,8 @@ public class TaskPrioritizer { List>> nonlocalsList = Lists.newArrayList(); for (CallableDescriptorCollector callableDescriptorCollector : c.callableDescriptorCollectors) { - Collection> members = - convertWithImpliedThis(c.scope, Collections.singletonList(NO_RECEIVER), callableDescriptorCollector - .getNonExtensionsByName(c.scope, c.name, c.context.trace)); + Collection> members = convertWithImpliedThisAndNoReceiver( + c.scope, callableDescriptorCollector.getNonExtensionsByName(c.scope, c.name, c.context.trace)); List> nonlocals = Lists.newArrayList(); List> locals = Lists.newArrayList(); @@ -200,9 +206,9 @@ public class TaskPrioritizer { //try all implicit receivers as explicit for (ReceiverValue implicitReceiver : implicitReceivers) { - addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*resolveInvoke=*/false); + addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*isExplicit=*/false); } - + //nonlocals c.result.addCandidates(nonlocalsList); } @@ -224,7 +230,7 @@ public class TaskPrioritizer { // (1) a.foo + foo.invoke() if (!explicitReceiver.exists()) { - addCandidatesForExplicitReceiver(variableReceiver, implicitReceivers, c, /*resolveInvoke=*/true); + addCandidatesForExplicitReceiver(variableReceiver, implicitReceivers, c, /*isExplicit=*/true); } // (2) foo + a.invoke() @@ -235,24 +241,25 @@ public class TaskPrioritizer { if (explicitReceiver.exists()) { //a.foo() - addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(variableReceiver, explicitReceiver, c); + addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(variableReceiver, explicitReceiver, c, BOTH_RECEIVERS); return; } // with (a) { foo() } for (ReceiverValue implicitReceiver : implicitReceivers) { - addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(variableReceiver, implicitReceiver, c); + addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(variableReceiver, implicitReceiver, c, THIS_OBJECT); } } - private static void addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver( - @NotNull ReceiverValue variableReceiver, - @NotNull ReceiverValue explicitReceiver, - @NotNull TaskPrioritizerContext c + private static void addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver( + @NotNull ReceiverValue thisObject, + @NotNull ReceiverValue receiverParameter, + @NotNull TaskPrioritizerContext c, + @NotNull ExplicitReceiverKind receiverKind ) { - List variantsForExplicitReceiver = AutoCastUtils.getAutoCastVariants(explicitReceiver, c.context); + List receiverParameters = AutoCastUtils.getAutoCastVariants(receiverParameter, c.context); for (CallableDescriptorCollector callableDescriptorCollector : c.callableDescriptorCollectors) { - addMemberExtensionCandidates(variableReceiver, variantsForExplicitReceiver, callableDescriptorCollector, c, /*resolveInvoke=*/true); + addMemberExtensionCandidates(thisObject, receiverParameters, callableDescriptorCollector, c, receiverKind); } } @@ -260,10 +267,10 @@ public class TaskPrioritizer { @NotNull Collection descriptors, @NotNull Iterable thisObjects, @NotNull Iterable receiverParameters, - boolean hasExplicitThisObject + @NotNull ExplicitReceiverKind explicitReceiverKind ) { Collection> result = Lists.newArrayList(); - convertWithReceivers(descriptors, thisObjects, receiverParameters, result, hasExplicitThisObject); + convertWithReceivers(descriptors, thisObjects, receiverParameters, result, explicitReceiverKind); return result; } @@ -272,7 +279,7 @@ public class TaskPrioritizer { @NotNull Iterable thisObjects, @NotNull Iterable receiverParameters, @NotNull Collection> result, - boolean hasExplicitThisObject + @NotNull ExplicitReceiverKind explicitReceiverKind ) { for (ReceiverValue thisObject : thisObjects) { for (ReceiverValue receiverParameter : receiverParameters) { @@ -284,26 +291,32 @@ public class TaskPrioritizer { ResolutionCandidate candidate = ResolutionCandidate.create(extension); candidate.setThisObject(thisObject); candidate.setReceiverArgument(receiverParameter); - candidate.setExplicitReceiverKind( - hasExplicitThisObject ? ExplicitReceiverKind.BOTH_RECEIVERS : ExplicitReceiverKind.THIS_OBJECT); + candidate.setExplicitReceiverKind(explicitReceiverKind); result.add(candidate); } } } } + public static Collection> convertWithImpliedThisAndNoReceiver( + @NotNull JetScope scope, + @NotNull Collection descriptors + ) { + return convertWithImpliedThis(scope, Collections.singletonList(NO_RECEIVER), descriptors, NO_EXPLICIT_RECEIVER); + } + public static Collection> convertWithImpliedThis( @NotNull JetScope scope, @NotNull Collection receiverParameters, - @NotNull Collection descriptors + @NotNull Collection descriptors, + ExplicitReceiverKind receiverKind ) { Collection> result = Lists.newArrayList(); for (ReceiverValue receiverParameter : receiverParameters) { for (D descriptor : descriptors) { ResolutionCandidate candidate = ResolutionCandidate.create(descriptor); candidate.setReceiverArgument(receiverParameter); - candidate.setExplicitReceiverKind( - receiverParameter.exists() ? ExplicitReceiverKind.RECEIVER_ARGUMENT : ExplicitReceiverKind.NO_EXPLICIT_RECEIVER); + candidate.setExplicitReceiverKind(receiverKind); if (setImpliedThis(scope, candidate)) { result.add(candidate); } diff --git a/compiler/testData/resolvedCalls/explicitReceiverIsReceiverArgument.kt b/compiler/testData/resolvedCalls/explicitReceiverIsReceiverArgument.kt new file mode 100644 index 00000000000..a29a87c99a7 --- /dev/null +++ b/compiler/testData/resolvedCalls/explicitReceiverIsReceiverArgument.kt @@ -0,0 +1,12 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: RECEIVER_ARGUMENT +// !THIS_OBJECT: NO_RECEIVER +// !RECEIVER_ARGUMENT: a + +class A {} + +fun A.foo() {} + +fun bar(a: A) { + a.foo() +} diff --git a/compiler/testData/resolvedCalls/explicitReceiverIsThisObject.kt b/compiler/testData/resolvedCalls/explicitReceiverIsThisObject.kt new file mode 100644 index 00000000000..85fcb2e3b5c --- /dev/null +++ b/compiler/testData/resolvedCalls/explicitReceiverIsThisObject.kt @@ -0,0 +1,12 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: THIS_OBJECT +// !THIS_OBJECT: a +// !RECEIVER_ARGUMENT: NO_RECEIVER + +class A { + fun foo() {} +} + +fun bar(a: A) { + a.foo() +} diff --git a/compiler/testData/resolvedCalls/functionTypes/invokeForExtensionFunctionType.kt b/compiler/testData/resolvedCalls/functionTypes/invokeForExtensionFunctionType.kt new file mode 100644 index 00000000000..228db5f50df --- /dev/null +++ b/compiler/testData/resolvedCalls/functionTypes/invokeForExtensionFunctionType.kt @@ -0,0 +1,8 @@ +// !CALL: invoke +// !EXPLICIT_RECEIVER_KIND: BOTH_RECEIVERS +// !THIS_OBJECT: f +// !RECEIVER_ARGUMENT: 1 + +fun bar(f: Int.()->Unit) { + 1.f() +} diff --git a/compiler/testData/resolvedCalls/functionTypes/invokeForFunctionType.kt b/compiler/testData/resolvedCalls/functionTypes/invokeForFunctionType.kt new file mode 100644 index 00000000000..6c37cc9dbda --- /dev/null +++ b/compiler/testData/resolvedCalls/functionTypes/invokeForFunctionType.kt @@ -0,0 +1,8 @@ +// !CALL: invoke +// !EXPLICIT_RECEIVER_KIND: THIS_OBJECT +// !THIS_OBJECT: f +// !RECEIVER_ARGUMENT: NO_RECEIVER + +fun bar(f: ()->Unit) { + f() +} diff --git a/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionType.kt b/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionType.kt new file mode 100644 index 00000000000..837db84c8f6 --- /dev/null +++ b/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionType.kt @@ -0,0 +1,12 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: NO_EXPLICIT_RECEIVER +// !THIS_OBJECT: Class{A} +// !RECEIVER_ARGUMENT: NO_RECEIVER + +trait A { + val foo: Int.()->Unit + + fun test() { + 1.foo() + } +} diff --git a/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionTypeInvoke.kt b/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionTypeInvoke.kt new file mode 100644 index 00000000000..53464c75bfd --- /dev/null +++ b/compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionTypeInvoke.kt @@ -0,0 +1,12 @@ +// !CALL: invoke +// !EXPLICIT_RECEIVER_KIND: BOTH_RECEIVERS +// !THIS_OBJECT: foo +// !RECEIVER_ARGUMENT: 1 + +trait A { + val foo: Int.()->Unit + + fun test() { + 1.foo() + } +} diff --git a/compiler/testData/resolvedCalls/functionTypes/valOfFunctionType.kt b/compiler/testData/resolvedCalls/functionTypes/valOfFunctionType.kt new file mode 100644 index 00000000000..86af46416ac --- /dev/null +++ b/compiler/testData/resolvedCalls/functionTypes/valOfFunctionType.kt @@ -0,0 +1,12 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: THIS_OBJECT +// !THIS_OBJECT: a +// !RECEIVER_ARGUMENT: NO_RECEIVER + +trait A { + val foo: (Int)->Int +} + +fun test(a: A) { + a.foo(1) +} \ No newline at end of file diff --git a/compiler/testData/resolvedCalls/functionTypes/valOfFunctionTypeInvoke.kt b/compiler/testData/resolvedCalls/functionTypes/valOfFunctionTypeInvoke.kt new file mode 100644 index 00000000000..9b9c8079d13 --- /dev/null +++ b/compiler/testData/resolvedCalls/functionTypes/valOfFunctionTypeInvoke.kt @@ -0,0 +1,12 @@ +// !CALL: invoke +// !EXPLICIT_RECEIVER_KIND: THIS_OBJECT +// !THIS_OBJECT: foo +// !RECEIVER_ARGUMENT: NO_RECEIVER + +trait A { + val foo: (Int)->Int +} + +fun test(a: A) { + a.foo(1) +} \ No newline at end of file diff --git a/compiler/testData/resolvedCalls/hasBothThisObjectAndReceiverArgument.kt b/compiler/testData/resolvedCalls/hasBothThisObjectAndReceiverArgument.kt new file mode 100644 index 00000000000..2369b1a54bd --- /dev/null +++ b/compiler/testData/resolvedCalls/hasBothThisObjectAndReceiverArgument.kt @@ -0,0 +1,18 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: RECEIVER_ARGUMENT +// !THIS_OBJECT: A +// !RECEIVER_ARGUMENT: b + +class A { + fun B.foo() {} +} + +trait B + +fun bar(a: A, b: B) { + with (a) { + b.foo() + } +} + +fun with(receiver: T, f: T.() -> R) : R = receiver.f() diff --git a/compiler/testData/resolvedCalls/hasBothThisObjectAndReceiverArgumentWithoutExplicitReceiver.kt b/compiler/testData/resolvedCalls/hasBothThisObjectAndReceiverArgumentWithoutExplicitReceiver.kt new file mode 100644 index 00000000000..17ef0f72d9b --- /dev/null +++ b/compiler/testData/resolvedCalls/hasBothThisObjectAndReceiverArgumentWithoutExplicitReceiver.kt @@ -0,0 +1,20 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: NO_EXPLICIT_RECEIVER +// !THIS_OBJECT: A +// !RECEIVER_ARGUMENT: B + +class A { + fun B.foo() {} +} + +trait B + +fun bar(a: A, b: B) { + with (a) { + with (b) { + foo() + } + } +} + +fun with(receiver: T, f: T.() -> R) : R = receiver.f() diff --git a/compiler/testData/resolvedCalls/implicitReceiverIsReceiverArgument.kt b/compiler/testData/resolvedCalls/implicitReceiverIsReceiverArgument.kt new file mode 100644 index 00000000000..d59a3daf2e3 --- /dev/null +++ b/compiler/testData/resolvedCalls/implicitReceiverIsReceiverArgument.kt @@ -0,0 +1,12 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: NO_EXPLICIT_RECEIVER +// !THIS_OBJECT: NO_RECEIVER +// !RECEIVER_ARGUMENT: A + +class A {} + +fun A.foo() {} + +fun A.bar() { + foo() +} diff --git a/compiler/testData/resolvedCalls/implicitReceiverIsThisObject.kt b/compiler/testData/resolvedCalls/implicitReceiverIsThisObject.kt new file mode 100644 index 00000000000..d6d17c1e268 --- /dev/null +++ b/compiler/testData/resolvedCalls/implicitReceiverIsThisObject.kt @@ -0,0 +1,12 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: NO_EXPLICIT_RECEIVER +// !THIS_OBJECT: A +// !RECEIVER_ARGUMENT: NO_RECEIVER + +class A { + fun foo() {} +} + +fun A.bar() { + foo() +} diff --git a/compiler/testData/resolvedCalls/impliedThisNoExplicitReceiver.kt b/compiler/testData/resolvedCalls/impliedThisNoExplicitReceiver.kt new file mode 100644 index 00000000000..57dee9f5a58 --- /dev/null +++ b/compiler/testData/resolvedCalls/impliedThisNoExplicitReceiver.kt @@ -0,0 +1,11 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: NO_EXPLICIT_RECEIVER +// !THIS_OBJECT: Class{A} +// !RECEIVER_ARGUMENT: NO_RECEIVER + +class A { + fun foo() {} + fun bar() { + foo() + } +} \ No newline at end of file diff --git a/compiler/testData/resolvedCalls/invoke/bothReceivers.kt b/compiler/testData/resolvedCalls/invoke/bothReceivers.kt new file mode 100644 index 00000000000..4d66d303456 --- /dev/null +++ b/compiler/testData/resolvedCalls/invoke/bothReceivers.kt @@ -0,0 +1,12 @@ +// !CALL: invoke +// !EXPLICIT_RECEIVER_KIND: BOTH_RECEIVERS +// !THIS_OBJECT: f +// !RECEIVER_ARGUMENT: 1 + +class Foo() { + fun Int.invoke() {} +} + +fun bar(f: Foo) { + 1.f() +} diff --git a/compiler/testData/resolvedCalls/invoke/implicitReceiverForInvoke.kt b/compiler/testData/resolvedCalls/invoke/implicitReceiverForInvoke.kt new file mode 100644 index 00000000000..79aa259fabc --- /dev/null +++ b/compiler/testData/resolvedCalls/invoke/implicitReceiverForInvoke.kt @@ -0,0 +1,16 @@ +// !CALL: invoke +// !EXPLICIT_RECEIVER_KIND: THIS_OBJECT +// !THIS_OBJECT: f +// !RECEIVER_ARGUMENT: Int + +class Foo() { + fun Int.invoke() {} +} + +fun bar(f: Foo, i: Int) { + with (i) { + f() + } +} + +fun with(receiver: T, f: T.() -> R) : R = throw Exception() \ No newline at end of file diff --git a/compiler/testData/resolvedCalls/invoke/receiverArgumentAsReceiverForInvoke.kt b/compiler/testData/resolvedCalls/invoke/receiverArgumentAsReceiverForInvoke.kt new file mode 100644 index 00000000000..a10dd8fa922 --- /dev/null +++ b/compiler/testData/resolvedCalls/invoke/receiverArgumentAsReceiverForInvoke.kt @@ -0,0 +1,11 @@ +// !CALL: invoke +// !EXPLICIT_RECEIVER_KIND: RECEIVER_ARGUMENT +// !THIS_OBJECT: NO_RECEIVER +// !RECEIVER_ARGUMENT: f + +class Foo +fun Foo.invoke() {} + +fun bar(f: Foo) { + f() +} diff --git a/compiler/testData/resolvedCalls/invoke/thisObjectAsReceiverForInvoke.kt b/compiler/testData/resolvedCalls/invoke/thisObjectAsReceiverForInvoke.kt new file mode 100644 index 00000000000..85cf906098a --- /dev/null +++ b/compiler/testData/resolvedCalls/invoke/thisObjectAsReceiverForInvoke.kt @@ -0,0 +1,12 @@ +// !CALL: invoke +// !EXPLICIT_RECEIVER_KIND: THIS_OBJECT +// !THIS_OBJECT: f +// !RECEIVER_ARGUMENT: NO_RECEIVER + +class Foo { + fun invoke() {} +} + +fun bar(f: Foo) { + f() +} diff --git a/compiler/testData/resolvedCalls/realExamples/stringPlusInBuilders.kt b/compiler/testData/resolvedCalls/realExamples/stringPlusInBuilders.kt new file mode 100644 index 00000000000..89fd399974a --- /dev/null +++ b/compiler/testData/resolvedCalls/realExamples/stringPlusInBuilders.kt @@ -0,0 +1,44 @@ +// !CALL: + +// !EXPLICIT_RECEIVER_KIND: RECEIVER_ARGUMENT +// !THIS_OBJECT: Title +// !RECEIVER_ARGUMENT: "Foo" + +trait Element { + fun render(builder: StringBuilder, indent: String) +} + +class TextElement(val text: String): Element { + override fun render(builder: StringBuilder, indent: String): Unit = fail +} + +abstract class Tag(val name: String): Element { + protected fun initTag(tag: T, init: T.() -> Unit): T = fail + + override fun render(builder: StringBuilder, indent: String): Unit = fail +} + +abstract class TagWithText(name: String): Tag(name) { + fun String.plus() {} +} + +class HTML(): TagWithText("html") { + fun head(init: Head.() -> Unit): Head = fail + +} + +class Head(): TagWithText("head") { + fun title(init: Title.() -> Unit): Title = fail +} + +class Title(): TagWithText("title") + +fun html(init: HTML.() -> Unit): HTML = fail + +fun result() = + html { + head { + title {+"Foo"} + } + } + +val fail: Nothing get() = throw Exception() diff --git a/compiler/testData/resolvedCalls/simpleCall.kt b/compiler/testData/resolvedCalls/simpleCall.kt new file mode 100644 index 00000000000..7d7c5ed6fce --- /dev/null +++ b/compiler/testData/resolvedCalls/simpleCall.kt @@ -0,0 +1,10 @@ +// !CALL: foo +// !EXPLICIT_RECEIVER_KIND: NO_EXPLICIT_RECEIVER +// !THIS_OBJECT: NO_RECEIVER +// !RECEIVER_ARGUMENT: NO_RECEIVER + +fun foo() {} + +fun bar() { + foo() +} diff --git a/compiler/tests/org/jetbrains/jet/JetTestUtils.java b/compiler/tests/org/jetbrains/jet/JetTestUtils.java index 2786b544eae..b43c822dec8 100644 --- a/compiler/tests/org/jetbrains/jet/JetTestUtils.java +++ b/compiler/tests/org/jetbrains/jet/JetTestUtils.java @@ -229,11 +229,13 @@ public class JetTestUtils { return AnalyzerFacadeForJVM.analyzeOneFileWithJavaIntegration(namespace, Collections.emptyList()); } + @NotNull public static JetCoreEnvironment createEnvironmentWithFullJdk(Disposable disposable) { return createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea(disposable, ConfigurationKind.ALL, TestJdkKind.FULL_JDK); } + @NotNull public static JetCoreEnvironment createEnvironmentWithMockJdkAndIdeaAnnotations(Disposable disposable) { return createEnvironmentWithMockJdkAndIdeaAnnotations(disposable, ConfigurationKind.ALL); } @@ -243,6 +245,7 @@ public class JetTestUtils { return createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea(disposable, configurationKind, TestJdkKind.MOCK_JDK); } + @NotNull public static JetCoreEnvironment createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea( @NotNull Disposable disposable, @NotNull ConfigurationKind configurationKind, @@ -445,6 +448,7 @@ public class JetTestUtils { return testFiles; } + @NotNull public static Map parseDirectives(String expectedText) { Map directives = Maps.newHashMap(); Matcher directiveMatcher = DIRECTIVE_PATTERN.matcher(expectedText); diff --git a/compiler/tests/org/jetbrains/jet/KotlinTestWithEnvironmentManagement.java b/compiler/tests/org/jetbrains/jet/KotlinTestWithEnvironmentManagement.java index 07aadf2eaca..4cb4d6ddfae 100644 --- a/compiler/tests/org/jetbrains/jet/KotlinTestWithEnvironmentManagement.java +++ b/compiler/tests/org/jetbrains/jet/KotlinTestWithEnvironmentManagement.java @@ -25,10 +25,12 @@ public abstract class KotlinTestWithEnvironmentManagement extends UsefulTestCase System.setProperty("java.awt.headless", "true"); } + @NotNull protected JetCoreEnvironment createEnvironmentWithMockJdk(@NotNull ConfigurationKind configurationKind) { return createEnvironmentWithJdk(configurationKind, TestJdkKind.MOCK_JDK); } + @NotNull protected JetCoreEnvironment createEnvironmentWithJdk(@NotNull ConfigurationKind configurationKind, @NotNull TestJdkKind jdkKind) { return JetTestUtils.createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea(getTestRootDisposable(), configurationKind, jdkKind); } diff --git a/compiler/tests/org/jetbrains/jet/resolve/calls/AbstractResolvedCallsTest.kt b/compiler/tests/org/jetbrains/jet/resolve/calls/AbstractResolvedCallsTest.kt new file mode 100644 index 00000000000..ae074c87ba2 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/resolve/calls/AbstractResolvedCallsTest.kt @@ -0,0 +1,116 @@ +/* + * 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.resolve.calls + +import com.google.common.collect.ImmutableMap +import org.jetbrains.annotations.NotNull +import org.jetbrains.jet.ConfigurationKind +import org.jetbrains.jet.JetLiteFixture +import org.jetbrains.jet.JetTestUtils +import org.jetbrains.jet.analyzer.AnalyzeExhaust +import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment +import org.jetbrains.jet.lang.descriptors.CallableDescriptor +import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils +import org.jetbrains.jet.lang.psi.JetElement +import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall +import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM +import org.jetbrains.jet.lang.resolve.scopes.receivers.AbstractReceiverValue +import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue + +import java.io.File +import java.util.Collections +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +public abstract class AbstractResolvedCallsTest() : JetLiteFixture() { + override fun createEnvironment(): JetCoreEnvironment = createEnvironmentWithMockJdk(ConfigurationKind.JDK_ONLY) + + public fun doTest(filePath: String) { + val file = File(filePath) + val text = JetTestUtils.doLoadFile(file) + val directives = JetTestUtils.parseDirectives(text) + + val (callName, thisObject, receiverArgument) = with (directives) { + Triple(get("CALL"), get("THIS_OBJECT"), get("RECEIVER_ARGUMENT")) + } + val explicitReceiverKind = directives.getExplicitReceiverKind() + + fun analyzeFileAndGetResolvedCallEntries(): Map> { + val psiFile = JetTestUtils.loadJetFile(getProject(), file) + val analyzeExhaust = AnalyzerFacadeForJVM.analyzeOneFileWithJavaIntegration(psiFile, Collections.emptyList()) + val bindingContext = analyzeExhaust!!.getBindingContext() + return bindingContext.getSliceContents(BindingContext.RESOLVED_CALL) + } + + fun checkResolvedCall(resolvedCall: ResolvedCall, element: JetElement) { + val lineAndColumn = DiagnosticUtils.getLineAndColumnInPsiFile(element.getContainingFile(), element.getTextRange()) + + val (actualThisObject, actualReceiverArgument, actualExplicitReceiverKind) = with(resolvedCall) { + Triple(getThisObject().getText(), getReceiverArgument().getText(), getExplicitReceiverKind()) + } + val actualDataMessage = "Actual data:\nThis object: $actualThisObject. Receiver argument: $actualReceiverArgument. " + + "Explicit receiver kind: $actualExplicitReceiverKind.\n" + + assertEquals(thisObject, actualThisObject, "${actualDataMessage}This object mismatch: ") + assertEquals(receiverArgument, actualReceiverArgument, "${actualDataMessage}Receiver argument mismatch: ") + assertEquals(explicitReceiverKind, actualExplicitReceiverKind, "$actualDataMessage" + + "Explicit receiver kind for resolved call for '${element.getText()}'$lineAndColumn in not as expected") + } + + var callFound = false + for ((element, resolvedCall) in analyzeFileAndGetResolvedCallEntries()) { + if (callName.equals(element.getText())) { + callFound = true + checkResolvedCall(resolvedCall, element) + } + } + assertTrue(callFound, "Resolved call for $callName was not found.") + } +} + +private fun ReceiverValue.getText() = + if (this is ExpressionReceiver) { + this.getExpression().getText() + } + else if (this is AbstractReceiverValue) { + this.getType().toString() + } + else toString() + +private val EXPLICIT_RECEIVER_KIND_DIRECTIVE: String = "EXPLICIT_RECEIVER_KIND" +private fun Map.getExplicitReceiverKind(): ExplicitReceiverKind { + val explicitReceiverKind = get(EXPLICIT_RECEIVER_KIND_DIRECTIVE) + assert(explicitReceiverKind != null) { "$EXPLICIT_RECEIVER_KIND_DIRECTIVE should be present." } + try + { + return ExplicitReceiverKind.valueOf(explicitReceiverKind!!) + } + catch (e: IllegalArgumentException) { + val message = StringBuilder() + message.append("$EXPLICIT_RECEIVER_KIND_DIRECTIVE must be one of the following: ") + for (kind in ExplicitReceiverKind.values()) { + message.append("$kind, ") + } + message.append("\nnot $explicitReceiverKind.") + throw AssertionError(message) + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/resolve/calls/JetResolvedCallsTestGenerated.java b/compiler/tests/org/jetbrains/jet/resolve/calls/JetResolvedCallsTestGenerated.java new file mode 100644 index 00000000000..1f2a1033b52 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/resolve/calls/JetResolvedCallsTestGenerated.java @@ -0,0 +1,167 @@ +/* + * 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.resolve.calls; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import java.io.File; +import java.util.regex.Pattern; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.test.InnerTestClasses; +import org.jetbrains.jet.test.TestMetadata; + +import org.jetbrains.jet.resolve.calls.AbstractResolvedCallsTest; + +/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/resolvedCalls") +@InnerTestClasses({JetResolvedCallsTestGenerated.FunctionTypes.class, JetResolvedCallsTestGenerated.Invoke.class, JetResolvedCallsTestGenerated.RealExamples.class}) +public class JetResolvedCallsTestGenerated extends AbstractResolvedCallsTest { + public void testAllFilesPresentInResolvedCalls() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/resolvedCalls"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("explicitReceiverIsReceiverArgument.kt") + public void testExplicitReceiverIsReceiverArgument() throws Exception { + doTest("compiler/testData/resolvedCalls/explicitReceiverIsReceiverArgument.kt"); + } + + @TestMetadata("explicitReceiverIsThisObject.kt") + public void testExplicitReceiverIsThisObject() throws Exception { + doTest("compiler/testData/resolvedCalls/explicitReceiverIsThisObject.kt"); + } + + @TestMetadata("hasBothThisObjectAndReceiverArgument.kt") + public void testHasBothThisObjectAndReceiverArgument() throws Exception { + doTest("compiler/testData/resolvedCalls/hasBothThisObjectAndReceiverArgument.kt"); + } + + @TestMetadata("hasBothThisObjectAndReceiverArgumentWithoutExplicitReceiver.kt") + public void testHasBothThisObjectAndReceiverArgumentWithoutExplicitReceiver() throws Exception { + doTest("compiler/testData/resolvedCalls/hasBothThisObjectAndReceiverArgumentWithoutExplicitReceiver.kt"); + } + + @TestMetadata("implicitReceiverIsReceiverArgument.kt") + public void testImplicitReceiverIsReceiverArgument() throws Exception { + doTest("compiler/testData/resolvedCalls/implicitReceiverIsReceiverArgument.kt"); + } + + @TestMetadata("implicitReceiverIsThisObject.kt") + public void testImplicitReceiverIsThisObject() throws Exception { + doTest("compiler/testData/resolvedCalls/implicitReceiverIsThisObject.kt"); + } + + @TestMetadata("impliedThisNoExplicitReceiver.kt") + public void testImpliedThisNoExplicitReceiver() throws Exception { + doTest("compiler/testData/resolvedCalls/impliedThisNoExplicitReceiver.kt"); + } + + @TestMetadata("simpleCall.kt") + public void testSimpleCall() throws Exception { + doTest("compiler/testData/resolvedCalls/simpleCall.kt"); + } + + @TestMetadata("compiler/testData/resolvedCalls/functionTypes") + public static class FunctionTypes extends AbstractResolvedCallsTest { + public void testAllFilesPresentInFunctionTypes() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/resolvedCalls/functionTypes"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("invokeForExtensionFunctionType.kt") + public void testInvokeForExtensionFunctionType() throws Exception { + doTest("compiler/testData/resolvedCalls/functionTypes/invokeForExtensionFunctionType.kt"); + } + + @TestMetadata("invokeForFunctionType.kt") + public void testInvokeForFunctionType() throws Exception { + doTest("compiler/testData/resolvedCalls/functionTypes/invokeForFunctionType.kt"); + } + + @TestMetadata("valOfExtensionFunctionType.kt") + public void testValOfExtensionFunctionType() throws Exception { + doTest("compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionType.kt"); + } + + @TestMetadata("valOfExtensionFunctionTypeInvoke.kt") + public void testValOfExtensionFunctionTypeInvoke() throws Exception { + doTest("compiler/testData/resolvedCalls/functionTypes/valOfExtensionFunctionTypeInvoke.kt"); + } + + @TestMetadata("valOfFunctionType.kt") + public void testValOfFunctionType() throws Exception { + doTest("compiler/testData/resolvedCalls/functionTypes/valOfFunctionType.kt"); + } + + @TestMetadata("valOfFunctionTypeInvoke.kt") + public void testValOfFunctionTypeInvoke() throws Exception { + doTest("compiler/testData/resolvedCalls/functionTypes/valOfFunctionTypeInvoke.kt"); + } + + } + + @TestMetadata("compiler/testData/resolvedCalls/invoke") + public static class Invoke extends AbstractResolvedCallsTest { + public void testAllFilesPresentInInvoke() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/resolvedCalls/invoke"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("bothReceivers.kt") + public void testBothReceivers() throws Exception { + doTest("compiler/testData/resolvedCalls/invoke/bothReceivers.kt"); + } + + @TestMetadata("implicitReceiverForInvoke.kt") + public void testImplicitReceiverForInvoke() throws Exception { + doTest("compiler/testData/resolvedCalls/invoke/implicitReceiverForInvoke.kt"); + } + + @TestMetadata("receiverArgumentAsReceiverForInvoke.kt") + public void testReceiverArgumentAsReceiverForInvoke() throws Exception { + doTest("compiler/testData/resolvedCalls/invoke/receiverArgumentAsReceiverForInvoke.kt"); + } + + @TestMetadata("thisObjectAsReceiverForInvoke.kt") + public void testThisObjectAsReceiverForInvoke() throws Exception { + doTest("compiler/testData/resolvedCalls/invoke/thisObjectAsReceiverForInvoke.kt"); + } + + } + + @TestMetadata("compiler/testData/resolvedCalls/realExamples") + public static class RealExamples extends AbstractResolvedCallsTest { + public void testAllFilesPresentInRealExamples() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/resolvedCalls/realExamples"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("stringPlusInBuilders.kt") + public void testStringPlusInBuilders() throws Exception { + doTest("compiler/testData/resolvedCalls/realExamples/stringPlusInBuilders.kt"); + } + + } + + public static Test suite() { + TestSuite suite = new TestSuite("JetResolvedCallsTestGenerated"); + suite.addTestSuite(JetResolvedCallsTestGenerated.class); + suite.addTestSuite(FunctionTypes.class); + suite.addTestSuite(Invoke.class); + suite.addTestSuite(RealExamples.class); + return suite; + } +} diff --git a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java index d486a14e7d8..e84cfb5d11c 100644 --- a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java +++ b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java @@ -66,6 +66,7 @@ import org.jetbrains.jet.resolve.AbstractResolveBaseTest; import org.jetbrains.jet.resolve.AbstractResolveTest; import org.jetbrains.jet.resolve.AbstractResolveWithLibTest; import org.jetbrains.jet.resolve.annotation.AbstractAnnotationParameterTest; +import org.jetbrains.jet.resolve.calls.AbstractResolvedCallsTest; import org.jetbrains.jet.safeDelete.AbstractJetSafeDeleteTest; import java.io.File; @@ -108,6 +109,13 @@ public class GenerateTests { testModel("compiler/testData/resolve", true, "resolve", "doTest") ); + generateTest( + "compiler/tests", + "JetResolvedCallsTestGenerated", + AbstractResolvedCallsTest.class, + testModel("compiler/testData/resolvedCalls") + ); + generateTest( "compiler/tests/", "JetParsingTestGenerated",