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