Ticket #696 (closed bug: fixed)

Opened 6 years ago

Last modified 5 years ago

Can't assign an object to Undef.

Reported by: coke Owned by: whiteknight
Priority: normal Milestone:
Component: none Version: 1.2.0
Severity: medium Keywords: tcl blocker
Cc: Language:
Patch status: Platform:

Description

.sub main :main
  say "1..2"

  $P0 = new "Undef"
  $P2 = new 'Integer'
  assign $P0, $P2
  say "ok 1"

  $P0 = new "Undef"
  $P1 = newclass "HI"
  $P2 = new $P1
  assign $P0, $P2
  say "ok 2"
.end

Generates

1..2
ok 1
Object must be created by a class.
current instr.: 'main' pc 22 (foo.pir:14)

partcl used this code in a few places, behavior changed sometime since 0.9.0 or so.

Change History

  Changed 6 years ago by whiteknight

  • status changed from new to assigned
  • owner changed from Whiteknight to whiteknight

  Changed 6 years ago by whiteknight

I was hoping that this would be very straight forward to fix, but it doesn't appear to be when I look (or maybe I make it more complicated then it is).

The assignment operation calls the Undef assign VTABLE, which calls the set_pmc VTABLE, which calls pmc_reuse, which eventually calls the init VTABLE on the new Object PMC, which throws the exception we see here.

My initial reaction was that we could easily modify pmc_reuse to not call VTABLE_init when the new PMC is an Object. However in some cases, such as the case above, this would allow us to create an object of a class without first instantiating that class (which is the problem we try to prevent by throwing an exception from Object:init in the first place).

Then, I tried this:

VTABLE void set_pmc(PMC *other) {
    if(other->vtable->base_type != enum_class_Object)
        pmc_reuse(INTERP, SELF, other->vtable->base_type, 0);
    else {
        PMC * temp = VTABLE_instantiate(INTERP, other->vtable->pmc_class, PMCNULL);
        SELF->vtable = temp->vtable;
    }
    VTABLE_set_pmc(INTERP, SELF, other);
}

...but that causes a segfault instead of an exception, which is worse.

So I'm not sure exactly what to do here. I'm sure there's an easy solution that I just can't think of, or a function to call that I'm not aware of. Any suggestions?

follow-up: ↓ 6   Changed 6 years ago by whiteknight

Okay, we looked at this for a while tonight, and here's what Allison++ came up with:

<allison> Whiteknight: okay, here's my recommendation:
<allison> Whiteknight: take the contents of the 'clone' vtable function in src/pmc/object.pmc and change them into a function in src/oo.c named Parrot_oo_clone_object
<allison> Whiteknight: make the function take an optional PMC argument, the destination of the clone
<allison> Whiteknight: when the (optional) destination PMC is passed, morph it to the object type, when it's not passed, create a new object
<allison> Whiteknight: otherwise, the behavior is the same as Object PMC's 'clone

So I'm going to start working on that tomorrowish. I'll post updates as I get them.

  Changed 6 years ago by whiteknight

Okay, this test example is working in the tt_696 branch now. I need to add a few tests for this behavior to prevent regression first and then I will merge it into trunk.

  Changed 6 years ago by whiteknight

  • status changed from assigned to closed
  • resolution set to fixed

I merged the branch into trunk in r39087. this makes everything work for me, so I'm closing the ticket. We can reopen it if somebody finds a problem.

in reply to: ↑ 3   Changed 6 years ago by pmichaud

Replying to whiteknight:

Okay, we looked at this for a while tonight, and here's what Allison++ came up with: {{{ <allison> Whiteknight: okay, here's my recommendation: <allison> Whiteknight: take the contents of the 'clone' vtable function in src/pmc/object.pmc and change them into a function in src/oo.c named Parrot_oo_clone_object <allison> Whiteknight: make the function take an optional PMC argument, the destination of the clone <allison> Whiteknight: when the (optional) destination PMC is passed, morph it to the object type, when it's not passed, create a new object <allison> Whiteknight: otherwise, the behavior is the same as Object PMC's 'clone }}}

For whatever it's worth, the above description sounds an awful lot like the behavior of the 'copy' opcode (which was created precisely to workaround the problems of assigning to existing PMCs such as Undef).

Pm

Note: See TracTickets for help on using tickets.