001 /*
002 * Copyright 2010-2015 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.kotlin.types.expressions;
018
019 import com.google.common.collect.Lists;
020 import com.google.common.collect.Maps;
021 import com.intellij.lang.ASTNode;
022 import com.intellij.openapi.diagnostic.Logger;
023 import com.intellij.openapi.util.Ref;
024 import com.intellij.psi.util.PsiTreeUtil;
025 import org.jetbrains.annotations.NotNull;
026 import org.jetbrains.annotations.Nullable;
027 import org.jetbrains.kotlin.descriptors.*;
028 import org.jetbrains.kotlin.descriptors.annotations.Annotations;
029 import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
030 import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
031 import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
032 import org.jetbrains.kotlin.lexer.KtTokens;
033 import org.jetbrains.kotlin.name.Name;
034 import org.jetbrains.kotlin.psi.*;
035 import org.jetbrains.kotlin.resolve.BindingContextUtils;
036 import org.jetbrains.kotlin.resolve.BindingTrace;
037 import org.jetbrains.kotlin.resolve.calls.CallResolver;
038 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
039 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemStatus;
040 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintsUtil;
041 import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
042 import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
043 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
044 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
045 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
046 import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
047 import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
048 import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
049 import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
050 import org.jetbrains.kotlin.resolve.descriptorUtil.AnnotationsForResolveKt;
051 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
052 import org.jetbrains.kotlin.types.KotlinType;
053 import org.jetbrains.kotlin.types.TypeUtils;
054 import org.jetbrains.kotlin.types.Variance;
055 import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
056
057 import java.util.*;
058
059 import static org.jetbrains.kotlin.resolve.BindingContext.CALL;
060 import static org.jetbrains.kotlin.resolve.BindingContext.RESOLVED_CALL;
061 import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION;
062
063 public class ControlStructureTypingUtils {
064 private static final Logger LOG = Logger.getInstance(ControlStructureTypingUtils.class);
065
066 public enum ResolveConstruct {
067 IF("if"), ELVIS("elvis"), EXCL_EXCL("ExclExcl");
068
069 private final String name;
070
071 ResolveConstruct(String name) {
072 this.name = name;
073 }
074
075 public String getName() {
076 return name;
077 }
078 }
079
080 private final CallResolver callResolver;
081 private final DataFlowAnalyzer dataFlowAnalyzer;
082 private final ModuleDescriptor moduleDescriptor;
083
084 public ControlStructureTypingUtils(
085 @NotNull CallResolver callResolver,
086 @NotNull DataFlowAnalyzer dataFlowAnalyzer,
087 @NotNull ModuleDescriptor moduleDescriptor
088 ) {
089 this.callResolver = callResolver;
090 this.dataFlowAnalyzer = dataFlowAnalyzer;
091 this.moduleDescriptor = moduleDescriptor;
092 }
093
094 /*package*/ ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall(
095 @NotNull Call call,
096 @NotNull ResolveConstruct construct,
097 @NotNull List<String> argumentNames,
098 @NotNull List<Boolean> isArgumentNullable,
099 @NotNull ExpressionTypingContext context,
100 @Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
101 ) {
102 SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
103 construct, argumentNames, isArgumentNullable);
104 TracingStrategy tracing = createTracingForSpecialConstruction(call, construct.getName(), context);
105 ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(call, function);
106 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
107 call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
108 assert results.isSingleResult() : "Not single result after resolving one known candidate";
109 return results.getResultingCall();
110 }
111
112 private SimpleFunctionDescriptorImpl createFunctionDescriptorForSpecialConstruction(
113 @NotNull ResolveConstruct construct,
114 @NotNull List<String> argumentNames,
115 @NotNull List<Boolean> isArgumentNullable
116 ) {
117 assert argumentNames.size() == isArgumentNullable.size();
118
119 String constructionName = construct.getName().toUpperCase();
120 Name specialFunctionName = Name.identifier("<SPECIAL-FUNCTION-FOR-" + constructionName + "-RESOLVE>");
121
122 SimpleFunctionDescriptorImpl function = SimpleFunctionDescriptorImpl.create(
123 moduleDescriptor, Annotations.Companion.getEMPTY(), specialFunctionName, CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE
124 );
125
126 TypeParameterDescriptor typeParameter = TypeParameterDescriptorImpl.createWithDefaultBound(
127 function, Annotations.Companion.getEMPTY(), false, Variance.INVARIANT,
128 Name.identifier("<TYPE-PARAMETER-FOR-" + constructionName + "-RESOLVE>"), 0);
129
130 KotlinType type = typeParameter.getDefaultType();
131 KotlinType nullableType = TypeUtils.makeNullable(type);
132
133 List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(argumentNames.size());
134 for (int i = 0; i < argumentNames.size(); i++) {
135 KotlinType argumentType = isArgumentNullable.get(i) ? nullableType : type;
136 ValueParameterDescriptorImpl valueParameter = new ValueParameterDescriptorImpl(
137 function, null, i, Annotations.Companion.getEMPTY(), Name.identifier(argumentNames.get(i)),
138 argumentType,
139 /* declaresDefaultValue = */ false,
140 /* isCrossinline = */ false,
141 /* isNoinline = */ false,
142 null, SourceElement.NO_SOURCE
143 );
144 valueParameters.add(valueParameter);
145 }
146 KotlinType returnType = construct != ResolveConstruct.ELVIS ? type : TypeUtilsKt.replaceAnnotations(type, AnnotationsForResolveKt.getExactInAnnotations());
147 function.initialize(
148 null,
149 null,
150 Lists.newArrayList(typeParameter),
151 valueParameters,
152 returnType,
153 Modality.FINAL,
154 Visibilities.PUBLIC
155 );
156 return function;
157 }
158
159 /*package*/ static MutableDataFlowInfoForArguments createIndependentDataFlowInfoForArgumentsForCall(
160 final Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap
161 ) {
162 return new MutableDataFlowInfoForArguments() {
163 private DataFlowInfo initialDataFlowInfo;
164
165 @Override
166 public void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo) {
167 this.initialDataFlowInfo = dataFlowInfo;
168 }
169
170 @Override
171 public void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo) {
172 //todo
173 }
174
175 @NotNull
176 @Override
177 public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
178 return dataFlowInfoForArgumentsMap.get(valueArgument);
179 }
180
181 @NotNull
182 @Override
183 public DataFlowInfo getResultInfo() {
184 //todo merge and use
185 return initialDataFlowInfo;
186 }
187 };
188 }
189
190 public static MutableDataFlowInfoForArguments createDataFlowInfoForArgumentsForIfCall(
191 @NotNull Call callForIf,
192 @NotNull DataFlowInfo thenInfo,
193 @NotNull DataFlowInfo elseInfo
194 ) {
195 Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap = Maps.newHashMap();
196 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(0), thenInfo);
197 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(1), elseInfo);
198 return createIndependentDataFlowInfoForArgumentsForCall(dataFlowInfoForArgumentsMap);
199 }
200
201 /*package*/ static Call createCallForSpecialConstruction(
202 @NotNull final KtExpression expression,
203 @NotNull final KtExpression calleeExpression,
204 @NotNull List<? extends KtExpression> arguments
205 ) {
206 final List<ValueArgument> valueArguments = Lists.newArrayList();
207 for (KtExpression argument : arguments) {
208 valueArguments.add(CallMaker.makeValueArgument(argument));
209 }
210 return new Call() {
211 @Nullable
212 @Override
213 public ASTNode getCallOperationNode() {
214 return expression.getNode();
215 }
216
217 @NotNull
218 @Override
219 public ReceiverValue getExplicitReceiver() {
220 return ReceiverValue.NO_RECEIVER;
221 }
222
223 @NotNull
224 @Override
225 public ReceiverValue getDispatchReceiver() {
226 return ReceiverValue.NO_RECEIVER;
227 }
228
229 @Nullable
230 @Override
231 public KtExpression getCalleeExpression() {
232 return calleeExpression;
233 }
234
235 @Nullable
236 @Override
237 public KtValueArgumentList getValueArgumentList() {
238 return null;
239 }
240
241 @NotNull
242 @Override
243 public List<? extends ValueArgument> getValueArguments() {
244 return valueArguments;
245 }
246
247 @NotNull
248 @Override
249 public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
250 return Collections.emptyList();
251 }
252
253 @NotNull
254 @Override
255 public List<KtTypeProjection> getTypeArguments() {
256 return Collections.emptyList();
257 }
258
259 @Nullable
260 @Override
261 public KtTypeArgumentList getTypeArgumentList() {
262 return null;
263 }
264
265 @NotNull
266 @Override
267 public KtElement getCallElement() {
268 return expression;
269 }
270
271 @NotNull
272 @Override
273 public CallType getCallType() {
274 return CallType.DEFAULT;
275 }
276 };
277 }
278
279 @NotNull
280 /*package*/ TracingStrategy createTracingForSpecialConstruction(
281 final @NotNull Call call,
282 @NotNull String constructionName,
283 final @NotNull ExpressionTypingContext context
284 ) {
285 class CheckTypeContext {
286 public BindingTrace trace;
287 public KotlinType expectedType;
288
289 CheckTypeContext(@NotNull BindingTrace trace, @NotNull KotlinType expectedType) {
290 this.trace = trace;
291 this.expectedType = expectedType;
292 }
293
294 CheckTypeContext makeTypeNullable() {
295 if (TypeUtils.noExpectedType(expectedType)) return this;
296 return new CheckTypeContext(trace, TypeUtils.makeNullable(expectedType));
297 }
298 }
299
300 final KtVisitor<Boolean, CheckTypeContext> checkTypeVisitor = new KtVisitor<Boolean, CheckTypeContext>() {
301
302 private boolean checkExpressionType(@NotNull KtExpression expression, CheckTypeContext c) {
303 KotlinTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
304 if (typeInfo == null) return false;
305
306 Ref<Boolean> hasError = Ref.create();
307 dataFlowAnalyzer.checkType(
308 typeInfo.getType(),
309 expression,
310 context
311 .replaceExpectedType(c.expectedType)
312 .replaceDataFlowInfo(typeInfo.getDataFlowInfo())
313 .replaceBindingTrace(c.trace),
314 hasError
315 );
316 return hasError.get();
317 }
318
319 private boolean checkExpressionTypeRecursively(@Nullable KtExpression expression, CheckTypeContext c) {
320 if (expression == null) return false;
321 return expression.accept(this, c);
322 }
323
324 private boolean checkSubExpressions(
325 KtExpression firstSub, KtExpression secondSub, KtExpression expression,
326 CheckTypeContext firstContext, CheckTypeContext secondContext, CheckTypeContext context
327 ) {
328 boolean errorWasReported = checkExpressionTypeRecursively(firstSub, firstContext);
329 errorWasReported |= checkExpressionTypeRecursively(secondSub, secondContext);
330 return errorWasReported || checkExpressionType(expression, context);
331 }
332
333 @Override
334 public Boolean visitIfExpression(@NotNull KtIfExpression ifExpression, CheckTypeContext c) {
335 KtExpression thenBranch = ifExpression.getThen();
336 KtExpression elseBranch = ifExpression.getElse();
337 if (thenBranch == null || elseBranch == null) {
338 return checkExpressionType(ifExpression, c);
339 }
340 return checkSubExpressions(thenBranch, elseBranch, ifExpression, c, c, c);
341 }
342
343 @Override
344 public Boolean visitBlockExpression(@NotNull KtBlockExpression expression, CheckTypeContext c) {
345 if (expression.getStatements().isEmpty()) {
346 return checkExpressionType(expression, c);
347 }
348 KtExpression lastStatement = KtPsiUtil.getLastStatementInABlock(expression);
349 if (lastStatement != null) {
350 return checkExpressionTypeRecursively(lastStatement, c);
351 }
352 return false;
353 }
354
355 @Override
356 public Boolean visitPostfixExpression(@NotNull KtPostfixExpression expression, CheckTypeContext c) {
357 if (expression.getOperationReference().getReferencedNameElementType() == KtTokens.EXCLEXCL) {
358 return checkExpressionTypeRecursively(expression.getBaseExpression(), c.makeTypeNullable());
359 }
360 return super.visitPostfixExpression(expression, c);
361 }
362
363 @Override
364 public Boolean visitBinaryExpression(@NotNull KtBinaryExpression expression, CheckTypeContext c) {
365 if (expression.getOperationReference().getReferencedNameElementType() == KtTokens.ELVIS) {
366
367 return checkSubExpressions(expression.getLeft(), expression.getRight(), expression, c.makeTypeNullable(), c, c);
368 }
369 return super.visitBinaryExpression(expression, c);
370 }
371
372 @Override
373 public Boolean visitExpression(@NotNull KtExpression expression, CheckTypeContext c) {
374 return checkExpressionType(expression, c);
375 }
376 };
377
378 return new ThrowingOnErrorTracingStrategy("resolve " + constructionName + " as a call") {
379 @Override
380 public <D extends CallableDescriptor> void bindReference(
381 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
382 ) {
383 //do nothing
384 }
385
386 @Override
387 public void bindCall(@NotNull BindingTrace trace, @NotNull Call call) {
388 trace.record(CALL, call.getCalleeExpression(), call);
389 }
390
391 @Override
392 public <D extends CallableDescriptor> void bindResolvedCall(
393 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
394 ) {
395 trace.record(RESOLVED_CALL, call, resolvedCall);
396 }
397
398 @Override
399 public void typeInferenceFailed(
400 @NotNull BindingTrace trace, @NotNull InferenceErrorData data
401 ) {
402 ConstraintSystem constraintSystem = data.constraintSystem;
403 ConstraintSystemStatus status = constraintSystem.getStatus();
404 assert !status.isSuccessful() : "Report error only for not successful constraint system";
405
406 if (status.hasErrorInConstrainingTypes() || status.hasUnknownParameters()) {
407 return;
408 }
409 KtExpression expression = (KtExpression) call.getCallElement();
410 if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION) || status.hasConflictingConstraints()
411 || status.hasTypeInferenceIncorporationError()) { // todo after KT-... remove this line
412 expression.accept(checkTypeVisitor, new CheckTypeContext(trace, data.expectedType));
413 return;
414 }
415 KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtNamedDeclaration.class);
416 logError("Expression: " + (parentDeclaration != null ? parentDeclaration.getText() : expression.getText()) +
417 "\nConstraint system status: \n" + ConstraintsUtil.getDebugMessageForStatus(status));
418 }
419 };
420 }
421
422 private abstract static class ThrowingOnErrorTracingStrategy implements TracingStrategy {
423 private final String debugName;
424
425 protected ThrowingOnErrorTracingStrategy(String debugName) {
426 this.debugName = debugName;
427 }
428
429 private void logError() {
430 logError(null);
431 }
432
433 protected void logError(@Nullable String additionalInformation) {
434 String errorMessage = "Resolution error of this type shouldn't occur for " + debugName;
435 if (additionalInformation != null) {
436 errorMessage += ".\n" + additionalInformation;
437 }
438 LOG.error(errorMessage);
439 }
440
441 @Override
442 public void unresolvedReference(@NotNull BindingTrace trace) {
443 logError();
444 }
445
446 @Override
447 public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(
448 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> candidates
449 ) {
450 logError();
451 }
452
453 @Override
454 public <D extends CallableDescriptor> void recordAmbiguity(
455 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> candidates
456 ) {
457 logError();
458 }
459
460 @Override
461 public void missingReceiver(
462 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver
463 ) {
464 logError();
465 }
466
467 @Override
468 public void wrongReceiverType(
469 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument
470 ) {
471 logError();
472 }
473
474 @Override
475 public void noReceiverAllowed(@NotNull BindingTrace trace) {
476 logError();
477 }
478
479 @Override
480 public void noValueForParameter(
481 @NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter
482 ) {
483 logError();
484 }
485
486 @Override
487 public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {
488 logError();
489 }
490
491 @Override
492 public <D extends CallableDescriptor> void ambiguity(
493 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
494 ) {
495 logError();
496 }
497
498 @Override
499 public <D extends CallableDescriptor> void noneApplicable(
500 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
501 ) {
502 logError();
503 }
504
505 @Override
506 public <D extends CallableDescriptor> void cannotCompleteResolve(
507 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
508 ) {
509 logError();
510 }
511
512 @Override
513 public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {
514 logError();
515 }
516
517 @Override
518 public void abstractSuperCall(@NotNull BindingTrace trace) {
519 logError();
520 }
521
522 @Override
523 public void nestedClassAccessViaInstanceReference(
524 @NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor,
525 @NotNull ExplicitReceiverKind explicitReceiverKind
526 ) {
527 logError();
528 }
529
530 @Override
531 public void unsafeCall(
532 @NotNull BindingTrace trace, @NotNull KotlinType type, boolean isCallForImplicitInvoke
533 ) {
534 logError();
535 }
536
537 @Override
538 public void invisibleMember(
539 @NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor
540 ) {
541 logError();
542 }
543
544 @Override
545 public void typeInferenceFailed(
546 @NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData
547 ) {
548 logError();
549 }
550
551 @Override
552 public void nonExtensionFunctionCalledAsExtension(@NotNull BindingTrace trace) {
553 logError();
554 }
555 }
556 }