Basic support for dynamic calls

This commit is contained in:
Andrey Breslav
2014-11-13 02:50:03 +02:00
parent d5932e1a33
commit 845f30975d
7 changed files with 213 additions and 0 deletions
@@ -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.types.ErrorUtils;
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.expressions.ExpressionTypingUtils;
import org.jetbrains.jet.storage.StorageManager;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.isOrOverridesSynthesized;
@@ -129,6 +131,7 @@ public class TaskPrioritizer {
if (receiver.exists()) {
addCandidatesForExplicitReceiver(receiver, implicitReceivers, c, /*isExplicit=*/true);
addMembers(receiver, c, /*static=*/true, /*isExplicit=*/true);
addCandidatesForDynamicReceiver(receiver, c);
return;
}
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) {
if (isExplicit) return kind;
return ExplicitReceiverKind.NO_EXPLICIT_RECEIVER;
@@ -235,6 +260,7 @@ public class TaskPrioritizer {
//try all implicit receivers as explicit
for (ReceiverValue implicitReceiver : implicitReceivers) {
addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*isExplicit=*/false);
addCandidatesForDynamicReceiver(implicitReceiver, c);
}
//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);
}
@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")
public void testNullable() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/nullable.kt");