Allow augmented assignments on dynamic receivers
This commit is contained in:
+6
-5
@@ -147,9 +147,12 @@ public class TaskPrioritizer {
|
|||||||
) {
|
) {
|
||||||
addMembers(explicitReceiver, c, /*static=*/false, isExplicit);
|
addMembers(explicitReceiver, c, /*static=*/false, isExplicit);
|
||||||
|
|
||||||
addCandidatesForDynamicReceiver(explicitReceiver, implicitReceivers, c, isExplicit);
|
if (TypesPackage.isDynamic(explicitReceiver.getType())) {
|
||||||
|
addCandidatesForDynamicReceiver(explicitReceiver, implicitReceivers, c, isExplicit);
|
||||||
addExtensionCandidates(explicitReceiver, implicitReceivers, c, isExplicit);
|
}
|
||||||
|
else {
|
||||||
|
addExtensionCandidates(explicitReceiver, implicitReceivers, c, isExplicit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <D extends CallableDescriptor, F extends D> void addExtensionCandidates(
|
private static <D extends CallableDescriptor, F extends D> void addExtensionCandidates(
|
||||||
@@ -208,8 +211,6 @@ public class TaskPrioritizer {
|
|||||||
@NotNull final TaskPrioritizerContext<D, F> c,
|
@NotNull final TaskPrioritizerContext<D, F> c,
|
||||||
boolean isExplicit
|
boolean isExplicit
|
||||||
) {
|
) {
|
||||||
if (!TypesPackage.isDynamic(explicitReceiver.getType())) return;
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve.calls.tasks
|
|||||||
|
|
||||||
import org.jetbrains.jet.lang.psi.Call
|
import org.jetbrains.jet.lang.psi.Call
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
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.impl.SimpleFunctionDescriptorImpl
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotations
|
import org.jetbrains.jet.lang.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor
|
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor
|
||||||
@@ -43,14 +42,13 @@ 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.lang.resolve.scopes.JetScopeImpl
|
||||||
import org.jetbrains.jet.utils.Printer
|
import org.jetbrains.jet.utils.Printer
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor
|
||||||
|
import org.jetbrains.jet.lexer.JetTokens
|
||||||
|
import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
||||||
|
import org.jetbrains.jet.lang.psi.JetOperationReferenceExpression
|
||||||
|
|
||||||
object DynamicCallableDescriptors {
|
object DynamicCallableDescriptors {
|
||||||
|
|
||||||
@@ -62,9 +60,27 @@ object DynamicCallableDescriptors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getFunctions(name: Name): Collection<FunctionDescriptor> {
|
override fun getFunctions(name: Name): Collection<FunctionDescriptor> {
|
||||||
|
if (isAugmentedAssignmentConvention(name)) return listOf()
|
||||||
return listOf(createDynamicFunction(owner, name, call))
|
return listOf(createDynamicFunction(owner, name, call))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detects the case when name "plusAssign" is requested for "+=" call,
|
||||||
|
* since both "plus" and "plusAssign" are resolvable on dynamic receivers,
|
||||||
|
* we have to prefer ne of them, and prefer "plusAssign" for generality:
|
||||||
|
* it may be called even on a val
|
||||||
|
*/
|
||||||
|
private fun isAugmentedAssignmentConvention(name: Name): Boolean {
|
||||||
|
val callee = call.getCalleeExpression()
|
||||||
|
if (callee is JetOperationReferenceExpression) {
|
||||||
|
val token = callee.getReferencedNameElementType()
|
||||||
|
if (token in JetTokens.AUGMENTED_ASSIGNMENTS && OperatorConventions.ASSIGNMENT_OPERATIONS[token] != name) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
override fun getProperties(name: Name): Collection<VariableDescriptor> {
|
override fun getProperties(name: Name): Collection<VariableDescriptor> {
|
||||||
return if (call.getValueArgumentList() == null && call.getValueArguments().isEmpty()) {
|
return if (call.getValueArgumentList() == null && call.getValueArguments().isEmpty()) {
|
||||||
listOf(createDynamicProperty(owner, name, call))
|
listOf(createDynamicProperty(owner, name, call))
|
||||||
|
|||||||
+2
-1
@@ -36,6 +36,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
|||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.JetTypeInfo;
|
import org.jetbrains.jet.lang.types.JetTypeInfo;
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
@@ -284,7 +285,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
|
|||||||
else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) {
|
else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) {
|
||||||
// There's 'plusAssign()', so we do a.plusAssign(b)
|
// There's 'plusAssign()', so we do a.plusAssign(b)
|
||||||
temporaryForAssignmentOperation.commit();
|
temporaryForAssignmentOperation.commit();
|
||||||
if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) {
|
if (!JetTypeChecker.DEFAULT.equalTypes(KotlinBuiltIns.getInstance().getUnitType(), assignmentOperationType)) {
|
||||||
context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
|
context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,17 +72,23 @@ fun test(d: dynamic) {
|
|||||||
dVar<!DEBUG_INFO_DYNAMIC!>--<!>
|
dVar<!DEBUG_INFO_DYNAMIC!>--<!>
|
||||||
<!DEBUG_INFO_DYNAMIC!>--<!>dVar
|
<!DEBUG_INFO_DYNAMIC!>--<!>dVar
|
||||||
|
|
||||||
// dVar += 1
|
dVar <!DEBUG_INFO_DYNAMIC!>+=<!> 1
|
||||||
// dVar -= 1
|
dVar <!DEBUG_INFO_DYNAMIC!>-=<!> 1
|
||||||
// dVar *= 1
|
dVar <!DEBUG_INFO_DYNAMIC!>*=<!> 1
|
||||||
// dVar /= 1
|
dVar <!DEBUG_INFO_DYNAMIC!>/=<!> 1
|
||||||
// dVar %= 1
|
dVar <!DEBUG_INFO_DYNAMIC!>%=<!> 1
|
||||||
|
|
||||||
// d[1] += 1
|
d <!DEBUG_INFO_DYNAMIC!>+=<!> 1
|
||||||
// d[1] -= 1
|
d <!DEBUG_INFO_DYNAMIC!>-=<!> 1
|
||||||
// d[1] *= 1
|
d <!DEBUG_INFO_DYNAMIC!>*=<!> 1
|
||||||
// d[1] /= 1
|
d <!DEBUG_INFO_DYNAMIC!>/=<!> 1
|
||||||
// d[1] %= 1
|
d <!DEBUG_INFO_DYNAMIC!>%=<!> 1
|
||||||
|
|
||||||
|
<!DEBUG_INFO_DYNAMIC!>d[1]<!> <!DEBUG_INFO_DYNAMIC!>+=<!> 1
|
||||||
|
<!DEBUG_INFO_DYNAMIC!>d[1]<!> <!DEBUG_INFO_DYNAMIC!>-=<!> 1
|
||||||
|
<!DEBUG_INFO_DYNAMIC!>d[1]<!> <!DEBUG_INFO_DYNAMIC!>*=<!> 1
|
||||||
|
<!DEBUG_INFO_DYNAMIC!>d[1]<!> <!DEBUG_INFO_DYNAMIC!>/=<!> 1
|
||||||
|
<!DEBUG_INFO_DYNAMIC!>d[1]<!> <!DEBUG_INFO_DYNAMIC!>%=<!> 1
|
||||||
}
|
}
|
||||||
|
|
||||||
val dyn: dynamic = null
|
val dyn: dynamic = null
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ Internally, `dynamic` is represented as a flexible type `Nothing..Any?`, with th
|
|||||||
the code may change its semantics just because somebody added some extension in another file.
|
the code may change its semantics just because somebody added some extension in another file.
|
||||||
- This means that an extension to a normal, non-dynamic type **can not** be called on a `dynamic` receiver.
|
- This means that an extension to a normal, non-dynamic type **can not** be called on a `dynamic` receiver.
|
||||||
If needed, one can force a call to an extension by casting the receiver to a static type: `(d as Foo).bar()`
|
If needed, one can force a call to an extension by casting the receiver to a static type: `(d as Foo).bar()`
|
||||||
|
- Augmented assignments on dynamic receivers (e.g. `dyn += foo`) are resolved to `plusAssign()` function, not `plus`, for generality:
|
||||||
|
this permits calling them on vals (e.g. those holding collection-like objects)
|
||||||
|
|
||||||
## Type Argument Inference
|
## Type Argument Inference
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user