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.replaceBindingTrace(traceAdapter),
085                                                 context.scope.getContainingDeclaration(),
086                                                 expression.getObjectDeclaration());
087    
088            DelegatingBindingTrace cloneDelta = new DelegatingBindingTrace(
089                    new BindingTraceContext().getBindingContext(), "cached delta trace for object literal expression resolve", expression);
090            temporaryTrace.addAllMyDataTo(cloneDelta);
091            context.trace.record(TRACE_DELTAS_CACHE, expression.getObjectDeclaration(), cloneDelta);
092            temporaryTrace.commit();
093            return DataFlowUtils.checkType(result[0], expression, context, context.dataFlowInfo);
094        }
095    
096        @Override
097        public JetTypeInfo visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
098            JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
099            if (bodyExpression == null) return null;
100    
101            JetType expectedType = context.expectedType;
102            boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(
103                    expectedType);
104    
105            AnonymousFunctionDescriptor functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected);
106            JetType safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected);
107            functionDescriptor.setReturnType(safeReturnType);
108    
109            JetType receiver = DescriptorUtils.getReceiverParameterType(functionDescriptor.getReceiverParameter());
110            List<JetType> valueParametersTypes = DescriptorUtils.getValueParametersTypes(functionDescriptor.getValueParameters());
111            JetType resultType = KotlinBuiltIns.getInstance().getFunctionType(
112                    Collections.<AnnotationDescriptor>emptyList(), receiver, valueParametersTypes, safeReturnType);
113            if (expectedType != NO_EXPECTED_TYPE && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType)) {
114                // all checks were done before
115                return JetTypeInfo.create(resultType, context.dataFlowInfo);
116            }
117            return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo);
118        }
119    
120        @NotNull
121        private static AnonymousFunctionDescriptor createFunctionDescriptor(
122                @NotNull JetFunctionLiteralExpression expression,
123                @NotNull ExpressionTypingContext context,
124                boolean functionTypeExpected
125        ) {
126            JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
127            JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef();
128            AnonymousFunctionDescriptor functionDescriptor = new AnonymousFunctionDescriptor(
129                    context.scope.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), CallableMemberDescriptor.Kind.DECLARATION);
130    
131            List<ValueParameterDescriptor> valueParameterDescriptors = createValueParameterDescriptors(context, functionLiteral, functionDescriptor, functionTypeExpected);
132    
133            JetType effectiveReceiverType;
134            if (receiverTypeRef == null) {
135                if (functionTypeExpected) {
136                    effectiveReceiverType = KotlinBuiltIns.getInstance().getReceiverType(context.expectedType);
137                }
138                else {
139                    effectiveReceiverType = null;
140                }
141            }
142            else {
143                effectiveReceiverType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, receiverTypeRef, context.trace, true);
144            }
145            functionDescriptor.initialize(effectiveReceiverType,
146                                          ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER,
147                                          Collections.<TypeParameterDescriptorImpl>emptyList(),
148                                          valueParameterDescriptors,
149                                          /*unsubstitutedReturnType = */ null,
150                                          Modality.FINAL,
151                                          Visibilities.LOCAL,
152                                          /*isInline = */ false
153            );
154            BindingContextUtils.recordFunctionDeclarationToDescriptor(context.trace, functionLiteral, functionDescriptor);
155            return functionDescriptor;
156        }
157    
158        @NotNull
159        private static List<ValueParameterDescriptor> createValueParameterDescriptors(
160                @NotNull ExpressionTypingContext context,
161                @NotNull JetFunctionLiteral functionLiteral,
162                @NotNull FunctionDescriptorImpl functionDescriptor,
163                boolean functionTypeExpected
164        ) {
165            List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
166            List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();
167    
168            List<ValueParameterDescriptor> expectedValueParameters =  (functionTypeExpected)
169                                                              ? KotlinBuiltIns.getInstance().getValueParameters(functionDescriptor, context.expectedType)
170                                                              : null;
171    
172            JetParameterList valueParameterList = functionLiteral.getValueParameterList();
173            boolean hasDeclaredValueParameters = valueParameterList != null;
174            if (functionTypeExpected && !hasDeclaredValueParameters && expectedValueParameters.size() == 1) {
175                ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
176                ValueParameterDescriptor it = new ValueParameterDescriptorImpl(
177                        functionDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), Name.identifier("it"),
178                        valueParameterDescriptor.getType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType()
179                );
180                valueParameterDescriptors.add(it);
181                context.trace.record(AUTO_CREATED_IT, it);
182            }
183            else {
184                if (expectedValueParameters != null && declaredValueParameters.size() != expectedValueParameters.size()) {
185                    List<JetType> expectedParameterTypes = DescriptorUtils.getValueParametersTypes(expectedValueParameters);
186                    context.trace.report(EXPECTED_PARAMETERS_NUMBER_MISMATCH.on(functionLiteral, expectedParameterTypes.size(), expectedParameterTypes));
187                }
188                for (int i = 0; i < declaredValueParameters.size(); i++) {
189                    ValueParameterDescriptor valueParameterDescriptor = createValueParameterDescriptor(
190                            context, functionDescriptor, declaredValueParameters, expectedValueParameters, i);
191                    valueParameterDescriptors.add(valueParameterDescriptor);
192                }
193            }
194            return valueParameterDescriptors;
195        }
196    
197        @NotNull
198        private static ValueParameterDescriptor createValueParameterDescriptor(
199                @NotNull ExpressionTypingContext context,
200                @NotNull FunctionDescriptorImpl functionDescriptor,
201                @NotNull List<JetParameter> declaredValueParameters,
202                @Nullable List<ValueParameterDescriptor> expectedValueParameters,
203                int index
204        ) {
205            JetParameter declaredParameter = declaredValueParameters.get(index);
206            JetTypeReference typeReference = declaredParameter.getTypeReference();
207    
208            JetType expectedType;
209            if (expectedValueParameters != null && index < expectedValueParameters.size()) {
210                expectedType = expectedValueParameters.get(index).getType();
211            }
212            else {
213                expectedType = null;
214            }
215            JetType type;
216            if (typeReference != null) {
217                type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true);
218                if (expectedType != null) {
219                    if (!JetTypeChecker.INSTANCE.isSubtypeOf(expectedType, type)) {
220                        context.trace.report(EXPECTED_PARAMETER_TYPE_MISMATCH.on(declaredParameter, expectedType));
221                    }
222                }
223            }
224            else {
225                if (expectedType == null || expectedType == CallResolverUtil.DONT_CARE || expectedType == CallResolverUtil.CANT_INFER_TYPE_PARAMETER) {
226                    context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter));
227                }
228                if (expectedType != null) {
229                    type = expectedType;
230                }
231                else {
232                    type = CANT_INFER_LAMBDA_PARAM_TYPE;
233                }
234            }
235            return context.expressionTypingServices.getDescriptorResolver().resolveValueParameterDescriptorWithAnnotationArguments(
236                    context.scope, functionDescriptor, declaredParameter, index, type, context.trace);
237        }
238    
239        @NotNull
240        private static JetType computeReturnType(
241                @NotNull JetFunctionLiteralExpression expression,
242                @NotNull ExpressionTypingContext context,
243                @NotNull SimpleFunctionDescriptorImpl functionDescriptor,
244                boolean functionTypeExpected
245        ) {
246            TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve function literal expression", expression);
247            JetType expectedReturnType = functionTypeExpected ? KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(context.expectedType) : null;
248            JetType returnType = computeUnsafeReturnType(expression, context, functionDescriptor, temporaryTrace, expectedReturnType);
249    
250            temporaryTrace.commit(new TraceEntryFilter() {
251                @Override
252                public boolean accept(@NotNull WritableSlice<?, ?> slice, Object key) {
253                    return (slice != BindingContext.TRACE_DELTAS_CACHE);
254                }
255            }, true);
256    
257            if (!expression.getFunctionLiteral().hasDeclaredReturnType() && functionTypeExpected) {
258                if (KotlinBuiltIns.getInstance().isUnit(expectedReturnType)) {
259                    return KotlinBuiltIns.getInstance().getUnitType();
260                }
261            }
262            return returnType == null ? CANT_INFER_LAMBDA_PARAM_TYPE : returnType;
263        }
264    
265        @Nullable
266        private static JetType computeUnsafeReturnType(
267                @NotNull JetFunctionLiteralExpression expression,
268                @NotNull ExpressionTypingContext context,
269                @NotNull SimpleFunctionDescriptorImpl functionDescriptor,
270                @NotNull TemporaryBindingTrace temporaryTrace,
271                @Nullable JetType expectedReturnType
272        ) {
273            JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
274            JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
275            assert bodyExpression != null;
276    
277            JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
278            JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
279            if (returnTypeRef != null) {
280                JetType returnType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, returnTypeRef, context.trace, true);
281                context.expressionTypingServices.checkFunctionReturnType(expression.getFunctionLiteral(), context.replaceScope(functionInnerScope).
282                        replaceExpectedType(returnType).replaceBindingTrace(temporaryTrace), temporaryTrace);
283                if (expectedReturnType != null) {
284                    if (!JetTypeChecker.INSTANCE.isSubtypeOf(returnType, expectedReturnType)) {
285                        temporaryTrace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType));
286                    }
287                }
288                return returnType;
289            }
290            ExpressionTypingContext newContext = context.replaceExpectedType(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE)
291                    .replaceBindingTrace(temporaryTrace);
292            return context.expressionTypingServices.getBlockReturnedType(functionInnerScope, bodyExpression, CoercionStrategy.COERCION_TO_UNIT,
293                                                                         newContext, temporaryTrace).getType();
294        }
295    }