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.base.Function;
020 import com.google.common.collect.Lists;
021 import com.intellij.openapi.project.Project;
022 import com.intellij.psi.PsiElement;
023 import com.intellij.psi.tree.IElementType;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
027 import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
028 import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorUtil;
029 import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
030 import org.jetbrains.jet.lang.psi.*;
031 import org.jetbrains.jet.lang.resolve.*;
032 import org.jetbrains.jet.lang.resolve.calls.CallExpressionResolver;
033 import org.jetbrains.jet.lang.resolve.calls.CallResolver;
034 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
035 import org.jetbrains.jet.lang.resolve.calls.context.ExpressionPosition;
036 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
037 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
038 import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
039 import org.jetbrains.jet.lang.types.CommonSupertypes;
040 import org.jetbrains.jet.lang.types.ErrorUtils;
041 import org.jetbrains.jet.lang.types.JetType;
042 import org.jetbrains.jet.lang.types.JetTypeInfo;
043 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
044 import org.jetbrains.jet.lexer.JetTokens;
045
046 import javax.inject.Inject;
047 import java.util.*;
048
049 import static org.jetbrains.jet.lang.resolve.BindingContext.LABEL_TARGET;
050 import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT;
051 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
052 import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.makeTraceInterceptingTypeMismatch;
053
054 public class ExpressionTypingServices {
055
056 private final ExpressionTypingFacade expressionTypingFacade = ExpressionTypingVisitorDispatcher.create();
057
058 @NotNull
059 private Project project;
060 @NotNull
061 private CallResolver callResolver;
062 @NotNull
063 private CallExpressionResolver callExpressionResolver;
064 @NotNull
065 private DescriptorResolver descriptorResolver;
066 @NotNull
067 private TypeResolver typeResolver;
068
069
070
071 @NotNull
072 public Project getProject() {
073 return project;
074 }
075
076 @Inject
077 public void setProject(@NotNull Project project) {
078 this.project = project;
079 }
080
081 @NotNull
082 public CallResolver getCallResolver() {
083 return callResolver;
084 }
085
086 @Inject
087 public void setCallResolver(@NotNull CallResolver callResolver) {
088 this.callResolver = callResolver;
089 }
090
091 @NotNull
092 public CallExpressionResolver getCallExpressionResolver() {
093 return callExpressionResolver;
094 }
095
096 @Inject
097 public void setCallExpressionResolver(@NotNull CallExpressionResolver callExpressionResolver) {
098 this.callExpressionResolver = callExpressionResolver;
099 }
100
101 @NotNull
102 public DescriptorResolver getDescriptorResolver() {
103 return descriptorResolver;
104 }
105
106 @Inject
107 public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
108 this.descriptorResolver = descriptorResolver;
109 }
110
111 @NotNull
112 public TypeResolver getTypeResolver() {
113 return typeResolver;
114 }
115
116 @Inject
117 public void setTypeResolver(@NotNull TypeResolver typeResolver) {
118 this.typeResolver = typeResolver;
119 }
120
121 @NotNull
122 public JetType safeGetType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
123 JetType type = getType(scope, expression, expectedType, dataFlowInfo, trace);
124 if (type != null) {
125 return type;
126 }
127 return ErrorUtils.createErrorType("Type for " + expression.getText());
128 }
129
130 @NotNull
131 public JetTypeInfo getTypeInfo(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
132 ExpressionTypingContext context = ExpressionTypingContext.newContext(
133 this, trace, scope, dataFlowInfo, expectedType, ExpressionPosition.FREE
134 );
135 return expressionTypingFacade.getTypeInfo(expression, context);
136 }
137
138 @Nullable
139 public JetType getType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
140 return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace).getType();
141 }
142
143 public JetTypeInfo getTypeInfoWithNamespaces(@NotNull JetExpression expression, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
144 ExpressionTypingContext context = ExpressionTypingContext.newContext(
145 this, trace, scope, dataFlowInfo, expectedType, ExpressionPosition.LHS_OF_DOT);
146 return expressionTypingFacade.getTypeInfo(expression, context);
147 }
148
149 @NotNull
150 public JetType inferFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor, @NotNull BindingTrace trace) {
151 Map<JetExpression, JetType> typeMap = collectReturnedExpressionsWithTypes(trace, outerScope, function, functionDescriptor);
152 Collection<JetType> types = typeMap.values();
153 return types.isEmpty()
154 ? KotlinBuiltIns.getInstance().getNothingType()
155 : CommonSupertypes.commonSupertype(types);
156 }
157
158
159 /////////////////////////////////////////////////////////
160
161 public void checkFunctionReturnType(@NotNull JetScope functionInnerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedReturnType, BindingTrace trace) {
162 if (expectedReturnType == null) {
163 expectedReturnType = functionDescriptor.getReturnType();
164 if (!function.hasBlockBody() && !function.hasDeclaredReturnType()) {
165 expectedReturnType = NO_EXPECTED_TYPE;
166 }
167 }
168 checkFunctionReturnType(function, ExpressionTypingContext.newContext(
169 this, trace, functionInnerScope, dataFlowInfo, expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE, ExpressionPosition.FREE
170 ), trace);
171 }
172
173 /*package*/ void checkFunctionReturnType(JetDeclarationWithBody function, ExpressionTypingContext context, BindingTrace trace) {
174 JetExpression bodyExpression = function.getBodyExpression();
175 if (bodyExpression == null) return;
176
177 boolean blockBody = function.hasBlockBody();
178 ExpressionTypingContext newContext =
179 blockBody
180 ? context.replaceExpectedType(NO_EXPECTED_TYPE)
181 : context;
182
183 if (function instanceof JetFunctionLiteral) {
184 JetFunctionLiteral functionLiteral = (JetFunctionLiteral) function;
185 JetBlockExpression blockExpression = functionLiteral.getBodyExpression();
186 assert blockExpression != null;
187 getBlockReturnedType(newContext.scope, blockExpression, CoercionStrategy.COERCION_TO_UNIT, context, trace);
188 }
189 else {
190 expressionTypingFacade.getTypeInfo(bodyExpression, newContext, !blockBody);
191 }
192 }
193
194 @NotNull
195 public JetTypeInfo getBlockReturnedType(@NotNull JetScope outerScope, @NotNull JetBlockExpression expression, @NotNull CoercionStrategy coercionStrategyForLastExpression, ExpressionTypingContext context, BindingTrace trace) {
196 List<JetElement> block = expression.getStatements();
197
198 DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
199 if (containingDescriptor instanceof ScriptDescriptor) {
200 if (!(expression.getParent() instanceof JetScript)) {
201 // top level script declarations should have ScriptDescriptor parent
202 // and lower level script declarations should be ScriptCodeDescriptor parent
203 containingDescriptor = ((ScriptDescriptor) containingDescriptor).getScriptCodeDescriptor();
204 }
205 }
206 WritableScope scope = new WritableScopeImpl(
207 outerScope, containingDescriptor, new TraceBasedRedeclarationHandler(context.trace), "getBlockReturnedType");
208 scope.changeLockLevel(WritableScope.LockLevel.BOTH);
209
210 JetTypeInfo r;
211 if (block.isEmpty()) {
212 r = DataFlowUtils.checkType(KotlinBuiltIns.getInstance().getUnitType(), expression, context, context.dataFlowInfo);
213 }
214 else {
215 r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, context, trace);
216 }
217 scope.changeLockLevel(WritableScope.LockLevel.READING);
218
219 if (containingDescriptor instanceof ScriptDescriptor) {
220 trace.record(BindingContext.SCRIPT_SCOPE, (ScriptDescriptor) containingDescriptor, scope);
221 }
222
223 return r;
224 }
225
226 private Map<JetExpression, JetType> collectReturnedExpressionsWithTypes(
227 final @NotNull BindingTrace trace,
228 JetScope outerScope,
229 final JetDeclarationWithBody function,
230 FunctionDescriptor functionDescriptor) {
231 JetExpression bodyExpression = function.getBodyExpression();
232 assert bodyExpression != null;
233 JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
234 expressionTypingFacade.getTypeInfo(bodyExpression, ExpressionTypingContext.newContext(
235 this,
236 trace, functionInnerScope, DataFlowInfo.EMPTY, NO_EXPECTED_TYPE, ExpressionPosition.FREE), !function.hasBlockBody());
237 //todo function literals
238 final Collection<JetExpression> returnedExpressions = Lists.newArrayList();
239 if (function.hasBlockBody()) {
240 //now this code is never invoked!, it should be invoked for inference of return type of function literal with local returns
241 bodyExpression.accept(new JetTreeVisitor<JetDeclarationWithBody>() {
242 @Override
243 public Void visitReturnExpression(JetReturnExpression expression, JetDeclarationWithBody outerFunction) {
244 JetSimpleNameExpression targetLabel = expression.getTargetLabel();
245 PsiElement element = targetLabel != null ? trace.get(LABEL_TARGET, targetLabel) : null;
246 if (element == function || (targetLabel == null && outerFunction == function)) {
247 returnedExpressions.add(expression);
248 }
249 return null;
250 }
251
252 @Override
253 public Void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, JetDeclarationWithBody outerFunction) {
254 return super.visitFunctionLiteralExpression(expression, expression.getFunctionLiteral());
255 }
256
257 @Override
258 public Void visitNamedFunction(JetNamedFunction function, JetDeclarationWithBody outerFunction) {
259 return super.visitNamedFunction(function, function);
260 }
261 }, function);
262 }
263 else {
264 returnedExpressions.add(bodyExpression);
265 }
266 Map<JetExpression, JetType> typeMap = new HashMap<JetExpression, JetType>();
267 for (JetExpression returnedExpression : returnedExpressions) {
268 JetType cachedType = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, returnedExpression);
269 trace.record(STATEMENT, returnedExpression, false);
270 if (cachedType != null) {
271 typeMap.put(returnedExpression, cachedType);
272 }
273 else {
274 typeMap.put(returnedExpression, ErrorUtils.createErrorType("Error function type"));
275 }
276 }
277 return typeMap;
278 }
279
280 /*package*/
281 @SuppressWarnings("SuspiciousMethodCalls")
282 JetTypeInfo getBlockReturnedTypeWithWritableScope(@NotNull WritableScope scope, @NotNull List<? extends JetElement> block, @NotNull CoercionStrategy coercionStrategyForLastExpression, ExpressionTypingContext context, BindingTrace trace) {
283 if (block.isEmpty()) {
284 return JetTypeInfo.create(KotlinBuiltIns.getInstance().getUnitType(), context.dataFlowInfo);
285 }
286
287 ExpressionTypingInternals blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(scope);
288 ExpressionTypingContext newContext = createContext(context, trace, scope, context.dataFlowInfo, NO_EXPECTED_TYPE);
289
290 JetTypeInfo result = JetTypeInfo.create(null, context.dataFlowInfo);
291 for (Iterator<? extends JetElement> iterator = block.iterator(); iterator.hasNext(); ) {
292 JetElement statement = iterator.next();
293 if (!(statement instanceof JetExpression)) {
294 continue;
295 }
296 trace.record(STATEMENT, statement);
297 JetExpression statementExpression = (JetExpression) statement;
298 //TODO constructor assert context.expectedType != FORBIDDEN : ""
299 if (!iterator.hasNext()) {
300 if (context.expectedType != NO_EXPECTED_TYPE) {
301 if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT && KotlinBuiltIns.getInstance().isUnit(context.expectedType)) {
302 // This implements coercion to Unit
303 TemporaryBindingTrace temporaryTraceExpectingUnit = TemporaryBindingTrace.create(trace, "trace to resolve coercion to unit with expected type");
304 boolean[] mismatch = new boolean[1];
305 ObservableBindingTrace errorInterceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceExpectingUnit, statementExpression, mismatch);
306 newContext = createContext(newContext, errorInterceptingTrace, scope, newContext.dataFlowInfo, context.expectedType);
307 result = blockLevelVisitor.getTypeInfo(statementExpression, newContext, true);
308 if (mismatch[0]) {
309 TemporaryBindingTrace temporaryTraceNoExpectedType = TemporaryBindingTrace.create(trace, "trace to resolve coercion to unit without expected type");
310 mismatch[0] = false;
311 ObservableBindingTrace interceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceNoExpectedType, statementExpression, mismatch);
312 newContext = createContext(newContext, interceptingTrace, scope, newContext.dataFlowInfo, NO_EXPECTED_TYPE);
313 result = blockLevelVisitor.getTypeInfo(statementExpression, newContext, true);
314 if (mismatch[0]) {
315 temporaryTraceExpectingUnit.commit();
316 }
317 else {
318 temporaryTraceNoExpectedType.commit();
319 }
320 }
321 else {
322 temporaryTraceExpectingUnit.commit();
323 }
324 }
325 else {
326 newContext = createContext(newContext, trace, scope, newContext.dataFlowInfo, context.expectedType);
327 result = blockLevelVisitor.getTypeInfo(statementExpression, newContext, true);
328 }
329 }
330 else {
331 result = blockLevelVisitor.getTypeInfo(statementExpression, newContext, true);
332 if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT) {
333 boolean mightBeUnit = false;
334 if (statementExpression instanceof JetDeclaration) {
335 mightBeUnit = true;
336 }
337 if (statementExpression instanceof JetBinaryExpression) {
338 JetBinaryExpression binaryExpression = (JetBinaryExpression) statementExpression;
339 IElementType operationType = binaryExpression.getOperationToken();
340 if (operationType == JetTokens.EQ || OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
341 mightBeUnit = true;
342 }
343 }
344 if (mightBeUnit) {
345 // ExpressionTypingVisitorForStatements should return only null or Unit for declarations and assignments
346 assert result.getType() == null || KotlinBuiltIns.getInstance().isUnit(result.getType());
347 result = JetTypeInfo.create(KotlinBuiltIns.getInstance().getUnitType(), newContext.dataFlowInfo);
348 }
349 }
350 }
351 }
352 else {
353 result = blockLevelVisitor.getTypeInfo(statementExpression, newContext, true);
354 }
355
356 DataFlowInfo newDataFlowInfo = result.getDataFlowInfo();
357 if (newDataFlowInfo != context.dataFlowInfo) {
358 newContext = createContext(newContext, trace, scope, newDataFlowInfo, NO_EXPECTED_TYPE);
359 }
360 blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(scope);
361 }
362 return result;
363 }
364
365 private ExpressionTypingContext createContext(ExpressionTypingContext oldContext, BindingTrace trace, WritableScope scope, DataFlowInfo dataFlowInfo, JetType expectedType) {
366 return ExpressionTypingContext.newContext(
367 this, oldContext.labelResolver, trace, scope, dataFlowInfo, expectedType, oldContext.expressionPosition);
368 }
369
370 @Nullable
371 public JetExpression deparenthesize(
372 @NotNull JetExpression expression,
373 @NotNull final ExpressionTypingContext context) {
374 return JetPsiUtil.deparenthesizeWithResolutionStrategy(expression, new Function<JetTypeReference, Void>() {
375 @Override
376 public Void apply(JetTypeReference reference) {
377 getTypeResolver().resolveType(context.scope, reference, context.trace, true);
378 return null;
379 }
380 });
381 }
382 }