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.collect.Lists;
020    import com.google.common.collect.Maps;
021    import com.google.common.collect.Sets;
022    import com.intellij.openapi.progress.ProgressIndicatorProvider;
023    import kotlin.Function1;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.jet.lang.descriptors.*;
027    import org.jetbrains.jet.lang.psi.*;
028    import org.jetbrains.jet.lang.resolve.*;
029    import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastUtils;
030    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
031    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
032    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
033    import org.jetbrains.jet.lang.resolve.calls.context.*;
034    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
035    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
036    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
037    import org.jetbrains.jet.lang.resolve.calls.model.*;
038    import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
039    import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
040    import org.jetbrains.jet.lang.resolve.calls.tasks.TaskPrioritizer;
041    import org.jetbrains.jet.lang.resolve.calls.util.FakeCallableDescriptorForObject;
042    import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
043    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
044    import org.jetbrains.jet.lang.types.*;
045    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
046    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
047    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
048    
049    import javax.inject.Inject;
050    import java.util.ArrayList;
051    import java.util.List;
052    import java.util.Map;
053    import java.util.Set;
054    
055    import static org.jetbrains.jet.lang.diagnostics.Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT;
056    import static org.jetbrains.jet.lang.diagnostics.Errors.SUPER_IS_NOT_AN_EXPRESSION;
057    import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
058    import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
059    import static org.jetbrains.jet.lang.resolve.calls.CallTransformer.CallForImplicitInvoke;
060    import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
061    import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.*;
062    import static org.jetbrains.jet.lang.types.TypeUtils.*;
063    
064    public class CandidateResolver {
065        @NotNull
066        private ArgumentTypeResolver argumentTypeResolver;
067    
068        @Inject
069        public void setArgumentTypeResolver(@NotNull ArgumentTypeResolver argumentTypeResolver) {
070            this.argumentTypeResolver = argumentTypeResolver;
071        }
072    
073        public <D extends CallableDescriptor, F extends D> void performResolutionForCandidateCall(
074                @NotNull CallCandidateResolutionContext<D> context,
075                @NotNull ResolutionTask<D, F> task) {
076    
077            ProgressIndicatorProvider.checkCanceled();
078    
079            MutableResolvedCall<D> candidateCall = context.candidateCall;
080            D candidate = candidateCall.getCandidateDescriptor();
081    
082            candidateCall.addStatus(checkReceiverTypeError(context));
083    
084            if (ErrorUtils.isError(candidate)) {
085                candidateCall.addStatus(SUCCESS);
086                return;
087            }
088    
089            if (!checkOuterClassMemberIsAccessible(context)) {
090                candidateCall.addStatus(OTHER_ERROR);
091                return;
092            }
093    
094    
095            DeclarationDescriptorWithVisibility invisibleMember =
096                    Visibilities.findInvisibleMember(candidate, context.scope.getContainingDeclaration());
097            if (invisibleMember != null) {
098                candidateCall.addStatus(OTHER_ERROR);
099                context.tracing.invisibleMember(context.trace, invisibleMember);
100            }
101    
102            if (task.checkArguments == CheckValueArgumentsMode.ENABLED) {
103                Set<ValueArgument> unmappedArguments = Sets.newLinkedHashSet();
104                ValueArgumentsToParametersMapper.Status argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
105                        context.call, context.tracing, candidateCall, unmappedArguments);
106                if (!argumentMappingStatus.isSuccess()) {
107                    //For the expressions like '42.(f)()' where f: () -> Unit we'd like to generate an error 'no receiver admitted',
108                    //not to throw away the candidate.
109                    if (argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR
110                                && !CallResolverUtil.isInvokeCallOnExpressionWithBothReceivers(context.call)) {
111                        candidateCall.addStatus(RECEIVER_PRESENCE_ERROR);
112                        return;
113                    }
114                    else {
115                        candidateCall.addStatus(OTHER_ERROR);
116                    }
117                }
118            }
119            if (!checkThisObject(context)) {
120                candidateCall.addStatus(OTHER_ERROR);
121            }
122    
123            List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments();
124            if (jetTypeArguments.isEmpty()) {
125                if (!candidate.getTypeParameters().isEmpty()) {
126                    ResolutionStatus status = inferTypeArguments(context);
127                    candidateCall.addStatus(status);
128                }
129                else {
130                    candidateCall.addStatus(checkAllValueArguments(context, SHAPE_FUNCTION_ARGUMENTS).status);
131                }
132            }
133            else {
134                // Explicit type arguments passed
135    
136                List<JetType> typeArguments = new ArrayList<JetType>();
137                for (JetTypeProjection projection : jetTypeArguments) {
138                    if (projection.getProjectionKind() != JetProjectionKind.NONE) {
139                        context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
140                    }
141                    typeArguments.add(argumentTypeResolver.resolveTypeRefWithDefault(
142                            projection.getTypeReference(), context.scope, context.trace, ErrorUtils.createErrorType("Star projection in a call")));
143                }
144                int expectedTypeArgumentCount = candidate.getTypeParameters().size();
145                for (int index = jetTypeArguments.size(); index < expectedTypeArgumentCount; index++) {
146                    typeArguments.add(ErrorUtils.createErrorType(
147                            "Explicit type argument expected for " + candidate.getTypeParameters().get(index).getName()));
148                }
149                Map<TypeConstructor, TypeProjection> substitutionContext =
150                        FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor) candidate, typeArguments);
151                TypeSubstitutor substitutor = TypeSubstitutor.create(substitutionContext);
152    
153                if (expectedTypeArgumentCount != jetTypeArguments.size()) {
154                    candidateCall.addStatus(OTHER_ERROR);
155                    context.tracing.wrongNumberOfTypeArguments(context.trace, expectedTypeArgumentCount);
156                }
157                else {
158                    checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, substitutor, context.trace);
159                }
160    
161                candidateCall.setResultingSubstitutor(substitutor);
162    
163                candidateCall.addStatus(checkAllValueArguments(context, SHAPE_FUNCTION_ARGUMENTS).status);
164            }
165    
166            task.performAdvancedChecks(candidate, context.trace, context.tracing);
167    
168            // 'super' cannot be passed as an argument, for receiver arguments expression typer does not track this
169            // See TaskPrioritizer for more
170            JetSuperExpression superExpression = TaskPrioritizer.getReceiverSuper(candidateCall.getReceiverArgument());
171            if (superExpression != null) {
172                context.trace.report(SUPER_IS_NOT_AN_EXPRESSION.on(superExpression, superExpression.getText()));
173                candidateCall.addStatus(OTHER_ERROR);
174            }
175        }
176    
177        private static boolean checkThisObject(@NotNull CallCandidateResolutionContext<?> context) {
178            MutableResolvedCall<? extends CallableDescriptor> candidateCall = context.candidateCall;
179            CallableDescriptor candidateDescriptor = candidateCall.getCandidateDescriptor();
180            ReceiverValue thisObject = candidateCall.getThisObject();
181            if (thisObject.exists()) {
182                ClassDescriptor nestedClass = null;
183                if (candidateDescriptor instanceof ConstructorDescriptor
184                    && DescriptorUtils.isStaticNestedClass(candidateDescriptor.getContainingDeclaration())) {
185                    nestedClass = (ClassDescriptor) candidateDescriptor.getContainingDeclaration();
186                }
187                else if (candidateDescriptor instanceof FakeCallableDescriptorForObject) {
188                    nestedClass = ((FakeCallableDescriptorForObject) candidateDescriptor).getReferencedDescriptor();
189                }
190                if (nestedClass != null) {
191                    context.tracing.nestedClassAccessViaInstanceReference(context.trace, nestedClass, candidateCall.getExplicitReceiverKind());
192                    return false;
193                }
194            }
195    
196            assert (thisObject.exists() == (candidateCall.getResultingDescriptor().getExpectedThisObject() != null))
197                    : "Shouldn't happen because of TaskPrioritizer: " + candidateDescriptor;
198    
199            return true;
200        }
201    
202        private static boolean checkOuterClassMemberIsAccessible(@NotNull CallCandidateResolutionContext<?> context) {
203            // In "this@Outer.foo()" the error will be reported on "this@Outer" instead
204            if (context.call.getExplicitReceiver().exists() || context.call.getThisObject().exists()) return true;
205    
206            ClassDescriptor candidateThis = getDeclaringClass(context.candidateCall.getCandidateDescriptor());
207            if (candidateThis == null || candidateThis.getKind().isSingleton()) return true;
208    
209            return DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, context.call.getCallElement(), candidateThis);
210        }
211    
212        @Nullable
213        private static ClassDescriptor getDeclaringClass(@NotNull CallableDescriptor candidate) {
214            ReceiverParameterDescriptor expectedThis = candidate.getExpectedThisObject();
215            if (expectedThis == null) return null;
216            DeclarationDescriptor descriptor = expectedThis.getContainingDeclaration();
217            return descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null;
218        }
219    
220        public <D extends CallableDescriptor> void completeTypeInferenceDependentOnFunctionLiteralsForCall(
221                CallCandidateResolutionContext<D> context
222        ) {
223            MutableResolvedCall<D> resolvedCall = context.candidateCall;
224            ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
225            if (constraintSystem == null) return;
226    
227            // constraints for function literals
228            // Value parameters
229            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
230                ResolvedValueArgument resolvedValueArgument = entry.getValue();
231                ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
232    
233                for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
234                    addConstraintForFunctionLiteral(valueArgument, valueParameterDescriptor, constraintSystem, context);
235                }
236            }
237            resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
238        }
239    
240        private <D extends CallableDescriptor> void addConstraintForFunctionLiteral(
241                @NotNull ValueArgument valueArgument,
242                @NotNull ValueParameterDescriptor valueParameterDescriptor,
243                @NotNull ConstraintSystem constraintSystem,
244                @NotNull CallCandidateResolutionContext<D> context
245        ) {
246            JetExpression argumentExpression = valueArgument.getArgumentExpression();
247            if (argumentExpression == null) return;
248            if (!ArgumentTypeResolver.isFunctionLiteralArgument(argumentExpression)) return;
249    
250            JetFunctionLiteralExpression functionLiteralExpression = ArgumentTypeResolver.getFunctionLiteralArgument(argumentExpression);
251    
252            JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
253            JetType expectedType = constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT);
254            if (expectedType == null || expectedType == DONT_CARE) {
255                expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, false);
256            }
257            if (expectedType == null || !KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType)
258                    || CallResolverUtil.hasUnknownFunctionParameter(expectedType)) {
259                return;
260            }
261            MutableDataFlowInfoForArguments dataFlowInfoForArguments = context.candidateCall.getDataFlowInfoForArguments();
262            DataFlowInfo dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument);
263    
264            //todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
265            boolean hasExpectedReturnType = !CallResolverUtil.hasUnknownReturnType(expectedType);
266            if (hasExpectedReturnType) {
267                TemporaryTraceAndCache temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
268                        context, "trace to resolve function literal with expected return type", argumentExpression);
269    
270                JetElement statementExpression = JetPsiUtil.getLastStatementInABlock(functionLiteralExpression.getBodyExpression());
271                if (statementExpression == null) return;
272                boolean[] mismatch = new boolean[1];
273                ObservableBindingTrace errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
274                        temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch);
275                CallCandidateResolutionContext<D> newContext = context
276                        .replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
277                        .replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
278                        .replaceContextDependency(INDEPENDENT);
279                JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(
280                        argumentExpression, functionLiteralExpression, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType();
281                if (!mismatch[0]) {
282                    constraintSystem.addSubtypeConstraint(
283                            type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex()));
284                    temporaryToResolveFunctionLiteral.commit();
285                    return;
286                }
287            }
288            JetType expectedTypeWithoutReturnType = hasExpectedReturnType ? CallResolverUtil.replaceReturnTypeByUnknown(expectedType) : expectedType;
289            CallCandidateResolutionContext<D> newContext = context
290                    .replaceExpectedType(expectedTypeWithoutReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
291                    .replaceContextDependency(INDEPENDENT);
292            JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteralExpression, newContext,
293                                                                           RESOLVE_FUNCTION_ARGUMENTS).getType();
294            constraintSystem.addSubtypeConstraint(
295                    type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex()));
296        }
297    
298        private <D extends CallableDescriptor> ResolutionStatus inferTypeArguments(CallCandidateResolutionContext<D> context) {
299            MutableResolvedCall<D> candidateCall = context.candidateCall;
300            final D candidate = candidateCall.getCandidateDescriptor();
301    
302            ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
303    
304            // If the call is recursive, e.g.
305            //   fun foo<T>(t : T) : T = foo(t)
306            // we can't use same descriptor objects for T's as actual type values and same T's as unknowns,
307            // because constraints become trivial (T :< T), and inference fails
308            //
309            // Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
310            CallableDescriptor candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate);
311    
312            Map<TypeParameterDescriptor, Variance> typeVariables = Maps.newLinkedHashMap();
313            for (TypeParameterDescriptor typeParameterDescriptor : candidateWithFreshVariables.getTypeParameters()) {
314                typeVariables.put(typeParameterDescriptor, Variance.INVARIANT); // TODO: variance of the occurrences
315            }
316            constraintSystem.registerTypeVariables(typeVariables);
317    
318            TypeSubstitutor substituteDontCare =
319                    makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE);
320    
321            // Value parameters
322            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
323                ResolvedValueArgument resolvedValueArgument = entry.getValue();
324                ValueParameterDescriptor valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex());
325    
326    
327                for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
328                    // TODO : more attempts, with different expected types
329    
330                    // Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
331                    // and throw the results away
332                    // We'll type check the arguments later, with the inferred types expected
333                    addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem,
334                                                  context, SHAPE_FUNCTION_ARGUMENTS);
335                }
336            }
337    
338            // Receiver
339            // Error is already reported if something is missing
340            ReceiverValue receiverArgument = candidateCall.getReceiverArgument();
341            ReceiverParameterDescriptor receiverParameter = candidateWithFreshVariables.getReceiverParameter();
342            if (receiverArgument.exists() && receiverParameter != null) {
343                JetType receiverType =
344                        context.candidateCall.isSafeCall()
345                        ? TypeUtils.makeNotNullable(receiverArgument.getType())
346                        : receiverArgument.getType();
347                if (receiverArgument instanceof ExpressionReceiver) {
348                    receiverType = updateResultTypeForSmartCasts(receiverType, ((ExpressionReceiver) receiverArgument).getExpression(),
349                                                                 context.dataFlowInfo, context.trace);
350                }
351                constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION);
352            }
353    
354            // Restore type variables before alpha-conversion
355            ConstraintSystem constraintSystemWithRightTypeParameters = constraintSystem.substituteTypeVariables(
356                    new Function1<TypeParameterDescriptor, TypeParameterDescriptor>() {
357                        @Override
358                        public TypeParameterDescriptor invoke(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
359                            return candidate.getTypeParameters().get(typeParameterDescriptor.getIndex());
360                        }
361                    }
362            );
363            candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters);
364    
365    
366            // Solution
367            boolean hasContradiction = constraintSystem.getStatus().hasContradiction();
368            if (!hasContradiction) {
369                return INCOMPLETE_TYPE_INFERENCE;
370            }
371            return OTHER_ERROR;
372        }
373    
374        private void addConstraintForValueArgument(
375                @NotNull ValueArgument valueArgument,
376                @NotNull ValueParameterDescriptor valueParameterDescriptor,
377                @NotNull TypeSubstitutor substitutor,
378                @NotNull ConstraintSystem constraintSystem,
379                @NotNull CallCandidateResolutionContext<?> context,
380                @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
381    
382            JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
383            JetExpression argumentExpression = valueArgument.getArgumentExpression();
384    
385            JetType expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT);
386            DataFlowInfo dataFlowInfoForArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(valueArgument);
387            CallResolutionContext<?> newContext = context.replaceExpectedType(expectedType).replaceDataFlowInfo(dataFlowInfoForArgument);
388    
389            JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(
390                    argumentExpression, newContext, resolveFunctionArgumentBodies);
391            context.candidateCall.getDataFlowInfoForArguments().updateInfo(valueArgument, typeInfoForCall.getDataFlowInfo());
392    
393            JetType type = updateResultTypeForSmartCasts(typeInfoForCall.getType(), argumentExpression, dataFlowInfoForArgument, context.trace);
394            constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(
395                    valueParameterDescriptor.getIndex()));
396        }
397    
398        @Nullable
399        private static JetType updateResultTypeForSmartCasts(
400                @Nullable JetType type,
401                @Nullable JetExpression argumentExpression,
402                @NotNull DataFlowInfo dataFlowInfoForArgument,
403                @NotNull BindingTrace trace
404        ) {
405            if (argumentExpression == null || type == null) return type;
406    
407            DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(
408                    argumentExpression, type, trace.getBindingContext());
409            if (!dataFlowValue.isStableIdentifier()) return type;
410    
411            Set<JetType> possibleTypes = dataFlowInfoForArgument.getPossibleTypes(dataFlowValue);
412            if (possibleTypes.isEmpty()) return type;
413    
414            return TypeUtils.intersect(JetTypeChecker.DEFAULT, possibleTypes);
415        }
416    
417        @NotNull
418        private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
419                @NotNull CallCandidateResolutionContext<D> context,
420                @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
421            return checkAllValueArguments(context, context.candidateCall.getTrace(), resolveFunctionArgumentBodies);
422        }
423    
424        @NotNull
425        public <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
426                @NotNull CallCandidateResolutionContext<D> context,
427                @NotNull BindingTrace trace,
428                @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies
429        ) {
430            ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(
431                    context, context.candidateCall, trace, resolveFunctionArgumentBodies);
432            ResolutionStatus resultStatus = checkingResult.status;
433            resultStatus = resultStatus.combine(checkReceivers(context, trace));
434    
435            return new ValueArgumentsCheckingResult(resultStatus, checkingResult.argumentTypes);
436        }
437    
438        private static <D extends CallableDescriptor> ResolutionStatus checkReceivers(
439                @NotNull CallCandidateResolutionContext<D> context,
440                @NotNull BindingTrace trace
441        ) {
442            ResolutionStatus resultStatus = SUCCESS;
443            ResolvedCall<D> candidateCall = context.candidateCall;
444    
445            resultStatus = resultStatus.combine(checkReceiverTypeError(context));
446    
447            // Comment about a very special case.
448            // 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
449            // both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'.
450            // Class 'CallForImplicitInvoke' helps up to recognise this case, and parameter 'implicitInvokeCheck' helps us to distinguish whether we check receiver or this object.
451    
452            resultStatus = resultStatus.combine(checkReceiver(
453                    context, candidateCall, trace,
454                    candidateCall.getResultingDescriptor().getReceiverParameter(),
455                    candidateCall.getReceiverArgument(), candidateCall.getExplicitReceiverKind().isReceiver(), false));
456    
457            resultStatus = resultStatus.combine(checkReceiver(
458                    context, candidateCall, trace,
459                    candidateCall.getResultingDescriptor().getExpectedThisObject(), candidateCall.getThisObject(),
460                    candidateCall.getExplicitReceiverKind().isThisObject(),
461                    // for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error
462                    context.call instanceof CallForImplicitInvoke));
463            return resultStatus;
464        }
465    
466        @NotNull
467        private <D extends CallableDescriptor, C extends CallResolutionContext<C>> ValueArgumentsCheckingResult checkValueArgumentTypes(
468                @NotNull CallResolutionContext<C> context,
469                @NotNull MutableResolvedCall<D> candidateCall,
470                @NotNull BindingTrace trace,
471                @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
472            ResolutionStatus resultStatus = SUCCESS;
473            List<JetType> argumentTypes = Lists.newArrayList();
474            MutableDataFlowInfoForArguments infoForArguments = candidateCall.getDataFlowInfoForArguments();
475            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
476                ValueParameterDescriptor parameterDescriptor = entry.getKey();
477                ResolvedValueArgument resolvedArgument = entry.getValue();
478    
479    
480                for (ValueArgument argument : resolvedArgument.getArguments()) {
481                    JetExpression expression = argument.getArgumentExpression();
482                    if (expression == null) continue;
483    
484                    JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
485                    if (TypeUtils.dependsOnTypeParameters(expectedType, candidateCall.getCandidateDescriptor().getTypeParameters())) {
486                        expectedType = NO_EXPECTED_TYPE;
487                    }
488    
489                    CallResolutionContext<?> newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument))
490                            .replaceBindingTrace(trace).replaceExpectedType(expectedType);
491                    JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(
492                            expression, newContext, resolveFunctionArgumentBodies);
493                    JetType type = typeInfoForCall.getType();
494                    infoForArguments.updateInfo(argument, typeInfoForCall.getDataFlowInfo());
495    
496                    ArgumentMatchStatus matchStatus = ArgumentMatchStatus.SUCCESS;
497                    JetType resultingType = type;
498                    if (type == null || (type.isError() && type != PLACEHOLDER_FUNCTION_TYPE)) {
499                        matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE;
500                    }
501                    else if (!noExpectedType(expectedType)) {
502                        if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
503                            JetType autocastType = autocastValueArgumentTypeIfPossible(expression, expectedType, type, newContext);
504                            if (autocastType == null) {
505                                resultStatus = OTHER_ERROR;
506                                matchStatus = ArgumentMatchStatus.TYPE_MISMATCH;
507                            }
508                            else {
509                                resultingType = autocastType;
510                            }
511                        }
512                        else if (ErrorUtils.containsUninferredParameter(expectedType)) {
513                            matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES;
514                        }
515                    }
516                    argumentTypes.add(resultingType);
517                    candidateCall.recordArgumentMatchStatus(argument, matchStatus);
518                }
519            }
520            return new ValueArgumentsCheckingResult(resultStatus, argumentTypes);
521        }
522    
523        @Nullable
524        private static JetType autocastValueArgumentTypeIfPossible(
525                @NotNull JetExpression expression,
526                @NotNull JetType expectedType,
527                @NotNull JetType actualType,
528                @NotNull ResolutionContext<?> context
529        ) {
530            ExpressionReceiver receiverToCast = new ExpressionReceiver(JetPsiUtil.safeDeparenthesize(expression, false), actualType);
531            List<JetType> variants =
532                    AutoCastUtils.getAutoCastVariantsExcludingReceiver(context.trace.getBindingContext(), context.dataFlowInfo, receiverToCast);
533            for (JetType possibleType : variants) {
534                if (JetTypeChecker.DEFAULT.isSubtypeOf(possibleType, expectedType)) {
535                    return possibleType;
536                }
537            }
538            return null;
539        }
540    
541        private static <D extends CallableDescriptor> ResolutionStatus checkReceiverTypeError(
542                @NotNull CallCandidateResolutionContext<D> context
543        ) {
544            MutableResolvedCall<D> candidateCall = context.candidateCall;
545            D candidateDescriptor = candidateCall.getCandidateDescriptor();
546    
547            ReceiverParameterDescriptor receiverDescriptor = candidateDescriptor.getReceiverParameter();
548            ReceiverParameterDescriptor expectedThisObjectDescriptor = candidateDescriptor.getExpectedThisObject();
549            ResolutionStatus status = SUCCESS;
550            // For the expressions like '42.(f)()' where f: String.() -> Unit we'd like to generate a type mismatch error on '1',
551            // not to throw away the candidate, so the following check is skipped.
552            if (!CallResolverUtil.isInvokeCallOnExpressionWithBothReceivers(context.call)) {
553                status = status.combine(checkReceiverTypeError(context, receiverDescriptor, candidateCall.getReceiverArgument()));
554            }
555            status = status.combine(checkReceiverTypeError(context, expectedThisObjectDescriptor, candidateCall.getThisObject()));
556            return status;
557        }
558    
559        private static <D extends CallableDescriptor> ResolutionStatus checkReceiverTypeError(
560                @NotNull CallCandidateResolutionContext<D> context,
561                @Nullable ReceiverParameterDescriptor receiverParameterDescriptor,
562                @NotNull ReceiverValue receiverArgument
563        ) {
564            if (receiverParameterDescriptor == null || !receiverArgument.exists()) return SUCCESS;
565    
566            D candidateDescriptor = context.candidateCall.getCandidateDescriptor();
567    
568            JetType erasedReceiverType = CallResolverUtil.getErasedReceiverType(receiverParameterDescriptor, candidateDescriptor);
569    
570            boolean isSubtypeByAutoCast = AutoCastUtils.isSubTypeByAutoCastIgnoringNullability(receiverArgument, erasedReceiverType, context);
571            if (!isSubtypeByAutoCast) {
572                return RECEIVER_TYPE_ERROR;
573            }
574    
575            return SUCCESS;
576        }
577    
578        private static <D extends CallableDescriptor> ResolutionStatus checkReceiver(
579                @NotNull CallCandidateResolutionContext<D> context,
580                @NotNull ResolvedCall<D> candidateCall,
581                @NotNull BindingTrace trace,
582                @Nullable ReceiverParameterDescriptor receiverParameter,
583                @NotNull ReceiverValue receiverArgument,
584                boolean isExplicitReceiver,
585                boolean implicitInvokeCheck
586        ) {
587            if (receiverParameter == null || !receiverArgument.exists()) return SUCCESS;
588            D candidateDescriptor = candidateCall.getCandidateDescriptor();
589            if (TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters())) return SUCCESS;
590    
591            boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall();
592            boolean isSubtypeByAutoCast = AutoCastUtils.isSubTypeByAutoCastIgnoringNullability(
593                    receiverArgument, receiverParameter.getType(), context);
594            if (!isSubtypeByAutoCast) {
595                context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument);
596                return OTHER_ERROR;
597            }
598            AutoCastUtils.recordAutoCastIfNecessary(receiverArgument, receiverParameter.getType(), context, safeAccess);
599    
600            JetType receiverArgumentType = receiverArgument.getType();
601    
602            BindingContext bindingContext = trace.getBindingContext();
603            if (!safeAccess && !receiverParameter.getType().isNullable() && receiverArgumentType.isNullable()) {
604                if (!AutoCastUtils.isNotNull(receiverArgument, bindingContext, context.dataFlowInfo)) {
605    
606                    context.tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck);
607                    return UNSAFE_CALL_ERROR;
608                }
609            }
610            DataFlowValue receiverValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, bindingContext);
611            if (safeAccess && !context.dataFlowInfo.getNullability(receiverValue).canBeNull()) {
612                context.tracing.unnecessarySafeCall(trace, receiverArgumentType);
613            }
614            return SUCCESS;
615        }
616    
617        public static class ValueArgumentsCheckingResult {
618            @NotNull
619            public final List<JetType> argumentTypes;
620            @NotNull
621            public final ResolutionStatus status;
622    
623            private ValueArgumentsCheckingResult(@NotNull ResolutionStatus status, @NotNull List<JetType> argumentTypes) {
624                this.status = status;
625                this.argumentTypes = argumentTypes;
626            }
627        }
628    
629        @NotNull
630        public static JetType getEffectiveExpectedType(ValueParameterDescriptor parameterDescriptor, ValueArgument argument) {
631            if (argument.getSpreadElement() != null) {
632                if (parameterDescriptor.getVarargElementType() == null) {
633                    // Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper
634                    return DONT_CARE;
635                }
636                else {
637                    return parameterDescriptor.getType();
638                }
639            }
640            else {
641                JetType varargElementType = parameterDescriptor.getVarargElementType();
642                if (varargElementType != null) {
643                    return varargElementType;
644                }
645    
646                return parameterDescriptor.getType();
647            }
648        }
649    
650        private static void checkGenericBoundsInAFunctionCall(
651                @NotNull List<JetTypeProjection> jetTypeArguments,
652                @NotNull List<JetType> typeArguments,
653                @NotNull CallableDescriptor functionDescriptor,
654                @NotNull TypeSubstitutor substitutor,
655                @NotNull BindingTrace trace
656        ) {
657            List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
658            for (int i = 0; i < typeParameters.size(); i++) {
659                TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
660                JetType typeArgument = typeArguments.get(i);
661                JetTypeReference typeReference = jetTypeArguments.get(i).getTypeReference();
662                if (typeReference != null) {
663                    DescriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace);
664                }
665            }
666        }
667    }