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.analyzer.AnalyzerPackage;
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.evaluate.ConstantExpressionEvaluator;
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.CallResolverExtension;
035 import org.jetbrains.jet.lang.resolve.calls.CallResolverExtensionProvider;
036 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
037 import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency;
038 import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
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.types.TypeUtils.*;
053 import static org.jetbrains.jet.lang.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
054
055 public class ExpressionTypingServices {
056
057 @NotNull
058 private final ExpressionTypingFacade expressionTypingFacade;
059 @NotNull
060 private final ExpressionTypingComponents expressionTypingComponents;
061
062 @NotNull
063 private Project project;
064 @NotNull
065 private CallResolver callResolver;
066 @NotNull
067 private CallExpressionResolver callExpressionResolver;
068 @NotNull
069 private DescriptorResolver descriptorResolver;
070 @NotNull
071 private TypeResolver typeResolver;
072 @NotNull
073 private AnnotationResolver annotationResolver;
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 setExtensionProvider(@NotNull CallResolverExtensionProvider extensionProvider) {
139 this.extensionProvider = extensionProvider;
140 }
141
142 public ExpressionTypingServices(@NotNull ExpressionTypingComponents components) {
143 this.expressionTypingComponents = components;
144 this.expressionTypingFacade = ExpressionTypingVisitorDispatcher.create(components);
145 }
146
147 @NotNull
148 public JetType safeGetType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
149 JetType type = getType(scope, expression, expectedType, dataFlowInfo, trace);
150 return AnalyzerPackage.safeType(type, expression);
151 }
152
153 @NotNull
154 public JetTypeInfo getTypeInfo(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
155 ExpressionTypingContext context = ExpressionTypingContext.newContext(this, trace, scope, dataFlowInfo, expectedType);
156 return expressionTypingFacade.getTypeInfo(expression, context);
157 }
158
159 @NotNull
160 public JetTypeInfo getTypeInfo(@NotNull JetExpression expression, @NotNull ResolutionContext resolutionContext) {
161 return expressionTypingFacade.getTypeInfo(expression, ExpressionTypingContext.newContext(resolutionContext));
162 }
163
164 @Nullable
165 public JetType getType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
166 return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace).getType();
167 }
168
169 /////////////////////////////////////////////////////////
170
171 public void checkFunctionReturnType(@NotNull JetScope functionInnerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedReturnType, BindingTrace trace) {
172 if (expectedReturnType == null) {
173 expectedReturnType = functionDescriptor.getReturnType();
174 if (!function.hasBlockBody() && !function.hasDeclaredReturnType()) {
175 expectedReturnType = NO_EXPECTED_TYPE;
176 }
177 }
178 checkFunctionReturnType(function, ExpressionTypingContext.newContext(
179 this, trace, functionInnerScope, dataFlowInfo, expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE
180 ));
181 }
182
183 /*package*/ void checkFunctionReturnType(JetDeclarationWithBody function, ExpressionTypingContext context) {
184 JetExpression bodyExpression = function.getBodyExpression();
185 if (bodyExpression == null) return;
186
187 boolean blockBody = function.hasBlockBody();
188 ExpressionTypingContext newContext =
189 blockBody
190 ? context.replaceExpectedType(NO_EXPECTED_TYPE)
191 : context;
192
193 expressionTypingFacade.getTypeInfo(bodyExpression, newContext, blockBody);
194 }
195
196 @NotNull
197 public JetTypeInfo getBlockReturnedType(JetBlockExpression expression, ExpressionTypingContext context, boolean isStatement) {
198 return getBlockReturnedType(expression, isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION, context);
199 }
200
201 @NotNull
202 public JetTypeInfo getBlockReturnedType(
203 @NotNull JetBlockExpression expression,
204 @NotNull CoercionStrategy coercionStrategyForLastExpression,
205 @NotNull ExpressionTypingContext context
206 ) {
207 List<JetElement> block = expression.getStatements();
208
209 // SCRIPT: get code descriptor for script declaration
210 DeclarationDescriptor containingDescriptor = context.scope.getContainingDeclaration();
211 if (containingDescriptor instanceof ScriptDescriptor) {
212 if (!(expression.getParent() instanceof JetScript)) {
213 // top level script declarations should have ScriptDescriptor parent
214 // and lower level script declarations should be ScriptCodeDescriptor parent
215 containingDescriptor = ((ScriptDescriptor) containingDescriptor).getScriptCodeDescriptor();
216 }
217 }
218 WritableScope scope = new WritableScopeImpl(
219 context.scope, containingDescriptor, new TraceBasedRedeclarationHandler(context.trace), "getBlockReturnedType");
220 scope.changeLockLevel(WritableScope.LockLevel.BOTH);
221
222 JetTypeInfo r;
223 if (block.isEmpty()) {
224 r = DataFlowUtils.checkType(KotlinBuiltIns.getInstance().getUnitType(), expression, context, context.dataFlowInfo);
225 }
226 else {
227 r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, context, context.trace);
228 }
229 scope.changeLockLevel(WritableScope.LockLevel.READING);
230
231 if (containingDescriptor instanceof ScriptDescriptor) {
232 context.trace.record(BindingContext.SCRIPT_SCOPE, (ScriptDescriptor) containingDescriptor, scope);
233 }
234
235 return r;
236 }
237
238 @NotNull
239 public JetType getBodyExpressionType(
240 @NotNull BindingTrace trace,
241 @NotNull JetScope outerScope,
242 @NotNull DataFlowInfo dataFlowInfo,
243 @NotNull JetDeclarationWithBody function,
244 @NotNull FunctionDescriptor functionDescriptor
245 ) {
246 JetExpression bodyExpression = function.getBodyExpression();
247 assert bodyExpression != null;
248 JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
249
250 ExpressionTypingContext context = ExpressionTypingContext.newContext(
251 this, trace, functionInnerScope, dataFlowInfo, NO_EXPECTED_TYPE
252 );
253 JetTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());
254
255 JetType type = typeInfo.getType();
256 if (type != null) {
257 return type;
258 }
259 else {
260 return ErrorUtils.createErrorType("Error function type");
261 }
262 }
263
264 /*package*/ JetTypeInfo getBlockReturnedTypeWithWritableScope(
265 @NotNull WritableScope scope,
266 @NotNull List<? extends JetElement> block,
267 @NotNull CoercionStrategy coercionStrategyForLastExpression,
268 @NotNull ExpressionTypingContext context,
269 @NotNull BindingTrace trace
270 ) {
271 if (block.isEmpty()) {
272 return JetTypeInfo.create(KotlinBuiltIns.getInstance().getUnitType(), context.dataFlowInfo);
273 }
274
275 ExpressionTypingInternals blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(expressionTypingComponents, scope);
276 ExpressionTypingContext newContext = createContext(context, trace, scope, context.dataFlowInfo, NO_EXPECTED_TYPE);
277
278 JetTypeInfo result = JetTypeInfo.create(null, context.dataFlowInfo);
279 for (Iterator<? extends JetElement> iterator = block.iterator(); iterator.hasNext(); ) {
280 JetElement statement = iterator.next();
281 if (!(statement instanceof JetExpression)) {
282 continue;
283 }
284 JetExpression statementExpression = (JetExpression) statement;
285 if (!iterator.hasNext()) {
286 result = getTypeOfLastExpressionInBlock(
287 statementExpression, newContext.replaceExpectedType(context.expectedType), coercionStrategyForLastExpression,
288 blockLevelVisitor);
289 }
290 else {
291 result = blockLevelVisitor.getTypeInfo(statementExpression, newContext.replaceContextDependency(ContextDependency.INDEPENDENT), true);
292 }
293
294 DataFlowInfo newDataFlowInfo = result.getDataFlowInfo();
295 if (newDataFlowInfo != context.dataFlowInfo) {
296 newContext = newContext.replaceDataFlowInfo(newDataFlowInfo);
297 }
298 blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(expressionTypingComponents, scope);
299 }
300 return result;
301 }
302
303 private JetTypeInfo getTypeOfLastExpressionInBlock(
304 @NotNull JetExpression statementExpression,
305 @NotNull ExpressionTypingContext context,
306 @NotNull CoercionStrategy coercionStrategyForLastExpression,
307 @NotNull ExpressionTypingInternals blockLevelVisitor
308 ) {
309 if (!noExpectedType(context.expectedType) || context.expectedType == UNIT_EXPECTED_TYPE) {
310 JetType expectedType;
311 if (context.expectedType == UNIT_EXPECTED_TYPE ||//the first check is necessary to avoid invocation 'isUnit(UNIT_EXPECTED_TYPE)'
312 (coercionStrategyForLastExpression == COERCION_TO_UNIT && KotlinBuiltIns.getInstance().isUnit(context.expectedType))) {
313 expectedType = UNIT_EXPECTED_TYPE;
314 }
315 else {
316 expectedType = context.expectedType;
317 }
318
319 return blockLevelVisitor.getTypeInfo(statementExpression, context.replaceExpectedType(expectedType), true);
320 }
321 JetTypeInfo result = blockLevelVisitor.getTypeInfo(statementExpression, context, true);
322 if (coercionStrategyForLastExpression == COERCION_TO_UNIT) {
323 boolean mightBeUnit = false;
324 if (statementExpression instanceof JetDeclaration) {
325 mightBeUnit = true;
326 }
327 if (statementExpression instanceof JetBinaryExpression) {
328 JetBinaryExpression binaryExpression = (JetBinaryExpression) statementExpression;
329 IElementType operationType = binaryExpression.getOperationToken();
330 //noinspection SuspiciousMethodCalls
331 if (operationType == JetTokens.EQ || OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
332 mightBeUnit = true;
333 }
334 }
335 if (mightBeUnit) {
336 // ExpressionTypingVisitorForStatements should return only null or Unit for declarations and assignments
337 assert result.getType() == null || KotlinBuiltIns.getInstance().isUnit(result.getType());
338 result = JetTypeInfo.create(KotlinBuiltIns.getInstance().getUnitType(), context.dataFlowInfo);
339 }
340 }
341 return result;
342 }
343
344 private ExpressionTypingContext createContext(ExpressionTypingContext oldContext, BindingTrace trace, WritableScope scope, DataFlowInfo dataFlowInfo, JetType expectedType) {
345 return ExpressionTypingContext.newContext(
346 trace, scope, dataFlowInfo, expectedType, oldContext.contextDependency, oldContext.resolutionResultsCache,
347 oldContext.callResolverExtension, oldContext.isAnnotationContext);
348 }
349
350 @Nullable
351 public JetExpression deparenthesizeWithTypeResolution(
352 @Nullable JetExpression expression,
353 @NotNull final ExpressionTypingContext context
354 ) {
355 return JetPsiUtil.deparenthesizeWithResolutionStrategy(expression, true, new Function<JetTypeReference, Void>() {
356 @Override
357 public Void apply(JetTypeReference reference) {
358 getTypeResolver().resolveType(context.scope, reference, context.trace, true);
359 return null;
360 }
361 });
362 }
363
364 public void resolveValueParameters(
365 @NotNull List<JetParameter> valueParameters,
366 @NotNull List<ValueParameterDescriptor> valueParameterDescriptors,
367 @NotNull JetScope declaringScope,
368 @NotNull DataFlowInfo dataFlowInfo,
369 @NotNull BindingTrace trace,
370 boolean needCompleteAnalysis
371 ) {
372 for (int i = 0; i < valueParameters.size(); i++) {
373 ValueParameterDescriptor valueParameterDescriptor = valueParameterDescriptors.get(i);
374 JetParameter jetParameter = valueParameters.get(i);
375
376 AnnotationResolver.resolveAnnotationsArguments(jetParameter.getModifierList(), trace);
377
378 if (!needCompleteAnalysis) continue;
379
380 resolveDefaultValue(declaringScope, valueParameterDescriptor, jetParameter, dataFlowInfo, trace);
381 }
382 }
383
384 private void resolveDefaultValue(
385 @NotNull JetScope declaringScope,
386 @NotNull ValueParameterDescriptor valueParameterDescriptor,
387 @NotNull JetParameter jetParameter,
388 @NotNull DataFlowInfo dataFlowInfo,
389 @NotNull BindingTrace trace
390 ) {
391 if (valueParameterDescriptor.hasDefaultValue()) {
392 JetExpression defaultValue = jetParameter.getDefaultValue();
393 if (defaultValue != null) {
394 getType(declaringScope, defaultValue, valueParameterDescriptor.getType(), dataFlowInfo, trace);
395 if (DescriptorUtils.isAnnotationClass(DescriptorResolver.getContainingClass(declaringScope))) {
396 ConstantExpressionEvaluator.OBJECT$.evaluate(defaultValue, trace, valueParameterDescriptor.getType());
397 }
398 }
399 }
400 }
401
402 @NotNull
403 public CallResolverExtension createExtension(@NotNull JetScope scope, boolean isAnnotationContext) {
404 return extensionProvider.createExtension(scope == JetScope.EMPTY ? null : scope.getContainingDeclaration(), isAnnotationContext);
405 }
406 }