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.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");
|
||||
|
||||
Reference in New Issue
Block a user