Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Make Proc::from_env reset klass if appropriate

Make Proc::from_env duplicate a passed object (env) and reset its klass if the
receiver class is different from env's class to support following code:

    class MyProc < Proc
    end
    MyProc.new(&proc) # => should return an instance of MyProc

By this modification, we shoudn't use the Proc::from_env to assign a block
to a method parameter like this:

    def each(&block)
      # ...
    end

Instead, we should use the original Proc::from_env. The reason is that when a
sub-classed proc instance is passed to such a method, the proc would
unnecessarily be converted to a Proc by the modified Proc::from_env.
  • Loading branch information...
commit 1abfbdf84e3dac829b9495d548ce43d10cf17d6b 1 parent 2539ba9
@ryoqun ryoqun authored
View
5 vm/builtin/proc.cpp
@@ -33,6 +33,11 @@ namespace rubinius {
Proc* Proc::from_env(STATE, Object* self, Object* env) {
if(Proc* p = try_as<Proc>(env)) {
+ if(p->klass() != self &&
+ p->klass() != G(proc)->get_const(state, "Method")) {
+ p = as<Proc>(p->duplicate(state));
+ p->klass(state, as<Class>(self));
+ }
return p;
}
View
9 vm/instructions.def
@@ -2149,8 +2149,13 @@ instruction push_proc() [ -- value ]
Object* obj = call_frame->arguments->block();
if(CBOOL(obj)) {
- Object* prc = Proc::from_env(state, G(proc), obj);
- if(prc == Primitives::failure()) {
+ Proc* prc;
+ if(BlockEnvironment *env = try_as<BlockEnvironment>(obj)) {
+ prc = Proc::create(state, G(proc));
+ prc->block(state, env);
+ } else if(Proc* p = try_as<Proc>(obj)) {
+ prc = p;
+ } else {
Exception::internal_error(state, call_frame, "invalid block type");
RUN_EXCEPTION();
}
View
9 vm/llvm/jit_util.cpp
@@ -1513,8 +1513,13 @@ extern "C" {
Object* rbx_make_proc(STATE, CallFrame* call_frame) {
Object* obj = call_frame->scope->block();
if(CBOOL(obj)) {
- Object* prc = Proc::from_env(state, G(proc), obj);
- if(prc == Primitives::failure()) {
+ Proc* prc;
+ if(BlockEnvironment *env = try_as<BlockEnvironment>(obj)) {
+ prc = Proc::create(state, G(proc));
+ prc->block(state, env);
+ } else if(Proc* p = try_as<Proc>(obj)) {
+ prc = p;
+ } else {
Exception::internal_error(state, call_frame, "invalid block type");
return 0;
}
Please sign in to comment.
Something went wrong with that request. Please try again.