001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.lang.resolve.calls;
018    
019    import com.google.common.base.Function;
020    import com.google.common.collect.Lists;
021    import com.google.common.collect.Maps;
022    import com.google.common.collect.Sets;
023    import com.intellij.openapi.progress.ProgressIndicatorProvider;
024    import com.intellij.psi.PsiElement;
025    import org.jetbrains.annotations.NotNull;
026    import org.jetbrains.annotations.Nullable;
027    import org.jetbrains.jet.lang.descriptors.*;
028    import org.jetbrains.jet.lang.psi.*;
029    import org.jetbrains.jet.lang.resolve.*;
030    import org.jetbrains.jet.lang.resolve.calls.autocasts.*;
031    import org.jetbrains.jet.lang.resolve.calls.context.*;
032    import org.jetbrains.jet.lang.resolve.calls.inference.*;
033    import org.jetbrains.jet.lang.resolve.calls.model.*;
034    import org.jetbrains.jet.lang.resolve.calls.results.ResolutionDebugInfo;
035    import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
036    import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
037    import org.jetbrains.jet.lang.resolve.calls.tasks.TaskPrioritizer;
038    import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
039    import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
040    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
041    import org.jetbrains.jet.lang.types.*;
042    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
043    import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
044    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
045    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
046    
047    import javax.inject.Inject;
048    import java.util.*;
049    
050    import static org.jetbrains.jet.lang.diagnostics.Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT;
051    import static org.jetbrains.jet.lang.diagnostics.Errors.SUPER_IS_NOT_AN_EXPRESSION;
052    import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
053    import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
054    import static org.jetbrains.jet.lang.resolve.calls.CallTransformer.CallForImplicitInvoke;
055    import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
056    import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.*;
057    import static org.jetbrains.jet.lang.types.TypeUtils.*;
058    
059    public class CandidateResolver {
060        @NotNull
061        private ArgumentTypeResolver argumentTypeResolver;
062    
063        @Inject
064        public void setArgumentTypeResolver(@NotNull ArgumentTypeResolver argumentTypeResolver) {
065            this.argumentTypeResolver = argumentTypeResolver;
066        }
067    
068        public <D extends CallableDescriptor, F extends D> void performResolutionForCandidateCall(
069                @NotNull CallCandidateResolutionContext<D> context,
070                @NotNull ResolutionTask<D, F> task) {
071    
072            ProgressIndicatorProvider.checkCanceled();
073    
074            ResolvedCallImpl<D> candidateCall = context.candidateCall;
075            D candidate = candidateCall.getCandidateDescriptor();
076    
077            candidateCall.addStatus(checkReceiverTypeError(context));
078    
079            if (ErrorUtils.isError(candidate)) {
080                candidateCall.addStatus(SUCCESS);
081                markAllArgumentsAsUnmapped(context);
082                return;
083            }
084    
085            if (!checkOuterClassMemberIsAccessible(context)) {
086                candidateCall.addStatus(OTHER_ERROR);
087                markAllArgumentsAsUnmapped(context);
088                return;
089            }
090    
091    
092            DeclarationDescriptorWithVisibility invisibleMember =
093                    Visibilities.findInvisibleMember(candidate, context.scope.getContainingDeclaration());
094            if (invisibleMember != null) {
095                candidateCall.addStatus(OTHER_ERROR);
096                context.tracing.invisibleMember(context.trace, invisibleMember);
097                markAllArgumentsAsUnmapped(context);
098                return;
099            }
100    
101            if (task.checkArguments == CheckValueArgumentsMode.ENABLED) {
102                Set<ValueArgument> unmappedArguments = Sets.newLinkedHashSet();
103                ValueArgumentsToParametersMapper.Status
104                        argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(context.call, context.tracing,
105                                                                                                                candidateCall, unmappedArguments);
106                if (!argumentMappingStatus.isSuccess()) {
107                    if (argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
108                        candidateCall.addStatus(RECEIVER_PRESENCE_ERROR);
109                    }
110                    else {
111                        candidateCall.addStatus(OTHER_ERROR);
112                    }
113                    candidateCall.setUnmappedArguments(unmappedArguments);
114                    if ((argumentMappingStatus == ValueArgumentsToParametersMapper.Status.ERROR && candidate.getTypeParameters().isEmpty()) ||
115                        argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
116                        return;
117                    }
118                }
119            }
120    
121            List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments();
122            if (jetTypeArguments.isEmpty()) {
123                if (!candidate.getTypeParameters().isEmpty()) {
124                    ResolutionStatus status = inferTypeArguments(context);
125                    candidateCall.addStatus(status);
126                }
127                else {
128                    candidateCall.addStatus(checkAllValueArguments(context, SHAPE_FUNCTION_ARGUMENTS).status);
129                }
130            }
131            else {
132                // Explicit type arguments passed
133    
134                List<JetType> typeArguments = new ArrayList<JetType>();
135                for (JetTypeProjection projection : jetTypeArguments) {
136                    if (projection.getProjectionKind() != JetProjectionKind.NONE) {
137                        context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
138                    }
139                    typeArguments.add(argumentTypeResolver.resolveTypeRefWithDefault(
140                            projection.getTypeReference(), context.scope, context.trace, ErrorUtils.createErrorType("Star projection in a call")));
141                }
142                int expectedTypeArgumentCount = candidate.getTypeParameters().size();
143                if (expectedTypeArgumentCount == jetTypeArguments.size()) {
144    
145                    checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, context.trace);
146    
147                    Map<TypeConstructor, TypeProjection>
148                            substitutionContext = FunctionDescriptorUtil
149                            .createSubstitutionContext((FunctionDescriptor) candidate, typeArguments);
150                    TypeSubstitutor substitutor = TypeSubstitutor.create(substitutionContext);
151                    candidateCall.setResultingSubstitutor(substitutor);
152    
153                    candidateCall.addStatus(checkAllValueArguments(context, SHAPE_FUNCTION_ARGUMENTS).status);
154                }
155                else {
156                    candidateCall.addStatus(OTHER_ERROR);
157                    context.tracing.wrongNumberOfTypeArguments(context.trace, expectedTypeArgumentCount);
158                }
159            }
160    
161            task.performAdvancedChecks(candidate, context.trace, context.tracing);
162    
163            // 'super' cannot be passed as an argument, for receiver arguments expression typer does not track this
164            // See TaskPrioritizer for more
165            JetSuperExpression superExpression = TaskPrioritizer.getReceiverSuper(candidateCall.getReceiverArgument());
166            if (superExpression != null) {
167                context.trace.report(SUPER_IS_NOT_AN_EXPRESSION.on(superExpression, superExpression.getText()));
168                candidateCall.addStatus(OTHER_ERROR);
169            }
170        }
171    
172        private static void markAllArgumentsAsUnmapped(CallCandidateResolutionContext<?> context) {
173            if (context.checkArguments == CheckValueArgumentsMode.ENABLED) {
174                context.candidateCall.setUnmappedArguments(context.call.getValueArguments());
175            }
176        }
177    
178        private static boolean checkOuterClassMemberIsAccessible(@NotNull CallCandidateResolutionContext<?> context) {
179            // In "this@Outer.foo()" the error will be reported on "this@Outer" instead
180            if (context.call.getExplicitReceiver().exists() || context.call.getThisObject().exists()) return true;
181    
182            ClassDescriptor candidateThis = getDeclaringClass(context.candidateCall.getCandidateDescriptor());
183            if (candidateThis == null || candidateThis.getKind().isSingleton()) return true;
184    
185            return DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, context.call.getCallElement(), candidateThis);
186        }
187    
188        @Nullable
189        private static ClassDescriptor getDeclaringClass(@NotNull CallableDescriptor candidate) {
190            ReceiverParameterDescriptor expectedThis = candidate.getExpectedThisObject();
191            if (expectedThis == null) return null;
192            DeclarationDescriptor descriptor = expectedThis.getContainingDeclaration();
193            return descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null;
194        }
195    
196        public <D extends CallableDescriptor> void completeTypeInferenceDependentOnFunctionLiteralsForCall(
197                CallCandidateResolutionContext<D> context
198        ) {
199            ResolvedCallImpl<D> resolvedCall = context.candidateCall;
200            ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
201            if (!resolvedCall.hasIncompleteTypeParameters() || constraintSystem == null) return;
202    
203            // constraints for function literals
204            // Value parameters
205            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
206                ResolvedValueArgument resolvedValueArgument = entry.getValue();
207                ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
208    
209                for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
210                    addConstraintForFunctionLiteral(valueArgument, valueParameterDescriptor, constraintSystem, context);
211                }
212            }
213            resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
214        }
215    
216        @Nullable
217        public <D extends CallableDescriptor> JetType completeTypeInferenceDependentOnExpectedTypeForCall(
218                @NotNull CallCandidateResolutionContext<D> context,
219                boolean isInnerCall
220        ) {
221            ResolvedCallImpl<D> resolvedCall = context.candidateCall;
222            assert resolvedCall.hasIncompleteTypeParameters();
223            assert resolvedCall.getConstraintSystem() != null;
224    
225            JetType unsubstitutedReturnType = resolvedCall.getCandidateDescriptor().getReturnType();
226            if (unsubstitutedReturnType != null) {
227                resolvedCall.getConstraintSystem().addSupertypeConstraint(
228                        context.expectedType, unsubstitutedReturnType, ConstraintPosition.EXPECTED_TYPE_POSITION);
229            }
230    
231            updateSystemWithConstraintSystemCompleter(context, resolvedCall);
232    
233            updateSystemIfExpectedTypeIsUnit(context, resolvedCall);
234    
235            ((ConstraintSystemImpl)resolvedCall.getConstraintSystem()).processDeclaredBoundConstraints();
236    
237            if (!resolvedCall.getConstraintSystem().getStatus().isSuccessful()) {
238                return reportInferenceError(context);
239            }
240            resolvedCall.setResultingSubstitutor(resolvedCall.getConstraintSystem().getResultingSubstitutor());
241    
242            completeNestedCallsInference(context);
243            // Here we type check the arguments with inferred types expected
244            checkAllValueArguments(context, context.trace, RESOLVE_FUNCTION_ARGUMENTS);
245    
246            resolvedCall.setHasUnknownTypeParameters(false);
247            ResolutionStatus status = resolvedCall.getStatus();
248            if (status == ResolutionStatus.UNKNOWN_STATUS || status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
249                resolvedCall.setStatusToSuccess();
250            }
251            JetType returnType = resolvedCall.getResultingDescriptor().getReturnType();
252            if (isInnerCall) {
253                PsiElement callElement = context.call.getCallElement();
254                if (callElement instanceof JetCallExpression) {
255                    DataFlowUtils.checkType(returnType, (JetCallExpression) callElement, context, context.dataFlowInfo);
256                }
257            }
258            return returnType;
259        }
260    
261        private static <D extends CallableDescriptor> void updateSystemWithConstraintSystemCompleter(
262                @NotNull CallCandidateResolutionContext<D> context,
263                @NotNull ResolvedCallImpl<D> resolvedCall
264        ) {
265            ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
266            assert constraintSystem != null;
267            ConstraintSystemCompleter constraintSystemCompleter = context.trace.get(
268                    BindingContext.CONSTRAINT_SYSTEM_COMPLETER, context.call.getCalleeExpression());
269            if (constraintSystemCompleter == null) return;
270    
271            ConstraintSystem copy = constraintSystem.copy();
272    
273            constraintSystemCompleter.completeConstraintSystem(copy, resolvedCall);
274    
275            //todo improve error reporting with errors in constraints from completer
276            if (!copy.getStatus().hasOnlyErrorsFromPosition(ConstraintPosition.FROM_COMPLETER)) {
277                resolvedCall.setConstraintSystem(copy);
278            }
279        }
280    
281        private static <D extends CallableDescriptor> void updateSystemIfExpectedTypeIsUnit(
282                @NotNull CallCandidateResolutionContext<D> context,
283                @NotNull ResolvedCallImpl<D> resolvedCall
284        ) {
285            ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
286            assert constraintSystem != null;
287            JetType returnType = resolvedCall.getCandidateDescriptor().getReturnType();
288            if (returnType == null) return;
289    
290            if (!constraintSystem.getStatus().isSuccessful() && context.expectedType == TypeUtils.UNIT_EXPECTED_TYPE) {
291                ConstraintSystemImpl copy = (ConstraintSystemImpl) constraintSystem.copy();
292    
293                copy.addSupertypeConstraint(KotlinBuiltIns.getInstance().getUnitType(), returnType, ConstraintPosition.EXPECTED_TYPE_POSITION);
294                if (copy.getStatus().isSuccessful()) {
295                    resolvedCall.setConstraintSystem(copy);
296                }
297            }
298        }
299    
300        private <D extends CallableDescriptor> JetType reportInferenceError(
301                @NotNull CallCandidateResolutionContext<D> context
302        ) {
303            ResolvedCallImpl<D> resolvedCall = context.candidateCall;
304            ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
305            assert constraintSystem != null;
306    
307            resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
308            completeNestedCallsInference(context);
309            List<JetType> argumentTypes = checkValueArgumentTypes(
310                    context, resolvedCall, context.trace, RESOLVE_FUNCTION_ARGUMENTS).argumentTypes;
311            JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
312            InferenceErrorData errorData = InferenceErrorData
313                    .create(resolvedCall.getCandidateDescriptor(), constraintSystem, argumentTypes, receiverType, context.expectedType);
314    
315            context.tracing.typeInferenceFailed(context.trace, errorData);
316            resolvedCall.addStatus(ResolutionStatus.OTHER_ERROR);
317            if (!resolvedCall.hasInferredReturnType()) return null;
318            return resolvedCall.getResultingDescriptor().getReturnType();
319        }
320    
321        public <D extends CallableDescriptor> void completeNestedCallsInference(
322                @NotNull CallCandidateResolutionContext<D> context
323        ) {
324            if (context.call.getCallType() == Call.CallType.INVOKE) return;
325            ResolvedCallImpl<D> resolvedCall = context.candidateCall;
326            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
327                ValueParameterDescriptor parameterDescriptor = entry.getKey();
328                ResolvedValueArgument resolvedArgument = entry.getValue();
329    
330                for (ValueArgument argument : resolvedArgument.getArguments()) {
331                    completeInferenceForArgument(argument, parameterDescriptor, context);
332                }
333            }
334            completeUnmappedArguments(context, context.candidateCall.getUnmappedArguments());
335            recordReferenceForInvokeFunction(context);
336        }
337    
338        private <D extends CallableDescriptor> void completeInferenceForArgument(
339                @NotNull ValueArgument argument,
340                @NotNull ValueParameterDescriptor parameterDescriptor,
341                @NotNull CallCandidateResolutionContext<D> context
342        ) {
343            JetExpression expression = argument.getArgumentExpression();
344            if (expression == null) return;
345    
346            JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
347            context = context.replaceExpectedType(expectedType);
348    
349            JetExpression keyExpression = getDeferredComputationKeyExpression(expression);
350            CallCandidateResolutionContext<? extends CallableDescriptor> storedContextForArgument =
351                    context.resolutionResultsCache.getDeferredComputation(keyExpression);
352    
353            PsiElement parent = expression.getParent();
354            if (parent instanceof JetWhenExpression && expression == ((JetWhenExpression) parent).getSubjectExpression()
355                || (expression instanceof JetFunctionLiteralExpression)) {
356                return;
357            }
358            if (storedContextForArgument == null) {
359                JetType type = ArgumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, expression);
360                checkResultArgumentType(type, argument, context);
361                return;
362            }
363    
364            CallCandidateResolutionContext<? extends CallableDescriptor> contextForArgument = storedContextForArgument
365                    .replaceContextDependency(INDEPENDENT).replaceBindingTrace(context.trace).replaceExpectedType(expectedType);
366            JetType type;
367            if (contextForArgument.candidateCall.hasIncompleteTypeParameters()
368                    && !contextForArgument.candidateCall.isCompleted()) { //e.g. 'equals' argument
369                type = completeTypeInferenceDependentOnExpectedTypeForCall(contextForArgument, true);
370            }
371            else {
372                completeNestedCallsInference(contextForArgument);
373                JetType recordedType = context.trace.get(BindingContext.EXPRESSION_TYPE, expression);
374                if (recordedType != null && !recordedType.getConstructor().isDenotable()) {
375                    type = ArgumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, expression);
376                }
377                else {
378                    type = contextForArgument.candidateCall.getResultingDescriptor().getReturnType();
379                }
380                checkValueArgumentTypes(contextForArgument);
381            }
382            JetType result = BindingContextUtils.updateRecordedType(
383                    type, expression, context.trace, isFairSafeCallExpression(expression, context.trace));
384    
385            markResultingCallAsCompleted(context, keyExpression);
386    
387            DataFlowUtils.checkType(result, expression, contextForArgument);
388        }
389    
390        public void completeNestedCallsForNotResolvedInvocation(@NotNull CallResolutionContext<?> context) {
391            completeNestedCallsForNotResolvedInvocation(context, context.call.getValueArguments());
392        }
393    
394        public void completeUnmappedArguments(@NotNull CallResolutionContext<?> context, @NotNull Collection<? extends ValueArgument> unmappedArguments) {
395            completeNestedCallsForNotResolvedInvocation(context, unmappedArguments);
396        }
397    
398        private void completeNestedCallsForNotResolvedInvocation(@NotNull CallResolutionContext<?> context, @NotNull Collection<? extends ValueArgument> arguments) {
399            if (context.call.getCallType() == Call.CallType.INVOKE) return;
400            if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
401    
402            for (ValueArgument argument : arguments) {
403                JetExpression expression = argument.getArgumentExpression();
404    
405                JetExpression keyExpression = getDeferredComputationKeyExpression(expression);
406                markResultingCallAsCompleted(context, keyExpression);
407    
408                CallCandidateResolutionContext<? extends CallableDescriptor> storedContextForArgument =
409                        context.resolutionResultsCache.getDeferredComputation(keyExpression);
410                if (storedContextForArgument != null) {
411                    completeNestedCallsForNotResolvedInvocation(storedContextForArgument);
412                    CallCandidateResolutionContext<? extends CallableDescriptor> newContext =
413                            storedContextForArgument.replaceBindingTrace(context.trace);
414                    completeUnmappedArguments(newContext, storedContextForArgument.candidateCall.getUnmappedArguments());
415                    argumentTypeResolver.checkTypesForFunctionArgumentsWithNoCallee(newContext.replaceContextDependency(INDEPENDENT));
416                }
417            }
418        }
419    
420        private static void markResultingCallAsCompleted(
421                @NotNull CallResolutionContext<?> context,
422                @Nullable JetExpression keyExpression
423        ) {
424            if (keyExpression == null) return;
425    
426            CallCandidateResolutionContext<? extends CallableDescriptor> storedContextForArgument =
427                    context.resolutionResultsCache.getDeferredComputation(keyExpression);
428            if (storedContextForArgument == null) return;
429    
430            storedContextForArgument.candidateCall.markCallAsCompleted();
431    
432            // clean data for "invoke" calls
433            ResolvedCallWithTrace<? extends CallableDescriptor> resolvedCall = context.resolutionResultsCache.getCallForArgument(keyExpression);
434            assert resolvedCall != null : "Resolved call for '" + keyExpression + "' is not stored, but CallCandidateResolutionContext is.";
435            resolvedCall.markCallAsCompleted();
436        }
437    
438        @Nullable
439        private JetExpression getDeferredComputationKeyExpression(@Nullable JetExpression expression) {
440            if (expression == null) return null;
441            return expression.accept(new JetVisitor<JetExpression, Void>() {
442                @Nullable
443                private JetExpression visitInnerExpression(@Nullable JetElement expression) {
444                    if (expression == null) return null;
445                    return expression.accept(this, null);
446                }
447    
448                @Override
449                public JetExpression visitQualifiedExpression(@NotNull JetQualifiedExpression expression, Void data) {
450                    return visitInnerExpression(expression.getSelectorExpression());
451                }
452    
453                @Override
454                public JetExpression visitExpression(@NotNull JetExpression expression, Void data) {
455                    return expression;
456                }
457    
458                @Override
459                public JetExpression visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, Void data) {
460                    return visitInnerExpression(expression.getExpression());
461                }
462    
463                @Override
464                public JetExpression visitUnaryExpression(@NotNull JetUnaryExpression expression, Void data) {
465                    return ExpressionTypingUtils.isUnaryExpressionDependentOnExpectedType(expression) ? expression : null;
466                }
467    
468                @Override
469                public JetExpression visitPrefixExpression(@NotNull JetPrefixExpression expression, Void data) {
470                    return visitInnerExpression(JetPsiUtil.getBaseExpressionIfLabeledExpression(expression));
471                }
472    
473                @Override
474                public JetExpression visitBlockExpression(@NotNull JetBlockExpression expression, Void data) {
475                    JetElement lastStatement = JetPsiUtil.getLastStatementInABlock(expression);
476                    if (lastStatement != null) {
477                        return visitInnerExpression(lastStatement);
478                    }
479                    return expression;
480                }
481    
482                @Override
483                public JetExpression visitBinaryExpression(@NotNull JetBinaryExpression expression, Void data) {
484                    return ExpressionTypingUtils.isBinaryExpressionDependentOnExpectedType(expression) ? expression : null;
485                }
486            }, null);
487        }
488    
489        private static boolean isFairSafeCallExpression(@NotNull JetExpression expression, @NotNull BindingTrace trace) {
490            // We are interested in type of the last call:
491            // 'a.b?.foo()' is safe call, but 'a?.b.foo()' is not.
492            // Since receiver is 'a.b' and selector is 'foo()',
493            // we can only check if an expression is safe call.
494            if (!(expression instanceof JetSafeQualifiedExpression)) return false;
495    
496            JetSafeQualifiedExpression safeQualifiedExpression = (JetSafeQualifiedExpression) expression;
497            //If a receiver type is not null, then this safe expression is useless, and we don't need to make the result type nullable.
498            JetType type = trace.get(BindingContext.EXPRESSION_TYPE, safeQualifiedExpression.getReceiverExpression());
499            return type != null && type.isNullable();
500        }
501    
502        private static <D extends CallableDescriptor> void checkResultArgumentType(
503                @Nullable JetType type,
504                @NotNull ValueArgument argument,
505                @NotNull CallCandidateResolutionContext<D> context
506        ) {
507            JetExpression expression = argument.getArgumentExpression();
508            if (expression == null) return;
509    
510            DataFlowInfo dataFlowInfoForValueArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(argument);
511            ResolutionContext<?> newContext = context.replaceExpectedType(context.expectedType).replaceDataFlowInfo(
512                    dataFlowInfoForValueArgument);
513            DataFlowUtils.checkType(type, expression, newContext);
514        }
515    
516        private static <D extends CallableDescriptor> void recordReferenceForInvokeFunction(CallCandidateResolutionContext<D> context) {
517            PsiElement callElement = context.call.getCallElement();
518            if (!(callElement instanceof JetCallExpression)) return;
519    
520            JetCallExpression callExpression = (JetCallExpression) callElement;
521            if (BindingContextUtils.isCallExpressionWithValidReference(callExpression, context.trace.getBindingContext())) {
522                CallableDescriptor resultingDescriptor = context.candidateCall.getResultingDescriptor();
523                context.trace.record(BindingContext.EXPRESSION_TYPE, callExpression, resultingDescriptor.getReturnType());
524                context.trace.record(BindingContext.REFERENCE_TARGET, callExpression, context.candidateCall.getCandidateDescriptor());
525            }
526        }
527    
528        private <D extends CallableDescriptor> void addConstraintForFunctionLiteral(
529                @NotNull ValueArgument valueArgument,
530                @NotNull ValueParameterDescriptor valueParameterDescriptor,
531                @NotNull ConstraintSystem constraintSystem,
532                @NotNull CallCandidateResolutionContext<D> context
533        ) {
534            JetExpression argumentExpression = valueArgument.getArgumentExpression();
535            if (argumentExpression == null) return;
536            if (!ArgumentTypeResolver.isFunctionLiteralArgument(argumentExpression)) return;
537    
538            JetFunctionLiteralExpression functionLiteralExpression = ArgumentTypeResolver.getFunctionLiteralArgument(argumentExpression);
539    
540            JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
541            JetType expectedType = constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT);
542            if (expectedType == null || expectedType == DONT_CARE) {
543                expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, false);
544            }
545            if (expectedType == null || !KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType)
546                    || CallResolverUtil.hasUnknownFunctionParameter(expectedType)) {
547                return;
548            }
549            MutableDataFlowInfoForArguments dataFlowInfoForArguments = context.candidateCall.getDataFlowInfoForArguments();
550            DataFlowInfo dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument);
551    
552            //todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
553            boolean hasExpectedReturnType = !CallResolverUtil.hasUnknownReturnType(expectedType);
554            if (hasExpectedReturnType) {
555                TemporaryTraceAndCache temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
556                        context, "trace to resolve function literal with expected return type", argumentExpression);
557    
558                JetElement statementExpression = JetPsiUtil.getLastStatementInABlock(functionLiteralExpression.getBodyExpression());
559                if (statementExpression == null) return;
560                boolean[] mismatch = new boolean[1];
561                ObservableBindingTrace errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
562                        temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch);
563                CallCandidateResolutionContext<D> newContext = context
564                        .replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
565                        .replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
566                        .replaceContextDependency(INDEPENDENT);
567                JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(
568                        argumentExpression, functionLiteralExpression, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType();
569                if (!mismatch[0]) {
570                    constraintSystem.addSubtypeConstraint(
571                            type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex()));
572                    temporaryToResolveFunctionLiteral.commit();
573                    return;
574                }
575            }
576            JetType expectedTypeWithoutReturnType = hasExpectedReturnType ? CallResolverUtil.replaceReturnTypeByUnknown(expectedType) : expectedType;
577            CallCandidateResolutionContext<D> newContext = context
578                    .replaceExpectedType(expectedTypeWithoutReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
579                    .replaceContextDependency(INDEPENDENT);
580            JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteralExpression, newContext,
581                                                                           RESOLVE_FUNCTION_ARGUMENTS).getType();
582            constraintSystem.addSubtypeConstraint(
583                    type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex()));
584        }
585    
586        private <D extends CallableDescriptor> ResolutionStatus inferTypeArguments(CallCandidateResolutionContext<D> context) {
587            ResolvedCallImpl<D> candidateCall = context.candidateCall;
588            final D candidate = candidateCall.getCandidateDescriptor();
589    
590            context.trace.get(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement());
591    
592            ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
593    
594            // If the call is recursive, e.g.
595            //   fun foo<T>(t : T) : T = foo(t)
596            // we can't use same descriptor objects for T's as actual type values and same T's as unknowns,
597            // because constraints become trivial (T :< T), and inference fails
598            //
599            // Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
600            CallableDescriptor candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate);
601    
602            Map<TypeParameterDescriptor, Variance> typeVariables = Maps.newLinkedHashMap();
603            for (TypeParameterDescriptor typeParameterDescriptor : candidateWithFreshVariables.getTypeParameters()) {
604                typeVariables.put(typeParameterDescriptor, Variance.INVARIANT); // TODO: variance of the occurrences
605            }
606            constraintSystem.registerTypeVariables(typeVariables);
607    
608            TypeSubstitutor substituteDontCare =
609                    makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE);
610    
611            // Value parameters
612            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
613                ResolvedValueArgument resolvedValueArgument = entry.getValue();
614                ValueParameterDescriptor valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex());
615    
616    
617                for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
618                    // TODO : more attempts, with different expected types
619    
620                    // Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
621                    // and throw the results away
622                    // We'll type check the arguments later, with the inferred types expected
623                    boolean[] isErrorType = new boolean[1];
624                    addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem,
625                                                  context, isErrorType, SHAPE_FUNCTION_ARGUMENTS);
626                    if (isErrorType[0]) {
627                        candidateCall.argumentHasNoType();
628                    }
629                }
630            }
631    
632            // Receiver
633            // Error is already reported if something is missing
634            ReceiverValue receiverArgument = candidateCall.getReceiverArgument();
635            ReceiverParameterDescriptor receiverParameter = candidateWithFreshVariables.getReceiverParameter();
636            if (receiverArgument.exists() && receiverParameter != null) {
637                JetType receiverType =
638                        context.candidateCall.isSafeCall()
639                        ? TypeUtils.makeNotNullable(receiverArgument.getType())
640                        : receiverArgument.getType();
641                if (receiverArgument instanceof ExpressionReceiver) {
642                    receiverType = updateResultTypeForSmartCasts(receiverType, ((ExpressionReceiver) receiverArgument).getExpression(),
643                                                                 context.dataFlowInfo, context.trace);
644                }
645                constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION);
646            }
647    
648            // Restore type variables before alpha-conversion
649            ConstraintSystem constraintSystemWithRightTypeParameters = constraintSystem.substituteTypeVariables(
650                    new Function<TypeParameterDescriptor, TypeParameterDescriptor>() {
651                        @Override
652                        public TypeParameterDescriptor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) {
653                            assert typeParameterDescriptor != null;
654                            return candidate.getTypeParameters().get(typeParameterDescriptor.getIndex());
655                        }
656                    });
657            candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters);
658    
659    
660            // Solution
661            boolean hasContradiction = constraintSystem.getStatus().hasContradiction();
662            candidateCall.setHasUnknownTypeParameters(true);
663            if (!hasContradiction) {
664                return INCOMPLETE_TYPE_INFERENCE;
665            }
666            ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context, SHAPE_FUNCTION_ARGUMENTS);
667            ResolutionStatus argumentsStatus = checkingResult.status;
668            return OTHER_ERROR.combine(argumentsStatus);
669        }
670    
671        private void addConstraintForValueArgument(
672                @NotNull ValueArgument valueArgument,
673                @NotNull ValueParameterDescriptor valueParameterDescriptor,
674                @NotNull TypeSubstitutor substitutor,
675                @NotNull ConstraintSystem constraintSystem,
676                @NotNull CallCandidateResolutionContext<?> context,
677                @Nullable boolean[] isErrorType,
678                @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
679    
680            JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
681            JetExpression argumentExpression = valueArgument.getArgumentExpression();
682    
683            JetType expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT);
684            DataFlowInfo dataFlowInfoForArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(valueArgument);
685            CallResolutionContext<?> newContext = context.replaceExpectedType(expectedType).replaceDataFlowInfo(dataFlowInfoForArgument);
686    
687            JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(
688                    argumentExpression, newContext, resolveFunctionArgumentBodies);
689            context.candidateCall.getDataFlowInfoForArguments().updateInfo(valueArgument, typeInfoForCall.getDataFlowInfo());
690    
691            JetType type = updateResultTypeForSmartCasts(typeInfoForCall.getType(), argumentExpression, dataFlowInfoForArgument, context.trace);
692            constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(
693                    valueParameterDescriptor.getIndex()));
694            if (isErrorType != null) {
695                isErrorType[0] = type == null || type.isError();
696            }
697        }
698    
699        @Nullable
700        private static JetType updateResultTypeForSmartCasts(
701                @Nullable JetType type,
702                @Nullable JetExpression argumentExpression,
703                @NotNull DataFlowInfo dataFlowInfoForArgument,
704                @NotNull BindingTrace trace
705        ) {
706            if (argumentExpression == null || type == null) return type;
707    
708            DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(
709                    argumentExpression, type, trace.getBindingContext());
710            if (!dataFlowValue.isStableIdentifier()) return type;
711    
712            Set<JetType> possibleTypes = dataFlowInfoForArgument.getPossibleTypes(dataFlowValue);
713            if (possibleTypes.isEmpty()) return type;
714    
715            return TypeUtils.intersect(JetTypeChecker.INSTANCE, possibleTypes);
716        }
717    
718        private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
719                @NotNull CallCandidateResolutionContext<D> context,
720                @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
721            return checkAllValueArguments(context, context.candidateCall.getTrace(), resolveFunctionArgumentBodies);
722        }
723    
724        private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
725                @NotNull CallCandidateResolutionContext<D> context,
726                @NotNull BindingTrace trace,
727                @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies
728        ) {
729            ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(
730                    context, context.candidateCall, trace, resolveFunctionArgumentBodies);
731            ResolutionStatus resultStatus = checkingResult.status;
732            resultStatus = resultStatus.combine(checkReceivers(context, trace));
733    
734            return new ValueArgumentsCheckingResult(resultStatus, checkingResult.argumentTypes);
735        }
736    
737        private static <D extends CallableDescriptor> ResolutionStatus checkReceivers(
738                @NotNull CallCandidateResolutionContext<D> context,
739                @NotNull BindingTrace trace
740        ) {
741            ResolutionStatus resultStatus = SUCCESS;
742            ResolvedCall<D> candidateCall = context.candidateCall;
743    
744            resultStatus = resultStatus.combine(checkReceiverTypeError(context));
745    
746            // Comment about a very special case.
747            // Call 'b.foo(1)' where class 'Foo' has an extension member 'fun B.invoke(Int)' should be checked two times for safe call (in 'checkReceiver'), because
748            // both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'.
749            // Class 'CallForImplicitInvoke' helps up to recognise this case, and parameter 'implicitInvokeCheck' helps us to distinguish whether we check receiver or this object.
750    
751            resultStatus = resultStatus.combine(checkReceiver(
752                    context, candidateCall, trace,
753                    candidateCall.getResultingDescriptor().getReceiverParameter(),
754                    candidateCall.getReceiverArgument(), candidateCall.getExplicitReceiverKind().isReceiver(), false));
755    
756            resultStatus = resultStatus.combine(checkReceiver(
757                    context, candidateCall, trace,
758                    candidateCall.getResultingDescriptor().getExpectedThisObject(), candidateCall.getThisObject(),
759                    candidateCall.getExplicitReceiverKind().isThisObject(),
760                    // for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error
761                    context.call instanceof CallForImplicitInvoke));
762            return resultStatus;
763        }
764    
765        public <D extends CallableDescriptor> ValueArgumentsCheckingResult checkValueArgumentTypes(
766                @NotNull CallCandidateResolutionContext<D> context
767        ) {
768            return checkValueArgumentTypes(context, context.candidateCall, context.trace, RESOLVE_FUNCTION_ARGUMENTS);
769        }
770    
771        private <D extends CallableDescriptor, C extends CallResolutionContext<C>> ValueArgumentsCheckingResult checkValueArgumentTypes(
772                @NotNull CallResolutionContext<C> context,
773                @NotNull ResolvedCallImpl<D> candidateCall,
774                @NotNull BindingTrace trace,
775                @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
776            ResolutionStatus resultStatus = SUCCESS;
777            List<JetType> argumentTypes = Lists.newArrayList();
778            MutableDataFlowInfoForArguments infoForArguments = candidateCall.getDataFlowInfoForArguments();
779            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
780                ValueParameterDescriptor parameterDescriptor = entry.getKey();
781                ResolvedValueArgument resolvedArgument = entry.getValue();
782    
783    
784                for (ValueArgument argument : resolvedArgument.getArguments()) {
785                    JetExpression expression = argument.getArgumentExpression();
786                    if (expression == null) continue;
787    
788                    JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
789                    if (TypeUtils.dependsOnTypeParameters(expectedType, candidateCall.getCandidateDescriptor().getTypeParameters())) {
790                        expectedType = NO_EXPECTED_TYPE;
791                    }
792    
793                    CallResolutionContext<?> newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument))
794                            .replaceBindingTrace(trace).replaceExpectedType(expectedType);
795                    JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(
796                            expression, newContext, resolveFunctionArgumentBodies);
797                    JetType type = typeInfoForCall.getType();
798                    infoForArguments.updateInfo(argument, typeInfoForCall.getDataFlowInfo());
799    
800                    if (type == null || (type.isError() && type != PLACEHOLDER_FUNCTION_TYPE)) {
801                        candidateCall.argumentHasNoType();
802                        argumentTypes.add(type);
803                    }
804                    else {
805                        JetType resultingType;
806                        if (noExpectedType(expectedType) || ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
807                            resultingType = type;
808                        }
809                        else {
810                            resultingType = autocastValueArgumentTypeIfPossible(expression, expectedType, type, newContext);
811                            if (resultingType == null) {
812                                resultingType = type;
813                                resultStatus = OTHER_ERROR;
814                            }
815                        }
816    
817                        argumentTypes.add(resultingType);
818                    }
819                }
820            }
821            return new ValueArgumentsCheckingResult(resultStatus, argumentTypes);
822        }
823    
824        @Nullable
825        private static JetType autocastValueArgumentTypeIfPossible(
826                @NotNull JetExpression expression,
827                @NotNull JetType expectedType,
828                @NotNull JetType actualType,
829                @NotNull ResolutionContext<?> context
830        ) {
831            ExpressionReceiver receiverToCast = new ExpressionReceiver(JetPsiUtil.safeDeparenthesize(expression, false), actualType);
832            List<JetType> variants =
833                    AutoCastUtils.getAutoCastVariantsExcludingReceiver(context.trace.getBindingContext(), context.dataFlowInfo, receiverToCast);
834            for (JetType possibleType : variants) {
835                if (JetTypeChecker.INSTANCE.isSubtypeOf(possibleType, expectedType)) {
836                    return possibleType;
837                }
838            }
839            return null;
840        }
841    
842        private static <D extends CallableDescriptor> ResolutionStatus checkReceiverTypeError(
843                @NotNull CallCandidateResolutionContext<D> context
844        ) {
845            ResolvedCallImpl<D> candidateCall = context.candidateCall;
846            D candidateDescriptor = candidateCall.getCandidateDescriptor();
847            if (candidateDescriptor instanceof ExpressionAsFunctionDescriptor) return SUCCESS;
848    
849            ReceiverParameterDescriptor receiverDescriptor = candidateDescriptor.getReceiverParameter();
850            ReceiverParameterDescriptor expectedThisObjectDescriptor = candidateDescriptor.getExpectedThisObject();
851            ReceiverParameterDescriptor receiverParameterDescriptor;
852            ReceiverValue receiverArgument;
853            if (receiverDescriptor != null && candidateCall.getReceiverArgument().exists()) {
854                receiverParameterDescriptor = receiverDescriptor;
855                receiverArgument = candidateCall.getReceiverArgument();
856            }
857            else if (expectedThisObjectDescriptor != null && candidateCall.getThisObject().exists()) {
858                receiverParameterDescriptor = expectedThisObjectDescriptor;
859                receiverArgument = candidateCall.getThisObject();
860            }
861            else {
862                return SUCCESS;
863            }
864    
865            JetType erasedReceiverType = CallResolverUtil.getErasedReceiverType(receiverParameterDescriptor, candidateDescriptor);
866    
867            boolean isSubtypeByAutoCast = AutoCastUtils.isSubTypeByAutoCastIgnoringNullability(receiverArgument, erasedReceiverType, context);
868            if (!isSubtypeByAutoCast) {
869                return RECEIVER_TYPE_ERROR;
870            }
871    
872            return SUCCESS;
873        }
874    
875        private static <D extends CallableDescriptor> ResolutionStatus checkReceiver(
876                @NotNull CallCandidateResolutionContext<D> context,
877                @NotNull ResolvedCall<D> candidateCall,
878                @NotNull BindingTrace trace,
879                @Nullable ReceiverParameterDescriptor receiverParameter,
880                @NotNull ReceiverValue receiverArgument,
881                boolean isExplicitReceiver,
882                boolean implicitInvokeCheck
883        ) {
884            if (receiverParameter == null || !receiverArgument.exists()) return SUCCESS;
885            D candidateDescriptor = candidateCall.getCandidateDescriptor();
886            if (TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters())) return SUCCESS;
887    
888            boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall();
889            boolean isSubtypeByAutoCast = AutoCastUtils.isSubTypeByAutoCastIgnoringNullability(
890                    receiverArgument, receiverParameter.getType(), context);
891            if (!isSubtypeByAutoCast) {
892                context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument);
893                return OTHER_ERROR;
894            }
895            AutoCastUtils.recordAutoCastIfNecessary(receiverArgument, receiverParameter.getType(), context, safeAccess);
896    
897            JetType receiverArgumentType = receiverArgument.getType();
898    
899            BindingContext bindingContext = trace.getBindingContext();
900            if (!safeAccess && !receiverParameter.getType().isNullable() && receiverArgumentType.isNullable()) {
901                if (!AutoCastUtils.isNotNull(receiverArgument, bindingContext, context.dataFlowInfo)) {
902    
903                    context.tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck);
904                    return UNSAFE_CALL_ERROR;
905                }
906            }
907            DataFlowValue receiverValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, bindingContext);
908            if (safeAccess && !context.dataFlowInfo.getNullability(receiverValue).canBeNull()) {
909                context.tracing.unnecessarySafeCall(trace, receiverArgumentType);
910            }
911            return SUCCESS;
912        }
913    
914        private static class ValueArgumentsCheckingResult {
915    
916            public final List<JetType> argumentTypes;
917            public final ResolutionStatus status;
918    
919            private ValueArgumentsCheckingResult(@NotNull ResolutionStatus status, @NotNull List<JetType> argumentTypes) {
920                this.status = status;
921                this.argumentTypes = argumentTypes;
922            }
923        }
924    
925        @NotNull
926        private static JetType getEffectiveExpectedType(ValueParameterDescriptor parameterDescriptor, ValueArgument argument) {
927            if (argument.getSpreadElement() != null) {
928                if (parameterDescriptor.getVarargElementType() == null) {
929                    // Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper
930                    return DONT_CARE;
931                }
932                else {
933                    return parameterDescriptor.getType();
934                }
935            }
936            else {
937                JetType varargElementType = parameterDescriptor.getVarargElementType();
938                if (varargElementType != null) {
939                    return varargElementType;
940                }
941    
942                return parameterDescriptor.getType();
943            }
944        }
945    
946        private static void checkGenericBoundsInAFunctionCall(
947                @NotNull List<JetTypeProjection> jetTypeArguments,
948                @NotNull List<JetType> typeArguments,
949                @NotNull CallableDescriptor functionDescriptor,
950                @NotNull BindingTrace trace) {
951            Map<TypeConstructor, TypeProjection> context = Maps.newHashMap();
952    
953            List<TypeParameterDescriptor> typeParameters = functionDescriptor.getOriginal().getTypeParameters();
954            for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
955                TypeParameterDescriptor typeParameter = typeParameters.get(i);
956                JetType typeArgument = typeArguments.get(i);
957                context.put(typeParameter.getTypeConstructor(), new TypeProjectionImpl(typeArgument));
958            }
959            TypeSubstitutor substitutor = TypeSubstitutor.create(context);
960            for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
961                TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
962                JetType typeArgument = typeArguments.get(i);
963                JetTypeReference typeReference = jetTypeArguments.get(i).getTypeReference();
964                if (typeReference != null) {
965                    DescriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace);
966                }
967            }
968        }
969    }