mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	proc.c: rb_block_min_max_arity * proc.c (rb_block_min_max_arity): new function to get arity range from the current block. vm_eval.c: rb_lambda_call * enum.c (enum_collect): make the block arity same as the given block. [Bug #13391] * internal.h (vm_ifunc): store arity instead of unused id. * proc.c (rb_vm_block_min_max_arity): return ifunc arity. * vm_eval.c (rb_lambda_call): call method with lambda block. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_4@59500 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									91b51140d7
								
							
						
					
					
						commit
						568472906b
					
				
					 6 changed files with 106 additions and 16 deletions
				
			
		
							
								
								
									
										4
									
								
								enum.c
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								enum.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -496,11 +496,13 @@ static VALUE
 | 
			
		|||
enum_collect(VALUE obj)
 | 
			
		||||
{
 | 
			
		||||
    VALUE ary;
 | 
			
		||||
    int min_argc, max_argc;
 | 
			
		||||
 | 
			
		||||
    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
 | 
			
		||||
 | 
			
		||||
    ary = rb_ary_new();
 | 
			
		||||
    rb_block_call(obj, id_each, 0, 0, collect_i, ary);
 | 
			
		||||
    min_argc = rb_block_min_max_arity(&max_argc);
 | 
			
		||||
    rb_lambda_call(obj, id_each, 0, 0, collect_i, min_argc, max_argc, ary);
 | 
			
		||||
 | 
			
		||||
    return ary;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										23
									
								
								internal.h
									
										
									
									
									
								
							
							
						
						
									
										23
									
								
								internal.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -790,15 +790,30 @@ struct vm_throw_data {
 | 
			
		|||
 | 
			
		||||
/* IFUNC */
 | 
			
		||||
 | 
			
		||||
struct vm_ifunc_argc {
 | 
			
		||||
#if SIZEOF_INT * 2 > SIZEOF_VALUE
 | 
			
		||||
    int min: (SIZEOF_VALUE * CHAR_BIT) / 2;
 | 
			
		||||
    int max: (SIZEOF_VALUE * CHAR_BIT) / 2;
 | 
			
		||||
#else
 | 
			
		||||
    int min, max;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct vm_ifunc {
 | 
			
		||||
    VALUE flags;
 | 
			
		||||
    VALUE reserved;
 | 
			
		||||
    VALUE (*func)(ANYARGS);
 | 
			
		||||
    const void *data;
 | 
			
		||||
    ID id;
 | 
			
		||||
    struct vm_ifunc_argc argc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define IFUNC_NEW(a, b, c) ((struct vm_ifunc *)rb_imemo_new(imemo_ifunc, (VALUE)(a), (VALUE)(b), (VALUE)(c), 0))
 | 
			
		||||
struct vm_ifunc *rb_vm_ifunc_new(VALUE (*func)(ANYARGS), const void *data, int min_argc, int max_argc);
 | 
			
		||||
static inline struct vm_ifunc *
 | 
			
		||||
rb_vm_ifunc_proc_new(VALUE (*func)(ANYARGS), const void *data)
 | 
			
		||||
{
 | 
			
		||||
    return rb_vm_ifunc_new(func, data, 0, UNLIMITED_ARGUMENTS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* MEMO */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1335,8 +1350,9 @@ ID rb_id_attrget(ID id);
 | 
			
		|||
VALUE rb_proc_location(VALUE self);
 | 
			
		||||
st_index_t rb_hash_proc(st_index_t hash, VALUE proc);
 | 
			
		||||
int rb_block_arity(void);
 | 
			
		||||
int rb_block_min_max_arity(int *max);
 | 
			
		||||
VALUE rb_func_proc_new(rb_block_call_func_t func, VALUE val);
 | 
			
		||||
VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val);
 | 
			
		||||
VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc);
 | 
			
		||||
 | 
			
		||||
/* process.c */
 | 
			
		||||
#define RB_MAX_GROUPS (65536)
 | 
			
		||||
| 
						 | 
				
			
			@ -1596,6 +1612,9 @@ VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE);
 | 
			
		|||
VALUE rb_catch_protect(VALUE t, rb_block_call_func *func, VALUE data, int *stateptr);
 | 
			
		||||
VALUE rb_yield_1(VALUE val);
 | 
			
		||||
VALUE rb_yield_lambda(VALUE values);
 | 
			
		||||
VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
 | 
			
		||||
		     rb_block_call_func_t bl_proc, int min_argc, int max_argc,
 | 
			
		||||
		     VALUE data2);
 | 
			
		||||
 | 
			
		||||
/* vm_insnhelper.c */
 | 
			
		||||
VALUE rb_equal_opt(VALUE obj1, VALUE obj2);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										70
									
								
								proc.c
									
										
									
									
									
								
							
							
						
						
									
										70
									
								
								proc.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -635,16 +635,47 @@ sym_proc_new(VALUE klass, VALUE sym)
 | 
			
		|||
    return procval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
rb_func_proc_new(rb_block_call_func_t func, VALUE val)
 | 
			
		||||
struct vm_ifunc *
 | 
			
		||||
rb_vm_ifunc_new(VALUE (*func)(ANYARGS), const void *data, int min_argc, int max_argc)
 | 
			
		||||
{
 | 
			
		||||
    return cfunc_proc_new(rb_cProc, (VALUE)IFUNC_NEW(func, val, 0), 0);
 | 
			
		||||
    union {
 | 
			
		||||
	struct vm_ifunc_argc argc;
 | 
			
		||||
	VALUE packed;
 | 
			
		||||
    } arity;
 | 
			
		||||
 | 
			
		||||
    if (min_argc < UNLIMITED_ARGUMENTS ||
 | 
			
		||||
#if SIZEOF_INT * 2 > SIZEOF_VALUE
 | 
			
		||||
	min_argc >= (int)(1U << (SIZEOF_VALUE * CHAR_BIT) / 2) ||
 | 
			
		||||
#endif
 | 
			
		||||
	0) {
 | 
			
		||||
	rb_raise(rb_eRangeError, "minimum argument number out of range: %d",
 | 
			
		||||
		 min_argc);
 | 
			
		||||
    }
 | 
			
		||||
    if (max_argc < UNLIMITED_ARGUMENTS ||
 | 
			
		||||
#if SIZEOF_INT * 2 > SIZEOF_VALUE
 | 
			
		||||
	max_argc >= (int)(1U << (SIZEOF_VALUE * CHAR_BIT) / 2) ||
 | 
			
		||||
#endif
 | 
			
		||||
	0) {
 | 
			
		||||
	rb_raise(rb_eRangeError, "maximum argument number out of range: %d",
 | 
			
		||||
		 max_argc);
 | 
			
		||||
    }
 | 
			
		||||
    arity.argc.min = min_argc;
 | 
			
		||||
    arity.argc.max = max_argc;
 | 
			
		||||
    return IFUNC_NEW(func, data, arity.packed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
rb_func_lambda_new(rb_block_call_func_t func, VALUE val)
 | 
			
		||||
rb_func_proc_new(rb_block_call_func_t func, VALUE val)
 | 
			
		||||
{
 | 
			
		||||
    return cfunc_proc_new(rb_cProc, (VALUE)IFUNC_NEW(func, val, 0), 1);
 | 
			
		||||
    struct vm_ifunc *ifunc = rb_vm_ifunc_proc_new(func, (void *)val);
 | 
			
		||||
    return cfunc_proc_new(rb_cProc, (VALUE)ifunc, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc)
 | 
			
		||||
{
 | 
			
		||||
    struct vm_ifunc *ifunc = rb_vm_ifunc_new(func, (void *)val, min_argc, max_argc);
 | 
			
		||||
    return cfunc_proc_new(rb_cProc, (VALUE)ifunc, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char proc_without_block[] = "tried to create Proc object without a block";
 | 
			
		||||
| 
						 | 
				
			
			@ -928,13 +959,13 @@ rb_iseq_min_max_arity(const rb_iseq_t *iseq, int *max)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
rb_block_min_max_arity(const struct rb_block *block, int *max)
 | 
			
		||||
rb_vm_block_min_max_arity(const struct rb_block *block, int *max)
 | 
			
		||||
{
 | 
			
		||||
    switch (vm_block_type(block)) {
 | 
			
		||||
      case block_type_iseq:
 | 
			
		||||
	return rb_iseq_min_max_arity(block->as.captured.code.iseq, max);
 | 
			
		||||
      case block_type_proc:
 | 
			
		||||
	return rb_block_min_max_arity(vm_proc_block(block->as.proc), max);
 | 
			
		||||
	return rb_vm_block_min_max_arity(vm_proc_block(block->as.proc), max);
 | 
			
		||||
      case block_type_ifunc:
 | 
			
		||||
	{
 | 
			
		||||
	    const struct vm_ifunc *ifunc = block->as.captured.code.ifunc;
 | 
			
		||||
| 
						 | 
				
			
			@ -942,8 +973,9 @@ rb_block_min_max_arity(const struct rb_block *block, int *max)
 | 
			
		|||
		/* e.g. method(:foo).to_proc.arity */
 | 
			
		||||
		return method_min_max_arity((VALUE)ifunc->data, max);
 | 
			
		||||
	    }
 | 
			
		||||
	    *max = ifunc->argc.max;
 | 
			
		||||
	    return ifunc->argc.min;
 | 
			
		||||
	}
 | 
			
		||||
	/* fall through */
 | 
			
		||||
      case block_type_symbol:
 | 
			
		||||
	break;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -962,7 +994,7 @@ rb_proc_min_max_arity(VALUE self, int *max)
 | 
			
		|||
{
 | 
			
		||||
    rb_proc_t *proc;
 | 
			
		||||
    GetProcPtr(self, proc);
 | 
			
		||||
    return rb_block_min_max_arity(&proc->block, max);
 | 
			
		||||
    return rb_vm_block_min_max_arity(&proc->block, max);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
| 
						 | 
				
			
			@ -971,7 +1003,7 @@ rb_proc_arity(VALUE self)
 | 
			
		|||
    rb_proc_t *proc;
 | 
			
		||||
    int max, min;
 | 
			
		||||
    GetProcPtr(self, proc);
 | 
			
		||||
    min = rb_block_min_max_arity(&proc->block, &max);
 | 
			
		||||
    min = rb_vm_block_min_max_arity(&proc->block, &max);
 | 
			
		||||
    return (proc->is_lambda ? min == max : max != UNLIMITED_ARGUMENTS) ? min : -min-1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1011,7 +1043,7 @@ rb_block_arity(void)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    block_setup(&block, block_handler);
 | 
			
		||||
    min = rb_block_min_max_arity(&block, &max);
 | 
			
		||||
    min = rb_vm_block_min_max_arity(&block, &max);
 | 
			
		||||
 | 
			
		||||
    switch (vm_block_type(&block)) {
 | 
			
		||||
      case block_handler_type_symbol:
 | 
			
		||||
| 
						 | 
				
			
			@ -1031,6 +1063,22 @@ rb_block_arity(void)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
rb_block_min_max_arity(int *max)
 | 
			
		||||
{
 | 
			
		||||
    rb_thread_t *th = GET_THREAD();
 | 
			
		||||
    rb_control_frame_t *cfp = th->cfp;
 | 
			
		||||
    VALUE block_handler = rb_vm_frame_block_handler(cfp);
 | 
			
		||||
    struct rb_block block;
 | 
			
		||||
 | 
			
		||||
    if (block_handler == VM_BLOCK_HANDLER_NONE) {
 | 
			
		||||
	rb_raise(rb_eArgError, "no block given");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    block_setup(&block, block_handler);
 | 
			
		||||
    return rb_vm_block_min_max_arity(&block, max);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rb_iseq_t *
 | 
			
		||||
rb_proc_get_iseq(VALUE self, int *is_proc)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -798,6 +798,10 @@ class TestEnumerable < Test::Unit::TestCase
 | 
			
		|||
    lambda2 = ->(x, i) { [x.upcase, i] }
 | 
			
		||||
    assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
 | 
			
		||||
      @obj.each_with_index.map(&lambda2))
 | 
			
		||||
 | 
			
		||||
    hash = { a: 'hoge', b: 'fuga' }
 | 
			
		||||
    lambda = -> (k, v) { "#{k}:#{v}" }
 | 
			
		||||
    assert_equal ["a:hoge", "b:fuga"], hash.map(&lambda)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_flat_map
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
#define RUBY_VERSION "2.4.2"
 | 
			
		||||
#define RUBY_RELEASE_DATE "2017-08-04"
 | 
			
		||||
#define RUBY_PATCHLEVEL 167
 | 
			
		||||
#define RUBY_PATCHLEVEL 168
 | 
			
		||||
 | 
			
		||||
#define RUBY_RELEASE_YEAR 2017
 | 
			
		||||
#define RUBY_RELEASE_MONTH 8
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								vm_eval.c
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								vm_eval.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1203,7 +1203,7 @@ rb_iterate(VALUE (* it_proc)(VALUE), VALUE data1,
 | 
			
		|||
	   VALUE (* bl_proc)(ANYARGS), VALUE data2)
 | 
			
		||||
{
 | 
			
		||||
    return rb_iterate0(it_proc, data1,
 | 
			
		||||
		       bl_proc ? IFUNC_NEW(bl_proc, data2, rb_frame_this_func()) : 0,
 | 
			
		||||
		       bl_proc ? rb_vm_ifunc_proc_new(bl_proc, (void *)data2) : 0,
 | 
			
		||||
		       GET_THREAD());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1236,6 +1236,23 @@ rb_block_call(VALUE obj, ID mid, int argc, const VALUE * argv,
 | 
			
		|||
    return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
 | 
			
		||||
	       rb_block_call_func_t bl_proc, int min_argc, int max_argc,
 | 
			
		||||
	       VALUE data2)
 | 
			
		||||
{
 | 
			
		||||
    struct iter_method_arg arg;
 | 
			
		||||
    struct vm_ifunc *block;
 | 
			
		||||
 | 
			
		||||
    if (!bl_proc) rb_raise(rb_eArgError, "NULL lambda function");
 | 
			
		||||
    arg.obj = obj;
 | 
			
		||||
    arg.mid = mid;
 | 
			
		||||
    arg.argc = argc;
 | 
			
		||||
    arg.argv = argv;
 | 
			
		||||
    block = rb_vm_ifunc_new(bl_proc, (void *)data2, min_argc, max_argc);
 | 
			
		||||
    return rb_iterate0(iterate_method, (VALUE)&arg, block, GET_THREAD());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
iterate_check_method(VALUE obj)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue