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.ValueParameterDescriptor;
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.CallResolverExtension;
034 import org.jetbrains.jet.lang.resolve.calls.CallResolverExtensionProvider;
035 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
036 import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency;
037 import org.jetbrains.jet.lang.resolve.calls.context.ExpressionPosition;
038 import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
039 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
040 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
041 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
042 import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
043 import org.jetbrains.jet.lang.types.ErrorUtils;
044 import org.jetbrains.jet.lang.types.JetType;
045 import org.jetbrains.jet.lang.types.JetTypeInfo;
046 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
047 import org.jetbrains.jet.lexer.JetTokens;
048
049 import javax.inject.Inject;
050 import java.util.Iterator;
051 import java.util.List;
052
053 import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT;
054 import static org.jetbrains.jet.lang.types.TypeUtils.*;
055 import static org.jetbrains.jet.lang.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
056
057 public class ExpressionTypingServices {
058
059 @NotNull
060 private ExpressionTypingFacade expressionTypingFacade;
061 @NotNull
062 private Project project;
063 @NotNull
064 private CallResolver callResolver;
065 @NotNull
066 private CallExpressionResolver callExpressionResolver;
067 @NotNull
068 private DescriptorResolver descriptorResolver;
069 @NotNull
070 private TypeResolver typeResolver;
071 @NotNull
072 private AnnotationResolver annotationResolver;
073 @NotNull
074 private PlatformToKotlinClassMap platformToKotlinClassMap;
075 @NotNull
076 private CallResolverExtensionProvider extensionProvider;
077
078 @NotNull
079 public Project getProject() {
080 return project;
081 }
082
083 @Inject
084 public void setProject(@NotNull Project project) {
085 this.project = project;
086 }
087
088 @NotNull
089 public CallResolver getCallResolver() {
090 return callResolver;
091 }
092
093 @Inject
094 public void setCallResolver(@NotNull CallResolver callResolver) {
095 this.callResolver = callResolver;
096 }
097
098 @NotNull
099 public CallExpressionResolver getCallExpressionResolver() {
100 return callExpressionResolver;
101 }
102
103 @Inject
104 public void setCallExpressionResolver(@NotNull CallExpressionResolver callExpressionResolver) {
105 this.callExpressionResolver = callExpressionResolver;
106 }
107
108 @NotNull
109 public DescriptorResolver getDescriptorResolver() {
110 return descriptorResolver;
111 }
112
113 @Inject
114 public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
115 this.descriptorResolver = descriptorResolver;
116 }
117
118 @NotNull
119 public TypeResolver getTypeResolver() {
120 return typeResolver;
121 }
122
123 @Inject
124 public void setTypeResolver(@NotNull TypeResolver typeResolver) {
125 this.typeResolver = typeResolver;
126 }
127
128 @NotNull
129 public AnnotationResolver getAnnotationResolver() {
130 return annotationResolver;
131 }
132
133 @Inject
134 public void setAnnotationResolver(@NotNull AnnotationResolver annotationResolver) {
135 this.annotationResolver = annotationResolver;
136 }
137
138 @Inject
139 public void setPlatformToKotlinClassMap(@NotNull PlatformToKotlinClassMap platformToKotlinClassMap) {
140 this.platformToKotlinClassMap = platformToKotlinClassMap;
141 this.expressionTypingFacade = ExpressionTypingVisitorDispatcher.create(platformToKotlinClassMap);
142 }
143
144 @NotNull
145 public PlatformToKotlinClassMap getPlatformToKotlinClassMap() {
146 return platformToKotlinClassMap;
147 }
148
149 @Inject
150 public void setExtensionProvider(@NotNull CallResolverExtensionProvider extensionProvider) {
151 this.extensionProvider = extensionProvider;
152 }
153
154 @NotNull
155 public JetType safeGetType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
156 JetType type = getType(scope, expression, expectedType, dataFlowInfo, trace);
157 if (type != null) {
158 return type;
159 }
160 return ErrorUtils.createErrorType("Type for " + expression.getText());
161 }
162
163 @NotNull
164 public JetTypeInfo getTypeInfo(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
165 ExpressionTypingContext context = ExpressionTypingContext.newContext(
166 this, trace, scope, dataFlowInfo, expectedType, ExpressionPosition.FREE
167 );
168 return expressionTypingFacade.getTypeInfo(expression, context);
169 }
170
171 @NotNull
172 public JetTypeInfo getTypeInfo(@NotNull JetExpression expression, @NotNull ResolutionContext resolutionContext) {
173 return expressionTypingFacade.getTypeInfo(expression, ExpressionTypingContext.newContext(this, resolutionContext));
174 }
175
176 @Nullable
177 public JetType getType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
178 return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace).getType();
179 }
180
181 /////////////////////////////////////////////////////////
182
183 public void checkFunctionReturnType(@NotNull JetScope functionInnerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedReturnType, BindingTrace trace) {
184 if (expectedReturnType == null) {
185 expectedReturnType = functionDescriptor.getReturnType();
186 if (!function.hasBlockBody() && !function.hasDeclaredReturnType()) {
187 expectedReturnType = NO_EXPECTED_TYPE;
188 }
189 }
190 checkFunctionReturnType(function, ExpressionTypingContext.newContext(
191 this, trace, functionInnerScope, dataFlowInfo, expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE,
192 ExpressionPosition.FREE
193 ));
194 }
195
196 /*package*/ void checkFunctionReturnType(JetDeclarationWithBody function, ExpressionTypingContext context) {
197 JetExpression bodyExpression = function.getBodyExpression();
198 if (bodyExpression == null) return;
199
200 boolean blockBody = function.hasBlockBody();
201 ExpressionTypingContext newContext =
202 blockBody
203 ? context.replaceExpectedType(NO_EXPECTED_TYPE)
204 : context;
205
206 expressionTypingFacade.getTypeInfo(bodyExpression, newContext, blockBody);
207 }
208
209 @NotNull
210 public JetTypeInfo getBlockReturnedType(
211 @NotNull JetBlockExpression expression,
212 @NotNull CoercionStrategy coercionStrategyForLastExpression,
213 @NotNull ExpressionTypingContext context
214 ) {
215 List<JetElement> block = expression.getStatements();
216
217 DeclarationDescriptor containingDescriptor = context.scope.getContainingDeclaration();
218 if (containingDescriptor instanceof ScriptDescriptor) {
219 if (!(expression.getParent() instanceof JetScript)) {
220 // top level script declarations should have ScriptDescriptor parent
221 // and lower level script declarations should be ScriptCodeDescriptor parent
222 containingDescriptor = ((ScriptDescriptor) containingDescriptor).getScriptCodeDescriptor();
223 }
224 }
225 WritableScope scope = new WritableScopeImpl(
226 context.scope, containingDescriptor, new TraceBasedRedeclarationHandler(context.trace), "getBlockReturnedType");
227 scope.changeLockLevel(WritableScope.LockLevel.BOTH);
228
229 JetTypeInfo r;
230 if (block.isEmpty()) {
231 r = DataFlowUtils.checkType(KotlinBuiltIns.getInstance().getUnitType(), expression, context, context.dataFlowInfo);
232 }
233 else {
234 r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, context, context.trace);
235 }
236 scope.changeLockLevel(WritableScope.LockLevel.READING);
237
238 if (containingDescriptor instanceof ScriptDescriptor) {
239 context.trace.record(BindingContext.SCRIPT_SCOPE, (ScriptDescriptor) containingDescriptor, scope);
240 }
241
242 return r;
243 }
244
245 @NotNull
246 public JetType getBodyExpressionType(
247 @NotNull BindingTrace trace,
248 @NotNull JetScope outerScope,
249 @NotNull DataFlowInfo dataFlowInfo,
250 @NotNull JetDeclarationWithBody function,
251 @NotNull FunctionDescriptor functionDescriptor
252 ) {
253 JetExpression bodyExpression = function.getBodyExpression();
254 assert bodyExpression != null;
255 JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
256
257 ExpressionTypingContext context = ExpressionTypingContext.newContext(
258 this, trace, functionInnerScope, dataFlowInfo, NO_EXPECTED_TYPE, ExpressionPosition.FREE
259 );
260 JetTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());
261
262 trace.record(STATEMENT, bodyExpression, false);
263 JetType type = typeInfo.getType();
264 if (type != null) {
265 return type;
266 }
267 else {
268 return ErrorUtils.createErrorType("Error function type");
269 }
270 }
271
272 /*package*/ JetTypeInfo getBlockReturnedTypeWithWritableScope(
273 @NotNull WritableScope scope,
274 @NotNull List<? extends JetElement> block,
275 @NotNull CoercionStrategy coercionStrategyForLastExpression,
276 @NotNull ExpressionTypingContext context,
277 @NotNull BindingTrace trace
278 ) {
279 if (block.isEmpty()) {
280 return JetTypeInfo.create(KotlinBuiltIns.getInstance().getUnitType(), context.dataFlowInfo);
281 }
282
283 ExpressionTypingInternals blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(platformToKotlinClassMap, scope);
284 ExpressionTypingContext newContext = createContext(context, trace, scope, context.dataFlowInfo, NO_EXPECTED_TYPE);
285
286 JetTypeInfo result = JetTypeInfo.create(null, context.dataFlowInfo);
287 for (Iterator<? extends JetElement> iterator = block.iterator(); iterator.hasNext(); ) {
288 JetElement statement = iterator.next();
289 if (!(statement instanceof JetExpression)) {
290 continue;
291 }
292 trace.record(STATEMENT, statement);
293 JetExpression statementExpression = (JetExpression) statement;
294 if (!iterator.hasNext()) {
295 result = getTypeOfLastExpressionInBlock(
296 statementExpression, newContext.replaceExpectedType(context.expectedType), coercionStrategyForLastExpression,
297 blockLevelVisitor);
298 }
299 else {
300 result = blockLevelVisitor.getTypeInfo(statementExpression, newContext.replaceContextDependency(ContextDependency.INDEPENDENT), true);
301 }
302
303 DataFlowInfo newDataFlowInfo = result.getDataFlowInfo();
304 if (newDataFlowInfo != context.dataFlowInfo) {
305 newContext = newContext.replaceDataFlowInfo(newDataFlowInfo);
306 }
307 blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(platformToKotlinClassMap, scope);
308 }
309 return result;
310 }
311
312 private JetTypeInfo getTypeOfLastExpressionInBlock(
313 @NotNull JetExpression statementExpression,
314 @NotNull ExpressionTypingContext context,
315 @NotNull CoercionStrategy coercionStrategyForLastExpression,
316 @NotNull ExpressionTypingInternals blockLevelVisitor
317 ) {
318 if (!noExpectedType(context.expectedType) || context.expectedType == UNIT_EXPECTED_TYPE) {
319 JetType expectedType;
320 if (context.expectedType == UNIT_EXPECTED_TYPE ||//the first check is necessary to avoid invocation 'isUnit(UNIT_EXPECTED_TYPE)'
321 (coercionStrategyForLastExpression == COERCION_TO_UNIT && KotlinBuiltIns.getInstance().isUnit(context.expectedType))) {
322 expectedType = UNIT_EXPECTED_TYPE;
323 }
324 else {
325 expectedType = context.expectedType;
326 }
327
328 return blockLevelVisitor.getTypeInfo(statementExpression, context.replaceExpectedType(expectedType), true);
329 }
330 JetTypeInfo result = blockLevelVisitor.getTypeInfo(statementExpression, context, true);
331 if (coercionStrategyForLastExpression == COERCION_TO_UNIT) {
332 boolean mightBeUnit = false;
333 if (statementExpression instanceof JetDeclaration) {
334 mightBeUnit = true;
335 }
336 if (statementExpression instanceof JetBinaryExpression) {
337 JetBinaryExpression binaryExpression = (JetBinaryExpression) statementExpression;
338 IElementType operationType = binaryExpression.getOperationToken();
339 //noinspection SuspiciousMethodCalls
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(), context.dataFlowInfo);
348 }
349 }
350 return result;
351 }
352
353 private ExpressionTypingContext createContext(ExpressionTypingContext oldContext, BindingTrace trace, WritableScope scope, DataFlowInfo dataFlowInfo, JetType expectedType) {
354 return ExpressionTypingContext.newContext(this, trace, scope, dataFlowInfo, expectedType, oldContext.expressionPosition,
355 oldContext.contextDependency, oldContext.resolutionResultsCache, oldContext.labelResolver,
356 oldContext.callResolverExtension);
357 }
358
359 @Nullable
360 public JetExpression deparenthesizeWithTypeResolution(
361 @Nullable JetExpression expression,
362 @NotNull final ExpressionTypingContext context
363 ) {
364 return JetPsiUtil.deparenthesizeWithResolutionStrategy(expression, true, new Function<JetTypeReference, Void>() {
365 @Override
366 public Void apply(JetTypeReference reference) {
367 getTypeResolver().resolveType(context.scope, reference, context.trace, true);
368 return null;
369 }
370 });
371 }
372
373 public void resolveValueParameters(
374 @NotNull List<JetParameter> valueParameters,
375 @NotNull List<ValueParameterDescriptor> valueParameterDescriptors,
376 @NotNull JetScope declaringScope,
377 @NotNull DataFlowInfo dataFlowInfo,
378 @NotNull BindingTrace trace
379 ) {
380 for (int i = 0; i < valueParameters.size(); i++) {
381 ValueParameterDescriptor valueParameterDescriptor = valueParameterDescriptors.get(i);
382 JetParameter jetParameter = valueParameters.get(i);
383
384 annotationResolver.resolveAnnotationsArguments(declaringScope, jetParameter.getModifierList(), trace);
385
386 resolveDefaultValue(declaringScope, valueParameterDescriptor, jetParameter, dataFlowInfo, trace);
387 }
388 }
389
390 private void resolveDefaultValue(
391 @NotNull JetScope declaringScope,
392 @NotNull ValueParameterDescriptor valueParameterDescriptor,
393 @NotNull JetParameter jetParameter,
394 @NotNull DataFlowInfo dataFlowInfo,
395 @NotNull BindingTrace trace
396 ) {
397 if (valueParameterDescriptor.hasDefaultValue()) {
398 JetExpression defaultValue = jetParameter.getDefaultValue();
399 if (defaultValue != null) {
400 getType(declaringScope, defaultValue, valueParameterDescriptor.getType(), dataFlowInfo, trace);
401 if (DescriptorUtils.isAnnotationClass(DescriptorUtils.getContainingClass(declaringScope))) {
402 CompileTimeConstant<?> constant =
403 annotationResolver.resolveExpressionToCompileTimeValue(defaultValue, valueParameterDescriptor.getType(), trace);
404 if (constant != null) {
405 trace.record(BindingContext.COMPILE_TIME_VALUE, defaultValue, constant);
406 }
407 }
408 }
409 }
410 }
411
412 @NotNull
413 public CallResolverExtension createExtension(@NotNull JetScope scope) {
414 return extensionProvider.createExtension(scope == JetScope.EMPTY ? null : scope.getContainingDeclaration());
415 }
416 }