public InlineCodegen( @NotNull ExpressionCodegen codegen, @NotNull GenerationState state, @NotNull SimpleFunctionDescriptor functionDescriptor, @NotNull JetElement callElement, @Nullable ReifiedTypeParameterMappings typeParameterMappings) { assert InlineUtil.isInline(functionDescriptor) : "InlineCodegen could inline only inline function: " + functionDescriptor; this.state = state; this.typeMapper = state.getTypeMapper(); this.codegen = codegen; this.callElement = callElement; this.functionDescriptor = functionDescriptor.getOriginal(); reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings); initialFrameSize = codegen.getFrameMap().getCurrentSize(); context = (MethodContext) getContext(functionDescriptor, state); jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); // TODO: implement AS_FUNCTION inline strategy InlineStrategy inlineStrategy = InlineUtil.getInlineStrategy(functionDescriptor); this.asFunctionInline = false; isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared( functionDescriptor, codegen.getContext(), state.getOutDirectory()); sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper(); reportIncrementalInfo( functionDescriptor, codegen.getContext().getFunctionDescriptor().getOriginal()); }
public static boolean shouldBeInlined(@NotNull CallableDescriptor descriptor) { if (descriptor instanceof SimpleFunctionDescriptor) { return InlineUtil.isInline(descriptor); } if (descriptor instanceof ValueParameterDescriptor) { return InlineUtil.isInline(descriptor.getContainingDeclaration()) && InlineUtil.isInlineLambdaParameter((ParameterDescriptor) descriptor); } return false; }
/*lambda or callable reference*/ public static boolean isInliningParameter( JetExpression expression, ValueParameterDescriptor valueParameterDescriptor) { // TODO deparenthisise typed JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression); return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized); }
private void checkValueParameter( @NotNull CallCheckerContext context, @NotNull CallableDescriptor targetDescriptor, @NotNull ValueArgument targetArgument, @NotNull ValueParameterDescriptor targetParameterDescriptor) { KtExpression argumentExpression = targetArgument.getArgumentExpression(); if (argumentExpression == null) { return; } CallableDescriptor argumentCallee = getCalleeDescriptor(context, argumentExpression, false); if (argumentCallee != null && inlinableParameters.contains(argumentCallee)) { if (InlineUtil.isInline(targetDescriptor) && isInlinableParameter(targetParameterDescriptor)) { if (allowsNonLocalReturns(argumentCallee) && !allowsNonLocalReturns(targetParameterDescriptor)) { context .getTrace() .report(NON_LOCAL_RETURN_NOT_ALLOWED.on(argumentExpression, argumentExpression)); } else { checkNonLocalReturn(context, argumentCallee, argumentExpression); } } else { context .getTrace() .report(USAGE_IS_NOT_INLINABLE.on(argumentExpression, argumentExpression, descriptor)); } } }
public InlineChecker(@NotNull FunctionDescriptor descriptor) { assert InlineUtil.isInline(descriptor) : "This extension should be created only for inline functions: " + descriptor; this.descriptor = descriptor; this.isEffectivelyPublicApiFunction = DescriptorUtilsKt.isEffectivelyPublicApi(descriptor); this.isEffectivelyPrivateApiFunction = DescriptorUtilsKt.isEffectivelyPrivateApi(descriptor); for (ValueParameterDescriptor param : descriptor.getValueParameters()) { if (isInlinableParameter(param)) { inlinableParameters.add(param); } } }
private static boolean isInvokeOrInlineExtension(@NotNull CallableDescriptor descriptor) { if (!(descriptor instanceof SimpleFunctionDescriptor)) { return false; } DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); boolean isInvoke = descriptor.getName().equals(OperatorNameConventions.INVOKE) && containingDeclaration instanceof ClassDescriptor && FunctionTypesKt.isFunctionType( ((ClassDescriptor) containingDeclaration).getDefaultType()); return isInvoke || InlineUtil.isInline(descriptor); }
/*descriptor is null for captured vars*/ public boolean shouldPutValue( @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor descriptor) { if (stackValue == null) { // default or vararg return true; } // remap only inline functions (and maybe non primitives) // TODO - clean asserion and remapping logic if (isPrimitive(type) != isPrimitive(stackValue.type)) { // don't remap boxing/unboxing primitives - lost identity and perfomance return true; } if (stackValue instanceof StackValue.Local) { return false; } StackValue field = stackValue; if (stackValue instanceof StackValue.FieldForSharedVar) { field = ((StackValue.FieldForSharedVar) stackValue).receiver; } // check that value corresponds to captured inlining parameter if (field instanceof StackValue.Field) { DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor; // check that variable is inline function parameter return !(varDescriptor instanceof ParameterDescriptor && InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) && InlineUtil.isInline(varDescriptor.getContainingDeclaration())); } return true; }
private static boolean isInlinableParameter(@NotNull ParameterDescriptor descriptor) { return InlineUtil.isInlineLambdaParameter(descriptor) && !descriptor.getType().isMarkedNullable(); }
@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); }