Support operator conventions for dynamic types

TODO:
- invoke
- += etc
This commit is contained in:
Andrey Breslav
2014-11-26 20:37:44 +03:00
parent fac53de40c
commit 300f484535
5 changed files with 189 additions and 53 deletions
@@ -20,6 +20,8 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.progress.ProgressIndicatorProvider;
import kotlin.Function0; import kotlin.Function0;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; 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.lang.types.expressions.ExpressionTypingUtils;
import org.jetbrains.jet.storage.StorageManager; import org.jetbrains.jet.storage.StorageManager;
import java.util.ArrayList;
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;
@@ -122,7 +124,8 @@ public class TaskPrioritizer {
) { ) {
ProgressIndicatorProvider.checkCanceled(); 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) { if (resolveInvoke) {
addCandidatesForInvoke(receiver, c); addCandidatesForInvoke(receiver, c);
return; return;
@@ -210,27 +213,36 @@ public class TaskPrioritizer {
TaskPrioritizerContext<D, F> onlyDynamicReceivers = c.replaceCollectors(TasksPackage.onlyDynamicReceivers(c.callableDescriptorCollectors)); TaskPrioritizerContext<D, F> onlyDynamicReceivers = c.replaceCollectors(TasksPackage.onlyDynamicReceivers(c.callableDescriptorCollectors));
addExtensionCandidates(explicitReceiver, implicitReceivers, onlyDynamicReceivers, isExplicit); addExtensionCandidates(explicitReceiver, implicitReceivers, onlyDynamicReceivers, isExplicit);
c.result.addCandidates( c.result.addCandidates(
new Function0<Collection<? extends ResolutionCandidate<D>>>() { new Function0<Collection<? extends ResolutionCandidate<D>>>() {
@Override @Override
public Collection<? extends ResolutionCandidate<D>> invoke() { public Collection<? extends ResolutionCandidate<D>> invoke() {
//noinspection unchecked JetScope dynamicScope = DynamicCallableDescriptors.createDynamicDescriptorScope(
D dynamicDescriptor = (D) DynamicCallableDescriptors.createCallableDescriptorForDynamicCall(
c.context.call, c.context.call,
c.scope.getContainingDeclaration() c.scope.getContainingDeclaration()
); );
if (dynamicDescriptor == null) return Collections.emptyList();
ResolutionCandidate<D> dynamicCandidate = ResolutionCandidate.create( Collection<D> dynamicDescriptors = new ArrayList<D>();
c.context.call, for (CallableDescriptorCollector<D> collector : c.callableDescriptorCollectors) {
dynamicDescriptor dynamicDescriptors.addAll(collector.getNonExtensionsByName(dynamicScope, c.name, c.context.trace));
}
return KotlinPackage.map(
dynamicDescriptors,
new Function1<D, ResolutionCandidate<D>>() {
@Override
public ResolutionCandidate<D> invoke(D dynamicDescriptor) {
ResolutionCandidate<D> 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);
} }
} }
); );
@@ -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.scopes.JetScope
import org.jetbrains.jet.lang.resolve.BindingTrace import org.jetbrains.jet.lang.resolve.BindingTrace
import org.jetbrains.jet.lang.resolve.calls.tasks.collectors.CallableDescriptorCollectors 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 { object DynamicCallableDescriptors {
platformStatic fun createCallableDescriptorForDynamicCall(call: Call, owner: DeclarationDescriptor): CallableDescriptor? { platformStatic fun createDynamicDescriptorScope(call: Call, owner: DeclarationDescriptor) = object : JetScopeImpl() {
val callee = call.getCalleeExpression() override fun getContainingDeclaration() = owner
if (callee !is JetSimpleNameExpression) return null
val name = callee.getReferencedNameAsName()
return if (call.getValueArgumentList() == null && call.getValueArguments().isEmpty()) { override fun printScopeStructure(p: Printer) {
val propertyDescriptor = PropertyDescriptorImpl.create( p.println(javaClass.getSimpleName(), ": dynamic candidates for " + call)
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 override fun getFunctions(name: Name): Collection<FunctionDescriptor> {
return listOf(createDynamicFunction(owner, name, call))
} }
else {
val functionDescriptor = SimpleFunctionDescriptorImpl.create( override fun getProperties(name: Name): Collection<VariableDescriptor> {
owner, return if (call.getValueArgumentList() == null && call.getValueArguments().isEmpty()) {
Annotations.EMPTY, listOf(createDynamicProperty(owner, name, call))
name, }
CallableMemberDescriptor.Kind.DECLARATION, else listOf()
SourceElement.NO_SOURCE
)
functionDescriptor.initialize(
null,
createDynamicDispatchReceiverParameter(functionDescriptor),
createTypeParameters(functionDescriptor, call),
createValueParameters(functionDescriptor, call),
DynamicType,
Modality.FINAL,
Visibilities.PUBLIC
)
functionDescriptor
} }
} }
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 { private fun createDynamicDispatchReceiverParameter(owner: CallableDescriptor): ReceiverParameterDescriptorImpl {
return ReceiverParameterDescriptorImpl( return ReceiverParameterDescriptorImpl(
owner, owner,
@@ -0,0 +1,90 @@
// !MARK_DYNAMIC_CALLS
// MODULE[js]: m1
// FILE: k.kt
fun test(d: dynamic) {
<!DEBUG_INFO_DYNAMIC!>+<!>d
<!DEBUG_INFO_DYNAMIC!>-<!>d
<!DEBUG_INFO_DYNAMIC!>!<!> d
d <!DEBUG_INFO_DYNAMIC!>+<!> d
d <!DEBUG_INFO_DYNAMIC!>+<!> 1
"" + d
d <!DEBUG_INFO_DYNAMIC!>-<!> d
d <!DEBUG_INFO_DYNAMIC!>*<!> d
d <!DEBUG_INFO_DYNAMIC!>/<!> d
d <!DEBUG_INFO_DYNAMIC!>%<!> d
d<!DEBUG_INFO_DYNAMIC!>..<!>d
d <!DEBUG_INFO_DYNAMIC!>and<!> d
d <!DEBUG_INFO_DYNAMIC!>in<!> d
d <!DEBUG_INFO_DYNAMIC!>!in<!> d
1 <!DEBUG_INFO_DYNAMIC!>in<!> d
1 <!DEBUG_INFO_DYNAMIC!>!in<!> d
<!DEBUG_INFO_DYNAMIC!>d[1]<!>
<!DEBUG_INFO_DYNAMIC!>d[1, 2]<!>
<!DEBUG_INFO_DYNAMIC!>d[1]<!> = 2
<!DEBUG_INFO_DYNAMIC!>d[1, 2]<!> = 3
<!DEBUG_INFO_DYNAMIC!>d[1]<!><!DEBUG_INFO_DYNAMIC!>++<!>
<!DEBUG_INFO_DYNAMIC!>++<!><!DEBUG_INFO_DYNAMIC!>d[1]<!>
<!DEBUG_INFO_DYNAMIC!>d[1]<!><!DEBUG_INFO_DYNAMIC!>--<!>
<!DEBUG_INFO_DYNAMIC!>--<!><!DEBUG_INFO_DYNAMIC!>d[1]<!>
// d()
// d(1)
// d(name = 1)
// d {}
d == d
d != d
d === d
d !== d
d <!DEBUG_INFO_DYNAMIC!><<!> d
d <!DEBUG_INFO_DYNAMIC!><=<!> d
d <!DEBUG_INFO_DYNAMIC!>>=<!> d
d <!DEBUG_INFO_DYNAMIC!>><!> d
for (i in <!DEBUG_INFO_DYNAMIC!>d<!>) {
i.<!DEBUG_INFO_DYNAMIC!>foo<!>()
}
val (<!DEBUG_INFO_DYNAMIC!>a<!>, <!DEBUG_INFO_DYNAMIC!>b<!>, <!DEBUG_INFO_DYNAMIC!>c<!>) = d
a.<!DEBUG_INFO_DYNAMIC!>foo<!>()
b.<!DEBUG_INFO_DYNAMIC!>foo<!>()
c.<!DEBUG_INFO_DYNAMIC!>foo<!>()
var dVar = d
dVar<!DEBUG_INFO_DYNAMIC!>++<!>
<!DEBUG_INFO_DYNAMIC!>++<!>dVar
dVar<!DEBUG_INFO_DYNAMIC!>--<!>
<!DEBUG_INFO_DYNAMIC!>--<!>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 <!DEBUG_INFO_DYNAMIC!>by dyn<!>
var bar : Int <!DEBUG_INFO_DYNAMIC!>by dyn<!>
@@ -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
@@ -3740,6 +3740,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName); 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") @TestMetadata("dynamicCalls.kt")
public void testDynamicCalls() throws Exception { public void testDynamicCalls() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/dynamicCalls.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/dynamicCalls.kt");