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