public DataClassMethodGenerator(JetClassOrObject declaration, BindingContext bindingContext) { this.declaration = declaration; this.bindingContext = bindingContext; this.classDescriptor = BindingContextUtils.getNotNull(bindingContext, BindingContext.CLASS, declaration); this.builtIns = DescriptorUtilsKt.getBuiltIns(classDescriptor); }
@Override public KotlinTypeInfo visitReturnExpression( @NotNull KtReturnExpression expression, ExpressionTypingContext context) { KtElement labelTargetElement = LabelResolver.INSTANCE.resolveControlLabel(expression, context); KtExpression returnedExpression = expression.getReturnedExpression(); KotlinType expectedType = NO_EXPECTED_TYPE; KotlinType resultType = components.builtIns.getNothingType(); KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtDeclaration.class); if (parentDeclaration instanceof KtParameter) { // In a default value for parameter context.trace.report(RETURN_NOT_ALLOWED.on(expression)); } if (expression.getTargetLabel() == null) { while (parentDeclaration instanceof KtMultiDeclaration) { // TODO: It's hacking fix for KT-5100: Strange "Return is not allowed here" for // multi-declaration initializer with elvis expression parentDeclaration = PsiTreeUtil.getParentOfType(parentDeclaration, KtDeclaration.class); } assert parentDeclaration != null : "Can't find parent declaration for " + expression.getText(); DeclarationDescriptor declarationDescriptor = context.trace.get(DECLARATION_TO_DESCRIPTOR, parentDeclaration); Pair<FunctionDescriptor, PsiElement> containingFunInfo = BindingContextUtils.getContainingFunctionSkipFunctionLiterals( declarationDescriptor, false); FunctionDescriptor containingFunctionDescriptor = containingFunInfo.getFirst(); if (containingFunctionDescriptor != null) { if (!InlineUtil.checkNonLocalReturnUsage( containingFunctionDescriptor, expression, context.trace) || isClassInitializer(containingFunInfo)) { // Unqualified, in a function literal context.trace.report(RETURN_NOT_ALLOWED.on(expression)); resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE); } expectedType = getFunctionExpectedReturnType( containingFunctionDescriptor, (KtElement) containingFunInfo.getSecond(), context); } else { // Outside a function context.trace.report(RETURN_NOT_ALLOWED.on(expression)); resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE); } } else if (labelTargetElement != null) { SimpleFunctionDescriptor functionDescriptor = context.trace.get(FUNCTION, labelTargetElement); if (functionDescriptor != null) { expectedType = getFunctionExpectedReturnType(functionDescriptor, labelTargetElement, context); if (!InlineUtil.checkNonLocalReturnUsage(functionDescriptor, expression, context.trace)) { // Qualified, non-local context.trace.report(RETURN_NOT_ALLOWED.on(expression)); resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE); } } else { context.trace.report(NOT_A_RETURN_LABEL.on(expression, expression.getLabelName())); } } if (returnedExpression != null) { facade.getTypeInfo( returnedExpression, context .replaceExpectedType(expectedType) .replaceScope(context.scope) .replaceContextDependency(INDEPENDENT)); } else { if (expectedType != null && !noExpectedType(expectedType) && !KotlinBuiltIns.isUnit(expectedType) && !isDontCarePlaceholder(expectedType)) // for lambda with implicit return type Unit { context.trace.report(RETURN_TYPE_MISMATCH.on(expression, expectedType)); } } return components.dataFlowAnalyzer.createCheckedTypeInfo(resultType, context, expression); }
public KotlinTypeInfo visitIfExpression( KtIfExpression ifExpression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE); KtExpression condition = ifExpression.getCondition(); DataFlowInfo conditionDataFlowInfo = checkCondition(context.scope, condition, context); KtExpression elseBranch = ifExpression.getElse(); KtExpression thenBranch = ifExpression.getThen(); LexicalWritableScope thenScope = newWritableScopeImpl(context, "Then scope"); LexicalWritableScope elseScope = newWritableScopeImpl(context, "Else scope"); DataFlowInfo thenInfo = components .dataFlowAnalyzer .extractDataFlowInfoFromCondition(condition, true, context) .and(conditionDataFlowInfo); DataFlowInfo elseInfo = components .dataFlowAnalyzer .extractDataFlowInfoFromCondition(condition, false, context) .and(conditionDataFlowInfo); if (elseBranch == null) { if (thenBranch != null) { KotlinTypeInfo result = getTypeInfoWhenOnlyOneBranchIsPresent( thenBranch, thenScope, thenInfo, elseInfo, contextWithExpectedType, ifExpression, isStatement); // If jump was possible, take condition check info as the jump info return result.getJumpOutPossible() ? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo) : result; } return TypeInfoFactoryKt.createTypeInfo( components.dataFlowAnalyzer.checkImplicitCast( components.builtIns.getUnitType(), ifExpression, contextWithExpectedType, isStatement), thenInfo.or(elseInfo)); } if (thenBranch == null) { return getTypeInfoWhenOnlyOneBranchIsPresent( elseBranch, elseScope, elseInfo, thenInfo, contextWithExpectedType, ifExpression, isStatement); } KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(ifExpression); KtBlockExpression thenBlock = psiFactory.wrapInABlockWrapper(thenBranch); KtBlockExpression elseBlock = psiFactory.wrapInABlockWrapper(elseBranch); Call callForIf = createCallForSpecialConstruction( ifExpression, ifExpression, Lists.newArrayList(thenBlock, elseBlock)); MutableDataFlowInfoForArguments dataFlowInfoForArguments = createDataFlowInfoForArgumentsForIfCall(callForIf, thenInfo, elseInfo); ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall( callForIf, ResolveConstruct.IF, Lists.newArrayList("thenBranch", "elseBranch"), Lists.newArrayList(false, false), contextWithExpectedType, dataFlowInfoForArguments); BindingContext bindingContext = context.trace.getBindingContext(); KotlinTypeInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext); KotlinTypeInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext); assert thenTypeInfo != null : "'Then' branch of if expression was not processed: " + ifExpression; assert elseTypeInfo != null : "'Else' branch of if expression was not processed: " + ifExpression; boolean loopBreakContinuePossible = thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible(); KotlinType thenType = thenTypeInfo.getType(); KotlinType elseType = elseTypeInfo.getType(); DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo(); DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo(); boolean jumpInThen = thenType != null && KotlinBuiltIns.isNothing(thenType); boolean jumpInElse = elseType != null && KotlinBuiltIns.isNothing(elseType); DataFlowInfo resultDataFlowInfo; if (thenType == null && elseType == null) { resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo); } else if (thenType == null || (jumpInThen && !jumpInElse)) { resultDataFlowInfo = elseDataFlowInfo; } else if (elseType == null || (jumpInElse && !jumpInThen)) { resultDataFlowInfo = thenDataFlowInfo; } else { resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo); } KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType(); // If break or continue was possible, take condition check info as the jump info return TypeInfoFactoryKt.createTypeInfo( components.dataFlowAnalyzer.checkImplicitCast( resultType, ifExpression, contextWithExpectedType, isStatement), resultDataFlowInfo, loopBreakContinuePossible, conditionDataFlowInfo); }