From 300f4845352345bdfb68298aaf39e0296ae99bd7 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 26 Nov 2014 20:37:44 +0300 Subject: [PATCH] Support operator conventions for dynamic types TODO: - invoke - += etc --- .../resolve/calls/tasks/TaskPrioritizer.java | 38 ++++--- .../lang/resolve/calls/tasks/dynamicCalls.kt | 102 +++++++++++------- .../tests/dynamicTypes/conventions.kt | 90 ++++++++++++++++ .../tests/dynamicTypes/conventions.txt | 6 ++ .../checkers/JetDiagnosticsTestGenerated.java | 6 ++ 5 files changed, 189 insertions(+), 53 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/dynamicTypes/conventions.kt create mode 100644 compiler/testData/diagnostics/tests/dynamicTypes/conventions.txt 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 667f73fce09..0b056534c4f 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 @@ -20,6 +20,8 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.intellij.openapi.progress.ProgressIndicatorProvider; import kotlin.Function0; +import kotlin.Function1; +import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -43,8 +45,8 @@ 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.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.isOrOverridesSynthesized; @@ -122,7 +124,8 @@ public class TaskPrioritizer { ) { ProgressIndicatorProvider.checkCanceled(); - boolean resolveInvoke = c.context.call.getDispatchReceiver().exists(); + ReceiverValue dispatchReceiver = c.context.call.getDispatchReceiver(); + boolean resolveInvoke = dispatchReceiver.exists() && !TypesPackage.isDynamic(dispatchReceiver.getType()); if (resolveInvoke) { addCandidatesForInvoke(receiver, c); return; @@ -210,27 +213,36 @@ public class TaskPrioritizer { TaskPrioritizerContext onlyDynamicReceivers = c.replaceCollectors(TasksPackage.onlyDynamicReceivers(c.callableDescriptorCollectors)); addExtensionCandidates(explicitReceiver, implicitReceivers, onlyDynamicReceivers, isExplicit); - c.result.addCandidates( new Function0>>() { @Override public Collection> invoke() { - //noinspection unchecked - D dynamicDescriptor = (D) DynamicCallableDescriptors.createCallableDescriptorForDynamicCall( + JetScope dynamicScope = DynamicCallableDescriptors.createDynamicDescriptorScope( c.context.call, c.scope.getContainingDeclaration() ); - if (dynamicDescriptor == null) return Collections.emptyList(); - ResolutionCandidate dynamicCandidate = ResolutionCandidate.create( - c.context.call, - dynamicDescriptor + Collection dynamicDescriptors = new ArrayList(); + for (CallableDescriptorCollector collector : c.callableDescriptorCollectors) { + dynamicDescriptors.addAll(collector.getNonExtensionsByName(dynamicScope, c.name, c.context.trace)); + } + + return KotlinPackage.map( + dynamicDescriptors, + new Function1>() { + @Override + public ResolutionCandidate invoke(D dynamicDescriptor) { + ResolutionCandidate dynamicCandidate = ResolutionCandidate.create( + c.context.call, + dynamicDescriptor + ); + dynamicCandidate.setDispatchReceiver(explicitReceiver); + dynamicCandidate.setExplicitReceiverKind(DISPATCH_RECEIVER); + return dynamicCandidate; + } + } ); - dynamicCandidate.setDispatchReceiver(explicitReceiver); - dynamicCandidate.setExplicitReceiverKind(DISPATCH_RECEIVER); - - return Collections.singletonList(dynamicCandidate); } } ); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/dynamicCalls.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/dynamicCalls.kt index 6c3507c6102..adfdb0616cc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/dynamicCalls.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/dynamicCalls.kt @@ -43,55 +43,77 @@ import org.jetbrains.jet.lang.resolve.calls.tasks.collectors.CallableDescriptorC import org.jetbrains.jet.lang.resolve.scopes.JetScope import org.jetbrains.jet.lang.resolve.BindingTrace import org.jetbrains.jet.lang.resolve.calls.tasks.collectors.CallableDescriptorCollectors +import org.jetbrains.jet.lexer.JetToken +import org.jetbrains.jet.lang.psi.JetOperationReferenceExpression +import org.jetbrains.jet.lang.psi.JetArrayAccessExpression +import java.util.ArrayList +import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl +import org.jetbrains.jet.utils.Printer +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.jet.lang.descriptors.VariableDescriptor object DynamicCallableDescriptors { - platformStatic fun createCallableDescriptorForDynamicCall(call: Call, owner: DeclarationDescriptor): CallableDescriptor? { - val callee = call.getCalleeExpression() - if (callee !is JetSimpleNameExpression) return null - val name = callee.getReferencedNameAsName() + platformStatic fun createDynamicDescriptorScope(call: Call, owner: DeclarationDescriptor) = object : JetScopeImpl() { + override fun getContainingDeclaration() = owner - 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? - ) + override fun printScopeStructure(p: Printer) { + p.println(javaClass.getSimpleName(), ": dynamic candidates for " + call) + } - propertyDescriptor + override fun getFunctions(name: Name): Collection { + return listOf(createDynamicFunction(owner, name, call)) } - 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 + + override fun getProperties(name: Name): Collection { + return if (call.getValueArgumentList() == null && call.getValueArguments().isEmpty()) { + listOf(createDynamicProperty(owner, name, call)) + } + else listOf() } } + private fun createDynamicProperty(owner: DeclarationDescriptor, name: Name, call: Call): PropertyDescriptorImpl { + 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? + ) + + return propertyDescriptor + } + + private fun createDynamicFunction(owner: DeclarationDescriptor, name: Name, call: Call): SimpleFunctionDescriptorImpl { + 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 + ) + return functionDescriptor + } + private fun createDynamicDispatchReceiverParameter(owner: CallableDescriptor): ReceiverParameterDescriptorImpl { return ReceiverParameterDescriptorImpl( owner, diff --git a/compiler/testData/diagnostics/tests/dynamicTypes/conventions.kt b/compiler/testData/diagnostics/tests/dynamicTypes/conventions.kt new file mode 100644 index 00000000000..2af34aa882c --- /dev/null +++ b/compiler/testData/diagnostics/tests/dynamicTypes/conventions.kt @@ -0,0 +1,90 @@ +// !MARK_DYNAMIC_CALLS + +// MODULE[js]: m1 +// FILE: k.kt + +fun test(d: dynamic) { + +d + -d + ! d + + + d + d + d + 1 + "" + d + + d - d + d * d + d / d + d % d + + d..d + + d and d + + d in d + d !in d + + 1 in d + 1 !in d + + d[1] + d[1, 2] + + d[1] = 2 + d[1, 2] = 3 + + d[1]++ + ++d[1] + + d[1]-- + --d[1] + +// d() +// d(1) +// d(name = 1) +// d {} + + d == d + d != d + + d === d + d !== d + + d < d + d <= d + d >= d + d > d + + for (i in d) { + i.foo() + } + + val (a, b, c) = d + a.foo() + b.foo() + c.foo() + + var dVar = d + dVar++ + ++dVar + + dVar-- + --dVar + +// dVar += 1 +// dVar -= 1 +// dVar *= 1 +// dVar /= 1 +// dVar %= 1 + +// d[1] += 1 +// d[1] -= 1 +// d[1] *= 1 +// d[1] /= 1 +// d[1] %= 1 +} + +val dyn: dynamic = null +val foo : Int by dyn +var bar : Int by dyn diff --git a/compiler/testData/diagnostics/tests/dynamicTypes/conventions.txt b/compiler/testData/diagnostics/tests/dynamicTypes/conventions.txt new file mode 100644 index 00000000000..a56ca719e31 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dynamicTypes/conventions.txt @@ -0,0 +1,6 @@ +package + +internal var bar: kotlin.Int +internal val dyn: dynamic = null +internal val foo: kotlin.Int +internal fun test(/*0*/ d: dynamic): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index e4dd85ea277..bf53278ffa0 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3740,6 +3740,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("conventions.kt") + public void testConventions() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/conventions.kt"); + doTest(fileName); + } + @TestMetadata("dynamicCalls.kt") public void testDynamicCalls() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/dynamicCalls.kt");