public LambdaInfo( @NotNull KtExpression expression, @NotNull KotlinTypeMapper typeMapper, boolean isCrossInline, boolean isBoundCallableReference) { this.isCrossInline = isCrossInline; this.expression = expression instanceof KtLambdaExpression ? ((KtLambdaExpression) expression).getFunctionLiteral() : expression; this.typeMapper = typeMapper; this.isBoundCallableReference = isBoundCallableReference; BindingContext bindingContext = typeMapper.getBindingContext(); FunctionDescriptor function = bindingContext.get(BindingContext.FUNCTION, this.expression); if (function == null && expression instanceof KtCallableReferenceExpression) { VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, this.expression); assert variableDescriptor instanceof VariableDescriptorWithAccessors : "Reference expression not resolved to variable descriptor with accessors: " + expression.getText(); classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor); closureClassType = typeMapper.mapClass(classDescriptor); SimpleFunctionDescriptor getFunction = PropertyReferenceCodegen.findGetFunction(variableDescriptor); functionDescriptor = PropertyReferenceCodegen.createFakeOpenDescriptor(getFunction, classDescriptor); ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert( ((KtCallableReferenceExpression) expression).getCallableReference(), bindingContext); propertyReferenceInfo = new PropertyReferenceInfo( (VariableDescriptor) resolvedCall.getResultingDescriptor(), getFunction); } else { propertyReferenceInfo = null; functionDescriptor = function; assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText(); classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor); closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor); } closure = bindingContext.get(CLOSURE, classDescriptor); assert closure != null : "Closure for lambda should be not null " + expression.getText(); labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor); }
@NotNull public List<CapturedParamDesc> getCapturedVars() { // lazy initialization cause it would be calculated after object creation if (capturedVars == null) { capturedVars = new ArrayList<CapturedParamDesc>(); if (closure.getCaptureThis() != null) { Type type = typeMapper.mapType(closure.getCaptureThis()); EnclosedValueDescriptor descriptor = new EnclosedValueDescriptor( AsmUtil.CAPTURED_THIS_FIELD, /* descriptor = */ null, StackValue.field( type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0), type); capturedVars.add(getCapturedParamInfo(descriptor)); } if (closure.getCaptureReceiverType() != null) { Type type = typeMapper.mapType(closure.getCaptureReceiverType()); EnclosedValueDescriptor descriptor = new EnclosedValueDescriptor( AsmUtil.CAPTURED_RECEIVER_FIELD, /* descriptor = */ null, StackValue.field( type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0), type); capturedVars.add(getCapturedParamInfo(descriptor)); } for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) { capturedVars.add(getCapturedParamInfo(descriptor)); } } return capturedVars; }
@NotNull public Parameters addAllParameters(@NotNull FieldRemapper remapper) { Method asmMethod = typeMapper.mapAsmMethod(getFunctionDescriptor()); ParametersBuilder builder = ParametersBuilder.initializeBuilderFrom( AsmTypes.OBJECT_TYPE, asmMethod.getDescriptor(), this); for (CapturedParamDesc info : getCapturedVars()) { CapturedParamInfo field = remapper.findField( new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), "")); assert field != null : "Captured field not found: " + info.getContainingLambdaName() + "." + info.getFieldName(); builder.addCapturedParam(field, info.getFieldName()); } return builder.buildParameters(); }
@NotNull public List<Type> getInvokeParamsWithoutCaptured() { return Arrays.asList(typeMapper.mapAsmMethod(functionDescriptor).getArgumentTypes()); }