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.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.jet.lang.descriptors.CallableDescriptor;
023 import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
024 import org.jetbrains.jet.lang.diagnostics.Errors;
025 import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.resolve.*;
028 import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
029 import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
030 import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
031 import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
032 import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor;
033 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
034 import org.jetbrains.jet.lang.types.JetType;
035 import org.jetbrains.jet.lang.types.JetTypeInfo;
036 import org.jetbrains.jet.lang.types.TypeUtils;
037 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
038 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
039 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
040
041 import javax.inject.Inject;
042 import java.util.Collections;
043 import java.util.List;
044 import java.util.Set;
045
046 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getRecordedTypeInfo;
047 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode;
048 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
049 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
050 import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.DEPENDENT;
051 import static org.jetbrains.jet.lang.types.TypeUtils.*;
052
053 public class ArgumentTypeResolver {
054
055 @NotNull
056 private TypeResolver typeResolver;
057 @NotNull
058 private ExpressionTypingServices expressionTypingServices;
059
060 @Inject
061 public void setTypeResolver(@NotNull TypeResolver typeResolver) {
062 this.typeResolver = typeResolver;
063 }
064
065 @Inject
066 public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
067 this.expressionTypingServices = expressionTypingServices;
068 }
069
070 public static boolean isSubtypeOfForArgumentType(
071 @NotNull JetType actualType,
072 @NotNull JetType expectedType
073 ) {
074 if (actualType == PLACEHOLDER_FUNCTION_TYPE) {
075 return isFunctionOrErrorType(expectedType) || KotlinBuiltIns.getInstance().isAnyOrNullableAny(expectedType); //todo function type extends
076 }
077 return JetTypeChecker.INSTANCE.isSubtypeOf(actualType, expectedType);
078 }
079
080 private static boolean isFunctionOrErrorType(@NotNull JetType supertype) {
081 return KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(supertype) || supertype.isError();
082 }
083
084 public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context) {
085 checkTypesWithNoCallee(context, SHAPE_FUNCTION_ARGUMENTS);
086 }
087
088 public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context, @NotNull ResolveArgumentsMode resolveFunctionArgumentBodies) {
089 if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
090
091 for (ValueArgument valueArgument : context.call.getValueArguments()) {
092 JetExpression argumentExpression = valueArgument.getArgumentExpression();
093 if (argumentExpression != null && !(argumentExpression instanceof JetFunctionLiteralExpression)) {
094 checkArgumentTypeWithNoCallee(context, argumentExpression);
095 }
096 }
097
098 if (resolveFunctionArgumentBodies == RESOLVE_FUNCTION_ARGUMENTS) {
099 checkTypesForFunctionArgumentsWithNoCallee(context);
100 }
101
102 for (JetTypeProjection typeProjection : context.call.getTypeArguments()) {
103 JetTypeReference typeReference = typeProjection.getTypeReference();
104 if (typeReference == null) {
105 context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeProjection));
106 }
107 else {
108 typeResolver.resolveType(context.scope, typeReference, context.trace, true);
109 }
110 }
111 }
112
113 public void checkTypesForFunctionArgumentsWithNoCallee(@NotNull CallResolutionContext<?> context) {
114 if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
115
116 for (ValueArgument valueArgument : context.call.getValueArguments()) {
117 JetExpression argumentExpression = valueArgument.getArgumentExpression();
118 if (argumentExpression != null && (argumentExpression instanceof JetFunctionLiteralExpression)) {
119 checkArgumentTypeWithNoCallee(context, argumentExpression);
120 }
121 }
122
123 for (JetExpression expression : context.call.getFunctionLiteralArguments()) {
124 checkArgumentTypeWithNoCallee(context, expression);
125 }
126 }
127
128 public void checkUnmappedArgumentTypes(CallResolutionContext<?> context, Set<ValueArgument> unmappedArguments) {
129 for (ValueArgument valueArgument : unmappedArguments) {
130 JetExpression argumentExpression = valueArgument.getArgumentExpression();
131 if (argumentExpression != null) {
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(@NotNull JetExpression expression) {
143 return getFunctionLiteralArgumentIfAny(expression) != null;
144 }
145
146 @NotNull
147 public static JetFunctionLiteralExpression getFunctionLiteralArgument(@NotNull JetExpression expression) {
148 assert isFunctionLiteralArgument(expression);
149 //noinspection ConstantConditions
150 return getFunctionLiteralArgumentIfAny(expression);
151 }
152
153 @Nullable
154 private static JetFunctionLiteralExpression getFunctionLiteralArgumentIfAny(@NotNull JetExpression expression) {
155 JetExpression deparenthesizedExpression = JetPsiUtil.deparenthesize(expression, false);
156 if (deparenthesizedExpression instanceof JetBlockExpression) {
157 // todo
158 // This case is a temporary hack for 'if' branches.
159 // The right way to implement this logic is to interpret 'if' branches as function literals with explicitly-typed signatures
160 // (no arguments and no receiver) and therefore analyze them straight away (not in the 'complete' phase).
161 JetElement lastStatementInABlock = JetPsiUtil.getLastStatementInABlock((JetBlockExpression) deparenthesizedExpression);
162 if (lastStatementInABlock instanceof JetExpression) {
163 deparenthesizedExpression = JetPsiUtil.deparenthesize((JetExpression) lastStatementInABlock, false);
164 }
165 }
166 if (deparenthesizedExpression instanceof JetFunctionLiteralExpression) {
167 return (JetFunctionLiteralExpression) deparenthesizedExpression;
168 }
169 return null;
170 }
171
172 @NotNull
173 public JetTypeInfo getArgumentTypeInfo(
174 @Nullable JetExpression expression,
175 @NotNull CallResolutionContext<?> context,
176 @NotNull ResolveArgumentsMode resolveArgumentsMode
177 ) {
178 if (expression == null) {
179 return JetTypeInfo.create(null, context.dataFlowInfo);
180 }
181 if (isFunctionLiteralArgument(expression)) {
182 return getFunctionLiteralTypeInfo(expression, getFunctionLiteralArgument(expression), context, resolveArgumentsMode);
183 }
184 JetTypeInfo recordedTypeInfo = getRecordedTypeInfo(expression, context.trace.getBindingContext());
185 if (recordedTypeInfo != null) {
186 return recordedTypeInfo;
187 }
188 ResolutionContext newContext = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(DEPENDENT);
189
190 return expressionTypingServices.getTypeInfo(expression, newContext);
191 }
192
193 @NotNull
194 public JetTypeInfo getFunctionLiteralTypeInfo(
195 @NotNull JetExpression expression,
196 @NotNull JetFunctionLiteralExpression functionLiteralExpression,
197 @NotNull CallResolutionContext<?> context,
198 @NotNull ResolveArgumentsMode resolveArgumentsMode
199 ) {
200 if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) {
201 JetType type = getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, true);
202 return JetTypeInfo.create(type, context.dataFlowInfo);
203 }
204 return expressionTypingServices.getTypeInfo(expression, context);
205 }
206
207 @Nullable
208 public JetType getShapeTypeOfFunctionLiteral(
209 @NotNull JetFunctionLiteralExpression expression,
210 @NotNull JetScope scope,
211 @NotNull BindingTrace trace,
212 boolean expectedTypeIsUnknown
213 ) {
214 if (expression.getFunctionLiteral().getValueParameterList() == null) {
215 return expectedTypeIsUnknown ? PLACEHOLDER_FUNCTION_TYPE : KotlinBuiltIns.getInstance().getFunctionType(
216 Annotations.EMPTY, null, Collections.<JetType>emptyList(), DONT_CARE);
217 }
218 List<JetParameter> valueParameters = expression.getValueParameters();
219 TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
220 trace, "trace to resolve function literal parameter types");
221 List<JetType> parameterTypes = Lists.newArrayList();
222 for (JetParameter parameter : valueParameters) {
223 parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace, DONT_CARE));
224 }
225 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
226 JetType returnType = resolveTypeRefWithDefault(functionLiteral.getReturnTypeRef(), scope, temporaryTrace, DONT_CARE);
227 assert returnType != null;
228 JetType receiverType = resolveTypeRefWithDefault(functionLiteral.getReceiverTypeRef(), scope, temporaryTrace, null);
229 return KotlinBuiltIns.getInstance().getFunctionType(Annotations.EMPTY, receiverType, parameterTypes,
230 returnType);
231 }
232
233 @Nullable
234 public JetType resolveTypeRefWithDefault(
235 @Nullable JetTypeReference returnTypeRef,
236 @NotNull JetScope scope,
237 @NotNull BindingTrace trace,
238 @Nullable JetType defaultValue
239 ) {
240 if (returnTypeRef != null) {
241 return expressionTypingServices.getTypeResolver().resolveType(scope, returnTypeRef, trace, true);
242 }
243 return defaultValue;
244 }
245
246 public <D extends CallableDescriptor> void analyzeArgumentsAndRecordTypes(
247 @NotNull CallResolutionContext<?> context
248 ) {
249 MutableDataFlowInfoForArguments infoForArguments = context.dataFlowInfoForArguments;
250 infoForArguments.setInitialDataFlowInfo(context.dataFlowInfo);
251
252 for (ValueArgument argument : context.call.getValueArguments()) {
253 JetExpression expression = argument.getArgumentExpression();
254 if (expression == null) continue;
255
256 CallResolutionContext<?> newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument));
257 JetTypeInfo typeInfoForCall = getArgumentTypeInfo(expression, newContext, SHAPE_FUNCTION_ARGUMENTS);
258 infoForArguments.updateInfo(argument, typeInfoForCall.getDataFlowInfo());
259 }
260 }
261
262 @Nullable
263 public static <D extends CallableDescriptor> JetType updateResultArgumentTypeIfNotDenotable(
264 @NotNull ResolutionContext context,
265 @NotNull JetExpression expression
266 ) {
267 JetType type = context.trace.get(BindingContext.EXPRESSION_TYPE, expression);
268 if (type != null && !type.getConstructor().isDenotable()) {
269 if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
270 IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor();
271 JetType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
272 updateNumberType(primitiveType, expression, context.trace);
273 return primitiveType;
274 }
275 }
276 return type;
277 }
278
279 public static <D extends CallableDescriptor> void updateNumberType(
280 @NotNull JetType numberType,
281 @Nullable JetExpression expression,
282 @NotNull BindingTrace trace
283 ) {
284 if (expression == null) return;
285 BindingContextUtils.updateRecordedType(numberType, expression, trace, false);
286
287 if (!(expression instanceof JetConstantExpression)) {
288 JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression, false);
289 if (deparenthesized != expression) {
290 updateNumberType(numberType, deparenthesized, trace);
291 }
292 if (deparenthesized instanceof JetBlockExpression) {
293 JetElement lastStatement = JetPsiUtil.getLastStatementInABlock((JetBlockExpression) deparenthesized);
294 if (lastStatement instanceof JetExpression) {
295 updateNumberType(numberType, (JetExpression) lastStatement, trace);
296 }
297 }
298 return;
299 }
300
301 ConstantExpressionEvaluator.object$.evaluate(expression, trace, numberType);
302 }
303 }