diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt index c36c7617231..92929e5df3a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt @@ -68,6 +68,8 @@ public class OperatorModifierChecker : DeclarationChecker { INVOKE == name -> {} CONTAINS == name -> {} ITERATOR == name -> {} + NEXT == name -> {} + HAS_NEXT == name -> {} EQUALS == name -> {} COMPARE_TO == name -> {} UNARY_OPERATION_NAMES.any { it.value == name } && functionDescriptor.valueParameters.isEmpty() -> {} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ForLoopConventionsChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ForLoopConventionsChecker.java index b82965c9874..b7c84078957 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ForLoopConventionsChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ForLoopConventionsChecker.java @@ -21,15 +21,22 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1; +import org.jetbrains.kotlin.diagnostics.DiagnosticSink; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.psi.JetExpression; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; +import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt; +import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver; +import org.jetbrains.kotlin.resolve.validation.OperatorValidator; import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator; +import org.jetbrains.kotlin.types.DynamicTypesKt; +import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.util.slicedMap.WritableSlice; @@ -70,6 +77,8 @@ public class ForLoopConventionsChecker { context.trace.record(LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall); FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor(); + checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace); + symbolUsageValidator.validateCall(iteratorFunction, context.trace, loopRangeExpression); JetType iteratorType = iteratorFunction.getReturnType(); @@ -94,6 +103,16 @@ public class ForLoopConventionsChecker { return null; } + private static void checkIfOperatorModifierPresent(JetExpression expression, FunctionDescriptor descriptor, DiagnosticSink sink) { + if (ErrorUtils.isError(descriptor)) return; + ReceiverParameterDescriptor extensionReceiverParameter = descriptor.getExtensionReceiverParameter(); + if ((extensionReceiverParameter != null) && (DynamicTypesKt.isDynamic(extensionReceiverParameter.getType()))) return; + + if (!descriptor.isOperator()) { + OperatorValidator.Companion.report(expression, descriptor, sink); + } + } + @Nullable private JetType checkConventionForIterator( @NotNull ExpressionTypingContext context, @@ -122,6 +141,9 @@ public class ForLoopConventionsChecker { context.trace.record(resolvedCallKey, loopRangeExpression, resolvedCall); FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); symbolUsageValidator.validateCall(functionDescriptor, context.trace, loopRangeExpression); + + checkIfOperatorModifierPresent(loopRangeExpression, functionDescriptor, context.trace); + return functionDescriptor.getReturnType(); } return null; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/OperatorConventions.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/OperatorConventions.java index a1634eb72b4..d7adeeb6fcd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/OperatorConventions.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/OperatorConventions.java @@ -33,6 +33,8 @@ public class OperatorConventions { public static final Name CONTAINS = Name.identifier("contains"); public static final Name INVOKE = Name.identifier("invoke"); public static final Name ITERATOR = Name.identifier("iterator"); + public static final Name NEXT = Name.identifier("next"); + public static final Name HAS_NEXT = Name.identifier("hasNext"); private OperatorConventions() {}