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 }