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    }