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