Support operator conventions for dynamic types
TODO: - invoke - += etc
This commit is contained in:
+25
-13
@@ -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<D, F> onlyDynamicReceivers = c.replaceCollectors(TasksPackage.onlyDynamicReceivers(c.callableDescriptorCollectors));
|
||||
addExtensionCandidates(explicitReceiver, implicitReceivers, onlyDynamicReceivers, isExplicit);
|
||||
|
||||
|
||||
c.result.addCandidates(
|
||||
new Function0<Collection<? extends ResolutionCandidate<D>>>() {
|
||||
@Override
|
||||
public Collection<? extends ResolutionCandidate<D>> 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<D> dynamicCandidate = ResolutionCandidate.create(
|
||||
c.context.call,
|
||||
dynamicDescriptor
|
||||
Collection<D> dynamicDescriptors = new ArrayList<D>();
|
||||
for (CallableDescriptorCollector<D> collector : c.callableDescriptorCollectors) {
|
||||
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.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<FunctionDescriptor> {
|
||||
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<VariableDescriptor> {
|
||||
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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@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");
|
||||
|
||||
Reference in New Issue
Block a user