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                @Nullable
218                @Override
219                public ReceiverValue getExplicitReceiver() {
220                    return null;
221                }
222    
223                @Nullable
224                @Override
225                public ReceiverValue getDispatchReceiver() {
226                    return null;
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<LambdaArgument> 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    }