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
045 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getRecordedTypeInfo;
046 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode;
047 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
048 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
049 import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.DEPENDENT;
050 import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
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.DEFAULT.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 && isFunctionLiteralArgument(argumentExpression)) {
119 checkArgumentTypeWithNoCallee(context, argumentExpression);
120 }
121 }
122 }
123
124 private void checkArgumentTypeWithNoCallee(CallResolutionContext<?> context, JetExpression argumentExpression) {
125 expressionTypingServices.getTypeInfo(argumentExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
126 updateResultArgumentTypeIfNotDenotable(context, argumentExpression);
127 }
128
129 public static boolean isFunctionLiteralArgument(@NotNull JetExpression expression) {
130 return getFunctionLiteralArgumentIfAny(expression) != null;
131 }
132
133 @NotNull
134 public static JetFunctionLiteralExpression getFunctionLiteralArgument(@NotNull JetExpression expression) {
135 assert isFunctionLiteralArgument(expression);
136 //noinspection ConstantConditions
137 return getFunctionLiteralArgumentIfAny(expression);
138 }
139
140 @Nullable
141 private static JetFunctionLiteralExpression getFunctionLiteralArgumentIfAny(@NotNull JetExpression expression) {
142 JetExpression deparenthesizedExpression = JetPsiUtil.deparenthesize(expression, false);
143 if (deparenthesizedExpression instanceof JetBlockExpression) {
144 // todo
145 // This case is a temporary hack for 'if' branches.
146 // The right way to implement this logic is to interpret 'if' branches as function literals with explicitly-typed signatures
147 // (no arguments and no receiver) and therefore analyze them straight away (not in the 'complete' phase).
148 JetElement lastStatementInABlock = JetPsiUtil.getLastStatementInABlock((JetBlockExpression) deparenthesizedExpression);
149 if (lastStatementInABlock instanceof JetExpression) {
150 deparenthesizedExpression = JetPsiUtil.deparenthesize((JetExpression) lastStatementInABlock, false);
151 }
152 }
153 if (deparenthesizedExpression instanceof JetFunctionLiteralExpression) {
154 return (JetFunctionLiteralExpression) deparenthesizedExpression;
155 }
156 return null;
157 }
158
159 @NotNull
160 public JetTypeInfo getArgumentTypeInfo(
161 @Nullable JetExpression expression,
162 @NotNull CallResolutionContext<?> context,
163 @NotNull ResolveArgumentsMode resolveArgumentsMode
164 ) {
165 if (expression == null) {
166 return JetTypeInfo.create(null, context.dataFlowInfo);
167 }
168 if (isFunctionLiteralArgument(expression)) {
169 return getFunctionLiteralTypeInfo(expression, getFunctionLiteralArgument(expression), context, resolveArgumentsMode);
170 }
171 JetTypeInfo recordedTypeInfo = getRecordedTypeInfo(expression, context.trace.getBindingContext());
172 if (recordedTypeInfo != null) {
173 return recordedTypeInfo;
174 }
175 ResolutionContext newContext = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(DEPENDENT);
176
177 return expressionTypingServices.getTypeInfo(expression, newContext);
178 }
179
180 @NotNull
181 public JetTypeInfo getFunctionLiteralTypeInfo(
182 @NotNull JetExpression expression,
183 @NotNull JetFunctionLiteralExpression functionLiteralExpression,
184 @NotNull CallResolutionContext<?> context,
185 @NotNull ResolveArgumentsMode resolveArgumentsMode
186 ) {
187 if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) {
188 JetType type = getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, true);
189 return JetTypeInfo.create(type, context.dataFlowInfo);
190 }
191 return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT));
192 }
193
194 @Nullable
195 public JetType getShapeTypeOfFunctionLiteral(
196 @NotNull JetFunctionLiteralExpression expression,
197 @NotNull JetScope scope,
198 @NotNull BindingTrace trace,
199 boolean expectedTypeIsUnknown
200 ) {
201 if (expression.getFunctionLiteral().getValueParameterList() == null) {
202 return expectedTypeIsUnknown ? PLACEHOLDER_FUNCTION_TYPE : KotlinBuiltIns.getInstance().getFunctionType(
203 Annotations.EMPTY, null, Collections.<JetType>emptyList(), DONT_CARE);
204 }
205 List<JetParameter> valueParameters = expression.getValueParameters();
206 TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
207 trace, "trace to resolve function literal parameter types");
208 List<JetType> parameterTypes = Lists.newArrayList();
209 for (JetParameter parameter : valueParameters) {
210 parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace, DONT_CARE));
211 }
212 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
213 JetType returnType = resolveTypeRefWithDefault(functionLiteral.getTypeReference(), scope, temporaryTrace, DONT_CARE);
214 assert returnType != null;
215 JetType receiverType = resolveTypeRefWithDefault(functionLiteral.getReceiverTypeReference(), scope, temporaryTrace, null);
216 return KotlinBuiltIns.getInstance().getFunctionType(Annotations.EMPTY, receiverType, parameterTypes,
217 returnType);
218 }
219
220 @Nullable
221 public JetType resolveTypeRefWithDefault(
222 @Nullable JetTypeReference returnTypeRef,
223 @NotNull JetScope scope,
224 @NotNull BindingTrace trace,
225 @Nullable JetType defaultValue
226 ) {
227 if (returnTypeRef != null) {
228 return expressionTypingServices.getTypeResolver().resolveType(scope, returnTypeRef, trace, true);
229 }
230 return defaultValue;
231 }
232
233 public <D extends CallableDescriptor> void analyzeArgumentsAndRecordTypes(
234 @NotNull CallResolutionContext<?> context
235 ) {
236 MutableDataFlowInfoForArguments infoForArguments = context.dataFlowInfoForArguments;
237 infoForArguments.setInitialDataFlowInfo(context.dataFlowInfo);
238
239 for (ValueArgument argument : context.call.getValueArguments()) {
240 JetExpression expression = argument.getArgumentExpression();
241 if (expression == null) continue;
242
243 CallResolutionContext<?> newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument));
244 JetTypeInfo typeInfoForCall = getArgumentTypeInfo(expression, newContext, SHAPE_FUNCTION_ARGUMENTS);
245 infoForArguments.updateInfo(argument, typeInfoForCall.getDataFlowInfo());
246 }
247 }
248
249 @Nullable
250 public static JetType updateResultArgumentTypeIfNotDenotable(
251 @NotNull ResolutionContext context,
252 @NotNull JetExpression expression
253 ) {
254 JetType type = context.trace.get(BindingContext.EXPRESSION_TYPE, expression);
255 if (type != null && !type.getConstructor().isDenotable()) {
256 if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
257 IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor();
258 JetType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
259 updateNumberType(primitiveType, expression, context.trace);
260 return primitiveType;
261 }
262 }
263 return type;
264 }
265
266 public static <D extends CallableDescriptor> void updateNumberType(
267 @NotNull JetType numberType,
268 @Nullable JetExpression expression,
269 @NotNull BindingTrace trace
270 ) {
271 if (expression == null) return;
272 BindingContextUtils.updateRecordedType(numberType, expression, trace, false);
273
274 if (!(expression instanceof JetConstantExpression)) {
275 JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression, false);
276 if (deparenthesized != expression) {
277 updateNumberType(numberType, deparenthesized, trace);
278 }
279 if (deparenthesized instanceof JetBlockExpression) {
280 JetElement lastStatement = JetPsiUtil.getLastStatementInABlock((JetBlockExpression) deparenthesized);
281 if (lastStatement instanceof JetExpression) {
282 updateNumberType(numberType, (JetExpression) lastStatement, trace);
283 }
284 }
285 return;
286 }
287
288 ConstantExpressionEvaluator.OBJECT$.evaluate(expression, trace, numberType);
289 }
290 }