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