Basic support for dynamic calls
This commit is contained in:
@@ -38,11 +38,13 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.QualifierReceiver;
|
|||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.TypesPackage;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
|
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
|
||||||
import org.jetbrains.jet.storage.StorageManager;
|
import org.jetbrains.jet.storage.StorageManager;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.isOrOverridesSynthesized;
|
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.isOrOverridesSynthesized;
|
||||||
@@ -129,6 +131,7 @@ public class TaskPrioritizer {
|
|||||||
if (receiver.exists()) {
|
if (receiver.exists()) {
|
||||||
addCandidatesForExplicitReceiver(receiver, implicitReceivers, c, /*isExplicit=*/true);
|
addCandidatesForExplicitReceiver(receiver, implicitReceivers, c, /*isExplicit=*/true);
|
||||||
addMembers(receiver, c, /*static=*/true, /*isExplicit=*/true);
|
addMembers(receiver, c, /*static=*/true, /*isExplicit=*/true);
|
||||||
|
addCandidatesForDynamicReceiver(receiver, c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
addCandidatesForNoReceiver(implicitReceivers, c);
|
addCandidatesForNoReceiver(implicitReceivers, c);
|
||||||
@@ -186,6 +189,28 @@ public class TaskPrioritizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <D extends CallableDescriptor, F extends D> void addCandidatesForDynamicReceiver(
|
||||||
|
@NotNull ReceiverValue receiver,
|
||||||
|
@NotNull TaskPrioritizerContext<D, F> c
|
||||||
|
) {
|
||||||
|
if (!TypesPackage.isDynamic(receiver.getType())) return;
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
D dynamicDescriptor = (D) DynamicCallableDescriptors.createCallableDescriptorForDynamicCall(
|
||||||
|
c.context.call,
|
||||||
|
c.scope.getContainingDeclaration()
|
||||||
|
);
|
||||||
|
if (dynamicDescriptor == null) return;
|
||||||
|
|
||||||
|
ResolutionCandidate<D> dynamicCandidate = ResolutionCandidate.create(
|
||||||
|
c.context.call,
|
||||||
|
dynamicDescriptor
|
||||||
|
);
|
||||||
|
dynamicCandidate.setDispatchReceiver(receiver);
|
||||||
|
dynamicCandidate.setExplicitReceiverKind(DISPATCH_RECEIVER);
|
||||||
|
c.result.addCandidates(Collections.singletonList(dynamicCandidate));
|
||||||
|
}
|
||||||
|
|
||||||
private static ExplicitReceiverKind createKind(ExplicitReceiverKind kind, boolean isExplicit) {
|
private static ExplicitReceiverKind createKind(ExplicitReceiverKind kind, boolean isExplicit) {
|
||||||
if (isExplicit) return kind;
|
if (isExplicit) return kind;
|
||||||
return ExplicitReceiverKind.NO_EXPLICIT_RECEIVER;
|
return ExplicitReceiverKind.NO_EXPLICIT_RECEIVER;
|
||||||
@@ -235,6 +260,7 @@ public class TaskPrioritizer {
|
|||||||
//try all implicit receivers as explicit
|
//try all implicit receivers as explicit
|
||||||
for (ReceiverValue implicitReceiver : implicitReceivers) {
|
for (ReceiverValue implicitReceiver : implicitReceivers) {
|
||||||
addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*isExplicit=*/false);
|
addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*isExplicit=*/false);
|
||||||
|
addCandidatesForDynamicReceiver(implicitReceiver, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
//nonlocals
|
//nonlocals
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* 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.jet.lang.psi.Call
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
||||||
|
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
|
import org.jetbrains.jet.lang.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.jet.lang.descriptors.SourceElement
|
||||||
|
import org.jetbrains.jet.lang.descriptors.impl.ReceiverParameterDescriptorImpl
|
||||||
|
import org.jetbrains.jet.lang.types.DynamicType
|
||||||
|
import org.jetbrains.jet.lang.descriptors.Modality
|
||||||
|
import org.jetbrains.jet.lang.descriptors.Visibilities
|
||||||
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.jet.lang.descriptors.impl.PropertyDescriptorImpl
|
||||||
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl
|
||||||
|
import org.jetbrains.jet.lang.types.Variance
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.Name
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
import org.jetbrains.jet.lang.types.JetType
|
||||||
|
import kotlin.platform.platformStatic
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver
|
||||||
|
|
||||||
|
object DynamicCallableDescriptors {
|
||||||
|
|
||||||
|
platformStatic fun createCallableDescriptorForDynamicCall(call: Call, owner: DeclarationDescriptor): CallableDescriptor? {
|
||||||
|
val callee = call.getCalleeExpression()
|
||||||
|
if (callee !is JetSimpleNameExpression) return null
|
||||||
|
val name = callee.getReferencedNameAsName()
|
||||||
|
|
||||||
|
return if (call.getValueArgumentList() == null && call.getValueArguments().isEmpty()) {
|
||||||
|
val propertyDescriptor = PropertyDescriptorImpl.create(
|
||||||
|
owner,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
Modality.FINAL,
|
||||||
|
Visibilities.PUBLIC,
|
||||||
|
true,
|
||||||
|
name,
|
||||||
|
CallableMemberDescriptor.Kind.DECLARATION,
|
||||||
|
SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
propertyDescriptor.setType(
|
||||||
|
DynamicType,
|
||||||
|
createTypeParameters(propertyDescriptor, call),
|
||||||
|
createDynamicDispatchReceiverParameter(propertyDescriptor),
|
||||||
|
null: JetType?
|
||||||
|
)
|
||||||
|
|
||||||
|
propertyDescriptor
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
|
owner,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
name,
|
||||||
|
CallableMemberDescriptor.Kind.DECLARATION,
|
||||||
|
SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
functionDescriptor.initialize(
|
||||||
|
null,
|
||||||
|
createDynamicDispatchReceiverParameter(functionDescriptor),
|
||||||
|
createTypeParameters(functionDescriptor, call),
|
||||||
|
createValueParameters(functionDescriptor, call),
|
||||||
|
DynamicType,
|
||||||
|
Modality.FINAL,
|
||||||
|
Visibilities.PUBLIC
|
||||||
|
)
|
||||||
|
functionDescriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDynamicDispatchReceiverParameter(owner: CallableDescriptor): ReceiverParameterDescriptorImpl {
|
||||||
|
return ReceiverParameterDescriptorImpl(
|
||||||
|
owner,
|
||||||
|
DynamicType,
|
||||||
|
TransientReceiver(DynamicType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTypeParameters(owner: DeclarationDescriptor, call: Call): List<TypeParameterDescriptor> = call.getTypeArguments().indices.map {
|
||||||
|
index
|
||||||
|
->
|
||||||
|
TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||||
|
owner,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
false,
|
||||||
|
Variance.INVARIANT,
|
||||||
|
Name.identifier("T$index"),
|
||||||
|
index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createValueParameters(owner: DeclarationDescriptor, call: Call): List<ValueParameterDescriptor> =
|
||||||
|
call.getValueArguments().indices.map {
|
||||||
|
index
|
||||||
|
->
|
||||||
|
ValueParameterDescriptorImpl(
|
||||||
|
owner,
|
||||||
|
null,
|
||||||
|
index,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
Name.identifier("p$index"),
|
||||||
|
DynamicType,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// MODULE[js]: m1
|
||||||
|
// FILE: k.kt
|
||||||
|
|
||||||
|
fun test(d: dynamic) {
|
||||||
|
val v1 = d.foo()
|
||||||
|
v1.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
val v2 = d.foo(1)
|
||||||
|
v2.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
val v3 = d.foo(1, "")
|
||||||
|
v3.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
// val v4 = d.foo<String>()
|
||||||
|
// v4.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
val v5 = d.foo
|
||||||
|
v5.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
d.foo = 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
internal fun test(/*0*/ d: dynamic): kotlin.Unit
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// MODULE[js]: m1
|
||||||
|
// FILE: k.kt
|
||||||
|
|
||||||
|
fun (dynamic).test() {
|
||||||
|
val v1 = foo()
|
||||||
|
v1.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
val v2 = foo(1)
|
||||||
|
v2.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
val v3 = foo(1, "")
|
||||||
|
v3.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
// val v4 = foo<String>()
|
||||||
|
// v4.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
val v5 = foo
|
||||||
|
v5.isDynamic() // to check that anything is resolvable
|
||||||
|
|
||||||
|
foo = 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
internal fun dynamic.test(): kotlin.Unit
|
||||||
@@ -3722,6 +3722,18 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("dynamicCalls.kt")
|
||||||
|
public void testDynamicCalls() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/dynamicCalls.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("implicitDynamicReceiver.kt")
|
||||||
|
public void testImplicitDynamicReceiver() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/implicitDynamicReceiver.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nullable.kt")
|
@TestMetadata("nullable.kt")
|
||||||
public void testNullable() throws Exception {
|
public void testNullable() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/nullable.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/nullable.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user