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.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 && (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    }