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