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