mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
Add Proc#refined(mod, ...), which returns a new Proc that behaves like the receiver but with the refinements activated by the given modules in effect inside its body, without affecting the original Proc. This is an alternative to the previously proposed Proc#using (https://bugs.ruby-lang.org/issues/16461) that does not modify the existing block and needs no `using Proc::Refinements` declaration. Refinements are resolved at run time through the cref, so a refined proc gets two pieces of its own: * A cref carrying the additional refinements, built by activating the modules (rb_using_module_recursive, under the VM lock) on a duplicate of the block's captured cref. It is stored in a hidden ivar on the Proc and injected into the block frame on every proc-invocation path (Proc#call, yield from C methods, invokeblock/opt_call, and instance_eval/instance_exec/module_eval/class_eval via yield_under). The captured environment stays shared, so closure variables are still shared with the original Proc. `using` inside the body is rejected (CREF_REFINED_PROC), so the cref's refinements never change after publication. * A recursive deep copy of the block's instruction sequences (rb_iseq_dup_with_independent_caches) so the new Proc has its own inline method caches. This is required for correctness: the VM caches refinement method resolution per call site assuming a single lexical cref per iseq, so sharing the iseq would leak the refined methods into the original Proc. Coverage keeps measuring the copied iseq. The copy and the cref are memoized in a hidden identity Hash keyed by the source iseq (one slot per iseq, matched by the captured cref and the module arguments, accessed under the VM lock), so repeated calls at the same site reuse one copy and procs refined with the same modules share the iseq and the cref. A differing module set or a ruby2_keywords flag mismatch rebuilds the entry (with a performance warning). The refinements table of the memoized cref is frozen and marked shareable so the memo also serves other Ractors. Procs without an iseq block (Symbol#to_proc, C-function procs), procs created from methods, and procs that already have refinements are rejected with ArgumentError. The YJIT/ZJIT Rust bindings are regenerated for the new rb_proc_t field. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
44 lines
1.6 KiB
C
44 lines
1.6 KiB
C
#ifndef INTERNAL_EVAL_H /*-*-C-*-vi:se ft=c:*/
|
|
#define INTERNAL_EVAL_H
|
|
/**
|
|
* @author Ruby developers <ruby-core@ruby-lang.org>
|
|
* @copyright This file is a part of the programming language Ruby.
|
|
* Permission is hereby granted, to either redistribute and/or
|
|
* modify this file, provided that the conditions mentioned in the
|
|
* file COPYING are met. Consult the file for details.
|
|
* @brief Internal header for the evaluator.
|
|
* @note There also is eval_intern.h, which is evaluator's internal
|
|
* header (related to this file, but not the same role).
|
|
*/
|
|
#include "ruby/ruby.h" /* for ID */
|
|
#include "vm_core.h" /* for ID */
|
|
|
|
#define id_signo ruby_static_id_signo
|
|
#define id_status ruby_static_id_status
|
|
|
|
/* eval.c */
|
|
struct rb_refinements_data {
|
|
VALUE refinement;
|
|
VALUE refinements;
|
|
};
|
|
|
|
extern ID ruby_static_id_signo;
|
|
extern ID ruby_static_id_status;
|
|
VALUE rb_refinement_module_get_refined_class(VALUE module);
|
|
void rb_class_modify_check(VALUE);
|
|
NORETURN(VALUE rb_f_raise(int argc, VALUE *argv));
|
|
VALUE rb_exception_setup(int argc, VALUE *argv);
|
|
void rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass);
|
|
void rb_using_module_recursive(rb_cref_t *cref, VALUE module);
|
|
VALUE rb_top_main_class(const char *method);
|
|
VALUE rb_ec_ensure(rb_execution_context_t *ec, VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2);
|
|
|
|
/* eval_error.c */
|
|
VALUE rb_get_backtrace(VALUE info);
|
|
|
|
/* eval_jump.c */
|
|
void rb_call_end_proc(VALUE data);
|
|
void rb_mark_end_proc(void);
|
|
|
|
#endif /* INTERNAL_EVAL_H */
|