typedef union {
TC type;
- HV *stash;
- CV *cv;
+ SV *sv;
OP *op;
bool (*fptr)(pTHX_ SV *type_constraint, SV *sv);
} TC_CHECK;
/* slot flags:
* instance reading writing
* 00000000 00000000 00000000 00000000
- * ^ trigger
- * ^ weak
+ * ^ trigger
+ * ^ weak
+ * ^ tc refcnt
* ^^^ tc_kind
* ^ coerce
* ^^^ default_kind
#define ATTR_LAZY 0x800
-#define ATTR_COERCE 0x08
-#define ATTR_WEAK 0x10
-#define ATTR_TRIGGER 0x10
+#define ATTR_COERCE 0x8
+#define ATTR_TCREFCNT 0x10
+#define ATTR_WEAK 0x20
+#define ATTR_TRIGGER 0x40
#define ATTR_ISWEAK(attr) ( attr->flags & ATTR_WEAK )
#define ATTR_ISLAZY(attr) ( attr->flags & ATTR_LAZY )
return SvTYPE(SvRV(sv)) == svt;
}
-STATIC bool check_sv_class (pTHX_ HV *stash, SV *sv) {
+STATIC bool check_sv_class(pTHX_ HV *stash, SV *sv) {
dSP;
bool ret;
+ SV *rv;
if (!sv)
return 0;
SvGETMAGIC(sv);
if (!SvROK(sv))
return 0;
- sv = (SV*)SvRV(sv);
- if (!SvOBJECT(sv))
+ rv = (SV*)SvRV(sv);
+ if (!SvOBJECT(rv))
return 0;
- if (SvSTASH(sv) == stash)
+ if (SvSTASH(rv) == stash)
return 1;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv);
- XPUSHs(newSVpv(HvNAME_get(SvSTASH(sv)), 0));
+ XPUSHs(sv_2mortal(newSVpv(HvNAME_get(stash), 0)));
PUTBACK;
call_method("isa", G_SCALAR);
if ( SvIOK(sv) ) {
return 1;
} else if ( SvPOK(sv) ) {
- croak("todo");
int i;
STRLEN len;
char *pv = SvPV(sv, len);
return sv_isobject(sv);
break;
case ClassName:
- {
+ if ( SvOK(sv) && !SvROK(sv) ) {
STRLEN len;
char *pv;
pv = SvPV(sv, len);
return ( gv_stashpvn(pv, len, 0) != NULL );
- break;
}
+ return 0;
+ break;
case RegexpRef:
return sv_isa(sv, "Regexp");
break;
return check_sv_type(tc_check.type, sv);
break;
case tc_stash:
- return check_sv_class(aTHX_ tc_check.stash, sv);
+ return check_sv_class(aTHX_ (HV *)tc_check.sv, sv);
break;
case tc_fptr:
return tc_check.fptr(aTHX_ type_constraint, sv);
SV *data = params[7];
switch (tc_kind) {
- case tc_stash:
- attr->tc_check.stash = gv_stashsv(data, 0);
- break;
case tc_type:
attr->tc_check.type = SvIV(data);
break;
+ case tc_stash:
+ flags |= ATTR_TCREFCNT;
+ attr->tc_check.sv = (SV *)gv_stashsv(data, 0);
+ break;
case tc_cv:
- attr->tc_check.cv = (CV *)SvRV(data);
- if ( SvTYPE(attr->tc_check.cv) != SVt_PVCV )
+ flags |= ATTR_TCREFCNT;
+ attr->tc_check.sv = SvRV(data);
+ if ( SvTYPE(attr->tc_check.sv) != SVt_PVCV )
croak("compiled type constraint is not a coderef");
break;
default:
/* copy refs */
attr->meta_attr = newSVsv(params[0]);
attr->type_constraint = newSVsv(tc);
- if ( attr->trigger ) SvREFCNT_inc(attr->trigger);
- if ( attr->initializer ) SvREFCNT_inc(attr->initializer);
+ SvREFCNT_inc(attr->trigger);
+ SvREFCNT_inc(attr->initializer);
+ if ( flags & ATTR_TCREFCNT ) SvREFCNT_inc(attr->tc_check.sv);
attr->slot_sv = newSVpvn_share(pv, len, hash);
attr->slot_u32 = hash;
return mi;
}
+STATIC void delete_mi (pTHX_ MI *mi) {
+ I32 i, j;
+
+ for ( i = 0; i < mi->num_attrs; i++ ) {
+ ATTR *attr = &mi->attrs[i];
+ /* clear the pointers to this meta attr from all the CVs */
+ SV **cvs = AvARRAY(attr->cvs);
+ for ( j = av_len(attr->cvs); j >= 0; j-- ) {
+ CV *cv = cvs[j];
+ XSANY.any_i32 = 0;
+ }
+
+ SvREFCNT_dec(attr->cvs);
+ SvREFCNT_dec(attr->slot_sv);
+ SvREFCNT_dec(attr->type_constraint);
+ if ( attr->flags & ATTR_TCREFCNT ) SvREFCNT_dec(attr->tc_check.sv);
+ SvREFCNT_dec(attr->initializer);
+ SvREFCNT_dec(attr->trigger);
+ SvREFCNT_dec(attr->meta_attr);
+ }
+
+ Safefree(mi->attrs);
+ Safefree(mi);
+}
+
STATIC SV *new_mi_obj (pTHX_ MI *mi) {
HV *stash = gv_stashpvs("Moose::XS::Meta::Instance",0);
SV *obj = newRV_noinc(newSViv(PTR2IV(mi)));
if (!c_mi) {
c_mi = perl_mi_to_c_mi(aTHX_ perl_mi);
stash_in_mg(aTHX_ SvRV(perl_mi), c_mi);
+ SvREFCNT_dec(c_mi);
}
sv_2mortal(perl_mi);
XSANY.any_i32 = PTR2IV(attr);
+ SvREFCNT_inc(cv);
av_push( attr->cvs, (SV *)cv );
return attr;
PREINIT:
MI *mi = INT2PTR(MI *, SvIV(SvRV(self)));
CODE:
- printf("destroying\n");
- /* foreach attr ( delete cvs XSANY ), free attrs free mi */
+ delete_mi(aTHX_ mi);
has c => ( isa => "ClassName", is => "rw" );
# FIXME Regexp, ScalarRef, parametrized, filehandle
+
+ package Gorch;
+ use Moose;
+
+ extends qw(Foo);
+
+ package Quxx;
+ use Moose;
+
+ sub isa {
+ return $_[1] eq 'Foo';
+ }
}
{
is( $foo->ref(), undef );
-ok( !eval { $foo->a("not a ref"); 1 } );
-ok( !eval { $foo->i(1.3); 1 } );
-ok( !eval { $foo->s(undef); 1 } );
-ok( !eval { $foo->o({}); 1 } );
-ok( !eval { $foo->f(bless {}, "Bar"); 1 } );
-ok( !eval { $foo->c("Horse"); 1 } );
-
-ok( eval { $foo->a([]); 1 } );
-ok( eval { $foo->i(3); 1 } );
-ok( eval { $foo->s("foo"); 1 } );
-ok( eval { $foo->o(bless {}, "Bar"); 1 } );
-ok( eval { $foo->f(Foo->new); 1 } );
-ok( eval { $foo->c("Foo"); 1 } );
-
-use Data::Dumper;
-warn Dumper($foo);
+ok( !eval { $foo->a("not a ref"); 1 }, "ArrayRef" );
+ok( !eval { $foo->a(3); 1 }, "ArrayRef" );
+ok( !eval { $foo->a({}); 1 }, "ArrayRef" );
+ok( !eval { $foo->a(undef); 1 }, "ArrayRef" );
+ok( !eval { $foo->i(1.3); 1 }, "Int" );
+ok( !eval { $foo->i("1.3"); 1 }, "Int" );
+ok( !eval { $foo->i("foo"); 1 }, "Int" );
+ok( !eval { $foo->i(undef); 1 }, "Int" );
+ok( !eval { $foo->s(undef); 1 }, "Str" );
+ok( !eval { $foo->s([]); 1 }, "Str" );
+ok( !eval { $foo->o({}); 1 }, "Object" );
+ok( !eval { $foo->o(undef); 1 }, "Object" );
+ok( !eval { $foo->o(42); 1 }, "Object" );
+ok( !eval { $foo->o("hi ho"); 1 }, "Object" );
+ok( !eval { $foo->o(" ho"); 1 }, "Object" );
+ok( !eval { $foo->f(bless {}, "Bar"); 1 }, "Class (Foo)" );
+ok( !eval { $foo->f(undef); 1 }, "Class (Foo)" );
+ok( !eval { $foo->f("foo"); 1 }, "Class (Foo)" );
+ok( !eval { $foo->f(3); 1 }, "Class (Foo)" );
+ok( !eval { $foo->f({}); 1 }, "Class (Foo)" );
+ok( !eval { $foo->f("Foo"); 1 }, "Class (Foo)" );
+ok( !eval { $foo->c("Horse"); 1 }, "ClassName" );
+ok( !eval { $foo->c(3); 1 }, "ClassName" );
+ok( !eval { $foo->c(undef); 1 }, "ClassName" );
+ok( !eval { $foo->c("feck"); 1 }, "ClassName" );
+ok( !eval { $foo->c({}); 1 }, "ClassName" );
+
+ok( eval { $foo->a([]); 1 }, "ArrayRef" );
+ok( eval { $foo->i(3); 1 }, "Int" );
+ok( eval { $foo->i("3"); 1 }, "Int" );
+ok( eval { $foo->i("-3"); 1 }, "Int" );
+ok( eval { $foo->s("foo"); 1 }, "Str" );
+ok( eval { $foo->s(""); 1 }, "Str" );
+ok( eval { $foo->s(4); 1 }, "Str" );
+ok( eval { $foo->o(bless {}, "Bar"); 1 }, "Object" );
+ok( eval { $foo->f(Foo->new); 1 }, "Class (Foo)" );
+ok( eval { $foo->f(Gorch->new); 1 }, "Class (Foo), real subclass");
+ok( eval { $foo->f(Quxx->new); 1 }, "Class (Foo), fake subclass");
+ok( eval { $foo->c("Foo"); 1 }, "ClassName" );
+
+
+
+$foo->meta->invalidate_meta_instance();
+isa_ok( $foo->f, 'Foo' );
+$foo->meta->invalidate_meta_instance();
+isa_ok( $foo->f, 'Foo' );