@Nullable private KotlinType checkConventionForIterator( @NotNull ExpressionTypingContext context, @NotNull KtExpression loopRangeExpression, @NotNull KotlinType iteratorType, @NotNull String name, @NotNull DiagnosticFactory1<KtExpression, KotlinType> ambiguity, @NotNull DiagnosticFactory1<KtExpression, KotlinType> missing, @NotNull DiagnosticFactory1<KtExpression, KotlinType> noneApplicable, @NotNull WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> resolvedCallKey) { OverloadResolutionResults<FunctionDescriptor> nextResolutionResults = fakeCallResolver.resolveFakeCall( context, new TransientReceiver(iteratorType), Name.identifier(name), loopRangeExpression); if (nextResolutionResults.isAmbiguity()) { context.trace.report(ambiguity.on(loopRangeExpression, iteratorType)); } else if (nextResolutionResults.isNothing()) { context.trace.report(missing.on(loopRangeExpression, iteratorType)); } else if (!nextResolutionResults.isSuccess()) { context.trace.report(noneApplicable.on(loopRangeExpression, iteratorType)); } else { assert nextResolutionResults.isSuccess(); ResolvedCall<FunctionDescriptor> resolvedCall = nextResolutionResults.getResultingCall(); context.trace.record(resolvedCallKey, loopRangeExpression, resolvedCall); FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); symbolUsageValidator.validateCall( resolvedCall, functionDescriptor, context.trace, loopRangeExpression); checkIfOperatorModifierPresent(loopRangeExpression, functionDescriptor, context.trace); return functionDescriptor.getReturnType(); } return null; }
@Nullable public KotlinType checkIterableConvention( @NotNull ExpressionReceiver loopRange, ExpressionTypingContext context) { KtExpression loopRangeExpression = loopRange.getExpression(); // Make a fake call loopRange.iterator(), and try to resolve it Name iterator = Name.identifier("iterator"); Pair<Call, OverloadResolutionResults<FunctionDescriptor>> calls = fakeCallResolver.makeAndResolveFakeCall( loopRange, context, Collections.<KtExpression>emptyList(), iterator, loopRangeExpression, FakeCallKind.ITERATOR, loopRangeExpression); OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResults = calls.getSecond(); if (iteratorResolutionResults.isSuccess()) { ResolvedCall<FunctionDescriptor> iteratorResolvedCall = iteratorResolutionResults.getResultingCall(); context.trace.record( LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall); FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor(); checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace); symbolUsageValidator.validateCall( iteratorResolvedCall, iteratorFunction, context.trace, loopRangeExpression); KotlinType iteratorType = iteratorFunction.getReturnType(); KotlinType hasNextType = checkConventionForIterator( context, loopRangeExpression, iteratorType, "hasNext", HAS_NEXT_FUNCTION_AMBIGUITY, HAS_NEXT_MISSING, HAS_NEXT_FUNCTION_NONE_APPLICABLE, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL); if (hasNextType != null && !builtIns.isBooleanOrSubtype(hasNextType)) { context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRangeExpression, hasNextType)); } return checkConventionForIterator( context, loopRangeExpression, iteratorType, "next", NEXT_AMBIGUITY, NEXT_MISSING, NEXT_NONE_APPLICABLE, LOOP_RANGE_NEXT_RESOLVED_CALL); } else { if (iteratorResolutionResults.isAmbiguity()) { context.trace.report( ITERATOR_AMBIGUITY.on( loopRangeExpression, iteratorResolutionResults.getResultingCalls())); } else { context.trace.report(ITERATOR_MISSING.on(loopRangeExpression)); } } return null; }