Merge branch 'metadata' into mooseish-types
Lukas Mai [Wed, 14 Nov 2012 14:16:45 +0000 (15:16 +0100)]
1  2 
Parameters.xs

diff --combined Parameters.xs
@@@ -96,9 -96,7 +96,9 @@@ enum 
        FLAG_DEFAULT_ARGS = 0x04,
        FLAG_CHECK_NARGS  = 0x08,
        FLAG_INVOCANT     = 0x10,
 -      FLAG_NAMED_PARAMS = 0x20
 +      FLAG_NAMED_PARAMS = 0x20,
 +      FLAG_TYPES_OK     = 0x40,
 +      FLAG_CHECK_TARGS  = 0x80
  };
  
  DEFSTRUCT(KWSpec) {
@@@ -121,9 -119,7 +121,9 @@@ static void sentinel_clear_void(pTHX_ v
        Resource **pp = p;
        while (*pp) {
                Resource *cur = *pp;
 -              cur->destroy(aTHX_ cur->data);
 +              if (cur->destroy) {
 +                      cur->destroy(aTHX_ cur->data);
 +              }
                cur->data = (void *)"no";
                cur->destroy = NULL;
                *pp = cur->next;
        }
  }
  
 -static void sentinel_register(Sentinel sen, void *data, void (*destroy)(pTHX_ void *)) {
 +static Resource *sentinel_register(Sentinel sen, void *data, void (*destroy)(pTHX_ void *)) {
        Resource *cur;
  
        Newx(cur, 1, Resource);
        cur->destroy = destroy;
        cur->next = *sen;
        *sen = cur;
 +
 +      return cur;
 +}
 +
 +static void sentinel_disarm(Resource *p) {
 +      p->destroy = NULL;
  }
  
  static void my_sv_refcnt_dec_void(pTHX_ void *p) {
@@@ -252,17 -242,12 +252,17 @@@ static int kw_flags(pTHX_ Sentinel sen
  }
  
  
 -static void free_ptr_op(pTHX_ void *vp) {
 +static void free_ptr_op_void(pTHX_ void *vp) {
        OP **pp = vp;
        op_free(*pp);
        Safefree(pp);
  }
  
 +static void free_op_void(pTHX_ void *vp) {
 +      OP *p = vp;
 +      op_free(p);
 +}
 +
  #define sv_eq_pvs(SV, S) my_sv_eq_pvn(aTHX_ SV, "" S "", sizeof (S) - 1)
  
  static int my_sv_eq_pvn(pTHX_ SV *sv, const char *p, STRLEN n) {
@@@ -504,97 -489,10 +504,97 @@@ static void my_check_prototype(pTHX_ Se
        }
  }
  
 +static SV *parse_type(pTHX_ Sentinel, const SV *);
 +
 +static SV *parse_type_paramd(pTHX_ Sentinel sen, const SV *declarator) {
 +      I32 c;
 +      SV *t;
 +
 +      t = my_scan_word(aTHX_ sen, TRUE);
 +      lex_read_space(0);
 +
 +      c = lex_peek_unichar(0);
 +      if (c == '[') {
 +              SV *u;
 +
 +              lex_read_unichar(0);
 +              lex_read_space(0);
 +              my_sv_cat_c(aTHX_ t, c);
 +
 +              u = parse_type(aTHX_ sen, declarator);
 +              sv_catsv(t, u);
 +
 +              c = lex_peek_unichar(0);
 +              if (c != ']') {
 +                      croak("In %"SVf": missing ']' after '%"SVf"'", SVfARG(declarator), SVfARG(t));
 +              }
 +              lex_read_unichar(0);
 +              lex_read_space(0);
 +
 +              my_sv_cat_c(aTHX_ t, c);
 +      }
 +
 +      return t;
 +}
 +
 +static SV *parse_type(pTHX_ Sentinel sen, const SV *declarator) {
 +      I32 c;
 +      SV *t;
 +
 +      t = parse_type_paramd(aTHX_ sen, declarator);
 +
 +      c = lex_peek_unichar(0);
 +      while (c == '|') {
 +              SV *u;
 +
 +              lex_read_unichar(0);
 +              lex_read_space(0);
 +
 +              my_sv_cat_c(aTHX_ t, c);
 +              u = parse_type_paramd(aTHX_ sen, declarator);
 +              sv_catsv(t, u);
 +
 +              c = lex_peek_unichar(0);
 +      }
 +
 +      return t;
 +}
 +
 +static SV *reify_type(pTHX_ Sentinel sen, const SV *declarator, SV *name) {
 +      SV *t;
 +      int n;
 +      dSP;
 +
 +      ENTER;
 +      SAVETMPS;
 +
 +      PUSHMARK(SP);
 +      EXTEND(SP, 1);
 +      PUSHs(name);
 +      PUTBACK;
 +
 +      n = call_pv("Moose::Util::TypeConstraints::find_or_parse_type_constraint", G_SCALAR);
 +      SPAGAIN;
 +
 +      assert(n == 1);
 +      t = sentinel_mortalize(sen, SvREFCNT_inc(POPs));
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +
 +      if (!SvTRUE(t)) {
 +              croak("In %"SVf": undefined type '%"SVf"'", SVfARG(declarator), SVfARG(name));
 +      }
 +
 +      return t;
 +}
 +
  
  DEFSTRUCT(Param) {
        SV *name;
        PADOFFSET padoff;
 +      SV *type;
  };
  
  DEFSTRUCT(ParamInit) {
@@@ -634,7 -532,6 +634,7 @@@ DEFVECTOR_INIT(piv_init, ParamInit)
  static void p_init(Param *p) {
        p->name = NULL;
        p->padoff = NOT_IN_PAD;
 +      p->type = NULL;
  }
  
  static void ps_init(ParamSpec *ps) {
@@@ -673,7 -570,6 +673,7 @@@ DEFVECTOR_EXTEND(piv_extend, ParamInit)
  static void p_clear(pTHX_ Param *p) {
        p->name = NULL;
        p->padoff = NOT_IN_PAD;
 +      p->type = NULL;
  }
  
  static void pi_clear(pTHX_ ParamInit *pi) {
@@@ -775,35 -671,6 +775,35 @@@ static size_t count_named_params(const 
        return ps->named_required.used + ps->named_optional.used;
  }
  
 +static void my_require(pTHX_ const char *file) {
 +      require_pv(file);
 +      if (SvTRUE(ERRSV)) {
 +              croak_sv(ERRSV);
 +      }
 +}
 +
 +static SV *my_eval(pTHX_ Sentinel sen, I32 floor, OP *op) {
 +      SV *sv;
 +      CV *cv;
 +      dSP;
 +
 +      cv = newATTRSUB(floor, NULL, NULL, NULL, op);
 +
 +      ENTER;
 +      SAVETMPS;
 +
 +      PUSHMARK(SP);
 +      call_sv((SV *)cv, G_SCALAR | G_NOARGS);
 +      SPAGAIN;
 +      sv = sentinel_mortalize(sen, SvREFCNT_inc(POPs));
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +
 +      return sv;
 +}
 +
  enum {
        PARAM_INVOCANT = 0x01,
        PARAM_NAMED    = 0x02
@@@ -816,7 -683,7 +816,7 @@@ static PADOFFSET parse_param
        pTHX_
        Sentinel sen,
        const SV *declarator, const KWSpec *spec, ParamSpec *param_spec,
 -      int *pflags, SV **pname, OP **pinit
 +      int *pflags, SV **pname, OP **pinit, SV **ptype
  ) {
        I32 c;
        char sigil;
  
        assert(!*pinit);
        *pflags = 0;
 +      *ptype = NULL;
  
        c = lex_peek_unichar(0);
  
 +      if (spec->flags & FLAG_TYPES_OK) {
 +              if (c == '(') {
 +                      I32 floor;
 +                      OP *expr;
 +                      Resource *expr_sentinel;
 +
 +                      lex_read_unichar(0);
 +
 +                      floor = start_subparse(FALSE, 0);
 +                      SAVEFREESV(PL_compcv);
 +                      CvSPECIAL_on(PL_compcv);
 +
 +                      if (!(expr = parse_fullexpr(PARSE_OPTIONAL))) {
 +                              croak("In %"SVf": invalid type expression", SVfARG(declarator));
 +                      }
 +                      expr_sentinel = sentinel_register(sen, expr, free_op_void);
 +
 +                      lex_read_space(0);
 +                      c = lex_peek_unichar(0);
 +                      if (c != ')') {
 +                              croak("In %"SVf": missing ')' after type expression", SVfARG(declarator));
 +                      }
 +                      lex_read_unichar(0);
 +                      lex_read_space(0);
 +
 +                      SvREFCNT_inc_simple_void(PL_compcv);
 +                      sentinel_disarm(expr_sentinel);
 +                      *ptype = my_eval(aTHX_ sen, floor, expr);
 +                      *ptype = reify_type(aTHX_ sen, declarator, *ptype);
 +                      if (!sv_isobject(*ptype)) {
 +                              croak("In %"SVf": (%"SVf") doesn't look like a type object", SVfARG(declarator), SVfARG(*ptype));
 +                      }
 +
 +                      c = lex_peek_unichar(0);
 +              } else if (my_is_uni_xidfirst(aTHX_ c)) {
 +                      *ptype = parse_type(aTHX_ sen, declarator);
 +                      my_require(aTHX_ "Moose/Util/TypeConstraints.pm");
 +                      *ptype = reify_type(aTHX_ sen, declarator, *ptype);
 +
 +                      c = lex_peek_unichar(0);
 +              }
 +      }
 +
        if (c == ':') {
                lex_read_unichar(0);
                lex_read_space(0);
        if (c == -1) {
                croak("In %"SVf": unterminated parameter list", SVfARG(declarator));
        }
 +
        if (!(c == '$' || c == '@' || c == '%')) {
                croak("In %"SVf": unexpected '%c' in parameter list (expecting a sigil)", SVfARG(declarator), (int)c);
        }
@@@ -964,63 -786,6 +964,63 @@@ static OP *mkconstpv(pTHX_ const char *
  
  #define mkconstpvs(S) mkconstpv(aTHX_ "" S "", sizeof S - 1)
  
 +static OP *mktypecheck(pTHX_ const SV *declarator, int nr, SV *name, PADOFFSET padoff, SV *type) {
 +      /* $type->check($value) or Carp::croak "...: " . $type->get_message($value) */
 +      OP *chk, *cond, *err, *msg, *xcroak;
 +
 +      err = mkconstsv(aTHX_ newSVpvf("In %"SVf": parameter %d (%"SVf"): ", SVfARG(declarator), nr, SVfARG(name)));
 +      {
 +              OP *args = NULL;
 +
 +              args = op_append_elem(OP_LIST, args, mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(type)));
 +              args = op_append_elem(
 +                      OP_LIST, args,
 +                      padoff == NOT_IN_PAD
 +                              ? S_newDEFSVOP(aTHX)
 +                              : my_var(aTHX_ 0, padoff)
 +              );
 +              args = op_append_elem(OP_LIST, args, newUNOP(OP_METHOD, 0, mkconstpvs("get_message")));
 +
 +              msg = args;
 +              msg->op_type = OP_ENTERSUB;
 +              msg->op_ppaddr = PL_ppaddr[OP_ENTERSUB];
 +              msg->op_flags |= OPf_STACKED;
 +      }
 +
 +      msg = newBINOP(OP_CONCAT, 0, err, msg);
 +
 +      xcroak = newCVREF(
 +              OPf_WANT_SCALAR,
 +              newGVOP(OP_GV, 0, gv_fetchpvs("Carp::croak", 0, SVt_PVCV))
 +      );
 +      xcroak = newUNOP(OP_ENTERSUB, OPf_STACKED, op_append_elem(OP_LIST, msg, xcroak));
 +
 +      {
 +              OP *args = NULL;
 +
 +              args = op_append_elem(OP_LIST, args, mkconstsv(aTHX_ SvREFCNT_inc_simple_NN(type)));
 +              args = op_append_elem(
 +                      OP_LIST, args,
 +                      padoff == NOT_IN_PAD
 +                              ? S_newDEFSVOP(aTHX)
 +                              : my_var(aTHX_ 0, padoff)
 +              );
 +              args = op_append_elem(OP_LIST, args, newUNOP(OP_METHOD, 0, mkconstpvs("check")));
 +
 +              chk = args;
 +              chk->op_type = OP_ENTERSUB;
 +              chk->op_ppaddr = PL_ppaddr[OP_ENTERSUB];
 +              chk->op_flags |= OPf_STACKED;
 +      }
 +
 +      chk = newLOGOP(OP_OR, 0, chk, xcroak);
 +      return chk;
 +}
 +
 +static OP *mktypecheckp(pTHX_ const SV *declarator, int nr, const Param *param) {
 +      return mktypecheck(aTHX_ declarator, nr, param->name, param->padoff, param->type);
 +}
 +
  static void register_info(pTHX_ UV key, SV *declarator, const KWSpec *kws, const ParamSpec *ps) {
        dSP;
  
        SAVETMPS;
  
        PUSHMARK(SP);
 -      EXTEND(SP, 8);
 +      EXTEND(SP, 10);
  
        /* 0 */ {
                mPUSHu(key);
                size_t n;
                char *p = SvPV(declarator, n);
                char *q = memchr(p, ' ', n);
-               mPUSHp(p, q ? q - p : n);
+               mPUSHp(p, q ? (size_t)(q - p) : n);
        }
        if (!ps) {
                if (SvTRUE(kws->shift)) {
                } else {
                        PUSHmortal;
                }
 +              PUSHmortal;
                mPUSHs(newRV_noinc((SV *)newAV()));
                mPUSHs(newRV_noinc((SV *)newAV()));
                mPUSHs(newRV_noinc((SV *)newAV()));
                mPUSHs(newRV_noinc((SV *)newAV()));
                mPUSHp("@_", 2);
 +              PUSHmortal;
        } else {
 -              /* 2 */ {
 +              /* 2, 3 */ {
                        if (ps->invocant.name) {
                                PUSHs(ps->invocant.name);
 +                              if (ps->invocant.type) {
 +                                      PUSHs(ps->invocant.type);
 +                              } else {
 +                                      PUSHmortal;
 +                              }
                        } else {
                                PUSHmortal;
 +                              PUSHmortal;
                        }
                }
 -              /* 3 */ {
 +              /* 4 */ {
                        size_t i, lim;
                        AV *av;
  
  
                        av = newAV();
                        if (lim) {
 -                              av_extend(av, lim - 1);
 +                              av_extend(av, (lim - 1) * 2);
                                for (i = 0; i < lim; i++) {
 -                                      av_push(av, SvREFCNT_inc_simple_NN(ps->positional_required.data[i].name));
 +                                      Param *cur = &ps->positional_required.data[i];
 +                                      av_push(av, SvREFCNT_inc_simple_NN(cur->name));
 +                                      av_push(av, cur->type ? SvREFCNT_inc_simple_NN(cur->type) : &PL_sv_undef);
                                }
                        }
  
                        mPUSHs(newRV_noinc((SV *)av));
                }
 -              /* 4 */ {
 +              /* 5 */ {
                        size_t i, lim;
                        AV *av;
  
  
                        av = newAV();
                        if (lim) {
 -                              av_extend(av, lim - 1);
 +                              av_extend(av, (lim - 1) * 2);
                                for (i = 0; i < lim; i++) {
 -                                      av_push(av, SvREFCNT_inc_simple_NN(ps->positional_optional.data[i].param.name));
 +                                      Param *cur = &ps->positional_optional.data[i].param;
 +                                      av_push(av, SvREFCNT_inc_simple_NN(cur->name));
 +                                      av_push(av, cur->type ? SvREFCNT_inc_simple_NN(cur->type) : &PL_sv_undef);
                                }
                        }
  
                        mPUSHs(newRV_noinc((SV *)av));
                }
 -              /* 5 */ {
 +              /* 6 */ {
                        size_t i, lim;
                        AV *av;
  
  
                        av = newAV();
                        if (lim) {
 -                              av_extend(av, lim - 1);
 +                              av_extend(av, (lim - 1) * 2);
                                for (i = 0; i < lim; i++) {
 -                                      av_push(av, SvREFCNT_inc_simple_NN(ps->named_required.data[i].name));
 +                                      Param *cur = &ps->named_required.data[i];
 +                                      av_push(av, SvREFCNT_inc_simple_NN(cur->name));
 +                                      av_push(av, cur->type ? SvREFCNT_inc_simple_NN(cur->type) : &PL_sv_undef);
                                }
                        }
  
                        mPUSHs(newRV_noinc((SV *)av));
                }
 -              /* 6 */ {
 +              /* 7 */ {
                        size_t i, lim;
                        AV *av;
  
  
                        av = newAV();
                        if (lim) {
 -                              av_extend(av, lim - 1);
 +                              av_extend(av, (lim - 1) * 2);
                                for (i = 0; i < lim; i++) {
 -                                      av_push(av, SvREFCNT_inc_simple_NN(ps->named_optional.data[i].param.name));
 +                                      Param *cur = &ps->named_optional.data[i].param;
 +                                      av_push(av, SvREFCNT_inc_simple_NN(cur->name));
 +                                      av_push(av, cur->type ? SvREFCNT_inc_simple_NN(cur->type) : &PL_sv_undef);
                                }
                        }
  
                        mPUSHs(newRV_noinc((SV *)av));
                }
 -              /* 7 */ {
 +              /* 8, 9 */ {
                        if (ps->slurpy.name) {
                                PUSHs(ps->slurpy.name);
 +                              if (ps->slurpy.type) {
 +                                      PUSHs(ps->slurpy.type);
 +                              } else {
 +                                      PUSHmortal;
 +                              }
                        } else {
                                PUSHmortal;
 +                              PUSHmortal;
                        }
                }
        }
@@@ -1217,7 -960,7 +1217,7 @@@ static int parse_fun(pTHX_ Sentinel sen
        /* initialize synthetic optree */
        Newx(prelude_sentinel, 1, OP *);
        *prelude_sentinel = NULL;
 -      sentinel_register(sen, prelude_sentinel, free_ptr_op);
 +      sentinel_register(sen, prelude_sentinel, free_ptr_op_void);
  
        /* parameters */
        param_spec = NULL;
  
                Newx(init_sentinel, 1, OP *);
                *init_sentinel = NULL;
 -              sentinel_register(sen, init_sentinel, free_ptr_op);
 +              sentinel_register(sen, init_sentinel, free_ptr_op_void);
  
                Newx(param_spec, 1, ParamSpec);
                ps_init(param_spec);
  
                while ((c = lex_peek_unichar(0)) != ')') {
                        int flags;
 -                      SV *name;
 +                      SV *name, *type;
                        char sigil;
                        PADOFFSET padoff;
  
 -                      padoff = parse_param(aTHX_ sen, declarator, spec, param_spec, &flags, &name, init_sentinel);
 +                      padoff = parse_param(aTHX_ sen, declarator, spec, param_spec, &flags, &name, init_sentinel, &type);
  
                        S_intro_my(aTHX);
  
                                assert(!*init_sentinel);
                                param_spec->slurpy.name = name;
                                param_spec->slurpy.padoff = padoff;
 +                              param_spec->slurpy.type = type;
                                continue;
                        }
  
                                }
                                param_spec->invocant.name = name;
                                param_spec->invocant.padoff = padoff;
 +                              param_spec->invocant.type = type;
                                continue;
                        }
  
                                        ParamInit *pi = piv_extend(&param_spec->named_optional);
                                        pi->param.name = name;
                                        pi->param.padoff = padoff;
 +                                      pi->param.type = type;
                                        pi->init = *init_sentinel;
                                        *init_sentinel = NULL;
                                        param_spec->named_optional.used++;
                                        p = pv_extend(&param_spec->named_required);
                                        p->name = name;
                                        p->padoff = padoff;
 +                                      p->type = type;
                                        param_spec->named_required.used++;
                                }
                        } else {
                                        ParamInit *pi = piv_extend(&param_spec->positional_optional);
                                        pi->param.name = name;
                                        pi->param.padoff = padoff;
 +                                      pi->param.type = type;
                                        pi->init = *init_sentinel;
                                        *init_sentinel = NULL;
                                        param_spec->positional_optional.used++;
                                        Param *p = pv_extend(&param_spec->positional_required);
                                        p->name = name;
                                        p->padoff = padoff;
 +                                      p->type = type;
                                        param_spec->positional_required.used++;
                                }
                        }
        /* attributes */
        Newx(attrs_sentinel, 1, OP *);
        *attrs_sentinel = NULL;
 -      sentinel_register(sen, attrs_sentinel, free_ptr_op);
 +      sentinel_register(sen, attrs_sentinel, free_ptr_op_void);
  
        if (c == ':' || c == '{') /* '}' - hi, vim */ {
  
                        var = newASSIGNOP(OPf_STACKED, var, 0, newOP(OP_SHIFT, 0));
  
                        *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, var));
 +
 +                      if (param_spec->invocant.type && (spec->flags & FLAG_CHECK_TARGS)) {
 +                              *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, mktypecheckp(aTHX_ declarator, 0, &param_spec->invocant)));
 +                      }
                }
  
                /* my (...) = @_; */
                                *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, clear));
                        }
                }
 +
 +              if (spec->flags & FLAG_CHECK_TARGS) {
 +                      size_t i, lim, base;
 +
 +                      base = 1;
 +                      for (i = 0, lim = param_spec->positional_required.used; i < lim; i++) {
 +                              Param *cur = &param_spec->positional_required.data[i];
 +
 +                              if (cur->type) {
 +                                      *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, mktypecheckp(aTHX_ declarator, base + i, cur)));
 +                              }
 +                      }
 +                      base += i;
 +
 +                      for (i = 0, lim = param_spec->positional_optional.used; i < lim; i++) {
 +                              Param *cur = &param_spec->positional_optional.data[i].param;
 +
 +                              if (cur->type) {
 +                                      *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, mktypecheckp(aTHX_ declarator, base + i, cur)));
 +                              }
 +                      }
 +                      base += i;
 +
 +                      for (i = 0, lim = param_spec->named_required.used; i < lim; i++) {
 +                              Param *cur = &param_spec->named_required.data[i];
 +
 +                              if (cur->type) {
 +                                      *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, mktypecheckp(aTHX_ declarator, base + i, cur)));
 +                              }
 +                      }
 +                      base += i;
 +
 +                      for (i = 0, lim = param_spec->named_optional.used; i < lim; i++) {
 +                              Param *cur = &param_spec->named_optional.data[i].param;
 +
 +                              if (cur->type) {
 +                                      *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, mktypecheckp(aTHX_ declarator, base + i, cur)));
 +                              }
 +                      }
 +                      base += i;
 +
 +                      if (param_spec->slurpy.type) {
 +                              /* $type->valid($_) or croak $type->get_message($_) for @rest / values %rest */
 +                              OP *body, *list, *loop;
 +
 +                              body = mktypecheck(aTHX_ declarator, base, param_spec->slurpy.name, NOT_IN_PAD, param_spec->slurpy.type);
 +
 +                              if (SvPV_nolen(param_spec->slurpy.name)[0] == '@') {
 +                                      list = my_var_g(aTHX_ OP_PADAV, 0, param_spec->slurpy.padoff);
 +                              } else {
 +                                      list = my_var_g(aTHX_ OP_PADHV, 0, param_spec->slurpy.padoff);
 +                                      list = newUNOP(OP_VALUES, 0, list);
 +                              }
 +
 +                              loop = newFOROP(0, NULL, list, body, NULL);
 +
 +                              *prelude_sentinel = op_append_list(OP_LINESEQ, *prelude_sentinel, newSTATEOP(0, NULL, loop));
 +                      }
 +              }
        }
  
        /* finally let perl parse the actual subroutine body */
  fp__cv_root(sv)
        SV * sv
        PREINIT:
