001    /*
002     * Copyright 2010-2015 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.kotlin.resolve.calls;
018    
019    import com.google.common.collect.Lists;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
023    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
024    import org.jetbrains.kotlin.diagnostics.Errors;
025    import org.jetbrains.kotlin.psi.*;
026    import org.jetbrains.kotlin.resolve.*;
027    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
028    import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext;
029    import org.jetbrains.kotlin.resolve.calls.context.CheckValueArgumentsMode;
030    import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
031    import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
032    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
033    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
034    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
035    import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
036    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
037    import org.jetbrains.kotlin.resolve.scopes.JetScope;
038    import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver;
039    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
040    import org.jetbrains.kotlin.types.ErrorUtils;
041    import org.jetbrains.kotlin.types.JetType;
042    import org.jetbrains.kotlin.types.TypeUtils;
043    import org.jetbrains.kotlin.types.checker.JetTypeChecker;
044    import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
045    import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
046    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
047    
048    import javax.inject.Inject;
049    import java.util.Collections;
050    import java.util.List;
051    
052    import static org.jetbrains.kotlin.resolve.BindingContextUtils.getRecordedTypeInfo;
053    import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode;
054    import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
055    import static org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
056    import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.DEPENDENT;
057    import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
058    import static org.jetbrains.kotlin.resolve.calls.inference.InferencePackage.createCorrespondingFunctionTypeForFunctionPlaceholder;
059    import static org.jetbrains.kotlin.types.TypeUtils.DONT_CARE;
060    import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
061    
062    public class ArgumentTypeResolver {
063    
064        private TypeResolver typeResolver;
065        private ExpressionTypingServices expressionTypingServices;
066        private KotlinBuiltIns builtIns;
067    
068        @Inject
069        public void setTypeResolver(@NotNull TypeResolver typeResolver) {
070            this.typeResolver = typeResolver;
071        }
072    
073        @Inject
074        public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
075            this.expressionTypingServices = expressionTypingServices;
076        }
077    
078        @Inject
079        public void setBuiltIns(@NotNull KotlinBuiltIns builtIns) {
080            this.builtIns = builtIns;
081        }
082    
083        public static boolean isSubtypeOfForArgumentType(
084                @NotNull JetType actualType,
085                @NotNull JetType expectedType
086        ) {
087            if (ErrorUtils.isFunctionPlaceholder(actualType)) {
088                JetType functionType = createCorrespondingFunctionTypeForFunctionPlaceholder(actualType, expectedType);
089                return JetTypeChecker.DEFAULT.isSubtypeOf(functionType, expectedType);
090            }
091            return JetTypeChecker.DEFAULT.isSubtypeOf(actualType, expectedType);
092        }
093    
094        public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context) {
095            checkTypesWithNoCallee(context, SHAPE_FUNCTION_ARGUMENTS);
096        }
097    
098        public void checkTypesWithNoCallee(
099                @NotNull CallResolutionContext<?> context,
100                @NotNull ResolveArgumentsMode resolveFunctionArgumentBodies
101        ) {
102            if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
103    
104            for (ValueArgument valueArgument : context.call.getValueArguments()) {
105                JetExpression argumentExpression = valueArgument.getArgumentExpression();
106                if (argumentExpression != null && !(argumentExpression instanceof JetFunctionLiteralExpression)) {
107                    checkArgumentTypeWithNoCallee(context, argumentExpression);
108                }
109            }
110    
111            if (resolveFunctionArgumentBodies == RESOLVE_FUNCTION_ARGUMENTS) {
112                checkTypesForFunctionArgumentsWithNoCallee(context);
113            }
114    
115            for (JetTypeProjection typeProjection : context.call.getTypeArguments()) {
116                JetTypeReference typeReference = typeProjection.getTypeReference();
117                if (typeReference == null) {
118                    context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeProjection));
119                }
120                else {
121                    typeResolver.resolveType(context.scope, typeReference, context.trace, true);
122                }
123            }
124        }
125    
126        public void checkTypesForFunctionArgumentsWithNoCallee(@NotNull CallResolutionContext<?> context) {
127            if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
128    
129            for (ValueArgument valueArgument : context.call.getValueArguments()) {
130                JetExpression argumentExpression = valueArgument.getArgumentExpression();
131                if (argumentExpression != null && isFunctionLiteralArgument(argumentExpression, context)) {
132                    checkArgumentTypeWithNoCallee(context, argumentExpression);
133                }
134            }
135        }
136    
137        private void checkArgumentTypeWithNoCallee(CallResolutionContext<?> context, JetExpression argumentExpression) {
138            expressionTypingServices.getTypeInfo(argumentExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
139            updateResultArgumentTypeIfNotDenotable(context, argumentExpression);
140        }
141    
142        public static boolean isFunctionLiteralArgument(
143                @NotNull JetExpression expression, @NotNull ResolutionContext context
144        ) {
145            return getFunctionLiteralArgumentIfAny(expression, context) != null;
146        }
147    
148        @NotNull
149        public static JetFunction getFunctionLiteralArgument(
150                @NotNull JetExpression expression, @NotNull ResolutionContext context
151        ) {
152            assert isFunctionLiteralArgument(expression, context);
153            //noinspection ConstantConditions
154            return getFunctionLiteralArgumentIfAny(expression, context);
155        }
156    
157        @Nullable
158        private static JetFunction getFunctionLiteralArgumentIfAny(
159                @NotNull JetExpression expression, @NotNull ResolutionContext context
160        ) {
161            JetExpression deparenthesizedExpression = getLastElementDeparenthesized(expression, context);
162            if (deparenthesizedExpression instanceof JetFunctionLiteralExpression) {
163                return ((JetFunctionLiteralExpression) deparenthesizedExpression).getFunctionLiteral();
164            }
165            if (deparenthesizedExpression instanceof JetFunction) {
166                return (JetFunction) deparenthesizedExpression;
167            }
168            return null;
169        }
170    
171        @Nullable
172        public static JetExpression getLastElementDeparenthesized(
173                @Nullable JetExpression expression,
174                @NotNull ResolutionContext context
175        ) {
176            JetExpression deparenthesizedExpression = JetPsiUtil.deparenthesize(expression, false);
177            if (deparenthesizedExpression instanceof JetBlockExpression) {
178                JetBlockExpression blockExpression = (JetBlockExpression) deparenthesizedExpression;
179                // todo
180                // This case is a temporary hack for 'if' branches.
181                // The right way to implement this logic is to interpret 'if' branches as function literals with explicitly-typed signatures
182                // (no arguments and no receiver) and therefore analyze them straight away (not in the 'complete' phase).
183                JetElement lastStatementInABlock = ResolvePackage.getLastStatementInABlock(context.statementFilter, blockExpression);
184                if (lastStatementInABlock instanceof JetExpression) {
185                    return getLastElementDeparenthesized((JetExpression) lastStatementInABlock, context);
186                }
187            }
188            return deparenthesizedExpression;
189        }
190    
191        @NotNull
192        public JetTypeInfo getArgumentTypeInfo(
193                @Nullable JetExpression expression,
194                @NotNull CallResolutionContext<?> context,
195                @NotNull ResolveArgumentsMode resolveArgumentsMode
196        ) {
197            if (expression == null) {
198                return TypeInfoFactoryPackage.noTypeInfo(context);
199            }
200            if (isFunctionLiteralArgument(expression, context)) {
201                return getFunctionLiteralTypeInfo(expression, getFunctionLiteralArgument(expression, context), context, resolveArgumentsMode);
202            }
203            JetTypeInfo recordedTypeInfo = getRecordedTypeInfo(expression, context.trace.getBindingContext());
204            if (recordedTypeInfo != null) {
205                return recordedTypeInfo;
206            }
207            ResolutionContext newContext = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(DEPENDENT);
208    
209            return expressionTypingServices.getTypeInfo(expression, newContext);
210        }
211    
212        @NotNull
213        public JetTypeInfo getFunctionLiteralTypeInfo(
214                @NotNull JetExpression expression,
215                @NotNull JetFunction functionLiteral,
216                @NotNull CallResolutionContext<?> context,
217                @NotNull ResolveArgumentsMode resolveArgumentsMode
218        ) {
219            if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) {
220                JetType type = getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, true);
221                return TypeInfoFactoryPackage.createTypeInfo(type, context);
222            }
223            return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT));
224        }
225    
226        @Nullable
227        public JetType getShapeTypeOfFunctionLiteral(
228                @NotNull JetFunction function,
229                @NotNull JetScope scope,
230                @NotNull BindingTrace trace,
231                boolean expectedTypeIsUnknown
232        ) {
233            boolean isFunctionLiteral = function instanceof JetFunctionLiteral;
234            if (function.getValueParameterList() == null && isFunctionLiteral) {
235                return expectedTypeIsUnknown
236                       ? ErrorUtils.createFunctionPlaceholderType(Collections.<JetType>emptyList(), /* hasDeclaredArguments = */ false)
237                       : builtIns.getFunctionType(Annotations.EMPTY, null, Collections.<JetType>emptyList(), DONT_CARE);
238            }
239            List<JetParameter> valueParameters = function.getValueParameters();
240            TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
241                    trace, "trace to resolve function literal parameter types");
242            List<JetType> parameterTypes = Lists.newArrayList();
243            for (JetParameter parameter : valueParameters) {
244                parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace, DONT_CARE));
245            }
246            JetType returnType = resolveTypeRefWithDefault(function.getTypeReference(), scope, temporaryTrace, DONT_CARE);
247            assert returnType != null;
248            JetType receiverType = resolveTypeRefWithDefault(function.getReceiverTypeReference(), scope, temporaryTrace, null);
249    
250            return expectedTypeIsUnknown && isFunctionLiteral
251                   ? ErrorUtils.createFunctionPlaceholderType(parameterTypes, /* hasDeclaredArguments = */ true)
252                   : builtIns.getFunctionType(Annotations.EMPTY, receiverType, parameterTypes, returnType);
253        }
254    
255        @Nullable
256        public JetType resolveTypeRefWithDefault(
257                @Nullable JetTypeReference returnTypeRef,
258                @NotNull JetScope scope,
259                @NotNull BindingTrace trace,
260                @Nullable JetType defaultValue
261        ) {
262            if (returnTypeRef != null) {
263                return typeResolver.resolveType(scope, returnTypeRef, trace, true);
264            }
265            return defaultValue;
266        }
267    
268        /**
269         * Visits function call arguments and determines data flow information changes
270         */
271        public void analyzeArgumentsAndRecordTypes(
272                @NotNull CallResolutionContext<?> context
273        ) {
274            MutableDataFlowInfoForArguments infoForArguments = context.dataFlowInfoForArguments;
275            Call call = context.call;
276            ReceiverValue receiver = call.getExplicitReceiver();
277            DataFlowInfo initialDataFlowInfo = context.dataFlowInfo;
278            // QualifierReceiver is a thing like Collections. which has no type or value
279            if (receiver.exists() && !(receiver instanceof QualifierReceiver)) {
280                DataFlowValue receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, context);
281                // Additional "receiver != null" information for KT-5840
282                // Should be applied if we consider a safe call
283                // For an unsafe call, we should not do it,
284                // otherwise not-null will propagate to successive statements
285                // Sample: x?.foo(x.bar()) // Inside foo call, x is not-nullable
286                if (CallUtilPackage.isSafeCall(call)) {
287                    initialDataFlowInfo = initialDataFlowInfo.disequate(receiverDataFlowValue, DataFlowValue.NULL);
288                }
289            }
290            infoForArguments.setInitialDataFlowInfo(initialDataFlowInfo);
291    
292            for (ValueArgument argument : call.getValueArguments()) {
293                JetExpression expression = argument.getArgumentExpression();
294                if (expression == null) continue;
295    
296                CallResolutionContext<?> newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument));
297                // Here we go inside arguments and determine additional data flow information for them
298                JetTypeInfo typeInfoForCall = getArgumentTypeInfo(expression, newContext, SHAPE_FUNCTION_ARGUMENTS);
299                infoForArguments.updateInfo(argument, typeInfoForCall.getDataFlowInfo());
300            }
301        }
302    
303        @Nullable
304        public static JetType updateResultArgumentTypeIfNotDenotable(
305                @NotNull ResolutionContext context,
306                @NotNull JetExpression expression
307        ) {
308            JetType type = context.trace.getType(expression);
309            if (type != null && !type.getConstructor().isDenotable()) {
310                if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
311                    IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor();
312                    JetType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
313                    updateNumberType(primitiveType, expression, context);
314                    return primitiveType;
315                }
316            }
317            return type;
318        }
319    
320        public static void updateNumberType(
321                @NotNull JetType numberType,
322                @Nullable JetExpression expression,
323                @NotNull ResolutionContext context
324        ) {
325            if (expression == null) return;
326            BindingContextUtils.updateRecordedType(numberType, expression, context.trace, false);
327    
328            if (!(expression instanceof JetConstantExpression)) {
329                JetExpression deparenthesized = getLastElementDeparenthesized(expression, context);
330                if (deparenthesized != expression) {
331                    updateNumberType(numberType, deparenthesized, context);
332                }
333                return;
334            }
335    
336            ConstantExpressionEvaluator.evaluate(expression, context.trace, numberType);
337        }
338    }