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 }