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