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.ValueParameterDescriptor;
024 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025 import org.jetbrains.jet.lang.diagnostics.Errors;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.resolve.BindingTrace;
028 import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
029 import org.jetbrains.jet.lang.resolve.TypeResolver;
030 import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
031 import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
032 import org.jetbrains.jet.lang.resolve.calls.context.ResolveMode;
033 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
034 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
035 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
036 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
037 import org.jetbrains.jet.lang.types.ErrorUtils;
038 import org.jetbrains.jet.lang.types.JetType;
039 import org.jetbrains.jet.lang.types.JetTypeInfo;
040 import org.jetbrains.jet.lang.types.TypeUtils;
041 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
042 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
043 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
044
045 import javax.inject.Inject;
046 import java.util.Collections;
047 import java.util.List;
048 import java.util.Map;
049 import java.util.Set;
050
051 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getRecordedTypeInfo;
052 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.recordExpressionType;
053 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*;
054 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
055 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SKIP_FUNCTION_ARGUMENTS;
056 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
057
058 public class ArgumentTypeResolver {
059
060 @NotNull
061 private TypeResolver typeResolver;
062 @NotNull
063 private ExpressionTypingServices expressionTypingServices;
064
065 @Inject
066 public void setTypeResolver(@NotNull TypeResolver typeResolver) {
067 this.typeResolver = typeResolver;
068 }
069
070 @Inject
071 public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
072 this.expressionTypingServices = expressionTypingServices;
073 }
074
075 public static boolean isSubtypeOfForArgumentType(@NotNull JetType subtype, @NotNull JetType supertype) {
076 if (subtype == PLACEHOLDER_FUNCTION_TYPE) {
077 return isFunctionOrErrorType(supertype) || KotlinBuiltIns.getInstance().isAny(supertype); //todo function type extends
078 }
079 if (supertype == PLACEHOLDER_FUNCTION_TYPE) {
080 return isFunctionOrErrorType(subtype); //todo extends function type
081 }
082 return JetTypeChecker.INSTANCE.isSubtypeOf(subtype, supertype);
083 }
084
085 private static boolean isFunctionOrErrorType(@NotNull JetType supertype) {
086 return KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(supertype) || ErrorUtils.isErrorType(supertype);
087 }
088
089 public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context) {
090 checkTypesWithNoCallee(context, SKIP_FUNCTION_ARGUMENTS);
091 }
092
093 public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context, @NotNull ResolveArgumentsMode resolveFunctionArgumentBodies) {
094 if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
095
096 for (ValueArgument valueArgument : context.call.getValueArguments()) {
097 JetExpression argumentExpression = valueArgument.getArgumentExpression();
098 if (argumentExpression != null && !(argumentExpression instanceof JetFunctionLiteralExpression)) {
099 expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
100 }
101 }
102
103 if (resolveFunctionArgumentBodies == RESOLVE_FUNCTION_ARGUMENTS) {
104 checkTypesForFunctionArgumentsWithNoCallee(context);
105 }
106
107 for (JetTypeProjection typeProjection : context.call.getTypeArguments()) {
108 JetTypeReference typeReference = typeProjection.getTypeReference();
109 if (typeReference == null) {
110 context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeProjection));
111 }
112 else {
113 typeResolver.resolveType(context.scope, typeReference, context.trace, true);
114 }
115 }
116 }
117
118 public void checkTypesForFunctionArgumentsWithNoCallee(@NotNull CallResolutionContext<?> context) {
119 if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
120
121 for (ValueArgument valueArgument : context.call.getValueArguments()) {
122 JetExpression argumentExpression = valueArgument.getArgumentExpression();
123 if (argumentExpression != null && (argumentExpression instanceof JetFunctionLiteralExpression)) {
124 expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
125 }
126 }
127
128 for (JetExpression expression : context.call.getFunctionLiteralArguments()) {
129 expressionTypingServices.getType(context.scope, expression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
130 }
131 }
132
133 public void checkUnmappedArgumentTypes(CallResolutionContext<?> context, Set<ValueArgument> unmappedArguments) {
134 for (ValueArgument valueArgument : unmappedArguments) {
135 JetExpression argumentExpression = valueArgument.getArgumentExpression();
136 if (argumentExpression != null) {
137 expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
138 }
139 }
140 }
141
142 public <D extends CallableDescriptor> void checkTypesForFunctionArguments(CallResolutionContext<?> context, ResolvedCallImpl<D> resolvedCall) {
143 Map<ValueParameterDescriptor, ResolvedValueArgument> arguments = resolvedCall.getValueArguments();
144 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : arguments.entrySet()) {
145 ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
146 JetType varargElementType = valueParameterDescriptor.getVarargElementType();
147 JetType functionType;
148 if (varargElementType != null) {
149 functionType = varargElementType;
150 }
151 else {
152 functionType = valueParameterDescriptor.getType();
153 }
154 ResolvedValueArgument valueArgument = entry.getValue();
155 List<ValueArgument> valueArguments = valueArgument.getArguments();
156 for (ValueArgument argument : valueArguments) {
157 JetExpression expression = argument.getArgumentExpression();
158 if (expression instanceof JetFunctionLiteralExpression) {
159 expressionTypingServices.getType(context.scope, expression, functionType, context.dataFlowInfo, context.trace);
160 }
161 }
162 }
163 }
164
165 @NotNull
166 public JetTypeInfo getArgumentTypeInfo(
167 @Nullable JetExpression expression,
168 @NotNull CallResolutionContext<?> context,
169 @NotNull ResolveArgumentsMode resolveArgumentsMode,
170 @Nullable TemporaryBindingTrace traceToCommitForCall
171 ) {
172 if (expression == null) {
173 return JetTypeInfo.create(null, context.dataFlowInfo);
174 }
175 if (expression instanceof JetFunctionLiteralExpression) {
176 return getFunctionLiteralTypeInfo((JetFunctionLiteralExpression) expression, context, resolveArgumentsMode);
177 }
178 JetTypeInfo recordedTypeInfo = getRecordedTypeInfo(expression, context.trace.getBindingContext());
179 if (recordedTypeInfo != null) {
180 return recordedTypeInfo;
181 }
182 //todo deparenthesize
183 CallExpressionResolver callExpressionResolver = expressionTypingServices.getCallExpressionResolver();
184 if (!(expression instanceof JetCallExpression) && !(expression instanceof JetQualifiedExpression)) {
185 return expressionTypingServices.getTypeInfo(context.scope, expression, context.expectedType, context.dataFlowInfo, context.trace);
186 }
187
188 JetTypeInfo result;
189 if (expression instanceof JetCallExpression) {
190 result = callExpressionResolver.getCallExpressionTypeInfo(
191 (JetCallExpression) expression, ReceiverValue.NO_RECEIVER, null,
192 context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE), ResolveMode.NESTED_CALL, context.resolutionResultsCache);
193 }
194 else { // expression instanceof JetQualifiedExpression
195 result = callExpressionResolver.getQualifiedExpressionTypeInfo(
196 (JetQualifiedExpression) expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE),
197 ResolveMode.NESTED_CALL, context.resolutionResultsCache);
198 }
199
200 recordExpressionType(expression, context.trace, context.scope, result);
201 if (traceToCommitForCall != null) {
202 traceToCommitForCall.commit();
203 }
204 return result;
205 }
206
207 @NotNull
208 public JetTypeInfo getFunctionLiteralTypeInfo(
209 @NotNull JetFunctionLiteralExpression functionLiteralExpression,
210 @NotNull CallResolutionContext<?> context,
211 @NotNull ResolveArgumentsMode resolveArgumentsMode
212 ) {
213 if (resolveArgumentsMode == SKIP_FUNCTION_ARGUMENTS) {
214 JetType type = getFunctionLiteralType(functionLiteralExpression, context.scope, context.trace);
215 return JetTypeInfo.create(type, context.dataFlowInfo);
216 }
217 return expressionTypingServices.getTypeInfo(context.scope, functionLiteralExpression, context.expectedType, context.dataFlowInfo, context.trace);
218 }
219
220 @Nullable
221 private JetType getFunctionLiteralType(
222 @NotNull JetFunctionLiteralExpression expression,
223 @NotNull JetScope scope,
224 @NotNull BindingTrace trace
225 ) {
226 List<JetParameter> valueParameters = expression.getValueParameters();
227 if (valueParameters.isEmpty()) {
228 return PLACEHOLDER_FUNCTION_TYPE;
229 }
230 TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
231 trace, "trace to resolve function literal parameter types");
232 List<JetType> parameterTypes = Lists.newArrayList();
233 for (JetParameter parameter : valueParameters) {
234 parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace, DONT_CARE));
235 }
236 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
237 JetType returnType = resolveTypeRefWithDefault(functionLiteral.getReturnTypeRef(), scope, temporaryTrace, DONT_CARE);
238 assert returnType != null;
239 JetType receiverType = resolveTypeRefWithDefault(functionLiteral.getReceiverTypeRef(), scope, temporaryTrace, null);
240 return KotlinBuiltIns.getInstance().getFunctionType(Collections.<AnnotationDescriptor>emptyList(), receiverType, parameterTypes, returnType);
241 }
242
243 @Nullable
244 public JetType resolveTypeRefWithDefault(
245 @Nullable JetTypeReference returnTypeRef,
246 @NotNull JetScope scope,
247 @NotNull BindingTrace trace,
248 @Nullable JetType defaultValue
249 ) {
250 if (returnTypeRef != null) {
251 return expressionTypingServices.getTypeResolver().resolveType(scope, returnTypeRef, trace, true);
252 }
253 return defaultValue;
254 }
255 }