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.types.expressions;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.psi.PsiElement;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025    import org.jetbrains.jet.lang.descriptors.impl.*;
026    import org.jetbrains.jet.lang.psi.*;
027    import org.jetbrains.jet.lang.resolve.*;
028    import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
029    import org.jetbrains.jet.lang.resolve.name.Name;
030    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
031    import org.jetbrains.jet.lang.types.DeferredType;
032    import org.jetbrains.jet.lang.types.ErrorUtils;
033    import org.jetbrains.jet.lang.types.JetType;
034    import org.jetbrains.jet.lang.types.JetTypeInfo;
035    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
036    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
037    import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValueWithDefault;
038    import org.jetbrains.jet.util.slicedmap.WritableSlice;
039    
040    import java.util.Collections;
041    import java.util.List;
042    
043    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
044    import static org.jetbrains.jet.lang.resolve.BindingContext.*;
045    import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
046    import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.CANT_INFER_LAMBDA_PARAM_TYPE;
047    
048    public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
049        protected ClosureExpressionsTypingVisitor(@NotNull ExpressionTypingInternals facade) {
050            super(facade);
051        }
052    
053        @Override
054        public JetTypeInfo visitObjectLiteralExpression(final JetObjectLiteralExpression expression, final ExpressionTypingContext context) {
055            DelegatingBindingTrace delegatingBindingTrace = context.trace.get(TRACE_DELTAS_CACHE, expression.getObjectDeclaration());
056            if (delegatingBindingTrace != null) {
057                delegatingBindingTrace.addAllMyDataTo(context.trace);
058                JetType type = context.trace.get(EXPRESSION_TYPE, expression);
059                return DataFlowUtils.checkType(type, expression, context, context.dataFlowInfo);
060            }
061            final JetType[] result = new JetType[1];
062            final TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve object literal expression", expression);
063            ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor> handler = new ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor>() {
064    
065                @Override
066                public void handleRecord(WritableSlice<PsiElement, ClassDescriptor> slice, PsiElement declaration, final ClassDescriptor descriptor) {
067                    if (slice == CLASS && declaration == expression.getObjectDeclaration()) {
068                        JetType defaultType = DeferredType.create(context.trace, new RecursionIntolerantLazyValueWithDefault<JetType>(ErrorUtils.createErrorType("Recursive dependency")) {
069                            @Override
070                            protected JetType compute() {
071                                return descriptor.getDefaultType();
072                            }
073                        });
074                        result[0] = defaultType;
075                        if (!context.trace.get(PROCESSED, expression)) {
076                            temporaryTrace.record(EXPRESSION_TYPE, expression, defaultType);
077                            temporaryTrace.record(PROCESSED, expression);
078                        }
079                    }
080                }
081            };
082            ObservableBindingTrace traceAdapter = new ObservableBindingTrace(temporaryTrace);
083            traceAdapter.addHandler(CLASS, handler);
084            TopDownAnalyzer.processClassOrObject(context.expressionTypingServices.getProject(), traceAdapter, context.scope,
085                                                 context.scope.getContainingDeclaration(), expression.getObjectDeclaration());
086    
087            DelegatingBindingTrace cloneDelta = new DelegatingBindingTrace(
088                    new BindingTraceContext().getBindingContext(), "cached delta trace for object literal expression resolve", expression);
089            temporaryTrace.addAllMyDataTo(cloneDelta);
090            context.trace.record(TRACE_DELTAS_CACHE, expression.getObjectDeclaration(), cloneDelta);
091            temporaryTrace.commit();
092            return DataFlowUtils.checkType(result[0], expression, context, context.dataFlowInfo);
093        }
094    
095        @Override
096        public JetTypeInfo visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
097            JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
098            if (bodyExpression == null) return null;
099    
100            JetType expectedType = context.expectedType;
101            boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(
102                    expectedType);
103    
104            AnonymousFunctionDescriptor functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected);
105            JetType safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected);
106            functionDescriptor.setReturnType(safeReturnType);
107    
108            JetType receiver = DescriptorUtils.getReceiverParameterType(functionDescriptor.getReceiverParameter());
109            List<JetType> valueParametersTypes = DescriptorUtils.getValueParametersTypes(functionDescriptor.getValueParameters());
110            JetType resultType = KotlinBuiltIns.getInstance().getFunctionType(
111                    Collections.<AnnotationDescriptor>emptyList(), receiver, valueParametersTypes, safeReturnType);
112            if (expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType)) {
113                // all checks were done before
114                return JetTypeInfo.create(resultType, context.dataFlowInfo);
115            }
116            return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo);
117        }
118    
119        @NotNull
120        private static AnonymousFunctionDescriptor createFunctionDescriptor(
121                @NotNull JetFunctionLiteralExpression expression,
122                @NotNull ExpressionTypingContext context,
123                boolean functionTypeExpected
124        ) {
125            JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
126            JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef();
127            AnonymousFunctionDescriptor functionDescriptor = new AnonymousFunctionDescriptor(
128                    context.scope.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), CallableMemberDescriptor.Kind.DECLARATION);
129    
130            List<ValueParameterDescriptor> valueParameterDescriptors = createValueParameterDescriptors(context, functionLiteral, functionDescriptor, functionTypeExpected);
131    
132            JetType effectiveReceiverType;
133            if (receiverTypeRef == null) {
134                if (functionTypeExpected) {
135                    effectiveReceiverType = KotlinBuiltIns.getInstance().getReceiverType(context.expectedType);
136                }
137                else {
138                    effectiveReceiverType = null;
139                }
140            }
141            else {
142                effectiveReceiverType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, receiverTypeRef, context.trace, true);
143            }
144            functionDescriptor.initialize(effectiveReceiverType,
145                                          ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER,
146                                          Collections.<TypeParameterDescriptorImpl>emptyList(),
147                                          valueParameterDescriptors,
148                                          /*unsubstitutedReturnType = */ null,
149                                          Modality.FINAL,
150                                          Visibilities.LOCAL,
151                                          /*isInline = */ false
152            );
153            BindingContextUtils.recordFunctionDeclarationToDescriptor(context.trace, functionLiteral, functionDescriptor);
154            return functionDescriptor;
155        }
156    
157        @NotNull
158        private static List<ValueParameterDescriptor> createValueParameterDescriptors(
159                @NotNull ExpressionTypingContext context,
160                @NotNull JetFunctionLiteral functionLiteral,
161                @NotNull FunctionDescriptorImpl functionDescriptor,
162                boolean functionTypeExpected
163        ) {
164            List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
165            List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();
166    
167            List<ValueParameterDescriptor> expectedValueParameters =  (functionTypeExpected)
168                                                              ? KotlinBuiltIns.getInstance().getValueParameters(functionDescriptor, context.expectedType)
169                                                              : null;
170    
171            JetParameterList valueParameterList = functionLiteral.getValueParameterList();
172            boolean hasDeclaredValueParameters = valueParameterList != null;
173            if (functionTypeExpected && !hasDeclaredValueParameters && expectedValueParameters.size() == 1) {
174                ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
175                ValueParameterDescriptor it = new ValueParameterDescriptorImpl(
176                        functionDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), Name.identifier("it"),
177                        valueParameterDescriptor.getType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType()
178                );
179                valueParameterDescriptors.add(it);
180                context.trace.record(AUTO_CREATED_IT, it);
181            }
182            else {
183                if (expectedValueParameters != null && declaredValueParameters.size() != expectedValueParameters.size()) {
184                    List<JetType> expectedParameterTypes = DescriptorUtils.getValueParametersTypes(expectedValueParameters);
185                    context.trace.report(EXPECTED_PARAMETERS_NUMBER_MISMATCH.on(functionLiteral, expectedParameterTypes.size(), expectedParameterTypes));
186                }
187                for (int i = 0; i < declaredValueParameters.size(); i++) {
188                    ValueParameterDescriptor valueParameterDescriptor = createValueParameterDescriptor(
189                            context, functionDescriptor, declaredValueParameters, expectedValueParameters, i);
190                    valueParameterDescriptors.add(valueParameterDescriptor);
191                }
192            }
193            return valueParameterDescriptors;
194        }
195    
196        @NotNull
197        private static ValueParameterDescriptor createValueParameterDescriptor(
198                @NotNull ExpressionTypingContext context,
199                @NotNull FunctionDescriptorImpl functionDescriptor,
200                @NotNull List<JetParameter> declaredValueParameters,
201                @Nullable List<ValueParameterDescriptor> expectedValueParameters,
202                int index
203        ) {
204            JetParameter declaredParameter = declaredValueParameters.get(index);
205            JetTypeReference typeReference = declaredParameter.getTypeReference();
206    
207            JetType expectedType;
208            if (expectedValueParameters != null && index < expectedValueParameters.size()) {
209                expectedType = expectedValueParameters.get(index).getType();
210            }
211            else {
212                expectedType = null;
213            }
214            JetType type;
215            if (typeReference != null) {
216                type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true);
217                if (expectedType != null) {
218                    if (!JetTypeChecker.INSTANCE.isSubtypeOf(expectedType, type)) {
219                        context.trace.report(EXPECTED_PARAMETER_TYPE_MISMATCH.on(declaredParameter, expectedType));
220                    }
221                }
222            }
223            else {
224                if (expectedType == null || expectedType == CallResolverUtil.DONT_CARE || expectedType == CallResolverUtil.CANT_INFER_TYPE_PARAMETER) {
225                    context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter));
226                }
227                if (expectedType != null) {
228                    type = expectedType;
229                }
230                else {
231                    type = CANT_INFER_LAMBDA_PARAM_TYPE;
232                }
233            }
234            return context.expressionTypingServices.getDescriptorResolver().resolveValueParameterDescriptorWithAnnotationArguments(
235                    context.scope, functionDescriptor, declaredParameter, index, type, context.trace);
236        }
237    
238        @NotNull
239        private static JetType computeReturnType(
240                @NotNull JetFunctionLiteralExpression expression,
241                @NotNull ExpressionTypingContext context,
242                @NotNull SimpleFunctionDescriptorImpl functionDescriptor,
243                boolean functionTypeExpected
244        ) {
245            TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve function literal expression", expression);
246            JetType expectedReturnType = functionTypeExpected ? KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(context.expectedType) : null;
247            JetType returnType = computeUnsafeReturnType(expression, context, functionDescriptor, temporaryTrace, expectedReturnType);
248    
249            temporaryTrace.commit(new TraceEntryFilter() {
250                @Override
251                public boolean accept(@NotNull WritableSlice<?, ?> slice, Object key) {
252                    return (slice != BindingContext.TRACE_DELTAS_CACHE);
253                }
254            }, true);
255    
256            if (!expression.getFunctionLiteral().hasDeclaredReturnType() && functionTypeExpected) {
257                if (KotlinBuiltIns.getInstance().isUnit(expectedReturnType)) {
258                    return KotlinBuiltIns.getInstance().getUnitType();
259                }
260            }
261            return returnType == null ? CANT_INFER_LAMBDA_PARAM_TYPE : returnType;
262        }
263    
264        @Nullable
265        private static JetType computeUnsafeReturnType(
266                @NotNull JetFunctionLiteralExpression expression,
267                @NotNull ExpressionTypingContext context,
268                @NotNull SimpleFunctionDescriptorImpl functionDescriptor,
269                @NotNull TemporaryBindingTrace temporaryTrace,
270                @Nullable JetType expectedReturnType
271        ) {
272            JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
273            JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
274            assert bodyExpression != null;
275    
276            JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
277            JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
278            if (returnTypeRef != null) {
279                JetType returnType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, returnTypeRef, context.trace, true);
280                context.expressionTypingServices.checkFunctionReturnType(expression.getFunctionLiteral(), context.replaceScope(functionInnerScope).
281                        replaceExpectedType(returnType).replaceBindingTrace(temporaryTrace), temporaryTrace);
282                if (expectedReturnType != null) {
283                    if (!JetTypeChecker.INSTANCE.isSubtypeOf(returnType, expectedReturnType)) {
284                        temporaryTrace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType));
285                    }
286                }
287                return returnType;
288            }
289            ExpressionTypingContext newContext = context.replaceExpectedType(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE)
290                    .replaceBindingTrace(temporaryTrace);
291            return context.expressionTypingServices.getBlockReturnedType(functionInnerScope, bodyExpression, CoercionStrategy.COERCION_TO_UNIT,
292                                                                         newContext, temporaryTrace).getType();
293        }
294    }