private ClassDescriptor recordClassForFunction(FunctionDescriptor funDescriptor) { ClassDescriptor classDescriptor; int arity = funDescriptor.getValueParameters().size(); classDescriptor = new ClassDescriptorImpl( funDescriptor.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), Modality.FINAL, Name.special("<closure>")); ((ClassDescriptorImpl) classDescriptor) .initialize( false, Collections.<TypeParameterDescriptor>emptyList(), Collections.singleton( (funDescriptor.getReceiverParameter().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity)) .getDefaultType()), JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null); assert PsiCodegenPredictor.checkPredictedClassNameForFun( bindingContext, funDescriptor, classDescriptor); bindingTrace.record(CLASS_FOR_FUNCTION, funDescriptor, classDescriptor); return classDescriptor; }
@Override public StackValue innerValue( DeclarationDescriptor d, LocalLookup localLookup, GenerationState state, MutableClosure closure, Type classType) { FunctionDescriptor vd = (FunctionDescriptor) d; boolean idx = localLookup != null && localLookup.lookupLocal(vd); if (!idx) return null; BindingContext bindingContext = state.getBindingContext(); Type localType = asmTypeForAnonymousClass(bindingContext, vd); MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_FUNCTION, vd)); if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) { // This is an optimization: we can obtain an instance of a const closure simply by // GETSTATIC ...$instance // (instead of passing this instance to the constructor and storing as a field) return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true); } String fieldName = "$" + vd.getName(); StackValue innerValue = StackValue.field(localType, classType, fieldName, false); closure.recordField(fieldName, localType); closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType)); return innerValue; }
@Override public void visitNamedFunction(JetNamedFunction function) { FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, function); // working around a problem with shallow analysis if (functionDescriptor == null) return; DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); if (containingDeclaration instanceof ClassDescriptor) { nameStack.push(peekFromStack(nameStack) + '$' + function.getName()); super.visitNamedFunction(function); nameStack.pop(); } else if (containingDeclaration instanceof NamespaceDescriptor) { String peek = peekFromStack(nameStack); if (peek.isEmpty()) { peek = JvmAbi.PACKAGE_CLASS; } else { peek += "/" + JvmAbi.PACKAGE_CLASS; } nameStack.push(peek + '$' + function.getName()); super.visitNamedFunction(function); nameStack.pop(); } else { String name = inventAnonymousClassName(function); ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor); recordClosure( bindingTrace, function, classDescriptor, peekFromStack(classStack), JvmClassName.byInternalName(name), true); classStack.push(classDescriptor); nameStack.push(name); super.visitNamedFunction(function); nameStack.pop(); classStack.pop(); } }