001    /*
002     * Copyright 2010-2017 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 kotlin.Pair;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.builtins.FunctionTypesKt;
023    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
024    import org.jetbrains.kotlin.builtins.ReflectionTypes;
025    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
026    import org.jetbrains.kotlin.diagnostics.Errors;
027    import org.jetbrains.kotlin.name.Name;
028    import org.jetbrains.kotlin.name.SpecialNames;
029    import org.jetbrains.kotlin.psi.*;
030    import org.jetbrains.kotlin.resolve.BindingTrace;
031    import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
032    import org.jetbrains.kotlin.resolve.TypeResolver;
033    import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode;
034    import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext;
035    import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
036    import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
037    import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImplKt;
038    import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
039    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
040    import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
041    import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
042    import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
043    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
044    import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
045    import org.jetbrains.kotlin.types.FunctionPlaceholders;
046    import org.jetbrains.kotlin.types.FunctionPlaceholdersKt;
047    import org.jetbrains.kotlin.types.KotlinType;
048    import org.jetbrains.kotlin.types.TypeUtils;
049    import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
050    import org.jetbrains.kotlin.types.expressions.*;
051    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
052    
053    import javax.inject.Inject;
054    import java.util.ArrayList;
055    import java.util.Collections;
056    import java.util.List;
057    
058    import static org.jetbrains.kotlin.psi.KtPsiUtil.getLastElementDeparenthesized;
059    import static org.jetbrains.kotlin.resolve.BindingContextUtils.getRecordedTypeInfo;
060    import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
061    import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
062    import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.DEPENDENT;
063    import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
064    import static org.jetbrains.kotlin.types.TypeUtils.DONT_CARE;
065    import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
066    
067    public class ArgumentTypeResolver {
068        @NotNull private final TypeResolver typeResolver;
069        @NotNull private final DoubleColonExpressionResolver doubleColonExpressionResolver;
070        @NotNull private final KotlinBuiltIns builtIns;
071        @NotNull private final ReflectionTypes reflectionTypes;
072        @NotNull private final ConstantExpressionEvaluator constantExpressionEvaluator;
073        @NotNull private final FunctionPlaceholders functionPlaceholders;
074    
075        private ExpressionTypingServices expressionTypingServices;
076    
077        public ArgumentTypeResolver(
078                @NotNull TypeResolver typeResolver,
079                @NotNull DoubleColonExpressionResolver doubleColonExpressionResolver,
080                @NotNull KotlinBuiltIns builtIns,
081                @NotNull ReflectionTypes reflectionTypes,
082                @NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
083                @NotNull FunctionPlaceholders functionPlaceholders
084        ) {
085            this.typeResolver = typeResolver;
086            this.doubleColonExpressionResolver = doubleColonExpressionResolver;
087            this.builtIns = builtIns;
088            this.reflectionTypes = reflectionTypes;
089            this.constantExpressionEvaluator = constantExpressionEvaluator;
090            this.functionPlaceholders = functionPlaceholders;
091        }
092    
093        // component dependency cycle
094        @Inject
095        public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
096            this.expressionTypingServices = expressionTypingServices;
097        }
098    
099        public static boolean isSubtypeOfForArgumentType(
100                @NotNull KotlinType actualType,
101                @NotNull KotlinType expectedType
102        ) {
103            if (FunctionPlaceholdersKt.isFunctionPlaceholder(actualType)) {
104                KotlinType functionType = ConstraintSystemBuilderImplKt.createTypeForFunctionPlaceholder(actualType, expectedType);
105                return KotlinTypeChecker.DEFAULT.isSubtypeOf(functionType, expectedType);
106            }
107            return KotlinTypeChecker.DEFAULT.isSubtypeOf(actualType, expectedType);
108        }
109    
110        public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context) {
111            checkTypesWithNoCallee(context, SHAPE_FUNCTION_ARGUMENTS);
112        }
113    
114        public void checkTypesWithNoCallee(
115                @NotNull CallResolutionContext<?> context,
116                @NotNull ResolveArgumentsMode resolveFunctionArgumentBodies
117        ) {
118            if (context.checkArguments != CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) return;
119    
120            for (ValueArgument valueArgument : context.call.getValueArguments()) {
121                KtExpression argumentExpression = valueArgument.getArgumentExpression();
122                if (argumentExpression != null && !(argumentExpression instanceof KtLambdaExpression)) {
123                    checkArgumentTypeWithNoCallee(context, argumentExpression);
124                }
125            }
126    
127            if (resolveFunctionArgumentBodies == RESOLVE_FUNCTION_ARGUMENTS) {
128                checkTypesForFunctionArgumentsWithNoCallee(context);
129            }
130    
131            for (KtTypeProjection typeProjection : context.call.getTypeArguments()) {
132                KtTypeReference typeReference = typeProjection.getTypeReference();
133                if (typeReference == null) {
134                    context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeProjection));
135                }
136                else {
137                    typeResolver.resolveType(context.scope, typeReference, context.trace, true);
138                }
139            }
140        }
141    
142        public void checkTypesForFunctionArgumentsWithNoCallee(@NotNull CallResolutionContext<?> context) {
143            if (context.checkArguments != CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) return;
144    
145            for (ValueArgument valueArgument : context.call.getValueArguments()) {
146                KtExpression argumentExpression = valueArgument.getArgumentExpression();
147                if (argumentExpression != null && isFunctionLiteralArgument(argumentExpression, context)) {
148                    checkArgumentTypeWithNoCallee(context, argumentExpression);
149                }
150            }
151        }
152    
153        private void checkArgumentTypeWithNoCallee(CallResolutionContext<?> context, KtExpression argumentExpression) {
154            expressionTypingServices.getTypeInfo(argumentExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
155            updateResultArgumentTypeIfNotDenotable(context, argumentExpression);
156        }
157    
158        public static boolean isFunctionLiteralArgument(
159                @NotNull KtExpression expression, @NotNull ResolutionContext context
160        ) {
161            return getFunctionLiteralArgumentIfAny(expression, context) != null;
162        }
163    
164        @NotNull
165        public static KtFunction getFunctionLiteralArgument(
166                @NotNull KtExpression expression, @NotNull ResolutionContext context
167        ) {
168            assert isFunctionLiteralArgument(expression, context);
169            //noinspection ConstantConditions
170            return getFunctionLiteralArgumentIfAny(expression, context);
171        }
172    
173        @Nullable
174        public static KtFunction getFunctionLiteralArgumentIfAny(
175                @NotNull KtExpression expression, @NotNull ResolutionContext context
176        ) {
177            KtExpression deparenthesizedExpression = getLastElementDeparenthesized(expression, context.statementFilter);
178            if (deparenthesizedExpression instanceof KtLambdaExpression) {
179                return ((KtLambdaExpression) deparenthesizedExpression).getFunctionLiteral();
180            }
181            if (deparenthesizedExpression instanceof KtFunction) {
182                return (KtFunction) deparenthesizedExpression;
183            }
184            return null;
185        }
186    
187        @Nullable
188        public static KtCallableReferenceExpression getCallableReferenceExpressionIfAny(
189                @NotNull KtExpression expression,
190                @NotNull CallResolutionContext<?> context
191        ) {
192            KtExpression deparenthesizedExpression = getLastElementDeparenthesized(expression, context.statementFilter);
193            if (deparenthesizedExpression instanceof KtCallableReferenceExpression) {
194                return (KtCallableReferenceExpression) deparenthesizedExpression;
195            }
196            return null;
197        }
198    
199        @NotNull
200        public KotlinTypeInfo getArgumentTypeInfo(
201                @Nullable KtExpression expression,
202                @NotNull CallResolutionContext<?> context,
203                @NotNull ResolveArgumentsMode resolveArgumentsMode
204        ) {
205            if (expression == null) {
206                return TypeInfoFactoryKt.noTypeInfo(context);
207            }
208    
209            KtFunction functionLiteralArgument = getFunctionLiteralArgumentIfAny(expression, context);
210            if (functionLiteralArgument != null) {
211                return getFunctionLiteralTypeInfo(expression, functionLiteralArgument, context, resolveArgumentsMode);
212            }
213    
214            KtCallableReferenceExpression callableReferenceExpression = getCallableReferenceExpressionIfAny(expression, context);
215            if (callableReferenceExpression != null) {
216                return getCallableReferenceTypeInfo(expression, callableReferenceExpression, context, resolveArgumentsMode);
217            }
218    
219            KotlinTypeInfo recordedTypeInfo = getRecordedTypeInfo(expression, context.trace.getBindingContext());
220            if (recordedTypeInfo != null) {
221                return recordedTypeInfo;
222            }
223    
224            ResolutionContext newContext = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(DEPENDENT);
225    
226            return expressionTypingServices.getTypeInfo(expression, newContext);
227        }
228    
229        @NotNull
230        public KotlinTypeInfo getCallableReferenceTypeInfo(
231                @NotNull KtExpression expression,
232                @NotNull KtCallableReferenceExpression callableReferenceExpression,
233                @NotNull CallResolutionContext<?> context,
234                @NotNull ResolveArgumentsMode resolveArgumentsMode
235        ) {
236            if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) {
237                KotlinType type = getShapeTypeOfCallableReference(callableReferenceExpression, context, true);
238                return TypeInfoFactoryKt.createTypeInfo(type);
239            }
240            return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT));
241        }
242    
243        @Nullable
244        public KotlinType getShapeTypeOfCallableReference(
245                @NotNull KtCallableReferenceExpression callableReferenceExpression,
246                @NotNull CallResolutionContext<?> context,
247                boolean expectedTypeIsUnknown
248        ) {
249            Pair<DoubleColonLHS, OverloadResolutionResults<?>> pair =
250                    doubleColonExpressionResolver.resolveCallableReference(
251                            callableReferenceExpression,
252                            ExpressionTypingContext.newContext(context),
253                            SHAPE_FUNCTION_ARGUMENTS
254                    );
255            DoubleColonLHS lhs = pair.getFirst();
256            OverloadResolutionResults<?> overloadResolutionResults = pair.getSecond();
257    
258            if (overloadResolutionResults == null) return null;
259    
260            if (overloadResolutionResults.isSingleResult()) {
261                ResolvedCall<?> resolvedCall =
262                        OverloadResolutionResultsUtil.getResultingCall(overloadResolutionResults, context.contextDependency);
263                if (resolvedCall == null) return null;
264    
265                return DoubleColonExpressionResolver.Companion.createKCallableTypeForReference(
266                        resolvedCall.getResultingDescriptor(), lhs, reflectionTypes, context.scope.getOwnerDescriptor()
267                );
268            }
269    
270            if (expectedTypeIsUnknown) {
271                return functionPlaceholders.createFunctionPlaceholderType(Collections.<KotlinType>emptyList(), false);
272            }
273    
274            return FunctionTypesKt.createFunctionType(
275                    builtIns, Annotations.Companion.getEMPTY(), null, Collections.<KotlinType>emptyList(), null, TypeUtils.DONT_CARE
276            );
277        }
278    
279        @NotNull
280        public KotlinTypeInfo getFunctionLiteralTypeInfo(
281                @NotNull KtExpression expression,
282                @NotNull KtFunction functionLiteral,
283                @NotNull CallResolutionContext<?> context,
284                @NotNull ResolveArgumentsMode resolveArgumentsMode
285        ) {
286            if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) {
287                KotlinType type = getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, true);
288                return TypeInfoFactoryKt.createTypeInfo(type, context);
289            }
290            return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT));
291        }
292    
293        @Nullable
294        public KotlinType getShapeTypeOfFunctionLiteral(
295                @NotNull KtFunction function,
296                @NotNull LexicalScope scope,
297                @NotNull BindingTrace trace,
298                boolean expectedTypeIsUnknown
299        ) {
300            boolean isFunctionLiteral = function instanceof KtFunctionLiteral;
301            if (function.getValueParameterList() == null && isFunctionLiteral) {
302                return expectedTypeIsUnknown
303                       ? functionPlaceholders
304                               .createFunctionPlaceholderType(Collections.<KotlinType>emptyList(), /* hasDeclaredArguments = */ false)
305                       : FunctionTypesKt.createFunctionType(
306                               builtIns, Annotations.Companion.getEMPTY(), null, Collections.<KotlinType>emptyList(), null, DONT_CARE
307                       );
308            }
309            List<KtParameter> valueParameters = function.getValueParameters();
310            TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
311                    trace, "trace to resolve function literal parameter types");
312            List<KotlinType> parameterTypes = new ArrayList<KotlinType>(valueParameters.size());
313            List<Name> parameterNames = new ArrayList<Name>(valueParameters.size());
314            for (KtParameter parameter : valueParameters) {
315                parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace, DONT_CARE));
316                Name name = parameter.getNameAsName();
317                if (name == null) {
318                    name = SpecialNames.NO_NAME_PROVIDED;
319                }
320                parameterNames.add(name);
321            }
322            KotlinType returnType = resolveTypeRefWithDefault(function.getTypeReference(), scope, temporaryTrace, DONT_CARE);
323            assert returnType != null;
324            KotlinType receiverType = resolveTypeRefWithDefault(function.getReceiverTypeReference(), scope, temporaryTrace, null);
325    
326            return expectedTypeIsUnknown && isFunctionLiteral
327                   ? functionPlaceholders.createFunctionPlaceholderType(parameterTypes, /* hasDeclaredArguments = */ true)
328                   : FunctionTypesKt.createFunctionType(
329                           builtIns, Annotations.Companion.getEMPTY(), receiverType, parameterTypes, parameterNames, returnType
330                   );
331        }
332    
333        @Nullable
334        public KotlinType resolveTypeRefWithDefault(
335                @Nullable KtTypeReference returnTypeRef,
336                @NotNull LexicalScope scope,
337                @NotNull BindingTrace trace,
338                @Nullable KotlinType defaultValue
339        ) {
340            if (returnTypeRef != null) {
341                return typeResolver.resolveType(scope, returnTypeRef, trace, true);
342            }
343            return defaultValue;
344        }
345    
346        /**
347         * Visits function call arguments and determines data flow information changes
348         */
349        public void analyzeArgumentsAndRecordTypes(
350                @NotNull CallResolutionContext<?> context, @NotNull ResolveArgumentsMode resolveArgumentsMode
351        ) {
352            MutableDataFlowInfoForArguments infoForArguments = context.dataFlowInfoForArguments;
353            Call call = context.call;
354    
355            for (ValueArgument argument : call.getValueArguments()) {
356                KtExpression expression = argument.getArgumentExpression();
357                if (expression == null) continue;
358    
359                CallResolutionContext<?> newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument));
360                // Here we go inside arguments and determine additional data flow information for them
361                KotlinTypeInfo typeInfoForCall = getArgumentTypeInfo(expression, newContext, resolveArgumentsMode);
362                infoForArguments.updateInfo(argument, typeInfoForCall.getDataFlowInfo());
363            }
364        }
365    
366        @Nullable
367        public KotlinType updateResultArgumentTypeIfNotDenotable(
368                @NotNull ResolutionContext context,
369                @NotNull KtExpression expression
370        ) {
371            KotlinType type = context.trace.getType(expression);
372            if (type != null && !type.getConstructor().isDenotable()) {
373                if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
374                    IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor();
375                    KotlinType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
376                    constantExpressionEvaluator.updateNumberType(primitiveType, expression, context.statementFilter, context.trace);
377                    return primitiveType;
378                }
379            }
380            return null;
381        }
382    }