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
017package org.jetbrains.jet.lang.resolve.calls;
018
019import com.google.common.base.Function;
020import com.google.common.collect.Lists;
021import com.google.common.collect.Maps;
022import com.google.common.collect.Sets;
023import com.intellij.openapi.progress.ProgressIndicatorProvider;
024import com.intellij.psi.PsiElement;
025import org.jetbrains.annotations.NotNull;
026import org.jetbrains.annotations.Nullable;
027import org.jetbrains.jet.lang.descriptors.*;
028import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorUtil;
029import org.jetbrains.jet.lang.psi.*;
030import org.jetbrains.jet.lang.resolve.*;
031import org.jetbrains.jet.lang.resolve.calls.autocasts.*;
032import org.jetbrains.jet.lang.resolve.calls.context.CallCandidateResolutionContext;
033import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
034import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
035import org.jetbrains.jet.lang.resolve.calls.context.ResolveMode;
036import org.jetbrains.jet.lang.resolve.calls.inference.*;
037import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
038import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
039import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
040import org.jetbrains.jet.lang.resolve.calls.results.ResolutionDebugInfo;
041import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
042import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
043import org.jetbrains.jet.lang.resolve.calls.tasks.TaskPrioritizer;
044import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
045import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
046import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
047import org.jetbrains.jet.lang.types.*;
048import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
049import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
050import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
051import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
052
053import javax.inject.Inject;
054import java.util.ArrayList;
055import java.util.List;
056import java.util.Map;
057import java.util.Set;
058
059import static org.jetbrains.jet.lang.diagnostics.Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT;
060import static org.jetbrains.jet.lang.diagnostics.Errors.SUPER_IS_NOT_AN_EXPRESSION;
061import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.DONT_CARE;
062import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.PLACEHOLDER_FUNCTION_TYPE;
063import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
064import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SKIP_FUNCTION_ARGUMENTS;
065import static org.jetbrains.jet.lang.resolve.calls.CallTransformer.CallForImplicitInvoke;
066import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.*;
067import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
068
069public class CandidateResolver {
070    @NotNull
071    private ArgumentTypeResolver argumentTypeResolver;
072
073    @Inject
074    public void setArgumentTypeResolver(@NotNull ArgumentTypeResolver argumentTypeResolver) {
075        this.argumentTypeResolver = argumentTypeResolver;
076    }
077
078    public <D extends CallableDescriptor, F extends D> void performResolutionForCandidateCall(
079            @NotNull CallCandidateResolutionContext<D> context,
080            @NotNull ResolutionTask<D, F> task) {
081
082        ProgressIndicatorProvider.checkCanceled();
083
084        ResolvedCallImpl<D> candidateCall = context.candidateCall;
085        D candidate = candidateCall.getCandidateDescriptor();
086
087        candidateCall.addStatus(checkReceiverTypeError(context.candidateCall));
088
089        if (ErrorUtils.isError(candidate)) {
090            candidateCall.addStatus(SUCCESS);
091            argumentTypeResolver.checkTypesWithNoCallee(context.toBasic());
092            return;
093        }
094
095        if (!checkOuterClassMemberIsAccessible(context)) {
096            candidateCall.addStatus(OTHER_ERROR);
097            return;
098        }
099
100
101        DeclarationDescriptorWithVisibility invisibleMember =
102                Visibilities.findInvisibleMember(candidate, context.scope.getContainingDeclaration());
103        if (invisibleMember != null) {
104            candidateCall.addStatus(OTHER_ERROR);
105            context.tracing.invisibleMember(context.trace, invisibleMember);
106            return;
107        }
108
109        if (task.checkArguments == CheckValueArgumentsMode.ENABLED) {
110            Set<ValueArgument> unmappedArguments = Sets.newLinkedHashSet();
111            ValueArgumentsToParametersMapper.Status
112                    argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(context.call, context.tracing,
113                                                                                                            candidateCall, unmappedArguments);
114            if (!argumentMappingStatus.isSuccess()) {
115                if (argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
116                    candidateCall.addStatus(RECEIVER_PRESENCE_ERROR);
117                }
118                else {
119                    candidateCall.addStatus(OTHER_ERROR);
120                }
121                if ((argumentMappingStatus == ValueArgumentsToParametersMapper.Status.ERROR && candidate.getTypeParameters().isEmpty()) ||
122                    argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
123                    argumentTypeResolver.checkTypesWithNoCallee(context.toBasic());
124                    return;
125                }
126                candidateCall.setUnmappedArguments(unmappedArguments);
127            }
128        }
129
130        List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments();
131        if (jetTypeArguments.isEmpty()) {
132            if (!candidate.getTypeParameters().isEmpty()) {
133                ResolutionStatus status = inferTypeArguments(context);
134                candidateCall.addStatus(status);
135            }
136            else {
137                candidateCall.addStatus(checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS).status);
138            }
139        }
140        else {
141            // Explicit type arguments passed
142
143            List<JetType> typeArguments = new ArrayList<JetType>();
144            for (JetTypeProjection projection : jetTypeArguments) {
145                if (projection.getProjectionKind() != JetProjectionKind.NONE) {
146                    context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
147                }
148                typeArguments.add(argumentTypeResolver.resolveTypeRefWithDefault(
149                        projection.getTypeReference(), context.scope, context.trace, ErrorUtils.createErrorType("Star projection in a call")));
150            }
151            int expectedTypeArgumentCount = candidate.getTypeParameters().size();
152            if (expectedTypeArgumentCount == jetTypeArguments.size()) {
153
154                checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, context.trace);
155
156                Map<TypeConstructor, TypeProjection>
157                        substitutionContext = FunctionDescriptorUtil
158                        .createSubstitutionContext((FunctionDescriptor) candidate, typeArguments);
159                TypeSubstitutor substitutor = TypeSubstitutor.create(substitutionContext);
160                candidateCall.setResultingSubstitutor(substitutor);
161
162                List<TypeParameterDescriptor> typeParameters = candidateCall.getCandidateDescriptor().getTypeParameters();
163                for (int i = 0; i < typeParameters.size(); i++) {
164                    TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
165                    candidateCall.recordTypeArgument(typeParameterDescriptor, typeArguments.get(i));
166                }
167                candidateCall.addStatus(checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS).status);
168            }
169            else {
170                candidateCall.addStatus(OTHER_ERROR);
171                context.tracing.wrongNumberOfTypeArguments(context.trace, expectedTypeArgumentCount);
172            }
173        }
174
175        task.performAdvancedChecks(candidate, context.trace, context.tracing);
176
177        // 'super' cannot be passed as an argument, for receiver arguments expression typer does not track this
178        // See TaskPrioritizer for more
179        JetSuperExpression superExpression = TaskPrioritizer.getReceiverSuper(candidateCall.getReceiverArgument());
180        if (superExpression != null) {
181            context.trace.report(SUPER_IS_NOT_AN_EXPRESSION.on(superExpression, superExpression.getText()));
182            candidateCall.addStatus(OTHER_ERROR);
183        }
184
185        AutoCastUtils.recordAutoCastIfNecessary(candidateCall.getReceiverArgument(), candidateCall.getTrace());
186        AutoCastUtils.recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace());
187    }
188
189    private static boolean checkOuterClassMemberIsAccessible(@NotNull CallCandidateResolutionContext<?> context) {
190        // In "this@Outer.foo()" the error will be reported on "this@Outer" instead
191        if (context.call.getExplicitReceiver().exists()) return true;
192
193        ClassDescriptor candidateThis = getDeclaringClass(context.candidateCall.getCandidateDescriptor());
194        if (candidateThis == null || candidateThis.getKind().isObject()) return true;
195
196        return DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, context.call.getCallElement(), candidateThis);
197    }
198
199    @Nullable
200    private static ClassDescriptor getDeclaringClass(@NotNull CallableDescriptor candidate) {
201        ReceiverParameterDescriptor expectedThis = candidate.getExpectedThisObject();
202        if (expectedThis == null) return null;
203        DeclarationDescriptor descriptor = expectedThis.getContainingDeclaration();
204        return descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null;
205    }
206
207    public <D extends CallableDescriptor> void completeTypeInferenceDependentOnFunctionLiteralsForCall(
208            CallCandidateResolutionContext<D> context
209    ) {
210        ResolvedCallImpl<D> resolvedCall = context.candidateCall;
211        ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
212        if (!resolvedCall.hasIncompleteTypeParameters() || constraintSystem == null) return;
213
214        // constraints for function literals
215        // Value parameters
216        for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
217            ResolvedValueArgument resolvedValueArgument = entry.getValue();
218            ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
219
220            for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
221                if (!(valueArgument.getArgumentExpression() instanceof JetFunctionLiteralExpression)) continue;
222
223                addConstraintForFunctionLiteral(valueArgument, valueParameterDescriptor, constraintSystem, context);
224            }
225        }
226        resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
227    }
228
229    @Nullable
230    public <D extends CallableDescriptor> JetType completeTypeInferenceDependentOnExpectedTypeForCall(
231            @NotNull CallCandidateResolutionContext<D> context,
232            boolean isInnerCall
233    ) {
234        ResolvedCallImpl<D> resolvedCall = context.candidateCall;
235        assert resolvedCall.hasIncompleteTypeParameters();
236        D descriptor = resolvedCall.getCandidateDescriptor();
237        ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
238        assert constraintSystem != null;
239
240        constraintSystem.addSupertypeConstraint(context.expectedType, descriptor.getReturnType(), ConstraintPosition.EXPECTED_TYPE_POSITION);
241
242        ConstraintSystemCompleter constraintSystemCompleter = context.trace.get(
243                BindingContext.CONSTRAINT_SYSTEM_COMPLETER, context.call.getCalleeExpression());
244        if (constraintSystemCompleter != null) {
245            ConstraintSystemImpl backup = (ConstraintSystemImpl) constraintSystem.copy();
246
247            //todo improve error reporting with errors in constraints from completer
248            constraintSystemCompleter.completeConstraintSystem(constraintSystem, resolvedCall);
249            if (constraintSystem.hasTypeConstructorMismatchAt(ConstraintPosition.FROM_COMPLETER) ||
250                (constraintSystem.hasContradiction() && !backup.hasContradiction())) {
251
252                constraintSystem = backup;
253                resolvedCall.setConstraintSystem(backup);
254            }
255        }
256
257        if (constraintSystem.hasContradiction()) {
258            return reportInferenceError(context);
259        }
260
261        boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/true);
262        if (!boundsAreSatisfied || constraintSystem.hasUnknownParameters()) {
263            ConstraintSystemImpl copy = (ConstraintSystemImpl) constraintSystem.copy();
264            copy.processDeclaredBoundConstraints();
265            boundsAreSatisfied = copy.isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(copy, /*substituteOtherTypeParametersInBounds=*/true);
266            if (boundsAreSatisfied) {
267                constraintSystem = copy;
268                resolvedCall.setConstraintSystem(constraintSystem);
269            }
270        }
271        if (!constraintSystem.isSuccessful()) {
272            return reportInferenceError(context);
273        }
274        if (!boundsAreSatisfied) {
275            context.tracing.upperBoundViolated(context.trace, InferenceErrorData.create(resolvedCall.getCandidateDescriptor(), constraintSystem));
276        }
277        resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
278
279        completeNestedCallsInference(context);
280        // Here we type check the arguments with inferred types expected
281        checkAllValueArguments(context, context.trace, RESOLVE_FUNCTION_ARGUMENTS);
282
283        resolvedCall.setHasUnknownTypeParameters(false);
284        ResolutionStatus status = resolvedCall.getStatus();
285        if (status == ResolutionStatus.UNKNOWN_STATUS || status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
286            resolvedCall.setStatusToSuccess();
287        }
288        JetType returnType = resolvedCall.getResultingDescriptor().getReturnType();
289        if (isInnerCall) {
290            PsiElement callElement = context.call.getCallElement();
291            if (callElement instanceof JetCallExpression) {
292                DataFlowUtils.checkType(returnType, (JetCallExpression) callElement, context, context.dataFlowInfo);
293            }
294        }
295        return returnType;
296    }
297
298    private <D extends CallableDescriptor> JetType reportInferenceError(
299            @NotNull CallCandidateResolutionContext<D> context
300    ) {
301        ResolvedCallImpl<D> resolvedCall = context.candidateCall;
302        ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
303
304        resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
305        completeNestedCallsInference(context);
306        List<JetType> argumentTypes = checkValueArgumentTypes(
307                context, resolvedCall, context.trace, RESOLVE_FUNCTION_ARGUMENTS).argumentTypes;
308        JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
309        InferenceErrorData.ExtendedInferenceErrorData errorData = InferenceErrorData
310                .create(resolvedCall.getCandidateDescriptor(), constraintSystem, argumentTypes, receiverType, context.expectedType);
311
312        context.tracing.typeInferenceFailed(context.trace, errorData);
313        resolvedCall.addStatus(ResolutionStatus.OTHER_ERROR);
314        if (!CallResolverUtil.hasInferredReturnType(resolvedCall)) return null;
315        return resolvedCall.getResultingDescriptor().getReturnType();
316    }
317
318    @Nullable
319    public <D extends CallableDescriptor> JetType completeNestedCallsInference(
320            @NotNull CallCandidateResolutionContext<D> context
321    ) {
322        ResolvedCallImpl<D> resolvedCall = context.candidateCall;
323        ConstraintSystem constraintSystem = context.candidateCall.getConstraintSystem();
324        for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
325            ValueParameterDescriptor parameterDescriptor = entry.getKey();
326            ResolvedValueArgument resolvedArgument = entry.getValue();
327
328            for (ValueArgument argument : resolvedArgument.getArguments()) {
329                JetExpression expression = argument.getArgumentExpression();
330                if (expression == null) continue;
331
332                JetType effectiveExpectedType = getEffectiveExpectedType(parameterDescriptor, argument);
333                JetType expectedType = constraintSystem != null
334                                       ? constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT)
335                                       : effectiveExpectedType;
336
337                //todo inner calls should be analyzed, for parenthesized, labeled, if, when expressions as well
338                JetVisitor<JetExpression, Void> selectorExpressionFinder = new JetVisitor<JetExpression, Void>() {
339                    @Override
340                    public JetExpression visitQualifiedExpression(JetQualifiedExpression expression, Void data) {
341                        JetExpression selector = expression.getSelectorExpression();
342                        return selector != null ? selector.accept(this, null) : null;
343                    }
344
345                    @Override
346                    public JetExpression visitCallExpression(JetCallExpression expression, Void data) {
347                        return expression;
348                    }
349
350                    @Override
351                    public JetExpression visitSimpleNameExpression(JetSimpleNameExpression expression, Void data) {
352                        return expression;
353                    }
354
355                    @Override
356                    public JetExpression visitJetElement(JetElement element, Void data) {
357                        return null;
358                    }
359                };
360                // selector expression is callExpression or simpleNameExpression (if it's inside qualified expression)
361                JetExpression selectorExpression = expression.accept(selectorExpressionFinder, null);
362                if (selectorExpression == null) continue;
363
364                if (selectorExpression instanceof JetSimpleNameExpression) {
365                    if (expression instanceof JetQualifiedExpression) {
366                        //todo get rid of this hack, 'checkType' once at the end of the analysis
367                        JetType type = context.trace.get(BindingContext.EXPRESSION_TYPE, selectorExpression);
368                        DataFlowUtils.checkType(type, expression, context.replaceExpectedType(expectedType));
369                    }
370                    continue;
371                }
372                CallCandidateResolutionContext<FunctionDescriptor> storedContextForArgument =
373                        context.resolutionResultsCache.getDeferredComputation(CallKey.create(Call.CallType.DEFAULT, selectorExpression));
374                //todo assert storedContextForArgument != null
375                if (storedContextForArgument == null) continue;
376
377                CallCandidateResolutionContext<FunctionDescriptor> contextForArgument =
378                        storedContextForArgument.replaceResolveMode(ResolveMode.TOP_LEVEL_CALL).replaceBindingTrace(context.trace).replaceExpectedType(expectedType);
379                JetType type;
380                if (contextForArgument.candidateCall.hasIncompleteTypeParameters()) {
381                    type = completeTypeInferenceDependentOnExpectedTypeForCall(contextForArgument, true);
382                }
383                else {
384                    type = completeNestedCallsInference(contextForArgument);
385                    checkValueArgumentTypes(contextForArgument);
386                }
387
388                DataFlowUtils.checkType(type, expression, contextForArgument);
389            }
390        }
391        recordReferenceForInvokeFunction(context);
392        return resolvedCall.getResultingDescriptor().getReturnType();
393    }
394
395    private static <D extends CallableDescriptor> void recordReferenceForInvokeFunction(CallCandidateResolutionContext<D> context) {
396        PsiElement callElement = context.call.getCallElement();
397        if (!(callElement instanceof JetCallExpression)) return;
398
399        JetCallExpression callExpression = (JetCallExpression) callElement;
400        CallableDescriptor resultingDescriptor = context.candidateCall.getResultingDescriptor();
401        if (BindingContextUtils.isCallExpressionWithValidReference(callExpression, context.trace.getBindingContext())) {
402            context.trace.record(BindingContext.EXPRESSION_TYPE, callExpression, resultingDescriptor.getReturnType());
403            context.trace.record(BindingContext.REFERENCE_TARGET, callExpression, resultingDescriptor);
404        }
405    }
406
407    private <D extends CallableDescriptor> void addConstraintForFunctionLiteral(
408            @NotNull ValueArgument valueArgument,
409            @NotNull ValueParameterDescriptor valueParameterDescriptor,
410            @NotNull ConstraintSystem constraintSystem,
411            @NotNull CallCandidateResolutionContext<D> context
412    ) {
413        JetExpression argumentExpression = valueArgument.getArgumentExpression();
414        assert argumentExpression instanceof JetFunctionLiteralExpression;
415        JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
416        JetType expectedType = constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT);
417        if (expectedType == null || !KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType)
418                || CallResolverUtil.hasUnknownFunctionParameter(expectedType)) {
419            return;
420        }
421        boolean hasExpectedReturnType = !CallResolverUtil.hasUnknownReturnType(expectedType);
422        if (hasExpectedReturnType) {
423            TemporaryBindingTrace traceToResolveFunctionLiteral = TemporaryBindingTrace.create(
424                    context.trace, "trace to resolve function literal with expected return type", argumentExpression);
425
426            JetElement statementExpression = JetPsiUtil.getLastStatementInABlock(((JetFunctionLiteralExpression) argumentExpression).getBodyExpression());
427            if (statementExpression == null) return;
428            boolean[] mismatch = new boolean[1];
429            ObservableBindingTrace errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
430                    traceToResolveFunctionLiteral, statementExpression, mismatch);
431            CallCandidateResolutionContext<D> newContext =
432                    context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType);
433            JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo((JetFunctionLiteralExpression) argumentExpression, newContext,
434                                                                           RESOLVE_FUNCTION_ARGUMENTS).getType();
435            if (!mismatch[0]) {
436                constraintSystem.addSubtypeConstraint(
437                        type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex()));
438                traceToResolveFunctionLiteral.commit();
439                return;
440            }
441        }
442        JetType expectedTypeWithoutReturnType = hasExpectedReturnType ? CallResolverUtil.replaceReturnTypeByUnknown(expectedType) : expectedType;
443        CallCandidateResolutionContext<D> newContext = context.replaceExpectedType(expectedTypeWithoutReturnType);
444        JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo((JetFunctionLiteralExpression) argumentExpression, newContext,
445                                                                       RESOLVE_FUNCTION_ARGUMENTS).getType();
446        constraintSystem.addSubtypeConstraint(
447                type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex()));
448    }
449
450    private <D extends CallableDescriptor> ResolutionStatus inferTypeArguments(CallCandidateResolutionContext<D> context) {
451        ResolvedCallImpl<D> candidateCall = context.candidateCall;
452        final D candidate = candidateCall.getCandidateDescriptor();
453
454        context.trace.get(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement());
455
456        ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
457
458        // If the call is recursive, e.g.
459        //   fun foo<T>(t : T) : T = foo(t)
460        // we can't use same descriptor objects for T's as actual type values and same T's as unknowns,
461        // because constraints become trivial (T :< T), and inference fails
462        //
463        // Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
464        CallableDescriptor candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate);
465
466
467        for (TypeParameterDescriptor typeParameterDescriptor : candidateWithFreshVariables.getTypeParameters()) {
468            constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO: variance of the occurrences
469        }
470
471        TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities
472                .makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE);
473
474        // Value parameters
475        for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
476            ResolvedValueArgument resolvedValueArgument = entry.getValue();
477            ValueParameterDescriptor valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex());
478
479
480            for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
481                // TODO : more attempts, with different expected types
482
483                // Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
484                // and throw the results away
485                // We'll type check the arguments later, with the inferred types expected
486                boolean[] isErrorType = new boolean[1];
487                addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem,
488                                              context, isErrorType, SKIP_FUNCTION_ARGUMENTS);
489                if (isErrorType[0]) {
490                    candidateCall.argumentHasNoType();
491                }
492            }
493        }
494
495        // Receiver
496        // Error is already reported if something is missing
497        ReceiverValue receiverArgument = candidateCall.getReceiverArgument();
498        ReceiverParameterDescriptor receiverParameter = candidateWithFreshVariables.getReceiverParameter();
499        if (receiverArgument.exists() && receiverParameter != null) {
500            JetType receiverType =
501                    context.candidateCall.isSafeCall()
502                    ? TypeUtils.makeNotNullable(receiverArgument.getType())
503                    : receiverArgument.getType();
504            constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION);
505        }
506
507        ConstraintSystem
508                constraintSystemWithRightTypeParameters = constraintSystem.replaceTypeVariables(new Function<TypeParameterDescriptor, TypeParameterDescriptor>() {
509            @Override
510            public TypeParameterDescriptor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) {
511                assert typeParameterDescriptor != null;
512                return candidate.getTypeParameters().get(typeParameterDescriptor.getIndex());
513            }
514        });
515        candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters);
516
517
518        // Solution
519        boolean hasContradiction = constraintSystem.hasContradiction();
520        boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/false);
521        candidateCall.setHasUnknownTypeParameters(true);
522        if (!hasContradiction && boundsAreSatisfied) {
523            return INCOMPLETE_TYPE_INFERENCE;
524        }
525        ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS);
526        ResolutionStatus argumentsStatus = checkingResult.status;
527        return OTHER_ERROR.combine(argumentsStatus);
528    }
529
530    private void addConstraintForValueArgument(
531            @NotNull ValueArgument valueArgument,
532            @NotNull ValueParameterDescriptor valueParameterDescriptor,
533            @NotNull TypeSubstitutor substitutor,
534            @NotNull ConstraintSystem constraintSystem,
535            @NotNull CallCandidateResolutionContext<?> context,
536            @Nullable boolean[] isErrorType,
537            @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
538
539        JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
540        JetExpression argumentExpression = valueArgument.getArgumentExpression();
541        TemporaryBindingTrace traceToResolveArgument = TemporaryBindingTrace.create(
542                context.trace, "transient trace to resolve argument", argumentExpression);
543        JetType expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT);
544        CallResolutionContext<?> newContext = context.replaceBindingTrace(traceToResolveArgument).replaceExpectedType(expectedType);
545        JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext,
546                                                                               resolveFunctionArgumentBodies, traceToResolveArgument);
547        JetType type = typeInfoForCall.getType();
548        constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(
549                valueParameterDescriptor.getIndex()));
550        if (isErrorType != null) {
551            isErrorType[0] = type == null || ErrorUtils.isErrorType(type);
552        }
553    }
554
555    private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
556            @NotNull CallCandidateResolutionContext<D> context,
557            @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
558        return checkAllValueArguments(context, context.candidateCall.getTrace(), resolveFunctionArgumentBodies);
559    }
560
561    private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
562            @NotNull CallCandidateResolutionContext<D> context,
563            @NotNull BindingTrace trace,
564            @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies
565    ) {
566        ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(
567                context, context.candidateCall, trace, resolveFunctionArgumentBodies);
568        ResolutionStatus resultStatus = checkingResult.status;
569        resultStatus = resultStatus.combine(checkReceiver(context, trace, false));
570
571        return new ValueArgumentsCheckingResult(resultStatus, checkingResult.argumentTypes);
572    }
573
574    private static <D extends CallableDescriptor> ResolutionStatus checkReceiver(
575            @NotNull CallCandidateResolutionContext<D> context,
576            @NotNull BindingTrace trace,
577            boolean checkOnlyReceiverTypeError
578    ) {
579        ResolutionStatus resultStatus = SUCCESS;
580        ResolvedCall<D> candidateCall = context.candidateCall;
581
582        resultStatus = resultStatus.combine(checkReceiverTypeError(candidateCall));
583
584        // Comment about a very special case.
585        // 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
586        // both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'.
587        // Class 'CallForImplicitInvoke' helps up to recognise this case, and parameter 'implicitInvokeCheck' helps us to distinguish whether we check receiver or this object.
588
589        resultStatus = resultStatus.combine(checkReceiver(
590                context, candidateCall, trace,
591                candidateCall.getResultingDescriptor().getReceiverParameter(),
592                candidateCall.getReceiverArgument(), candidateCall.getExplicitReceiverKind().isReceiver(), false));
593
594        resultStatus = resultStatus.combine(checkReceiver(
595                context, candidateCall, trace,
596                candidateCall.getResultingDescriptor().getExpectedThisObject(), candidateCall.getThisObject(),
597                candidateCall.getExplicitReceiverKind().isThisObject(),
598                // for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error
599                context.call instanceof CallForImplicitInvoke));
600        return resultStatus;
601    }
602
603    public <D extends CallableDescriptor> ValueArgumentsCheckingResult checkValueArgumentTypes(
604            @NotNull CallCandidateResolutionContext<D> context
605    ) {
606        return checkValueArgumentTypes(context, context.candidateCall, context.trace, RESOLVE_FUNCTION_ARGUMENTS);
607    }
608
609    private <D extends CallableDescriptor, C extends CallResolutionContext<C>> ValueArgumentsCheckingResult checkValueArgumentTypes(
610            @NotNull CallResolutionContext<C> context,
611            @NotNull ResolvedCallImpl<D> candidateCall,
612            @NotNull BindingTrace trace,
613            @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
614        ResolutionStatus resultStatus = SUCCESS;
615        List<JetType> argumentTypes = Lists.newArrayList();
616        for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
617            ValueParameterDescriptor parameterDescriptor = entry.getKey();
618            ResolvedValueArgument resolvedArgument = entry.getValue();
619
620
621            for (ValueArgument argument : resolvedArgument.getArguments()) {
622                JetExpression expression = argument.getArgumentExpression();
623                if (expression == null) continue;
624
625                JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
626                if (TypeUtils.dependsOnTypeParameters(expectedType, candidateCall.getCandidateDescriptor().getTypeParameters())) {
627                    expectedType = NO_EXPECTED_TYPE;
628                }
629                CallResolutionContext<?> newContext = context.replaceDataFlowInfo(candidateCall.getDataFlowInfo()).replaceBindingTrace(trace)
630                        .replaceExpectedType(expectedType);
631                JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(
632                        expression, newContext, resolveFunctionArgumentBodies, null);
633                JetType type = typeInfoForCall.getType();
634                candidateCall.addDataFlowInfo(typeInfoForCall.getDataFlowInfo());
635
636                if (type == null || (ErrorUtils.isErrorType(type) && type != PLACEHOLDER_FUNCTION_TYPE)) {
637                    candidateCall.argumentHasNoType();
638                    argumentTypes.add(type);
639                }
640                else {
641                    JetType resultingType;
642                    if (expectedType == NO_EXPECTED_TYPE || ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
643                        resultingType = type;
644                    }
645                    else {
646                        resultingType = autocastValueArgumentTypeIfPossible(expression, expectedType, type, trace, candidateCall.getDataFlowInfo());
647                        if (resultingType == null) {
648                            resultingType = type;
649                            resultStatus = OTHER_ERROR;
650                        }
651                    }
652
653                    argumentTypes.add(resultingType);
654                }
655            }
656        }
657        return new ValueArgumentsCheckingResult(resultStatus, argumentTypes);
658    }
659
660    @Nullable
661    private static JetType autocastValueArgumentTypeIfPossible(
662            @NotNull JetExpression expression,
663            @NotNull JetType expectedType,
664            @NotNull JetType actualType,
665            @NotNull BindingTrace trace,
666            @NotNull DataFlowInfo dataFlowInfo
667    ) {
668        ExpressionReceiver receiverToCast = new ExpressionReceiver(expression, actualType);
669        List<ReceiverValue> variants = AutoCastUtils.getAutoCastVariants(trace.getBindingContext(), dataFlowInfo, receiverToCast);
670        for (ReceiverValue receiverValue : variants) {
671            JetType possibleType = receiverValue.getType();
672            if (ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType)) {
673                return possibleType;
674            }
675        }
676        return null;
677    }
678
679    private static <D extends CallableDescriptor> ResolutionStatus checkReceiverTypeError(
680            @NotNull ResolvedCall<D> candidateCall
681    ) {
682        D candidateDescriptor = candidateCall.getCandidateDescriptor();
683        if (candidateDescriptor instanceof ExpressionAsFunctionDescriptor) return SUCCESS;
684
685        ReceiverParameterDescriptor receiverDescriptor = candidateDescriptor.getReceiverParameter();
686        ReceiverParameterDescriptor expectedThisObjectDescriptor = candidateDescriptor.getExpectedThisObject();
687        ReceiverParameterDescriptor receiverParameterDescriptor;
688        JetType receiverArgumentType;
689        if (receiverDescriptor != null && candidateCall.getReceiverArgument().exists()) {
690            receiverParameterDescriptor = receiverDescriptor;
691            receiverArgumentType = candidateCall.getReceiverArgument().getType();
692        }
693        else if (expectedThisObjectDescriptor != null && candidateCall.getThisObject().exists()) {
694            receiverParameterDescriptor = expectedThisObjectDescriptor;
695            receiverArgumentType = candidateCall.getThisObject().getType();
696        }
697        else {
698            return SUCCESS;
699        }
700
701        JetType effectiveReceiverArgumentType = TypeUtils.makeNotNullable(receiverArgumentType);
702        JetType erasedReceiverType = CallResolverUtil.getErasedReceiverType(receiverParameterDescriptor, candidateDescriptor);
703
704        if (!JetTypeChecker.INSTANCE.isSubtypeOf(effectiveReceiverArgumentType, erasedReceiverType)) {
705            return RECEIVER_TYPE_ERROR;
706        }
707        return SUCCESS;
708    }
709
710    private static <D extends CallableDescriptor> ResolutionStatus checkReceiver(
711            @NotNull CallCandidateResolutionContext<D> context,
712            @NotNull ResolvedCall<D> candidateCall,
713            @NotNull BindingTrace trace,
714            @Nullable ReceiverParameterDescriptor receiverParameter,
715            @NotNull ReceiverValue receiverArgument,
716            boolean isExplicitReceiver,
717            boolean implicitInvokeCheck
718    ) {
719        if (receiverParameter == null || !receiverArgument.exists()) return SUCCESS;
720
721        JetType receiverArgumentType = receiverArgument.getType();
722        JetType effectiveReceiverArgumentType = TypeUtils.makeNotNullable(receiverArgumentType);
723        D candidateDescriptor = candidateCall.getCandidateDescriptor();
724        if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType())
725                && !TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters())) {
726            context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument);
727            return OTHER_ERROR;
728        }
729
730        BindingContext bindingContext = trace.getBindingContext();
731        boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall();
732        AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, bindingContext);
733        if (!safeAccess && !receiverParameter.getType().isNullable() && !autoCastService.isNotNull(receiverArgument)) {
734
735            context.tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck);
736            return UNSAFE_CALL_ERROR;
737        }
738        DataFlowValue receiverValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiverArgument, bindingContext);
739        if (safeAccess && !context.dataFlowInfo.getNullability(receiverValue).canBeNull()) {
740            context.tracing.unnecessarySafeCall(trace, receiverArgumentType);
741        }
742        return SUCCESS;
743    }
744
745    private static class ValueArgumentsCheckingResult {
746
747        public final List<JetType> argumentTypes;
748        public final ResolutionStatus status;
749
750        private ValueArgumentsCheckingResult(@NotNull ResolutionStatus status, @NotNull List<JetType> argumentTypes) {
751            this.status = status;
752            this.argumentTypes = argumentTypes;
753        }
754    }
755
756    @NotNull
757    private static JetType getEffectiveExpectedType(ValueParameterDescriptor parameterDescriptor, ValueArgument argument) {
758        if (argument.getSpreadElement() != null) {
759            if (parameterDescriptor.getVarargElementType() == null) {
760                // Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper
761                return DONT_CARE;
762            }
763            else {
764                return parameterDescriptor.getType();
765            }
766        }
767        else {
768            if (argument.isNamed()) {
769                return parameterDescriptor.getType();
770            }
771            else {
772                JetType varargElementType = parameterDescriptor.getVarargElementType();
773                if (varargElementType == null) {
774                    return parameterDescriptor.getType();
775                }
776                return varargElementType;
777            }
778        }
779    }
780
781    private static void checkGenericBoundsInAFunctionCall(
782            @NotNull List<JetTypeProjection> jetTypeArguments,
783            @NotNull List<JetType> typeArguments,
784            @NotNull CallableDescriptor functionDescriptor,
785            @NotNull BindingTrace trace) {
786        Map<TypeConstructor, TypeProjection> context = Maps.newHashMap();
787
788        List<TypeParameterDescriptor> typeParameters = functionDescriptor.getOriginal().getTypeParameters();
789        for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
790            TypeParameterDescriptor typeParameter = typeParameters.get(i);
791            JetType typeArgument = typeArguments.get(i);
792            context.put(typeParameter.getTypeConstructor(), new TypeProjection(typeArgument));
793        }
794        TypeSubstitutor substitutor = TypeSubstitutor.create(context);
795        for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
796            TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
797            JetType typeArgument = typeArguments.get(i);
798            JetTypeReference typeReference = jetTypeArguments.get(i).getTypeReference();
799            if (typeReference != null) {
800                DescriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace);
801            }
802        }
803    }
804}