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