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