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