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