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 com.intellij.util.Function;
022    import com.intellij.util.containers.ContainerUtil;
023    import kotlin.Function0;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.jet.lang.descriptors.*;
027    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
028    import org.jetbrains.jet.lang.descriptors.impl.*;
029    import org.jetbrains.jet.lang.psi.*;
030    import org.jetbrains.jet.lang.resolve.*;
031    import org.jetbrains.jet.lang.resolve.name.Name;
032    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
033    import org.jetbrains.jet.lang.types.*;
034    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
035    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
036    import org.jetbrains.jet.util.slicedmap.WritableSlice;
037    
038    import java.util.Collection;
039    import java.util.Collections;
040    import java.util.List;
041    
042    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
043    import static org.jetbrains.jet.lang.resolve.BindingContext.*;
044    import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
045    import static org.jetbrains.jet.lang.types.TypeUtils.*;
046    import static org.jetbrains.jet.lang.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
047    
048    public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
049    
050        protected ClosureExpressionsTypingVisitor(@NotNull ExpressionTypingInternals facade) {
051            super(facade);
052        }
053    
054        @Override
055        public JetTypeInfo visitObjectLiteralExpression(@NotNull final JetObjectLiteralExpression expression, final ExpressionTypingContext context) {
056            DelegatingBindingTrace delegatingBindingTrace = context.trace.get(TRACE_DELTAS_CACHE, expression.getObjectDeclaration());
057            if (delegatingBindingTrace != null) {
058                delegatingBindingTrace.addAllMyDataTo(context.trace);
059                JetType type = context.trace.get(EXPRESSION_TYPE, expression);
060                return DataFlowUtils.checkType(type, expression, context, context.dataFlowInfo);
061            }
062            final JetType[] result = new JetType[1];
063            final TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve object literal expression", expression);
064            ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor> handler = new ObservableBindingTrace.RecordHandler<PsiElement, ClassDescriptor>() {
065    
066                @Override
067                public void handleRecord(WritableSlice<PsiElement, ClassDescriptor> slice, PsiElement declaration, final ClassDescriptor descriptor) {
068                    if (slice == CLASS && declaration == expression.getObjectDeclaration()) {
069                        JetType defaultType = DeferredType.createRecursionIntolerant(components.globalContext.getStorageManager(),
070                                                                                     context.trace,
071                                                                                     new Function0<JetType>() {
072                                                                                         @Override
073                                                                                         public JetType invoke() {
074                                                                                             return descriptor.getDefaultType();
075                                                                                         }
076                                                                                     });
077                        result[0] = defaultType;
078                        if (!context.trace.get(PROCESSED, expression)) {
079                            temporaryTrace.record(EXPRESSION_TYPE, expression, defaultType);
080                            temporaryTrace.record(PROCESSED, expression);
081                        }
082                    }
083                }
084            };
085            ObservableBindingTrace traceAdapter = new ObservableBindingTrace(temporaryTrace);
086            traceAdapter.addHandler(CLASS, handler);
087            TopDownAnalyzer.processClassOrObject(components.globalContext,
088                                                 null, // don't need to add classifier of object literal to any scope
089                                                 context.replaceBindingTrace(traceAdapter).replaceContextDependency(INDEPENDENT),
090                                                 context.scope.getContainingDeclaration(),
091                                                 expression.getObjectDeclaration());
092    
093            DelegatingBindingTrace cloneDelta = new DelegatingBindingTrace(
094                    new BindingTraceContext().getBindingContext(), "cached delta trace for object literal expression resolve", expression);
095            temporaryTrace.addAllMyDataTo(cloneDelta);
096            context.trace.record(TRACE_DELTAS_CACHE, expression.getObjectDeclaration(), cloneDelta);
097            temporaryTrace.commit();
098            return DataFlowUtils.checkType(result[0], expression, context, context.dataFlowInfo);
099        }
100    
101        @Override
102        public JetTypeInfo visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
103            if (!expression.getFunctionLiteral().hasBody()) return null;
104    
105            JetType expectedType = context.expectedType;
106            boolean functionTypeExpected = !noExpectedType(expectedType) && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(
107                    expectedType);
108    
109            AnonymousFunctionDescriptor functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected);
110            JetType safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected);
111            functionDescriptor.setReturnType(safeReturnType);
112    
113            JetType receiver = DescriptorUtils.getReceiverParameterType(functionDescriptor.getReceiverParameter());
114            List<JetType> valueParametersTypes = ExpressionTypingUtils.getValueParametersTypes(functionDescriptor.getValueParameters());
115            JetType resultType = KotlinBuiltIns.getInstance().getFunctionType(
116                    Annotations.EMPTY, receiver, valueParametersTypes, safeReturnType);
117            if (!noExpectedType(expectedType) && KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(expectedType)) {
118                // all checks were done before
119                return JetTypeInfo.create(resultType, context.dataFlowInfo);
120            }
121    
122            return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo);
123        }
124    
125        @NotNull
126        private AnonymousFunctionDescriptor createFunctionDescriptor(
127                @NotNull JetFunctionLiteralExpression expression,
128                @NotNull ExpressionTypingContext context,
129                boolean functionTypeExpected
130        ) {
131            JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
132            JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef();
133            AnonymousFunctionDescriptor functionDescriptor = new AnonymousFunctionDescriptor(
134                    context.scope.getContainingDeclaration(), Annotations.EMPTY, CallableMemberDescriptor.Kind.DECLARATION);
135    
136            List<ValueParameterDescriptor> valueParameterDescriptors = createValueParameterDescriptors(context, functionLiteral,
137                                                                                                       functionDescriptor, functionTypeExpected);
138    
139            JetType effectiveReceiverType;
140            if (receiverTypeRef == null) {
141                if (functionTypeExpected) {
142                    effectiveReceiverType = KotlinBuiltIns.getInstance().getReceiverType(context.expectedType);
143                }
144                else {
145                    effectiveReceiverType = null;
146                }
147            }
148            else {
149                effectiveReceiverType = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, receiverTypeRef, context.trace, true);
150            }
151            functionDescriptor.initialize(effectiveReceiverType,
152                                          ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER,
153                                          Collections.<TypeParameterDescriptorImpl>emptyList(),
154                                          valueParameterDescriptors,
155                                          /*unsubstitutedReturnType = */ null,
156                                          Modality.FINAL,
157                                          Visibilities.LOCAL
158            );
159            BindingContextUtils.recordFunctionDeclarationToDescriptor(context.trace, functionLiteral, functionDescriptor);
160            return functionDescriptor;
161        }
162    
163        @NotNull
164        private List<ValueParameterDescriptor> createValueParameterDescriptors(
165                @NotNull ExpressionTypingContext context,
166                @NotNull JetFunctionLiteral functionLiteral,
167                @NotNull FunctionDescriptorImpl functionDescriptor,
168                boolean functionTypeExpected
169        ) {
170            List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
171            List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();
172    
173            List<ValueParameterDescriptor> expectedValueParameters =  (functionTypeExpected)
174                                                              ? KotlinBuiltIns.getInstance().getValueParameters(functionDescriptor, context.expectedType)
175                                                              : null;
176    
177            JetParameterList valueParameterList = functionLiteral.getValueParameterList();
178            boolean hasDeclaredValueParameters = valueParameterList != null;
179            if (functionTypeExpected && !hasDeclaredValueParameters && expectedValueParameters.size() == 1) {
180                ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
181                ValueParameterDescriptor it = new ValueParameterDescriptorImpl(
182                        functionDescriptor, null, 0, Annotations.EMPTY, Name.identifier("it"),
183                        valueParameterDescriptor.getType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType()
184                );
185                valueParameterDescriptors.add(it);
186                context.trace.record(AUTO_CREATED_IT, it);
187            }
188            else {
189                if (expectedValueParameters != null && declaredValueParameters.size() != expectedValueParameters.size()) {
190                    List<JetType> expectedParameterTypes = ExpressionTypingUtils.getValueParametersTypes(expectedValueParameters);
191                    context.trace.report(EXPECTED_PARAMETERS_NUMBER_MISMATCH.on(functionLiteral, expectedParameterTypes.size(), expectedParameterTypes));
192                }
193                for (int i = 0; i < declaredValueParameters.size(); i++) {
194                    ValueParameterDescriptor valueParameterDescriptor = createValueParameterDescriptor(
195                            context, functionDescriptor, declaredValueParameters, expectedValueParameters, i);
196                    valueParameterDescriptors.add(valueParameterDescriptor);
197                }
198            }
199            return valueParameterDescriptors;
200        }
201    
202        @NotNull
203        private ValueParameterDescriptor createValueParameterDescriptor(
204                @NotNull ExpressionTypingContext context,
205                @NotNull FunctionDescriptorImpl functionDescriptor,
206                @NotNull List<JetParameter> declaredValueParameters,
207                @Nullable List<ValueParameterDescriptor> expectedValueParameters,
208                int index
209        ) {
210            JetParameter declaredParameter = declaredValueParameters.get(index);
211            JetTypeReference typeReference = declaredParameter.getTypeReference();
212    
213            JetType expectedType;
214            if (expectedValueParameters != null && index < expectedValueParameters.size()) {
215                expectedType = expectedValueParameters.get(index).getType();
216            }
217            else {
218                expectedType = null;
219            }
220            JetType type;
221            if (typeReference != null) {
222                type = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true);
223                if (expectedType != null) {
224                    if (!JetTypeChecker.DEFAULT.isSubtypeOf(expectedType, type)) {
225                        context.trace.report(EXPECTED_PARAMETER_TYPE_MISMATCH.on(declaredParameter, expectedType));
226                    }
227                }
228            }
229            else {
230                if (expectedType == null || expectedType == DONT_CARE || ErrorUtils.isUninferredParameter(expectedType)) {
231                    context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter));
232                }
233                if (expectedType != null) {
234                    type = expectedType;
235                }
236                else {
237                    type = CANT_INFER_LAMBDA_PARAM_TYPE;
238                }
239            }
240            return components.expressionTypingServices.getDescriptorResolver().resolveValueParameterDescriptorWithAnnotationArguments(
241                    context.scope, functionDescriptor, declaredParameter, index, type, context.trace);
242        }
243    
244        @NotNull
245        private JetType computeReturnType(
246                @NotNull JetFunctionLiteralExpression expression,
247                @NotNull ExpressionTypingContext context,
248                @NotNull SimpleFunctionDescriptorImpl functionDescriptor,
249                boolean functionTypeExpected
250        ) {
251            JetType expectedReturnType = functionTypeExpected ? KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(context.expectedType) : null;
252            JetType returnType = computeUnsafeReturnType(expression, context, functionDescriptor, expectedReturnType);
253    
254            if (!expression.getFunctionLiteral().hasDeclaredReturnType() && functionTypeExpected) {
255                if (KotlinBuiltIns.getInstance().isUnit(expectedReturnType)) {
256                    return KotlinBuiltIns.getInstance().getUnitType();
257                }
258            }
259            return returnType == null ? CANT_INFER_LAMBDA_PARAM_TYPE : returnType;
260        }
261    
262        @Nullable
263        private JetType computeUnsafeReturnType(
264                @NotNull JetFunctionLiteralExpression expression,
265                @NotNull ExpressionTypingContext context,
266                @NotNull SimpleFunctionDescriptorImpl functionDescriptor,
267                @Nullable JetType expectedReturnType
268        ) {
269            JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
270            JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
271            assert bodyExpression != null;
272    
273            JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
274            JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
275            JetType declaredReturnType = null;
276            if (returnTypeRef != null) {
277                declaredReturnType = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, returnTypeRef, context.trace, true);
278                // This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions
279                functionDescriptor.setReturnType(declaredReturnType);
280                if (expectedReturnType != null) {
281                    if (!JetTypeChecker.DEFAULT.isSubtypeOf(declaredReturnType, expectedReturnType)) {
282                        context.trace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType));
283                    }
284                }
285            }
286    
287            // Type-check the body
288            ExpressionTypingContext newContext = context.replaceScope(functionInnerScope)
289                    .replaceExpectedType(declaredReturnType != null
290                                         ? declaredReturnType
291                                         : (expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE));
292    
293            JetType typeOfBodyExpression = components.expressionTypingServices.getBlockReturnedType(bodyExpression, COERCION_TO_UNIT, newContext).getType();
294    
295            List<JetType> returnedExpressionTypes = Lists.newArrayList(getTypesOfLocallyReturnedExpressions(
296                    functionLiteral, context.trace, collectReturns(bodyExpression)));
297            ContainerUtil.addIfNotNull(returnedExpressionTypes, typeOfBodyExpression);
298    
299            if (declaredReturnType != null) return declaredReturnType;
300            if (returnedExpressionTypes.isEmpty()) return null;
301            return CommonSupertypes.commonSupertype(returnedExpressionTypes);
302        }
303    
304        private static List<JetType> getTypesOfLocallyReturnedExpressions(
305                final JetFunctionLiteral functionLiteral,
306                final BindingTrace trace,
307                Collection<JetReturnExpression> returnExpressions
308        ) {
309            return ContainerUtil.mapNotNull(returnExpressions, new Function<JetReturnExpression, JetType>() {
310                @Override
311                public JetType fun(JetReturnExpression returnExpression) {
312                    JetSimpleNameExpression label = returnExpression.getTargetLabel();
313                    if (label == null) {
314                        // No label => non-local return
315                        return null;
316                    }
317    
318                    PsiElement labelTarget = trace.get(BindingContext.LABEL_TARGET, label);
319                    if (labelTarget != functionLiteral) {
320                        // Either a local return of inner lambda/function or a non-local return
321                        return null;
322                    }
323    
324                    JetExpression returnedExpression = returnExpression.getReturnedExpression();
325                    if (returnedExpression == null) {
326                        return KotlinBuiltIns.getInstance().getUnitType();
327                    }
328                    JetType returnedType = trace.get(EXPRESSION_TYPE, returnedExpression);
329                    assert returnedType != null : "No type for returned expression: " + returnedExpression + ",\n" +
330                                                  "the type should have been computed by getBlockReturnedType() above";
331                    return returnedType;
332                }
333            });
334        }
335    
336        public static Collection<JetReturnExpression> collectReturns(@NotNull JetExpression expression) {
337            Collection<JetReturnExpression> result = Lists.newArrayList();
338            expression.accept(
339                    new JetTreeVisitor<Collection<JetReturnExpression>>() {
340                        @Override
341                        public Void visitReturnExpression(
342                                @NotNull JetReturnExpression expression, Collection<JetReturnExpression> data
343                        ) {
344                            data.add(expression);
345                            return null;
346                        }
347                    },
348                    result
349            );
350            return result;
351        }
352    }