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