-               CV *cv;
+               CV *xcv;
                HV *hv;
                GV *gv;
        CODE:
-               cv = sv_2cv(sv, &hv, &gv, 0);
-               RETVAL = PTR2UV(cv ? CvROOT(cv) : NULL);
+               xcv = sv_2cv(sv, &hv, &gv, 0);
+               RETVAL = PTR2UV(xcv ? CvROOT(xcv) : NULL);
        OUTPUT:
                RETVAL
  
@@@ -2054,8 -1728,6 +2054,8 @@@ WARNINGS_ENABLE 
        newCONSTSUB(stash, "FLAG_CHECK_NARGS",  newSViv(FLAG_CHECK_NARGS));
        newCONSTSUB(stash, "FLAG_INVOCANT",     newSViv(FLAG_INVOCANT));
        newCONSTSUB(stash, "FLAG_NAMED_PARAMS", newSViv(FLAG_NAMED_PARAMS));
 +      newCONSTSUB(stash, "FLAG_TYPES_OK",     newSViv(FLAG_TYPES_OK));
 +      newCONSTSUB(stash, "FLAG_CHECK_TARGS",  newSViv(FLAG_CHECK_TARGS));
        newCONSTSUB(stash, "HINTK_KEYWORDS", newSVpvs(HINTK_KEYWORDS));
        newCONSTSUB(stash, "HINTK_FLAGS_",   newSVpvs(HINTK_FLAGS_));
        newCONSTSUB(stash, "HINTK_SHIFT_",   newSVpvs(HINTK_SHIFT_));