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