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
017package org.jetbrains.jet.lang.types.expressions;
018
019import com.google.common.collect.Lists;
020import com.intellij.psi.PsiElement;
021import org.jetbrains.annotations.NotNull;
022import org.jetbrains.annotations.Nullable;
023import org.jetbrains.jet.lang.descriptors.*;
024import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025import org.jetbrains.jet.lang.descriptors.impl.*;
026import org.jetbrains.jet.lang.psi.*;
027import org.jetbrains.jet.lang.resolve.*;
028import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
029import org.jetbrains.jet.lang.resolve.name.Name;
030import org.jetbrains.jet.lang.resolve.scopes.JetScope;
031import org.jetbrains.jet.lang.types.DeferredType;
032import org.jetbrains.jet.lang.types.ErrorUtils;
033import org.jetbrains.jet.lang.types.JetType;
034import org.jetbrains.jet.lang.types.JetTypeInfo;
035import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
036import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
037import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValueWithDefault;
038import org.jetbrains.jet.util.slicedmap.WritableSlice;
039
040import java.util.Collections;
041import java.util.List;
042
043import static org.jetbrains.jet.lang.diagnostics.Errors.*;
044import static org.jetbrains.jet.lang.resolve.BindingContext.*;
045import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
046import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.CANT_INFER_LAMBDA_PARAM_TYPE;
047
048public 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}