The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Build.PL 34
ChangeLog 08
MANIFEST 24
META.yml 56
Makefile.PL 76
README 221
c3.patch 04701
lib/Class/C3/next.pm 0106
lib/Class/C3.pm 8088
t/00_load.t 23
t/10_Inconsistent_hierarchy.t 2323
t/20_reinitialize.t 17
t/21_C3_with_overload.t 120
13 files changed (This is a version diff) 1264997
@@ -6,13 +6,14 @@ my $build = Module::Build->new(
     module_name => 'Class::C3',
     license => 'perl',
     requires => {
+        'Algorithm::C3'   => 0.06,
         'Scalar::Util'    => 1.10,
-        'Algorithm::C3'   => 0.05,
     },
-    optional => {},
+    recommends => {
+        'Class::C3::XS'   => 0.02,
+    },
     build_requires => {
         'Test::More' => '0.47',
-        'Test::Exception' => 0.15,
     },
     create_makefile_pl => 'traditional',
     recursive_test_files => 1,
@@ -1,5 +1,13 @@
 Revision history for Perl extension Class::C3.
 
+0.15_02 Sun, Apr 15, 2007
+    - Fix for overloading to method name string,
+       from Ittetsu Miyazaki.
+    - Supports Class::C3::XS
+
+0.15_01 Fri, Apr 13, 2007
+    - Supports bleadperl + c3 patches (experimental)
+
 0.14 Tues, Sep 19, 2006
     - Fix for rt.cpan.org #21558
     - converted to Module::Build
@@ -1,7 +1,11 @@
 Build.PL
+c3.patch
 ChangeLog
 lib/Class/C3.pm
+lib/Class/C3/next.pm
+Makefile.PL
 MANIFEST			This list of files
+META.yml
 opt/c3.pm
 README
 t/00_load.t
@@ -31,5 +35,3 @@ t/lib/F.pm
 t/pod.t
 t/pod_coverage.t
 util/visualize_c3.pl
-Makefile.PL
-META.yml
@@ -1,6 +1,6 @@
 ---
 name: Class-C3
-version: 0.14
+version: 0.15_02
 author:
   - 'Stevan Little, E<lt>stevan@iinteractive.comE<gt>'
   - 'Brandon L. Black, E<lt>blblack@gmail.comE<gt>'
@@ -9,16 +9,17 @@ license: perl
 resources:
   license: http://dev.perl.org/licenses/
 requires:
-  Algorithm::C3: 0.05
+  Algorithm::C3: 0.06
   Scalar::Util: 1.1
 build_requires:
-  Test::Exception: 0.15
   Test::More: 0.47
+recommends:
+  Class::C3::XS: 0.02
 provides:
   Class::C3:
     file: lib/Class/C3.pm
-    version: 0.14
-generated_by: Module::Build version 0.2805
+    version: 0.15_02
+generated_by: Module::Build version 0.2807
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.2.html
   version: 1.2
@@ -2,16 +2,15 @@
 use ExtUtils::MakeMaker;
 WriteMakefile
 (
+          'PL_FILES' => {},
+          'INSTALLDIRS' => 'site',
           'NAME' => 'Class::C3',
+          'EXE_FILES' => [],
           'VERSION_FROM' => 'lib/Class/C3.pm',
           'PREREQ_PM' => {
-                           'Algorithm::C3' => '0.05',
+                           'Test::More' => '0.47',
                            'Scalar::Util' => '1.1',
-                           'Test::Exception' => '0.15',
-                           'Test::More' => '0.47'
-                         },
-          'INSTALLDIRS' => 'site',
-          'EXE_FILES' => [],
-          'PL_FILES' => {}
+                           'Algorithm::C3' => '0.06'
+                         }
         )
 ;
@@ -1,4 +1,4 @@
-Class::C3 version 0.14
+Class::C3 version 0.15_01
 ===========================
 
 INSTALLATION
@@ -14,7 +14,26 @@ DEPENDENCIES
 
 This module requires these other modules and libraries:
 
-	None
+	Algorithm::C3 0.06
+	Scalar::Util 1.10
+
+Additionally, this module will optionally take advantage of
+these if installed:
+
+	Class::C3::XS 0.01_01
+
+SPECIAL NOTE FOR 0.15_01
+
+To try this with the experimental perl core c3 patch,
+download a recent copy perl-current:
+
+http://mirrors.develooper.com/perl/APC/perl-current-snap/perl-current@30943.tar.bz2
+
+apply the enclosed c3.patch, and install this perl:
+
+sh Configure -Dusedevel -Dprefix=/where/I/want/it -d -e && make && make test && make install
+
+then try your C3-using software against this perl + Class::C3 0.15_01.
 
 COPYRIGHT AND LICENCE
 
@@ -0,0 +1,4701 @@
+=== Makefile.micro
+==================================================================
+--- Makefile.micro	(/local/perl-current)	(revision 30454)
++++ Makefile.micro	(/local/perl-c3-subg)	(revision 30454)
+@@ -10,7 +10,7 @@
+ all:	microperl
+ 
+ O = uav$(_O) udeb$(_O) udoio$(_O) udoop$(_O) udump$(_O) \
+-	uglobals$(_O) ugv$(_O) uhv$(_O) \
++	uglobals$(_O) ugv$(_O) uhv$(_O) umro$(_O)\
+ 	umg$(_O) uperlmain$(_O) uop$(_O) ureentr$(_O) \
+ 	upad$(_O) uperl$(_O) uperlio$(_O) uperly$(_O) upp$(_O) \
+ 	upp_ctl$(_O) upp_hot$(_O) upp_sys$(_O) upp_pack$(_O) upp_sort$(_O) \
+@@ -76,6 +76,9 @@
+ ugv$(_O):	$(HE) gv.c
+ 	$(CC) -c -o $@ $(CFLAGS) gv.c
+ 
++umro$(_O):	$(HE) mro.c
++	$(CC) -c -o $@ $(CFLAGS) mro.c
++
+ uhv$(_O):	$(HE) hv.c
+ 	$(CC) -c -o $@ $(CFLAGS) hv.c
+ 
+=== embed.h
+==================================================================
+--- embed.h	(/local/perl-current)	(revision 30454)
++++ embed.h	(/local/perl-c3-subg)	(revision 30454)
+@@ -267,6 +267,13 @@
+ #define gv_efullname4		Perl_gv_efullname4
+ #define gv_fetchfile		Perl_gv_fetchfile
+ #define gv_fetchfile_flags	Perl_gv_fetchfile_flags
++#define mro_meta_init		Perl_mro_meta_init
++#define mro_get_linear_isa	Perl_mro_get_linear_isa
++#define mro_get_linear_isa_c3	Perl_mro_get_linear_isa_c3
++#define mro_get_linear_isa_dfs	Perl_mro_get_linear_isa_dfs
++#define mro_isa_changed_in	Perl_mro_isa_changed_in
++#define mro_method_changed_in	Perl_mro_method_changed_in
++#define boot_core_mro		Perl_boot_core_mro
+ #define gv_fetchmeth		Perl_gv_fetchmeth
+ #define gv_fetchmeth_autoload	Perl_gv_fetchmeth_autoload
+ #define gv_fetchmethod_autoload	Perl_gv_fetchmethod_autoload
+@@ -2511,6 +2518,13 @@
+ #define gv_efullname4(a,b,c,d)	Perl_gv_efullname4(aTHX_ a,b,c,d)
+ #define gv_fetchfile(a)		Perl_gv_fetchfile(aTHX_ a)
+ #define gv_fetchfile_flags(a,b,c)	Perl_gv_fetchfile_flags(aTHX_ a,b,c)
++#define mro_meta_init(a)	Perl_mro_meta_init(aTHX_ a)
++#define mro_get_linear_isa(a)	Perl_mro_get_linear_isa(aTHX_ a)
++#define mro_get_linear_isa_c3(a,b)	Perl_mro_get_linear_isa_c3(aTHX_ a,b)
++#define mro_get_linear_isa_dfs(a,b)	Perl_mro_get_linear_isa_dfs(aTHX_ a,b)
++#define mro_isa_changed_in(a)	Perl_mro_isa_changed_in(aTHX_ a)
++#define mro_method_changed_in(a)	Perl_mro_method_changed_in(aTHX_ a)
++#define boot_core_mro()		Perl_boot_core_mro(aTHX)
+ #define gv_fetchmeth(a,b,c,d)	Perl_gv_fetchmeth(aTHX_ a,b,c,d)
+ #define gv_fetchmeth_autoload(a,b,c,d)	Perl_gv_fetchmeth_autoload(aTHX_ a,b,c,d)
+ #define gv_fetchmethod_autoload(a,b,c)	Perl_gv_fetchmethod_autoload(aTHX_ a,b,c)
+=== pod/perlapi.pod
+==================================================================
+--- pod/perlapi.pod	(/local/perl-current)	(revision 30454)
++++ pod/perlapi.pod	(/local/perl-c3-subg)	(revision 30454)
+@@ -1326,7 +1326,7 @@
+ The argument C<level> should be either 0 or -1.  If C<level==0>, as a
+ side-effect creates a glob with the given C<name> in the given C<stash>
+ which in the case of success contains an alias for the subroutine, and sets
+-up caching info for this glob.  Similarly for all the searched stashes.
++up caching info for this glob.
+ 
+ This function grants C<"SUPER"> token as a postfix of the stash name. The
+ GV returned from C<gv_fetchmeth> may be a method cache entry, which is not
+=== global.sym
+==================================================================
+--- global.sym	(/local/perl-current)	(revision 30454)
++++ global.sym	(/local/perl-c3-subg)	(revision 30454)
+@@ -135,6 +135,13 @@
+ Perl_gv_efullname4
+ Perl_gv_fetchfile
+ Perl_gv_fetchfile_flags
++Perl_mro_meta_init
++Perl_mro_get_linear_isa
++Perl_mro_get_linear_isa_c3
++Perl_mro_get_linear_isa_dfs
++Perl_mro_isa_changed_in
++Perl_mro_method_changed_in
++Perl_boot_core_mro
+ Perl_gv_fetchmeth
+ Perl_gv_fetchmeth_autoload
+ Perl_gv_fetchmethod
+=== perl.c
+==================================================================
+--- perl.c	(/local/perl-current)	(revision 30454)
++++ perl.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -2163,6 +2163,7 @@
+     boot_core_PerlIO();
+     boot_core_UNIVERSAL();
+     boot_core_xsutils();
++    boot_core_mro();
+ 
+     if (xsinit)
+ 	(*xsinit)(aTHX);	/* in case linked C routines want magical variables */
+=== universal.c
+==================================================================
+--- universal.c	(/local/perl-current)	(revision 30454)
++++ universal.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -36,12 +36,12 @@
+              int len, int level)
+ {
+     dVAR;
+-    AV* av;
+-    GV* gv;
+-    GV** gvp;
+-    HV* hv = NULL;
+-    SV* subgen = NULL;
++    AV* stash_linear_isa;
++    SV** svp;
+     const char *hvname;
++    I32 items;
++    PERL_UNUSED_ARG(len);
++    PERL_UNUSED_ARG(level);
+ 
+     /* A stash/class can go by many names (ie. User == main::User), so 
+        we compare the stash itself just in case */
+@@ -56,75 +56,23 @@
+     if (strEQ(name, "UNIVERSAL"))
+ 	return TRUE;
+ 
+-    if (level > 100)
+-	Perl_croak(aTHX_ "Recursive inheritance detected in package '%s'",
+-		   hvname);
+-
+-    gvp = (GV**)hv_fetchs(stash, "::ISA::CACHE::", FALSE);
+-
+-    if (gvp && (gv = *gvp) && isGV_with_GP(gv) && (subgen = GvSV(gv))
+-	&& (hv = GvHV(gv)))
+-    {
+-	if (SvIV(subgen) == (IV)PL_sub_generation) {
+-	    SV** const svp = (SV**)hv_fetch(hv, name, len, FALSE);
+-	    if (svp) {
+-		SV * const sv = *svp;
+-#ifdef DEBUGGING
+-		if (sv != &PL_sv_undef)
+-		    DEBUG_o( Perl_deb(aTHX_ "Using cached ISA %s for package %s\n",
+-				    name, hvname) );
+-#endif
+-		return (sv == &PL_sv_yes);
+-	    }
++    stash_linear_isa = (AV*)sv_2mortal((SV*)mro_get_linear_isa(stash));
++    svp = AvARRAY(stash_linear_isa) + 1;
++    items = AvFILLp(stash_linear_isa);
++    while (items--) {
++	SV* const basename_sv = *svp++;
++        HV* basestash = gv_stashsv(basename_sv, 0);
++	if (!basestash) {
++	    if (ckWARN(WARN_MISC))
++		Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
++			    "Can't locate package %"SVf" for the parents of %s",
++			    SVfARG(basename_sv), hvname);
++	    continue;
+ 	}
+-	else {
+-	    DEBUG_o( Perl_deb(aTHX_ "ISA Cache in package %s is stale\n",
+-			      hvname) );
+-	    hv_clear(hv);
+-	    sv_setiv(subgen, PL_sub_generation);
+-	}
++        if(name_stash == basestash || strEQ(name, SvPVX(basename_sv)))
++	    return TRUE;
+     }
+ 
+-    gvp = (GV**)hv_fetchs(stash, "ISA", FALSE);
+-
+-    if (gvp && (gv = *gvp) && isGV_with_GP(gv) && (av = GvAV(gv))) {
+-	if (!hv || !subgen) {
+-	    gvp = (GV**)hv_fetchs(stash, "::ISA::CACHE::", TRUE);
+-
+-	    gv = *gvp;
+-
+-	    if (SvTYPE(gv) != SVt_PVGV)
+-		gv_init(gv, stash, "::ISA::CACHE::", 14, TRUE);
+-
+-	    if (!hv)
+-		hv = GvHVn(gv);
+-	    if (!subgen) {
+-		subgen = newSViv(PL_sub_generation);
+-		GvSV(gv) = subgen;
+-	    }
+-	}
+-	if (hv) {
+-	    SV** svp = AvARRAY(av);
+-	    /* NOTE: No support for tied ISA */
+-	    I32 items = AvFILLp(av) + 1;
+-	    while (items--) {
+-		SV* const sv = *svp++;
+-		HV* const basestash = gv_stashsv(sv, 0);
+-		if (!basestash) {
+-		    if (ckWARN(WARN_MISC))
+-			Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
+-				    "Can't locate package %"SVf" for @%s::ISA",
+-				    SVfARG(sv), hvname);
+-		    continue;
+-		}
+-		if (isa_lookup(basestash, name, name_stash, len, level + 1)) {
+-		    (void)hv_store(hv,name,len,&PL_sv_yes,0);
+-		    return TRUE;
+-		}
+-	    }
+-	    (void)hv_store(hv,name,len,&PL_sv_no,0);
+-	}
+-    }
+     return FALSE;
+ }
+ 
+=== scope.c
+==================================================================
+--- scope.c	(/local/perl-current)	(revision 30454)
++++ scope.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -256,7 +256,7 @@
+ 	GP *gp = Perl_newGP(aTHX_ gv);
+ 
+ 	if (GvCVu(gv))
+-	    PL_sub_generation++;	/* taking a method out of circulation */
++            mro_method_changed_in(GvSTASH(gv)); /* taking a method out of circulation ("local")*/
+ 	if (GvIOp(gv) && (IoFLAGS(GvIOp(gv)) & IOf_ARGV)) {
+ 	    gp->gp_io = newIO();
+ 	    IoFLAGS(gp->gp_io) |= IOf_ARGV|IOf_START;
+@@ -740,7 +740,7 @@
+ 	    gp_free(gv);
+ 	    GvGP(gv) = (GP*)ptr;
+ 	    if (GvCVu(gv))
+-		PL_sub_generation++;  /* putting a method back into circulation */
++                mro_method_changed_in(GvSTASH(gv)); /* putting a method back into circulation ("local")*/
+ 	    SvREFCNT_dec(gv);
+ 	    break;
+ 	case SAVEt_FREESV:
+=== gv.c
+==================================================================
+--- gv.c	(/local/perl-current)	(revision 30454)
++++ gv.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -260,7 +260,7 @@
+ 	}
+ 	LEAVE;
+ 
+-	PL_sub_generation++;
++        mro_method_changed_in(GvSTASH(gv)); /* sub Foo::bar($) { (shift) } sub ASDF::baz($); *ASDF::baz = \&Foo::bar */
+ 	CvGV(GvCV(gv)) = gv;
+ 	CvFILE_set_from_cop(GvCV(gv), PL_curcop);
+ 	CvSTASH(GvCV(gv)) = PL_curstash;
+@@ -310,7 +310,7 @@
+ The argument C<level> should be either 0 or -1.  If C<level==0>, as a
+ side-effect creates a glob with the given C<name> in the given C<stash>
+ which in the case of success contains an alias for the subroutine, and sets
+-up caching info for this glob.  Similarly for all the searched stashes.
++up caching info for this glob.
+ 
+ This function grants C<"SUPER"> token as a postfix of the stash name. The
+ GV returned from C<gv_fetchmeth> may be a method cache entry, which is not
+@@ -321,133 +321,150 @@
+ =cut
+ */
+ 
++/* NOTE: No support for tied ISA */
++
+ GV *
+ Perl_gv_fetchmeth(pTHX_ HV *stash, const char *name, STRLEN len, I32 level)
+ {
+     dVAR;
+-    AV* av;
+-    GV* topgv;
+-    GV* gv;
+     GV** gvp;
+-    CV* cv;
++    AV* linear_av;
++    SV** linear_svp;
++    SV* linear_sv;
++    HV* curstash;
++    GV* candidate = NULL;
++    CV* cand_cv = NULL;
++    CV* old_cv;
++    GV* topgv = NULL;
+     const char *hvname;
+-    HV* lastchance = NULL;
++    I32 create = (level >= 0) ? 1 : 0;
++    I32 items;
++    STRLEN packlen;
++    U32 topgen_cmp;
+ 
+     /* UNIVERSAL methods should be callable without a stash */
+     if (!stash) {
+-	level = -1;  /* probably appropriate */
++	create = 0;  /* probably appropriate */
+ 	if(!(stash = gv_stashpvs("UNIVERSAL", 0)))
+ 	    return 0;
+     }
+ 
++    assert(stash);
++
+     hvname = HvNAME_get(stash);
+     if (!hvname)
+-      Perl_croak(aTHX_
+-		 "Can't use anonymous symbol table for method lookup");
++      Perl_croak(aTHX_ "Can't use anonymous symbol table for method lookup");
+ 
+-    if ((level > 100) || (level < -100))
+-	Perl_croak(aTHX_ "Recursive inheritance detected while looking for method '%s' in package '%s'",
+-	      name, hvname);
++    assert(hvname);
++    assert(name);
++    assert(len >= 0);
+ 
+     DEBUG_o( Perl_deb(aTHX_ "Looking for method %s in package %s\n",name,hvname) );
+ 
+-    gvp = (GV**)hv_fetch(stash, name, len, (level >= 0));
+-    if (!gvp)
+-	topgv = NULL;
++    topgen_cmp = HvMROMETA(stash)->sub_generation + PL_sub_generation;
++
++    /* check locally for a real method or a cache entry */
++    gvp = (GV**)hv_fetch(stash, name, len, create);
++    if(gvp) {
++        topgv = *gvp;
++        assert(topgv);
++        if (SvTYPE(topgv) != SVt_PVGV)
++            gv_init(topgv, stash, name, len, TRUE);
++        if ((cand_cv = GvCV(topgv))) {
++            /* If genuine method or valid cache entry, use it */
++            if (!GvCVGEN(topgv) || GvCVGEN(topgv) == topgen_cmp) {
++                return topgv;
++            }
++            else {
++                /* stale cache entry, junk it and move on */
++	        SvREFCNT_dec(cand_cv);
++	        GvCV(topgv) = cand_cv = NULL;
++	        GvCVGEN(topgv) = 0;
++            }
++        }
++        else if (GvCVGEN(topgv) == topgen_cmp) {
++            /* cache indicates no such method definitively */
++            return 0;
++        }
++    }
++
++    packlen = HvNAMELEN_get(stash);
++    if (packlen >= 7 && strEQ(hvname + packlen - 7, "::SUPER")) {
++        HV* basestash;
++        packlen -= 7;
++        basestash = gv_stashpvn(hvname, packlen, GV_ADD);
++        linear_av = mro_get_linear_isa(basestash);
++    }
+     else {
+-	topgv = *gvp;
+-	if (SvTYPE(topgv) != SVt_PVGV)
+-	    gv_init(topgv, stash, name, len, TRUE);
+-	if ((cv = GvCV(topgv))) {
+-	    /* If genuine method or valid cache entry, use it */
+-	    if (!GvCVGEN(topgv) || GvCVGEN(topgv) == PL_sub_generation)
+-		return topgv;
+-	    /* Stale cached entry: junk it */
+-	    SvREFCNT_dec(cv);
+-	    GvCV(topgv) = cv = NULL;
+-	    GvCVGEN(topgv) = 0;
+-	}
+-	else if (GvCVGEN(topgv) == PL_sub_generation)
+-	    return 0;  /* cache indicates sub doesn't exist */
++        linear_av = mro_get_linear_isa(stash); /* has ourselves at the top of the list */
+     }
++    sv_2mortal((SV*)linear_av);
+ 
+-    gvp = (GV**)hv_fetchs(stash, "ISA", FALSE);
+-    av = (gvp && (gv = *gvp) && isGV_with_GP(gv)) ? GvAV(gv) : NULL;
++    linear_svp = AvARRAY(linear_av) + 1; /* skip over self */
++    items = AvFILLp(linear_av); /* no +1, to skip over self */
++    while (items--) {
++        linear_sv = *linear_svp++;
++        assert(linear_sv);
++        curstash = gv_stashsv(linear_sv, 0);
+ 
+-    /* create and re-create @.*::SUPER::ISA on demand */
+-    if (!av || !SvMAGIC(av)) {
+-	STRLEN packlen = HvNAMELEN_get(stash);
++        /* mg.c:Perl_magic_setisa sets the fake flag on packages it had
++           to create that the user did not.  The "package" statement
++           clears it.  We also check if there's anything in the symbol
++           table at all, which would indicate a previously "fake" package
++           where someone adding things via $Foo::Bar = 1 without ever
++           using a "package" statement.
++           This was all neccesary because magic_setisa needs a place to
++           keep isarev information on packages that aren't yet defined,
++           yet we still need to issue this warning when appropriate.
++        */
++        if (!curstash || (HvMROMETA(curstash)->fake && !HvFILL(curstash))) {
++            if (ckWARN(WARN_MISC))
++                Perl_warner(aTHX_ packWARN(WARN_MISC), "Can't locate package %"SVf" for @%s::ISA",
++                    SVfARG(linear_sv), hvname);
++            continue;
++        }
+ 
+-	if (packlen >= 7 && strEQ(hvname + packlen - 7, "::SUPER")) {
+-	    HV* basestash;
++        assert(curstash);
+ 
+-	    packlen -= 7;
+-	    basestash = gv_stashpvn(hvname, packlen, GV_ADD);
+-	    gvp = (GV**)hv_fetchs(basestash, "ISA", FALSE);
+-	    if (gvp && (gv = *gvp) && isGV_with_GP(gv) && (av = GvAV(gv))) {
+-		gvp = (GV**)hv_fetchs(stash, "ISA", TRUE);
+-		if (!gvp || !(gv = *gvp))
+-		    Perl_croak(aTHX_ "Cannot create %s::ISA", hvname);
+-		if (SvTYPE(gv) != SVt_PVGV)
+-		    gv_init(gv, stash, "ISA", 3, TRUE);
+-		SvREFCNT_dec(GvAV(gv));
+-		GvAV(gv) = (AV*)SvREFCNT_inc_simple(av);
+-	    }
+-	}
++        gvp = (GV**)hv_fetch(curstash, name, len, 0);
++        if (!gvp) continue;
++        candidate = *gvp;
++        assert(candidate);
++        if (SvTYPE(candidate) != SVt_PVGV) gv_init(candidate, curstash, name, len, TRUE);
++        if (SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) {
++            /*
++             * Found real method, cache method in topgv if:
++             *  1. topgv has no synonyms (else inheritance crosses wires)
++             *  2. method isn't a stub (else AUTOLOAD fails spectacularly)
++             */
++            if (topgv && (GvREFCNT(topgv) == 1) && (CvROOT(cand_cv) || CvXSUB(cand_cv))) {
++                  if ((old_cv = GvCV(topgv))) SvREFCNT_dec(old_cv);
++                  SvREFCNT_inc_simple_void_NN(cand_cv);
++                  GvCV(topgv) = cand_cv;
++                  GvCVGEN(topgv) = topgen_cmp;
++            }
++	    return candidate;
++        }
+     }
+ 
+-    if (av) {
+-	SV** svp = AvARRAY(av);
+-	/* NOTE: No support for tied ISA */
+-	I32 items = AvFILLp(av) + 1;
+-	while (items--) {
+-	    SV* const sv = *svp++;
+-	    HV* const basestash = gv_stashsv(sv, 0);
+-	    if (!basestash) {
+-		if (ckWARN(WARN_MISC))
+-		    Perl_warner(aTHX_ packWARN(WARN_MISC), "Can't locate package %"SVf" for @%s::ISA",
+-			SVfARG(sv), hvname);
+-		continue;
+-	    }
+-	    gv = gv_fetchmeth(basestash, name, len,
+-			      (level >= 0) ? level + 1 : level - 1);
+-	    if (gv)
+-		goto gotcha;
+-	}
++    /* Check UNIVERSAL without caching */
++    if(level == 0 || level == -1) {
++        candidate = gv_fetchmeth(NULL, name, len, 1);
++        if(candidate) {
++            cand_cv = GvCV(candidate);
++            if (topgv && (GvREFCNT(topgv) == 1) && (CvROOT(cand_cv) || CvXSUB(cand_cv))) {
++                  if ((old_cv = GvCV(topgv))) SvREFCNT_dec(old_cv);
++                  SvREFCNT_inc_simple_void_NN(cand_cv);
++                  GvCV(topgv) = cand_cv;
++                  GvCVGEN(topgv) = topgen_cmp;
++            }
++            return candidate;
++        }
+     }
+ 
+-    /* if at top level, try UNIVERSAL */
+-
+-    if (level == 0 || level == -1) {
+-	lastchance = gv_stashpvs("UNIVERSAL", 0);
+-
+-	if (lastchance) {
+-	    if ((gv = gv_fetchmeth(lastchance, name, len,
+-				  (level >= 0) ? level + 1 : level - 1)))
+-	    {
+-	  gotcha:
+-		/*
+-		 * Cache method in topgv if:
+-		 *  1. topgv has no synonyms (else inheritance crosses wires)
+-		 *  2. method isn't a stub (else AUTOLOAD fails spectacularly)
+-		 */
+-		if (topgv &&
+-		    GvREFCNT(topgv) == 1 &&
+-		    (cv = GvCV(gv)) &&
+-		    (CvROOT(cv) || CvXSUB(cv)))
+-		{
+-		    if ((cv = GvCV(topgv)))
+-			SvREFCNT_dec(cv);
+-		    GvCV(topgv) = (CV*)SvREFCNT_inc(GvCV(gv));
+-		    GvCVGEN(topgv) = PL_sub_generation;
+-		}
+-		return gv;
+-	    }
+-	    else if (topgv && GvREFCNT(topgv) == 1) {
+-		/* cache the fact that the method is not defined */
+-		GvCVGEN(topgv) = PL_sub_generation;
+-	    }
+-	}
++    if (topgv && GvREFCNT(topgv) == 1) {
++        /* cache the fact that the method is not defined */
++        GvCVGEN(topgv) = topgen_cmp;
+     }
+ 
+     return 0;
+@@ -1436,15 +1453,22 @@
+     gp->gp_refcnt++;
+     if (gp->gp_cv) {
+ 	if (gp->gp_cvgen) {
+-	    /* multi-named GPs cannot be used for method cache */
++	    /* If the GP they asked for a reference to contains
++               a method cache entry, clear it first, so that we
++               don't infect them with our cached entry */
+ 	    SvREFCNT_dec(gp->gp_cv);
+ 	    gp->gp_cv = NULL;
+ 	    gp->gp_cvgen = 0;
+ 	}
+-	else {
+-	    /* Adding a new name to a subroutine invalidates method cache */
+-	    PL_sub_generation++;
+-	}
++        /* XXX if anyone finds a method cache regression with
++           the "mro" stuff, turning this else block back on
++           is probably the first place to look --blblack
++        */
++        /*
++        else {
++            PL_sub_generation++;
++        }
++        */
+     }
+     return gp;
+ }
+@@ -1523,11 +1547,13 @@
+   dVAR;
+   MAGIC* const mg = mg_find((SV*)stash, PERL_MAGIC_overload_table);
+   AMT amt;
++  U32 newgen;
+ 
++  newgen = PL_sub_generation + HvMROMETA(stash)->sub_generation;
+   if (mg) {
+       const AMT * const amtp = (AMT*)mg->mg_ptr;
+       if (amtp->was_ok_am == PL_amagic_generation
+-	  && amtp->was_ok_sub == PL_sub_generation) {
++	  && amtp->was_ok_sub == newgen) {
+ 	  return (bool)AMT_OVERLOADED(amtp);
+       }
+       sv_unmagic((SV*)stash, PERL_MAGIC_overload_table);
+@@ -1537,7 +1563,7 @@
+ 
+   Zero(&amt,1,AMT);
+   amt.was_ok_am = PL_amagic_generation;
+-  amt.was_ok_sub = PL_sub_generation;
++  amt.was_ok_sub = newgen;
+   amt.fallback = AMGfallNO;
+   amt.flags = 0;
+ 
+@@ -1649,9 +1675,13 @@
+     dVAR;
+     MAGIC *mg;
+     AMT *amtp;
++    U32 newgen;
+ 
+     if (!stash || !HvNAME_get(stash))
+         return NULL;
++
++    newgen = PL_sub_generation + HvMROMETA(stash)->sub_generation;
++
+     mg = mg_find((SV*)stash, PERL_MAGIC_overload_table);
+     if (!mg) {
+       do_update:
+@@ -1661,7 +1691,7 @@
+     assert(mg);
+     amtp = (AMT*)mg->mg_ptr;
+     if ( amtp->was_ok_am != PL_amagic_generation
+-	 || amtp->was_ok_sub != PL_sub_generation )
++	 || amtp->was_ok_sub != newgen )
+ 	goto do_update;
+     if (AMT_AMAGIC(amtp)) {
+ 	CV * const ret = amtp->table[id];
+=== lib/constant.pm
+==================================================================
+--- lib/constant.pm	(/local/perl-current)	(revision 30454)
++++ lib/constant.pm	(/local/perl-c3-subg)	(revision 30454)
+@@ -5,7 +5,7 @@
+ use warnings::register;
+ 
+ our($VERSION, %declared);
+-$VERSION = '1.09';
++$VERSION = '1.10';
+ 
+ #=======================================================================
+ 
+@@ -109,7 +109,7 @@
+ 		    # constants from cv_const_sv are read only. So we have to:
+ 		    Internals::SvREADONLY($scalar, 1);
+ 		    $symtab->{$name} = \$scalar;
+-		    &Internals::inc_sub_generation;
++		    mro::method_changed_in($pkg);
+ 		} else {
+ 		    *$full_name = sub () { $scalar };
+ 		}
+=== lib/overload.pm
+==================================================================
+--- lib/overload.pm	(/local/perl-current)	(revision 30454)
++++ lib/overload.pm	(/local/perl-c3-subg)	(revision 30454)
+@@ -1,6 +1,6 @@
+ package overload;
+ 
+-our $VERSION = '1.04';
++our $VERSION = '1.05';
+ 
+ sub nil {}
+ 
+@@ -95,12 +95,13 @@
+ 
+ sub mycan {				# Real can would leave stubs.
+   my ($package, $meth) = @_;
+-  return \*{$package . "::$meth"} if defined &{$package . "::$meth"};
+-  my $p;
+-  foreach $p (@{$package . "::ISA"}) {
+-    my $out = mycan($p, $meth);
+-    return $out if $out;
++
++  my $mro = mro::get_linear_isa($package);
++  foreach my $p (@$mro) {
++    my $fqmeth = $p . q{::} . $meth;
++    return \*{$fqmeth} if defined &{$fqmeth};
+   }
++
+   return undef;
+ }
+ 
+=== lib/mro.pm
+==================================================================
+--- lib/mro.pm	(/local/perl-current)	(revision 30454)
++++ lib/mro.pm	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,266 @@
++#      mro.pm
++#
++#      Copyright (c) 2007 Brandon L Black
++#
++#      You may distribute under the terms of either the GNU General Public
++#      License or the Artistic License, as specified in the README file.
++#
++package mro;
++use strict;
++use warnings;
++
++our $VERSION = '0.01';
++
++sub import {
++    mro::set_mro(scalar(caller), $_[1]) if $_[1];
++}
++
++1;
++
++__END__
++
++=head1 NAME
++
++mro - Method Resolution Order
++
++=head1 SYNOPSIS
++
++  use mro 'dfs'; # enable DFS mro for this class (Perl default)
++  use mro 'c3'; # enable C3 mro for this class
++
++=head1 DESCRIPTION
++
++The "mro" namespace provides several utilities for dealing
++with method resolution order and method caching in general.
++
++=head1 OVERVIEW
++
++One can change the mro of a given class by either C<use mro>
++as shown in the synopsis, or by using the L</mro::set_mro>
++function below.  The functions below do not require that one
++loads the "mro" module, they are provided by the core.  The
++C<use mro> syntax is just syntax sugar for setting the current
++package's mro.
++
++=head1 The C3 MRO
++
++In addition to the traditional Perl default MRO (depth first
++search, called C<dfs> here), Perl now offers the C3 MRO as
++well.  Perl's support for C3 is based on the work done in
++Stevan Little's L<Class::C3>, and most of the C3-related
++documentation here is ripped directly from there.
++
++=head2 What is C3?
++
++C3 is the name of an algorithm which aims to provide a sane method resolution order under multiple
++inheritence. It was first introduced in the langauge Dylan (see links in the L<SEE ALSO> section),
++and then later adopted as the prefered MRO (Method Resolution Order) for the new-style classes in 
++Python 2.3. Most recently it has been adopted as the 'canonical' MRO for Perl 6 classes, and the 
++default MRO for Parrot objects as well.
++
++=head2 How does C3 work.
++
++C3 works by always preserving local precendence ordering. This essentially means that no class will appear before any of it's subclasses. Take the classic diamond inheritence pattern for instance:
++
++     <A>
++    /   \
++  <B>   <C>
++    \   /
++     <D>
++
++The standard Perl 5 MRO would be (D, B, A, C). The result being that B<A> appears before B<C>, even though B<C> is the subclass of B<A>. The C3 MRO algorithm however, produces the following MRO (D, B, C, A), which does not have this same issue.
++
++This example is fairly trival, for more complex examples and a deeper explaination, see the links in the L<SEE ALSO - C3 Links> section.
++
++=head1 Functions
++
++=head2 mro::get_linear_isa
++
++Arguments: classname[, type]
++
++Return an arrayref which is the linearized MRO of the given class.
++Uses whichever MRO is currently in effect for that class by default,
++or the given mro (either C<c3> or C<dfs> if specified as C<type>).
++
++=head2 mro::set_mro
++
++Arguments: classname, type
++
++Sets the MRO of the given class to the C<type> argument (either
++C<c3> or C<dfs>).
++
++=head2 mro::get_mro
++
++Arguments: classname
++
++Returns the MRO of the given class (either C<c3> or C<dfs>)
++
++=head2 mro::get_global_sub_generation
++
++Arguments: none
++
++Returns the current value of C<PL_sub_generation>.
++
++=head2 mro::invalidate_all_method_caches
++
++Arguments: none
++
++Increments C<PL_sub_generation>, which invalidates method
++caching in all packages.
++
++=head2 mro::get_sub_generation
++
++Arguments: classname
++
++Returns the current value of a given package's C<sub_generation>.
++This is only incremented when necessary for that package.
++
++If one is trying to determine whether significant (method/cache-
++affecting) changes have occured for a given stash since you last
++checked, you should check both this and the global one above.
++
++=head2 mro::method_changed_in
++
++Arguments: classname
++
++Invalidates the method cache of any classes dependant on the
++given class.
++
++=head2 next::method
++
++This is somewhat like C<SUPER>, but it uses the C3 method
++resolution order to get better consistency in multiple
++inheritance situations.  Note that while inheritance in
++general follows whichever MRO is in effect for the
++given class, C<next::method> only uses the C3 MRO.
++
++One generally uses it like so:
++
++  sub some_method {
++    my $self = shift;
++
++    my $superclass_answer = $self->next::method(@_);
++    return $superclass_answer + 1;
++  }
++
++Note that you don't (re-)specify the method name.
++It forces you to always use the same method name
++as the method you started in.
++
++It can be called on an object or a class, of course.
++
++The way it resolves which actual method to call is:
++
++1) First, it determines the linearized C3 MRO of
++the object or class it is being called on.
++
++2) Then, it determines the class and method name
++of the context it was invoked from.
++
++3) Finally, it searches down the C3 MRO list until
++it reaches the contextually enclosing class, then
++searches further down the MRO list for the next
++method with the same name as the contextually
++enclosing method.
++
++Failure to find a next method will result in an
++exception being thrown (see below for alternatives).
++
++This is substantially different than the behavior
++of C<SUPER> under complex multiple inheritance,
++(this becomes obvious when one realizes that the
++common superclasses in the C3 linearizations of
++a given class and one of its parents will not
++always be ordered the same for both).
++
++Caveat - Calling C<next::method> from methods defined outside the class:
++
++There is an edge case when using C<next::method> from within a subroutine which was created in a different module than the one it is called from. It sounds complicated, but it really isn't. Here is an example which will not work correctly:
++
++  *Foo::foo = sub { (shift)->next::method(@_) };
++
++The problem exists because the anonymous subroutine being assigned to the glob C<*Foo::foo> will show up in the call stack as being called C<__ANON__> and not C<foo> as you might expect. Since C<next::method> uses C<caller> to find the name of the method it was called in, it will fail in this case. 
++
++But fear not, there is a simple solution. The module C<Sub::Name> will reach into the perl internals and assign a name to an anonymous subroutine for you. Simply do this:
++    
++  use Sub::Name 'subname';
++  *Foo::foo = subname 'Foo::foo' => sub { (shift)->next::method(@_) };
++
++and things will Just Work.
++
++=head2 next::can
++
++Like C<next::method>, but just returns either
++a code reference or C<undef> to indicate that
++no further methods of this name exist.
++
++=head2 maybe::next::method
++
++In simple cases it is equivalent to:
++
++   $self->next::method(@_) if $self->next_can;
++
++But there are some cases where only this solution
++works (like "goto &maybe::next::method");
++
++=head1 SEE ALSO - C3 Links
++
++=head2 The original Dylan paper
++
++=over 4
++
++=item L<http://www.webcom.com/haahr/dylan/linearization-oopsla96.html>
++
++=back
++
++=head2 The prototype Perl 6 Object Model uses C3
++
++=over 4
++
++=item L<http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/>
++
++=back
++
++=head2 Parrot now uses C3
++
++=over 4
++
++=item L<http://aspn.activestate.com/ASPN/Mail/Message/perl6-internals/2746631>
++
++=item L<http://use.perl.org/~autrijus/journal/25768>
++
++=back
++
++=head2 Python 2.3 MRO related links
++
++=over 4
++
++=item L<http://www.python.org/2.3/mro.html>
++
++=item L<http://www.python.org/2.2.2/descrintro.html#mro>
++
++=back
++
++=head2 C3 for TinyCLOS
++
++=over 4
++
++=item L<http://www.call-with-current-continuation.org/eggs/c3.html>
++
++=back 
++
++=head2 Class::C3
++
++=over 4
++
++=item L<Class::C3>
++
++=back
++
++=head1 AUTHOR
++
++Brandon L. Black, E<lt>blblack@gmail.comE<gt>
++
++Based on Stevan Little's L<Class::C3>
++
++=cut
+=== win32/Makefile
+==================================================================
+--- win32/Makefile	(/local/perl-current)	(revision 30454)
++++ win32/Makefile	(/local/perl-c3-subg)	(revision 30454)
+@@ -647,6 +647,7 @@
+ 		..\dump.c	\
+ 		..\globals.c	\
+ 		..\gv.c		\
++		..\mro.c	\
+ 		..\hv.c		\
+ 		..\locale.c	\
+ 		..\mathoms.c    \
+=== win32/makefile.mk
+==================================================================
+--- win32/makefile.mk	(/local/perl-current)	(revision 30454)
++++ win32/makefile.mk	(/local/perl-c3-subg)	(revision 30454)
+@@ -816,6 +816,7 @@
+ 		..\dump.c	\
+ 		..\globals.c	\
+ 		..\gv.c		\
++		..\mro.c	\
+ 		..\hv.c		\
+ 		..\locale.c	\
+ 		..\mathoms.c    \
+=== win32/Makefile.ce
+==================================================================
+--- win32/Makefile.ce	(/local/perl-current)	(revision 30454)
++++ win32/Makefile.ce	(/local/perl-c3-subg)	(revision 30454)
+@@ -571,6 +571,7 @@
+ 		..\dump.c	\
+ 		..\globals.c	\
+ 		..\gv.c		\
++		..\mro.c	\
+ 		..\hv.c		\
+ 		..\mg.c		\
+ 		..\op.c		\
+@@ -790,6 +791,7 @@
+ $(DLLDIR)\dump.obj \
+ $(DLLDIR)\globals.obj \
+ $(DLLDIR)\gv.obj \
++$(DLLDIR)\mro.obj \
+ $(DLLDIR)\hv.obj \
+ $(DLLDIR)\locale.obj \
+ $(DLLDIR)\mathoms.obj \
+=== t/TEST
+==================================================================
+--- t/TEST	(/local/perl-current)	(revision 30454)
++++ t/TEST	(/local/perl-c3-subg)	(revision 30454)
+@@ -104,7 +104,7 @@
+ }
+ 
+ unless (@ARGV) {
+-    foreach my $dir (qw(base comp cmd run io op uni)) {
++    foreach my $dir (qw(base comp cmd run io op uni mro)) {
+ 	_find_tests($dir);
+     }
+     _find_tests("lib") unless $::core;
+=== t/mro	(new directory)
+==================================================================
+=== t/mro/basic_01_dfs.t
+==================================================================
+--- t/mro/basic_01_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_01_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,53 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 4;
++
++=pod
++
++This tests the classic diamond inheritence pattern.
++
++   <A>
++  /   \
++<B>   <C>
++  \   /
++   <D>
++
++=cut
++
++{
++    package Diamond_A;
++    sub hello { 'Diamond_A::hello' }
++}
++{
++    package Diamond_B;
++    use base 'Diamond_A';
++}
++{
++    package Diamond_C;
++    use base 'Diamond_A';     
++    
++    sub hello { 'Diamond_C::hello' }
++}
++{
++    package Diamond_D;
++    use base ('Diamond_B', 'Diamond_C');
++    use mro 'dfs';
++}
++
++is_deeply(
++    mro::get_linear_isa('Diamond_D'),
++    [ qw(Diamond_D Diamond_B Diamond_A Diamond_C) ],
++    '... got the right MRO for Diamond_D');
++
++is(Diamond_D->hello, 'Diamond_A::hello', '... method resolved itself as expected');
++is(Diamond_D->can('hello')->(), 'Diamond_A::hello', '... can(method) resolved itself as expected');
++is(UNIVERSAL::can("Diamond_D", 'hello')->(), 'Diamond_A::hello', '... can(method) resolved itself as expected');
+=== t/mro/vulcan_c3.t
+==================================================================
+--- t/mro/vulcan_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/vulcan_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,73 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 1;
++use mro;
++
++=pod
++
++example taken from: L<http://gauss.gwydiondylan.org/books/drm/drm_50.html>
++
++         Object
++           ^
++           |
++        LifeForm 
++         ^    ^
++        /      \
++   Sentient    BiPedal
++      ^          ^
++      |          |
++ Intelligent  Humanoid
++       ^        ^
++        \      /
++         Vulcan
++
++ define class <sentient> (<life-form>) end class;
++ define class <bipedal> (<life-form>) end class;
++ define class <intelligent> (<sentient>) end class;
++ define class <humanoid> (<bipedal>) end class;
++ define class <vulcan> (<intelligent>, <humanoid>) end class;
++
++=cut
++
++{
++    package Object;    
++    use mro 'c3';
++    
++    package LifeForm;
++    use mro 'c3';
++    use base 'Object';
++    
++    package Sentient;
++    use mro 'c3';
++    use base 'LifeForm';
++    
++    package BiPedal;
++    use mro 'c3';    
++    use base 'LifeForm';
++    
++    package Intelligent;
++    use mro 'c3';    
++    use base 'Sentient';
++    
++    package Humanoid;
++    use mro 'c3';    
++    use base 'BiPedal';
++    
++    package Vulcan;
++    use mro 'c3';    
++    use base ('Intelligent', 'Humanoid');
++}
++
++is_deeply(
++    mro::get_linear_isa('Vulcan'),
++    [ qw(Vulcan Intelligent Sentient Humanoid BiPedal LifeForm Object) ],
++    '... got the right MRO for the Vulcan Dylan Example');  
+=== t/mro/basic_02_dfs.t
+==================================================================
+--- t/mro/basic_02_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_02_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,121 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 10;
++
++=pod
++
++This example is take from: http://www.python.org/2.3/mro.html
++
++"My first example"
++class O: pass
++class F(O): pass
++class E(O): pass
++class D(O): pass
++class C(D,F): pass
++class B(D,E): pass
++class A(B,C): pass
++
++
++                          6
++                         ---
++Level 3                 | O |                  (more general)
++                      /  ---  \
++                     /    |    \                      |
++                    /     |     \                     |
++                   /      |      \                    |
++                  ---    ---    ---                   |
++Level 2        3 | D | 4| E |  | F | 5                |
++                  ---    ---    ---                   |
++                   \  \ _ /       |                   |
++                    \    / \ _    |                   |
++                     \  /      \  |                   |
++                      ---      ---                    |
++Level 1            1 | B |    | C | 2                 |
++                      ---      ---                    |
++                        \      /                      |
++                         \    /                      \ /
++                           ---
++Level 0                 0 | A |                (more specialized)
++                           ---
++
++=cut
++
++{
++    package Test::O;
++    use mro 'dfs'; 
++    
++    package Test::F;   
++    use mro 'dfs';  
++    use base 'Test::O';        
++    
++    package Test::E;
++    use base 'Test::O';    
++    use mro 'dfs';     
++    
++    sub C_or_E { 'Test::E' }
++
++    package Test::D;
++    use mro 'dfs'; 
++    use base 'Test::O';     
++    
++    sub C_or_D { 'Test::D' }       
++      
++    package Test::C;
++    use base ('Test::D', 'Test::F');
++    use mro 'dfs'; 
++    
++    sub C_or_D { 'Test::C' }
++    sub C_or_E { 'Test::C' }    
++        
++    package Test::B;    
++    use mro 'dfs'; 
++    use base ('Test::D', 'Test::E');    
++        
++    package Test::A;    
++    use base ('Test::B', 'Test::C');
++    use mro 'dfs';    
++}
++
++is_deeply(
++    mro::get_linear_isa('Test::F'),
++    [ qw(Test::F Test::O) ],
++    '... got the right MRO for Test::F');
++
++is_deeply(
++    mro::get_linear_isa('Test::E'),
++    [ qw(Test::E Test::O) ],
++    '... got the right MRO for Test::E');    
++
++is_deeply(
++    mro::get_linear_isa('Test::D'),
++    [ qw(Test::D Test::O) ],
++    '... got the right MRO for Test::D');       
++
++is_deeply(
++    mro::get_linear_isa('Test::C'),
++    [ qw(Test::C Test::D Test::O Test::F) ],
++    '... got the right MRO for Test::C'); 
++
++is_deeply(
++    mro::get_linear_isa('Test::B'),
++    [ qw(Test::B Test::D Test::O Test::E) ],
++    '... got the right MRO for Test::B');     
++
++is_deeply(
++    mro::get_linear_isa('Test::A'),
++    [ qw(Test::A Test::B Test::D Test::O Test::E Test::C Test::F) ],
++    '... got the right MRO for Test::A');  
++    
++is(Test::A->C_or_D, 'Test::D', '... got the expected method output');
++is(Test::A->can('C_or_D')->(), 'Test::D', '... can got the expected method output');
++is(Test::A->C_or_E, 'Test::E', '... got the expected method output');
++is(Test::A->can('C_or_E')->(), 'Test::E', '... can got the expected method output');
+=== t/mro/next_method.t
+==================================================================
+--- t/mro/next_method.t	(/local/perl-current)	(revision 30454)
++++ t/mro/next_method.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,65 @@
++#!/usr/bin/perl
++
++use strict;
++use warnings;
++
++use Test::More tests => 5;
++
++=pod
++
++This tests the classic diamond inheritence pattern.
++
++   <A>
++  /   \
++<B>   <C>
++  \   /
++   <D>
++
++=cut
++
++{
++    package Diamond_A;
++    use mro 'c3'; 
++    sub hello { 'Diamond_A::hello' }
++    sub foo { 'Diamond_A::foo' }       
++}
++{
++    package Diamond_B;
++    use base 'Diamond_A';
++    use mro 'c3';     
++    sub foo { 'Diamond_B::foo => ' . (shift)->next::method() }       
++}
++{
++    package Diamond_C;
++    use mro 'c3';    
++    use base 'Diamond_A';     
++
++    sub hello { 'Diamond_C::hello => ' . (shift)->next::method() }
++    sub foo { 'Diamond_C::foo => ' . (shift)->next::method() }   
++}
++{
++    package Diamond_D;
++    use base ('Diamond_B', 'Diamond_C');
++    use mro 'c3'; 
++    
++    sub foo { 'Diamond_D::foo => ' . (shift)->next::method() }   
++}
++
++is_deeply(
++    mro::get_linear_isa('Diamond_D'),
++    [ qw(Diamond_D Diamond_B Diamond_C Diamond_A) ],
++    '... got the right MRO for Diamond_D');
++
++is(Diamond_D->hello, 'Diamond_C::hello => Diamond_A::hello', '... method resolved itself as expected');
++
++is(Diamond_D->can('hello')->('Diamond_D'), 
++   'Diamond_C::hello => Diamond_A::hello', 
++   '... can(method) resolved itself as expected');
++   
++is(UNIVERSAL::can("Diamond_D", 'hello')->('Diamond_D'), 
++   'Diamond_C::hello => Diamond_A::hello', 
++   '... can(method) resolved itself as expected');
++
++is(Diamond_D->foo, 
++    'Diamond_D::foo => Diamond_B::foo => Diamond_C::foo => Diamond_A::foo', 
++    '... method foo resolved itself as expected');
+=== t/mro/basic_03_dfs.t
+==================================================================
+--- t/mro/basic_03_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_03_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,107 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 4;
++
++=pod
++
++This example is take from: http://www.python.org/2.3/mro.html
++
++"My second example"
++class O: pass
++class F(O): pass
++class E(O): pass
++class D(O): pass
++class C(D,F): pass
++class B(E,D): pass
++class A(B,C): pass
++
++                           6
++                          ---
++Level 3                  | O |
++                       /  ---  \
++                      /    |    \
++                     /     |     \
++                    /      |      \
++                  ---     ---    ---
++Level 2        2 | E | 4 | D |  | F | 5
++                  ---     ---    ---
++                   \      / \     /
++                    \    /   \   /
++                     \  /     \ /
++                      ---     ---
++Level 1            1 | B |   | C | 3
++                      ---     ---
++                       \       /
++                        \     /
++                          ---
++Level 0                0 | A |
++                          ---
++
++>>> A.mro()
++(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>,
++<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>,
++<type 'object'>)
++
++=cut
++
++{
++    package Test::O;
++    use mro 'dfs';
++    
++    sub O_or_D { 'Test::O' }
++    sub O_or_F { 'Test::O' }    
++    
++    package Test::F;
++    use base 'Test::O';
++    use mro 'dfs';
++    
++    sub O_or_F { 'Test::F' }    
++    
++    package Test::E;
++    use base 'Test::O';
++    use mro 'dfs';
++        
++    package Test::D;
++    use base 'Test::O';    
++    use mro 'dfs';
++    
++    sub O_or_D { 'Test::D' }
++    sub C_or_D { 'Test::D' }
++        
++    package Test::C;
++    use base ('Test::D', 'Test::F');
++    use mro 'dfs';    
++
++    sub C_or_D { 'Test::C' }
++    
++    package Test::B;
++    use base ('Test::E', 'Test::D');
++    use mro 'dfs';
++        
++    package Test::A;
++    use base ('Test::B', 'Test::C');
++    use mro 'dfs';
++}
++
++is_deeply(
++    mro::get_linear_isa('Test::A'),
++    [ qw(Test::A Test::B Test::E Test::O Test::D Test::C Test::F) ],
++    '... got the right MRO for Test::A');      
++    
++is(Test::A->O_or_D, 'Test::O', '... got the right method dispatch');    
++is(Test::A->O_or_F, 'Test::O', '... got the right method dispatch');   
++
++# NOTE: 
++# this test is particularly interesting because the p5 dispatch
++# would actually call Test::D before Test::C and Test::D is a
++# subclass of Test::C 
++is(Test::A->C_or_D, 'Test::D', '... got the right method dispatch');    
+=== t/mro/next_method_in_anon.t
+==================================================================
+--- t/mro/next_method_in_anon.t	(/local/perl-current)	(revision 30454)
++++ t/mro/next_method_in_anon.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,57 @@
++#!/usr/bin/perl
++
++use strict;
++use warnings;
++
++use Test::More tests => 2;
++
++=pod
++
++This tests the successful handling of a next::method call from within an
++anonymous subroutine.
++
++=cut
++
++{
++    package A;
++    use mro 'c3'; 
++
++    sub foo {
++      return 'A::foo';
++    }
++
++    sub bar {
++      return 'A::bar';
++    }
++}
++
++{
++    package B;
++    use base 'A';
++    use mro 'c3'; 
++    
++    sub foo {
++      my $code = sub {
++        return 'B::foo => ' . (shift)->next::method();
++      };
++      return (shift)->$code;
++    }
++
++    sub bar {
++      my $code1 = sub {
++        my $code2 = sub {
++          return 'B::bar => ' . (shift)->next::method();
++        };
++        return (shift)->$code2;
++      };
++      return (shift)->$code1;
++    }
++}
++
++is(B->foo, "B::foo => A::foo",
++   'method resolved inside anonymous sub');
++
++is(B->bar, "B::bar => A::bar",
++   'method resolved inside nested anonymous subs');
++
++
+=== t/mro/basic_04_dfs.t
+==================================================================
+--- t/mro/basic_04_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_04_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,40 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 1;
++
++=pod 
++
++From the parrot test t/pmc/object-meths.t
++
++ A   B A   E
++  \ /   \ /
++   C     D
++    \   /
++     \ /
++      F
++
++=cut
++
++{
++    package t::lib::A; use mro 'dfs';
++    package t::lib::B; use mro 'dfs';
++    package t::lib::E; use mro 'dfs';
++    package t::lib::C; use mro 'dfs'; use base ('t::lib::A', 't::lib::B');
++    package t::lib::D; use mro 'dfs'; use base ('t::lib::A', 't::lib::E');
++    package t::lib::F; use mro 'dfs'; use base ('t::lib::C', 't::lib::D');
++}
++
++is_deeply(
++    mro::get_linear_isa('t::lib::F'),
++    [ qw(t::lib::F t::lib::C t::lib::A t::lib::B t::lib::D t::lib::E) ],
++    '... got the right MRO for t::lib::F');  
++
+=== t/mro/next_method_edge_cases.t
+==================================================================
+--- t/mro/next_method_edge_cases.t	(/local/perl-current)	(revision 30454)
++++ t/mro/next_method_edge_cases.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,82 @@
++#!/usr/bin/perl
++
++use strict;
++use warnings;
++
++use Test::More tests => 11;
++
++{
++
++    {
++        package Foo;
++        use strict;
++        use warnings;
++        use mro 'c3';
++        sub new { bless {}, $_[0] }
++        sub bar { 'Foo::bar' }
++    }
++
++    # call the submethod in the direct instance
++
++    my $foo = Foo->new();
++    isa_ok($foo, 'Foo');
++
++    can_ok($foo, 'bar');
++    is($foo->bar(), 'Foo::bar', '... got the right return value');    
++
++    # fail calling it from a subclass
++
++    {
++        package Bar;
++        use strict;
++        use warnings;
++        use mro 'c3';
++        our @ISA = ('Foo');
++    }  
++    
++    my $bar = Bar->new();
++    isa_ok($bar, 'Bar');
++    isa_ok($bar, 'Foo');    
++    
++    # test it working with with Sub::Name
++    SKIP: {    
++        eval 'use Sub::Name';
++        skip "Sub::Name is required for this test", 3 if $@;
++    
++        my $m = sub { (shift)->next::method() };
++        Sub::Name::subname('Bar::bar', $m);
++        {
++            no strict 'refs';
++            *{'Bar::bar'} = $m;
++        }
++
++        can_ok($bar, 'bar');
++        my $value = eval { $bar->bar() };
++        ok(!$@, '... calling bar() succedded') || diag $@;
++        is($value, 'Foo::bar', '... got the right return value too');
++    }
++    
++    # test it failing without Sub::Name
++    {
++        package Baz;
++        use strict;
++        use warnings;
++        use mro 'c3';
++        our @ISA = ('Foo');
++    }      
++    
++    my $baz = Baz->new();
++    isa_ok($baz, 'Baz');
++    isa_ok($baz, 'Foo');    
++    
++    {
++        my $m = sub { (shift)->next::method() };
++        {
++            no strict 'refs';
++            *{'Baz::bar'} = $m;
++        }
++
++        eval { $baz->bar() };
++        ok($@, '... calling bar() with next::method failed') || diag $@;
++    }    
++}
+=== t/mro/basic_05_dfs.t
+==================================================================
+--- t/mro/basic_05_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_05_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,61 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 2;
++
++=pod
++
++This tests a strange bug found by Matt S. Trout 
++while building DBIx::Class. Thanks Matt!!!! 
++
++   <A>
++  /   \
++<C>   <B>
++  \   /
++   <D>
++
++=cut
++
++{
++    package Diamond_A;
++    use mro 'dfs'; 
++
++    sub foo { 'Diamond_A::foo' }
++}
++{
++    package Diamond_B;
++    use base 'Diamond_A';
++    use mro 'dfs';     
++
++    sub foo { 'Diamond_B::foo => ' . (shift)->SUPER::foo }
++}
++{
++    package Diamond_C;
++    use mro 'dfs';    
++    use base 'Diamond_A';     
++
++}
++{
++    package Diamond_D;
++    use base ('Diamond_C', 'Diamond_B');
++    use mro 'dfs';    
++    
++    sub foo { 'Diamond_D::foo => ' . (shift)->SUPER::foo }    
++}
++
++is_deeply(
++    mro::get_linear_isa('Diamond_D'),
++    [ qw(Diamond_D Diamond_C Diamond_A Diamond_B) ],
++    '... got the right MRO for Diamond_D');
++
++is(Diamond_D->foo, 
++   'Diamond_D::foo => Diamond_A::foo', 
++   '... got the right next::method dispatch path');
+=== t/mro/vulcan_dfs.t
+==================================================================
+--- t/mro/vulcan_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/vulcan_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,73 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 1;
++use mro;
++
++=pod
++
++example taken from: L<http://gauss.gwydiondylan.org/books/drm/drm_50.html>
++
++         Object
++           ^
++           |
++        LifeForm 
++         ^    ^
++        /      \
++   Sentient    BiPedal
++      ^          ^
++      |          |
++ Intelligent  Humanoid
++       ^        ^
++        \      /
++         Vulcan
++
++ define class <sentient> (<life-form>) end class;
++ define class <bipedal> (<life-form>) end class;
++ define class <intelligent> (<sentient>) end class;
++ define class <humanoid> (<bipedal>) end class;
++ define class <vulcan> (<intelligent>, <humanoid>) end class;
++
++=cut
++
++{
++    package Object;    
++    use mro 'dfs';
++    
++    package LifeForm;
++    use mro 'dfs';
++    use base 'Object';
++    
++    package Sentient;
++    use mro 'dfs';
++    use base 'LifeForm';
++    
++    package BiPedal;
++    use mro 'dfs';    
++    use base 'LifeForm';
++    
++    package Intelligent;
++    use mro 'dfs';    
++    use base 'Sentient';
++    
++    package Humanoid;
++    use mro 'dfs';    
++    use base 'BiPedal';
++    
++    package Vulcan;
++    use mro 'dfs';    
++    use base ('Intelligent', 'Humanoid');
++}
++
++is_deeply(
++    mro::get_linear_isa('Vulcan'),
++    [ qw(Vulcan Intelligent Sentient LifeForm Object Humanoid BiPedal) ],
++    '... got the right MRO for the Vulcan Dylan Example');  
+=== t/mro/dbic_c3.t
+==================================================================
+--- t/mro/dbic_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/dbic_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,125 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 1;
++
++=pod
++
++This example is taken from the inheritance graph of DBIx::Class::Core in DBIx::Class v0.07002:
++(No ASCII art this time, this graph is insane)
++
++The xx:: prefixes are just to be sure these bogus declarations never stomp on real ones
++
++=cut
++
++{
++    package xx::DBIx::Class::Core; use mro 'c3';
++    our @ISA = qw/
++      xx::DBIx::Class::Serialize::Storable
++      xx::DBIx::Class::InflateColumn
++      xx::DBIx::Class::Relationship
++      xx::DBIx::Class::PK::Auto
++      xx::DBIx::Class::PK
++      xx::DBIx::Class::Row
++      xx::DBIx::Class::ResultSourceProxy::Table
++      xx::DBIx::Class::AccessorGroup
++    /;
++
++    package xx::DBIx::Class::InflateColumn; use mro 'c3';
++    our @ISA = qw/ xx::DBIx::Class::Row /;
++
++    package xx::DBIx::Class::Row; use mro 'c3';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::DBIx::Class; use mro 'c3';
++    our @ISA = qw/
++      xx::DBIx::Class::Componentised
++      xx::Class::Data::Accessor
++    /;
++
++    package xx::DBIx::Class::Relationship; use mro 'c3';
++    our @ISA = qw/
++      xx::DBIx::Class::Relationship::Helpers
++      xx::DBIx::Class::Relationship::Accessor
++      xx::DBIx::Class::Relationship::CascadeActions
++      xx::DBIx::Class::Relationship::ProxyMethods
++      xx::DBIx::Class::Relationship::Base
++      xx::DBIx::Class
++    /;
++
++    package xx::DBIx::Class::Relationship::Helpers; use mro 'c3';
++    our @ISA = qw/
++      xx::DBIx::Class::Relationship::HasMany
++      xx::DBIx::Class::Relationship::HasOne
++      xx::DBIx::Class::Relationship::BelongsTo
++      xx::DBIx::Class::Relationship::ManyToMany
++    /;
++
++    package xx::DBIx::Class::Relationship::ProxyMethods; use mro 'c3';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::DBIx::Class::Relationship::Base; use mro 'c3';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::DBIx::Class::PK::Auto; use mro 'c3';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::DBIx::Class::PK; use mro 'c3';
++    our @ISA = qw/ xx::DBIx::Class::Row /;
++
++    package xx::DBIx::Class::ResultSourceProxy::Table; use mro 'c3';
++    our @ISA = qw/
++      xx::DBIx::Class::AccessorGroup
++      xx::DBIx::Class::ResultSourceProxy
++    /;
++
++    package xx::DBIx::Class::ResultSourceProxy; use mro 'c3';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::Class::Data::Accessor; our @ISA = (); use mro 'c3';
++    package xx::DBIx::Class::Relationship::HasMany; our @ISA = (); use mro 'c3';
++    package xx::DBIx::Class::Relationship::HasOne; our @ISA = (); use mro 'c3';
++    package xx::DBIx::Class::Relationship::BelongsTo; our @ISA = (); use mro 'c3';
++    package xx::DBIx::Class::Relationship::ManyToMany; our @ISA = (); use mro 'c3';
++    package xx::DBIx::Class::Componentised; our @ISA = (); use mro 'c3';
++    package xx::DBIx::Class::AccessorGroup; our @ISA = (); use mro 'c3';
++    package xx::DBIx::Class::Serialize::Storable; our @ISA = (); use mro 'c3';
++    package xx::DBIx::Class::Relationship::Accessor; our @ISA = (); use mro 'c3';
++    package xx::DBIx::Class::Relationship::CascadeActions; our @ISA = (); use mro 'c3';
++}
++
++is_deeply(
++    mro::get_linear_isa('xx::DBIx::Class::Core'),
++    [qw/
++        xx::DBIx::Class::Core
++        xx::DBIx::Class::Serialize::Storable
++        xx::DBIx::Class::InflateColumn
++        xx::DBIx::Class::Relationship
++        xx::DBIx::Class::Relationship::Helpers
++        xx::DBIx::Class::Relationship::HasMany
++        xx::DBIx::Class::Relationship::HasOne
++        xx::DBIx::Class::Relationship::BelongsTo
++        xx::DBIx::Class::Relationship::ManyToMany
++        xx::DBIx::Class::Relationship::Accessor
++        xx::DBIx::Class::Relationship::CascadeActions
++        xx::DBIx::Class::Relationship::ProxyMethods
++        xx::DBIx::Class::Relationship::Base
++        xx::DBIx::Class::PK::Auto
++        xx::DBIx::Class::PK
++        xx::DBIx::Class::Row
++        xx::DBIx::Class::ResultSourceProxy::Table
++        xx::DBIx::Class::AccessorGroup
++        xx::DBIx::Class::ResultSourceProxy
++        xx::DBIx::Class
++        xx::DBIx::Class::Componentised
++        xx::Class::Data::Accessor
++    /],
++    '... got the right C3 merge order for xx::DBIx::Class::Core');
+=== t/mro/next_method_used_with_NEXT.t
+==================================================================
+--- t/mro/next_method_used_with_NEXT.t	(/local/perl-current)	(revision 30454)
++++ t/mro/next_method_used_with_NEXT.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,53 @@
++#!/usr/bin/perl
++
++use strict;
++use warnings;
++
++use Test::More;
++
++BEGIN {
++    eval "use NEXT";
++    plan skip_all => "NEXT required for this test" if $@;
++    plan tests => 4;
++}
++
++{
++    package Foo;
++    use strict;
++    use warnings;
++    use mro 'c3';
++    
++    sub foo { 'Foo::foo' }
++    
++    package Fuz;
++    use strict;
++    use warnings;
++    use mro 'c3';
++    use base 'Foo';
++
++    sub foo { 'Fuz::foo => ' . (shift)->next::method }
++        
++    package Bar;
++    use strict;
++    use warnings;    
++    use mro 'c3';
++    use base 'Foo';
++
++    sub foo { 'Bar::foo => ' . (shift)->next::method }
++    
++    package Baz;
++    use strict;
++    use warnings;    
++    require NEXT; # load this as late as possible so we can catch the test skip
++
++    use base 'Bar', 'Fuz';
++    
++    sub foo { 'Baz::foo => ' . (shift)->NEXT::foo }    
++}
++
++is(Foo->foo, 'Foo::foo', '... got the right value from Foo->foo');
++is(Fuz->foo, 'Fuz::foo => Foo::foo', '... got the right value from Fuz->foo');
++is(Bar->foo, 'Bar::foo => Foo::foo', '... got the right value from Bar->foo');
++
++is(Baz->foo, 'Baz::foo => Bar::foo => Fuz::foo => Foo::foo', '... got the right value using NEXT in a subclass of a C3 class');
++
+=== t/mro/c3_with_overload.t
+==================================================================
+--- t/mro/c3_with_overload.t	(/local/perl-current)	(revision 30454)
++++ t/mro/c3_with_overload.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,47 @@
++#!/usr/bin/perl
++
++use strict;
++use warnings;
++
++use Test::More tests => 7;
++
++{
++    package BaseTest;
++    use strict;
++    use warnings;
++    use mro 'c3';
++    
++    package OverloadingTest;
++    use strict;
++    use warnings;
++    use mro 'c3';
++    use base 'BaseTest';        
++    use overload '""' => sub { ref(shift) . " stringified" },
++                 fallback => 1;
++    
++    sub new { bless {} => shift }    
++    
++    package InheritingFromOverloadedTest;
++    use strict;
++    use warnings;
++    use base 'OverloadingTest';
++    use mro 'c3';
++}
++
++my $x = InheritingFromOverloadedTest->new();
++isa_ok($x, 'InheritingFromOverloadedTest');
++
++my $y = OverloadingTest->new();
++isa_ok($y, 'OverloadingTest');
++
++is("$x", 'InheritingFromOverloadedTest stringified', '... got the right value when stringifing');
++is("$y", 'OverloadingTest stringified', '... got the right value when stringifing');
++
++ok(($y eq 'OverloadingTest stringified'), '... eq was handled correctly');
++
++my $result;
++eval { 
++    $result = $x eq 'InheritingFromOverloadedTest stringified' 
++};
++ok(!$@, '... this should not throw an exception');
++ok($result, '... and we should get the true value');
+=== t/mro/complex_c3.t
+==================================================================
+--- t/mro/complex_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/complex_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,148 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 12;
++
++=pod
++
++This example is taken from: http://rt.cpan.org/Public/Bug/Display.html?id=20879
++
++               ---     ---     ---
++Level 5     8 | A | 9 | B | A | C |    (More General)
++               ---     ---     ---       V
++                  \     |     /          |
++                   \    |    /           |
++                    \   |   /            |
++                     \  |  /             |
++                       ---               |
++Level 4             7 | D |              |
++                       ---               |
++                      /   \              |
++                     /     \             |
++                  ---       ---          |
++Level 3        4 | G |   6 | E |         |
++                  ---       ---          |
++                   |         |           |
++                   |         |           |
++                  ---       ---          |
++Level 2        3 | H |   5 | F |         |
++                  ---       ---          |
++                      \   /  |           |
++                       \ /   |           |
++                        \    |           |
++                       / \   |           |
++                      /   \  |           |
++                  ---       ---          |
++Level 1        1 | J |   2 | I |         |
++                  ---       ---          |
++                    \       /            |
++                     \     /             |
++                       ---               v
++Level 0             0 | K |            (More Specialized)
++                       ---
++
++
++0123456789A
++KJIHGFEDABC
++
++=cut
++
++{
++    package Test::A; use mro 'c3';
++
++    package Test::B; use mro 'c3';
++
++    package Test::C; use mro 'c3';
++
++    package Test::D; use mro 'c3';
++    use base qw/Test::A Test::B Test::C/;
++
++    package Test::E; use mro 'c3';
++    use base qw/Test::D/;
++
++    package Test::F; use mro 'c3';
++    use base qw/Test::E/;
++    sub testmeth { "wrong" }
++
++    package Test::G; use mro 'c3';
++    use base qw/Test::D/;
++
++    package Test::H; use mro 'c3';
++    use base qw/Test::G/;
++
++    package Test::I; use mro 'c3';
++    use base qw/Test::H Test::F/;
++    sub testmeth { "right" }
++
++    package Test::J; use mro 'c3';
++    use base qw/Test::F/;
++
++    package Test::K; use mro 'c3';
++    use base qw/Test::J Test::I/;
++    sub testmeth { shift->next::method }
++}
++
++is_deeply(
++    mro::get_linear_isa('Test::A'),
++    [ qw(Test::A) ],
++    '... got the right C3 merge order for Test::A');
++
++is_deeply(
++    mro::get_linear_isa('Test::B'),
++    [ qw(Test::B) ],
++    '... got the right C3 merge order for Test::B');
++
++is_deeply(
++    mro::get_linear_isa('Test::C'),
++    [ qw(Test::C) ],
++    '... got the right C3 merge order for Test::C');
++
++is_deeply(
++    mro::get_linear_isa('Test::D'),
++    [ qw(Test::D Test::A Test::B Test::C) ],
++    '... got the right C3 merge order for Test::D');
++
++is_deeply(
++    mro::get_linear_isa('Test::E'),
++    [ qw(Test::E Test::D Test::A Test::B Test::C) ],
++    '... got the right C3 merge order for Test::E');
++
++is_deeply(
++    mro::get_linear_isa('Test::F'),
++    [ qw(Test::F Test::E Test::D Test::A Test::B Test::C) ],
++    '... got the right C3 merge order for Test::F');
++
++is_deeply(
++    mro::get_linear_isa('Test::G'),
++    [ qw(Test::G Test::D Test::A Test::B Test::C) ],
++    '... got the right C3 merge order for Test::G');
++
++is_deeply(
++    mro::get_linear_isa('Test::H'),
++    [ qw(Test::H Test::G Test::D Test::A Test::B Test::C) ],
++    '... got the right C3 merge order for Test::H');
++
++is_deeply(
++    mro::get_linear_isa('Test::I'),
++    [ qw(Test::I Test::H Test::G Test::F Test::E Test::D Test::A Test::B Test::C) ],
++    '... got the right C3 merge order for Test::I');
++
++is_deeply(
++    mro::get_linear_isa('Test::J'),
++    [ qw(Test::J Test::F Test::E Test::D Test::A Test::B Test::C) ],
++    '... got the right C3 merge order for Test::J');
++
++is_deeply(
++    mro::get_linear_isa('Test::K'),
++    [ qw(Test::K Test::J Test::I Test::H Test::G Test::F Test::E Test::D Test::A Test::B Test::C) ],
++    '... got the right C3 merge order for Test::K');
++
++is(Test::K->testmeth(), "right", 'next::method working ok');
+=== t/mro/method_caching.t
+==================================================================
+--- t/mro/method_caching.t	(/local/perl-current)	(revision 30454)
++++ t/mro/method_caching.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,46 @@
++#!./perl
++
++use strict;
++use warnings;
++no warnings 'redefine'; # we do a lot of this
++no warnings 'prototype'; # we do a lot of this
++
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More;
++
++{
++    package MCTest::Base;
++    sub foo { return $_[1]+1 };
++    sub bar { 42 };
++
++    package MCTest::Derived;
++    our @ISA = qw/MCTest::Base/;
++}
++
++# These are various ways of re-defining MCTest::Base::foo and checking whether the method is cached when it shouldn't be
++my @testsubs = (
++    sub { eval 'sub MCTest::Base::foo { return $_[1]+2 }'; is(MCTest::Derived->foo(0), 2); },
++    sub { eval 'sub MCTest::Base::foo($) { return $_[1]+3 }'; is(MCTest::Derived->foo(0), 3); },
++    sub { eval 'sub MCTest::Base::foo($) { 4 }'; is(MCTest::Derived->foo(0), 4); },
++    sub { *MCTest::Base::foo = sub { $_[1]+5 }; is(MCTest::Derived->foo(0), 5); },
++    sub { local *MCTest::Base::foo = sub { $_[1]+6 }; is(MCTest::Derived->foo(0), 6); },
++    sub { is(MCTest::Derived->foo(0), 5); },
++    sub { sub FFF { $_[1]+9 }; local *MCTest::Base::foo = *FFF; is(MCTest::Derived->foo(0), 9); },
++    sub { is(MCTest::Derived->foo(0), 5); },
++    sub { *ASDF::asdf = sub { $_[1]+7 }; *MCTest::Base::foo = \&ASDF::asdf; is(MCTest::Derived->foo(0), 7); },
++    sub { *ASDF::asdf = sub { $_[1]+7 }; *MCTest::Base::foo = \&ASDF::asdf; is(MCTest::Derived->foo(0), 7); },
++    sub { undef *MCTest::Base::foo; eval { MCTest::Derived->foo(0) }; like($@, qr/locate object method/); },
++    sub { sub MCTest::Base::foo($); *MCTest::Base::foo = \&ASDF::asdf; is(MCTest::Derived->foo(0), 7); },
++    sub { *XYZ = sub { $_[1]+8 }; ${MCTest::Base::}{foo} = \&XYZ; is(MCTest::Derived->foo(0), 8); },
++);
++
++plan tests => scalar(@testsubs) + 1;
++
++is(MCTest::Derived->foo(0), 1);
++$_->() for (@testsubs);
+=== t/mro/dbic_dfs.t
+==================================================================
+--- t/mro/dbic_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/dbic_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,125 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 1;
++
++=pod
++
++This example is taken from the inheritance graph of DBIx::Class::Core in DBIx::Class v0.07002:
++(No ASCII art this time, this graph is insane)
++
++The xx:: prefixes are just to be sure these bogus declarations never stomp on real ones
++
++=cut
++
++{
++    package xx::DBIx::Class::Core; use mro 'dfs';
++    our @ISA = qw/
++      xx::DBIx::Class::Serialize::Storable
++      xx::DBIx::Class::InflateColumn
++      xx::DBIx::Class::Relationship
++      xx::DBIx::Class::PK::Auto
++      xx::DBIx::Class::PK
++      xx::DBIx::Class::Row
++      xx::DBIx::Class::ResultSourceProxy::Table
++      xx::DBIx::Class::AccessorGroup
++    /;
++
++    package xx::DBIx::Class::InflateColumn; use mro 'dfs';
++    our @ISA = qw/ xx::DBIx::Class::Row /;
++
++    package xx::DBIx::Class::Row; use mro 'dfs';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::DBIx::Class; use mro 'dfs';
++    our @ISA = qw/
++      xx::DBIx::Class::Componentised
++      xx::Class::Data::Accessor
++    /;
++
++    package xx::DBIx::Class::Relationship; use mro 'dfs';
++    our @ISA = qw/
++      xx::DBIx::Class::Relationship::Helpers
++      xx::DBIx::Class::Relationship::Accessor
++      xx::DBIx::Class::Relationship::CascadeActions
++      xx::DBIx::Class::Relationship::ProxyMethods
++      xx::DBIx::Class::Relationship::Base
++      xx::DBIx::Class
++    /;
++
++    package xx::DBIx::Class::Relationship::Helpers; use mro 'dfs';
++    our @ISA = qw/
++      xx::DBIx::Class::Relationship::HasMany
++      xx::DBIx::Class::Relationship::HasOne
++      xx::DBIx::Class::Relationship::BelongsTo
++      xx::DBIx::Class::Relationship::ManyToMany
++    /;
++
++    package xx::DBIx::Class::Relationship::ProxyMethods; use mro 'dfs';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::DBIx::Class::Relationship::Base; use mro 'dfs';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::DBIx::Class::PK::Auto; use mro 'dfs';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::DBIx::Class::PK; use mro 'dfs';
++    our @ISA = qw/ xx::DBIx::Class::Row /;
++
++    package xx::DBIx::Class::ResultSourceProxy::Table; use mro 'dfs';
++    our @ISA = qw/
++      xx::DBIx::Class::AccessorGroup
++      xx::DBIx::Class::ResultSourceProxy
++    /;
++
++    package xx::DBIx::Class::ResultSourceProxy; use mro 'dfs';
++    our @ISA = qw/ xx::DBIx::Class /;
++
++    package xx::Class::Data::Accessor; our @ISA = (); use mro 'dfs';
++    package xx::DBIx::Class::Relationship::HasMany; our @ISA = (); use mro 'dfs';
++    package xx::DBIx::Class::Relationship::HasOne; our @ISA = (); use mro 'dfs';
++    package xx::DBIx::Class::Relationship::BelongsTo; our @ISA = (); use mro 'dfs';
++    package xx::DBIx::Class::Relationship::ManyToMany; our @ISA = (); use mro 'dfs';
++    package xx::DBIx::Class::Componentised; our @ISA = (); use mro 'dfs';
++    package xx::DBIx::Class::AccessorGroup; our @ISA = (); use mro 'dfs';
++    package xx::DBIx::Class::Serialize::Storable; our @ISA = (); use mro 'dfs';
++    package xx::DBIx::Class::Relationship::Accessor; our @ISA = (); use mro 'dfs';
++    package xx::DBIx::Class::Relationship::CascadeActions; our @ISA = (); use mro 'dfs';
++}
++
++is_deeply(
++    mro::get_linear_isa('xx::DBIx::Class::Core'),
++    [qw/
++        xx::DBIx::Class::Core
++        xx::DBIx::Class::Serialize::Storable
++        xx::DBIx::Class::InflateColumn
++        xx::DBIx::Class::Row
++        xx::DBIx::Class
++        xx::DBIx::Class::Componentised
++        xx::Class::Data::Accessor
++        xx::DBIx::Class::Relationship
++        xx::DBIx::Class::Relationship::Helpers
++        xx::DBIx::Class::Relationship::HasMany
++        xx::DBIx::Class::Relationship::HasOne
++        xx::DBIx::Class::Relationship::BelongsTo
++        xx::DBIx::Class::Relationship::ManyToMany
++        xx::DBIx::Class::Relationship::Accessor
++        xx::DBIx::Class::Relationship::CascadeActions
++        xx::DBIx::Class::Relationship::ProxyMethods
++        xx::DBIx::Class::Relationship::Base
++        xx::DBIx::Class::PK::Auto
++        xx::DBIx::Class::PK
++        xx::DBIx::Class::ResultSourceProxy::Table
++        xx::DBIx::Class::AccessorGroup
++        xx::DBIx::Class::ResultSourceProxy
++    /],
++    '... got the right DFS merge order for xx::DBIx::Class::Core');
+=== t/mro/recursion_c3.t
+==================================================================
+--- t/mro/recursion_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/recursion_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,88 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More;
++use mro;
++
++plan skip_all => "Your system has no SIGALRM" if !exists $SIG{ALRM};
++plan tests => 8;
++
++=pod
++
++These are like the 010_complex_merge_classless test,
++but an infinite loop has been made in the heirarchy,
++to test that we can fail cleanly instead of going
++into an infinite loop
++
++=cut
++
++# initial setup, everything sane
++{
++    package K;
++    our @ISA = qw/J I/;
++    package J;
++    our @ISA = qw/F/;
++    package I;
++    our @ISA = qw/H F/;
++    package H;
++    our @ISA = qw/G/;
++    package G;
++    our @ISA = qw/D/;
++    package F;
++    our @ISA = qw/E/;
++    package E;
++    our @ISA = qw/D/;
++    package D;
++    our @ISA = qw/A B C/;
++    package C;
++    our @ISA = qw//;
++    package B;
++    our @ISA = qw//;
++    package A;
++    our @ISA = qw//;
++}
++
++# A series of 8 abberations that would cause infinite loops,
++#  each one undoing the work of the previous
++my @loopies = (
++    sub { @E::ISA = qw/F/ },
++    sub { @E::ISA = qw/D/; @C::ISA = qw/F/ },
++    sub { @C::ISA = qw//; @A::ISA = qw/K/ },
++    sub { @A::ISA = qw//; @J::ISA = qw/F K/ },
++    sub { @J::ISA = qw/F/; @H::ISA = qw/K G/ },
++    sub { @H::ISA = qw/G/; @B::ISA = qw/B/ },
++    sub { @B::ISA = qw//; @K::ISA = qw/K J I/ },
++    sub { @K::ISA = qw/J I/; @D::ISA = qw/A H B C/ },
++);
++
++foreach my $loopy (@loopies) {
++    eval {
++        local $SIG{ALRM} = sub { die "ALRMTimeout" };
++        alarm(3);
++        $loopy->();
++        mro::get_linear_isa('K', 'c3');
++    };
++
++    if(my $err = $@) {
++        if($err =~ /ALRMTimeout/) {
++            ok(0, "Loop terminated by SIGALRM");
++        }
++        elsif($err =~ /Recursive inheritance detected/) {
++            ok(1, "Graceful exception thrown");
++        }
++        else {
++            ok(0, "Unrecognized exception: $err");
++        }
++    }
++    else {
++        ok(0, "Infinite loop apparently succeeded???");
++    }
++}
+=== t/mro/overload_c3.t
+==================================================================
+--- t/mro/overload_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/overload_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,54 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 7;
++
++{
++    package BaseTest;
++    use strict;
++    use warnings;
++    use mro 'c3';
++    
++    package OverloadingTest;
++    use strict;
++    use warnings;
++    use mro 'c3';
++    use base 'BaseTest';        
++    use overload '""' => sub { ref(shift) . " stringified" },
++                 fallback => 1;
++    
++    sub new { bless {} => shift }    
++    
++    package InheritingFromOverloadedTest;
++    use strict;
++    use warnings;
++    use base 'OverloadingTest';
++    use mro 'c3';
++}
++
++my $x = InheritingFromOverloadedTest->new();
++isa_ok($x, 'InheritingFromOverloadedTest');
++
++my $y = OverloadingTest->new();
++isa_ok($y, 'OverloadingTest');
++
++is("$x", 'InheritingFromOverloadedTest stringified', '... got the right value when stringifing');
++is("$y", 'OverloadingTest stringified', '... got the right value when stringifing');
++
++ok(($y eq 'OverloadingTest stringified'), '... eq was handled correctly');
++
++my $result;
++eval { 
++    $result = $x eq 'InheritingFromOverloadedTest stringified' 
++};
++ok(!$@, '... this should not throw an exception');
++ok($result, '... and we should get the true value');
++
+=== t/mro/complex_dfs.t
+==================================================================
+--- t/mro/complex_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/complex_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,143 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 11;
++
++=pod
++
++This example is taken from: http://rt.cpan.org/Public/Bug/Display.html?id=20879
++
++               ---     ---     ---
++Level 5     8 | A | 9 | B | A | C |    (More General)
++               ---     ---     ---       V
++                  \     |     /          |
++                   \    |    /           |
++                    \   |   /            |
++                     \  |  /             |
++                       ---               |
++Level 4             7 | D |              |
++                       ---               |
++                      /   \              |
++                     /     \             |
++                  ---       ---          |
++Level 3        4 | G |   6 | E |         |
++                  ---       ---          |
++                   |         |           |
++                   |         |           |
++                  ---       ---          |
++Level 2        3 | H |   5 | F |         |
++                  ---       ---          |
++                      \   /  |           |
++                       \ /   |           |
++                        \    |           |
++                       / \   |           |
++                      /   \  |           |
++                  ---       ---          |
++Level 1        1 | J |   2 | I |         |
++                  ---       ---          |
++                    \       /            |
++                     \     /             |
++                       ---               v
++Level 0             0 | K |            (More Specialized)
++                       ---
++
++
++0123456789A
++KJIHGFEDABC
++
++=cut
++
++{
++    package Test::A; use mro 'dfs';
++
++    package Test::B; use mro 'dfs';
++
++    package Test::C; use mro 'dfs';
++
++    package Test::D; use mro 'dfs';
++    use base qw/Test::A Test::B Test::C/;
++
++    package Test::E; use mro 'dfs';
++    use base qw/Test::D/;
++
++    package Test::F; use mro 'dfs';
++    use base qw/Test::E/;
++
++    package Test::G; use mro 'dfs';
++    use base qw/Test::D/;
++
++    package Test::H; use mro 'dfs';
++    use base qw/Test::G/;
++
++    package Test::I; use mro 'dfs';
++    use base qw/Test::H Test::F/;
++
++    package Test::J; use mro 'dfs';
++    use base qw/Test::F/;
++
++    package Test::K; use mro 'dfs';
++    use base qw/Test::J Test::I/;
++}
++
++is_deeply(
++    mro::get_linear_isa('Test::A'),
++    [ qw(Test::A) ],
++    '... got the right DFS merge order for Test::A');
++
++is_deeply(
++    mro::get_linear_isa('Test::B'),
++    [ qw(Test::B) ],
++    '... got the right DFS merge order for Test::B');
++
++is_deeply(
++    mro::get_linear_isa('Test::C'),
++    [ qw(Test::C) ],
++    '... got the right DFS merge order for Test::C');
++
++is_deeply(
++    mro::get_linear_isa('Test::D'),
++    [ qw(Test::D Test::A Test::B Test::C) ],
++    '... got the right DFS merge order for Test::D');
++
++is_deeply(
++    mro::get_linear_isa('Test::E'),
++    [ qw(Test::E Test::D Test::A Test::B Test::C) ],
++    '... got the right DFS merge order for Test::E');
++
++is_deeply(
++    mro::get_linear_isa('Test::F'),
++    [ qw(Test::F Test::E Test::D Test::A Test::B Test::C) ],
++    '... got the right DFS merge order for Test::F');
++
++is_deeply(
++    mro::get_linear_isa('Test::G'),
++    [ qw(Test::G Test::D Test::A Test::B Test::C) ],
++    '... got the right DFS merge order for Test::G');
++
++is_deeply(
++    mro::get_linear_isa('Test::H'),
++    [ qw(Test::H Test::G Test::D Test::A Test::B Test::C) ],
++    '... got the right DFS merge order for Test::H');
++
++is_deeply(
++    mro::get_linear_isa('Test::I'),
++    [ qw(Test::I Test::H Test::G Test::D Test::A Test::B Test::C Test::F Test::E) ],
++    '... got the right DFS merge order for Test::I');
++
++is_deeply(
++    mro::get_linear_isa('Test::J'),
++    [ qw(Test::J Test::F Test::E Test::D Test::A Test::B Test::C) ],
++    '... got the right DFS merge order for Test::J');
++
++is_deeply(
++    mro::get_linear_isa('Test::K'),
++    [ qw(Test::K Test::J Test::F Test::E Test::D Test::A Test::B Test::C Test::I Test::H Test::G) ],
++    '... got the right DFS merge order for Test::K');
+=== t/mro/next_method_skip.t
+==================================================================
+--- t/mro/next_method_skip.t	(/local/perl-current)	(revision 30454)
++++ t/mro/next_method_skip.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,75 @@
++#!/usr/bin/perl
++
++use strict;
++use warnings;
++
++use Test::More tests => 10;
++
++=pod
++
++This tests the classic diamond inheritence pattern.
++
++   <A>
++  /   \
++<B>   <C>
++  \   /
++   <D>
++
++=cut
++
++{
++    package Diamond_A;
++    use mro 'c3'; 
++    sub bar { 'Diamond_A::bar' }        
++    sub baz { 'Diamond_A::baz' }
++}
++{
++    package Diamond_B;
++    use base 'Diamond_A';
++    use mro 'c3';    
++    sub baz { 'Diamond_B::baz => ' . (shift)->next::method() }         
++}
++{
++    package Diamond_C;
++    use mro 'c3';    
++    use base 'Diamond_A';     
++    sub foo { 'Diamond_C::foo' }   
++    sub buz { 'Diamond_C::buz' }     
++    
++    sub woz { 'Diamond_C::woz' }
++    sub maybe { 'Diamond_C::maybe' }         
++}
++{
++    package Diamond_D;
++    use base ('Diamond_B', 'Diamond_C');
++    use mro 'c3'; 
++    sub foo { 'Diamond_D::foo => ' . (shift)->next::method() } 
++    sub bar { 'Diamond_D::bar => ' . (shift)->next::method() }   
++    sub buz { 'Diamond_D::buz => ' . (shift)->baz() }  
++    sub fuz { 'Diamond_D::fuz => ' . (shift)->next::method() }  
++    
++    sub woz { 'Diamond_D::woz can => ' . ((shift)->next::can() ? 1 : 0) }
++    sub noz { 'Diamond_D::noz can => ' . ((shift)->next::can() ? 1 : 0) }
++
++    sub maybe { 'Diamond_D::maybe => ' . ((shift)->maybe::next::method() || 0) }
++    sub moybe { 'Diamond_D::moybe => ' . ((shift)->maybe::next::method() || 0) }             
++
++}
++
++is_deeply(
++    mro::get_linear_isa('Diamond_D'),
++    [ qw(Diamond_D Diamond_B Diamond_C Diamond_A) ],
++    '... got the right MRO for Diamond_D');
++
++is(Diamond_D->foo, 'Diamond_D::foo => Diamond_C::foo', '... skipped B and went to C correctly');
++is(Diamond_D->bar, 'Diamond_D::bar => Diamond_A::bar', '... skipped B & C and went to A correctly');
++is(Diamond_D->baz, 'Diamond_B::baz => Diamond_A::baz', '... called B method, skipped C and went to A correctly');
++is(Diamond_D->buz, 'Diamond_D::buz => Diamond_B::baz => Diamond_A::baz', '... called D method dispatched to , different method correctly');
++eval { Diamond_D->fuz };
++like($@, qr/^No next::method 'fuz' found for Diamond_D/, '... cannot re-dispatch to a method which is not there');
++
++is(Diamond_D->woz, 'Diamond_D::woz can => 1', '... can re-dispatch figured out correctly');
++is(Diamond_D->noz, 'Diamond_D::noz can => 0', '... cannot re-dispatch figured out correctly');
++
++is(Diamond_D->maybe, 'Diamond_D::maybe => Diamond_C::maybe', '... redispatched D to C when it exists');
++is(Diamond_D->moybe, 'Diamond_D::moybe => 0', '... quietly failed redispatch from D');
+=== t/mro/inconsistent_c3.t
+==================================================================
+--- t/mro/inconsistent_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/inconsistent_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,47 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 1;
++
++=pod
++
++This example is take from: http://www.python.org/2.3/mro.html
++
++"Serious order disagreement" # From Guido
++class O: pass
++class X(O): pass
++class Y(O): pass
++class A(X,Y): pass
++class B(Y,X): pass
++try:
++    class Z(A,B): pass #creates Z(A,B) in Python 2.2
++except TypeError:
++    pass # Z(A,B) cannot be created in Python 2.3
++
++=cut
++
++{
++    package X;
++    
++    package Y;
++    
++    package XY;
++    our @ISA = ('X', 'Y');
++    
++    package YX;
++    our @ISA = ('Y', 'X');
++
++    package Z;
++    our @ISA = ('XY', 'YX');
++}
++
++eval { mro::get_linear_isa('Z', 'c3') };
++like($@, qr/^Inconsistent /, '... got the right error with an inconsistent hierarchy');
+=== t/mro/recursion_dfs.t
+==================================================================
+--- t/mro/recursion_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/recursion_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,88 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More;
++use mro;
++
++plan skip_all => "Your system has no SIGALRM" if !exists $SIG{ALRM};
++plan tests => 8;
++
++=pod
++
++These are like the 010_complex_merge_classless test,
++but an infinite loop has been made in the heirarchy,
++to test that we can fail cleanly instead of going
++into an infinite loop
++
++=cut
++
++# initial setup, everything sane
++{
++    package K;
++    our @ISA = qw/J I/;
++    package J;
++    our @ISA = qw/F/;
++    package I;
++    our @ISA = qw/H F/;
++    package H;
++    our @ISA = qw/G/;
++    package G;
++    our @ISA = qw/D/;
++    package F;
++    our @ISA = qw/E/;
++    package E;
++    our @ISA = qw/D/;
++    package D;
++    our @ISA = qw/A B C/;
++    package C;
++    our @ISA = qw//;
++    package B;
++    our @ISA = qw//;
++    package A;
++    our @ISA = qw//;
++}
++
++# A series of 8 abberations that would cause infinite loops,
++#  each one undoing the work of the previous
++my @loopies = (
++    sub { @E::ISA = qw/F/ },
++    sub { @E::ISA = qw/D/; @C::ISA = qw/F/ },
++    sub { @C::ISA = qw//; @A::ISA = qw/K/ },
++    sub { @A::ISA = qw//; @J::ISA = qw/F K/ },
++    sub { @J::ISA = qw/F/; @H::ISA = qw/K G/ },
++    sub { @H::ISA = qw/G/; @B::ISA = qw/B/ },
++    sub { @B::ISA = qw//; @K::ISA = qw/K J I/ },
++    sub { @K::ISA = qw/J I/; @D::ISA = qw/A H B C/ },
++);
++
++foreach my $loopy (@loopies) {
++    eval {
++        local $SIG{ALRM} = sub { die "ALRMTimeout" };
++        alarm(3);
++        $loopy->();
++        mro::get_linear_isa('K', 'dfs');
++    };
++
++    if(my $err = $@) {
++        if($err =~ /ALRMTimeout/) {
++            ok(0, "Loop terminated by SIGALRM");
++        }
++        elsif($err =~ /Recursive inheritance detected/) {
++            ok(1, "Graceful exception thrown");
++        }
++        else {
++            ok(0, "Unrecognized exception: $err");
++        }
++    }
++    else {
++        ok(0, "Infinite loop apparently succeeded???");
++    }
++}
+=== t/mro/basic_01_c3.t
+==================================================================
+--- t/mro/basic_01_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_01_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,53 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 4;
++
++=pod
++
++This tests the classic diamond inheritence pattern.
++
++   <A>
++  /   \
++<B>   <C>
++  \   /
++   <D>
++
++=cut
++
++{
++    package Diamond_A;
++    sub hello { 'Diamond_A::hello' }
++}
++{
++    package Diamond_B;
++    use base 'Diamond_A';
++}
++{
++    package Diamond_C;
++    use base 'Diamond_A';     
++    
++    sub hello { 'Diamond_C::hello' }
++}
++{
++    package Diamond_D;
++    use base ('Diamond_B', 'Diamond_C');
++    use mro 'c3';
++}
++
++is_deeply(
++    mro::get_linear_isa('Diamond_D'),
++    [ qw(Diamond_D Diamond_B Diamond_C Diamond_A) ],
++    '... got the right MRO for Diamond_D');
++
++is(Diamond_D->hello, 'Diamond_C::hello', '... method resolved itself as expected');
++is(Diamond_D->can('hello')->(), 'Diamond_C::hello', '... can(method) resolved itself as expected');
++is(UNIVERSAL::can("Diamond_D", 'hello')->(), 'Diamond_C::hello', '... can(method) resolved itself as expected');
+=== t/mro/basic_02_c3.t
+==================================================================
+--- t/mro/basic_02_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_02_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,121 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 10;
++
++=pod
++
++This example is take from: http://www.python.org/2.3/mro.html
++
++"My first example"
++class O: pass
++class F(O): pass
++class E(O): pass
++class D(O): pass
++class C(D,F): pass
++class B(D,E): pass
++class A(B,C): pass
++
++
++                          6
++                         ---
++Level 3                 | O |                  (more general)
++                      /  ---  \
++                     /    |    \                      |
++                    /     |     \                     |
++                   /      |      \                    |
++                  ---    ---    ---                   |
++Level 2        3 | D | 4| E |  | F | 5                |
++                  ---    ---    ---                   |
++                   \  \ _ /       |                   |
++                    \    / \ _    |                   |
++                     \  /      \  |                   |
++                      ---      ---                    |
++Level 1            1 | B |    | C | 2                 |
++                      ---      ---                    |
++                        \      /                      |
++                         \    /                      \ /
++                           ---
++Level 0                 0 | A |                (more specialized)
++                           ---
++
++=cut
++
++{
++    package Test::O;
++    use mro 'c3'; 
++    
++    package Test::F;   
++    use mro 'c3';  
++    use base 'Test::O';        
++    
++    package Test::E;
++    use base 'Test::O';    
++    use mro 'c3';     
++    
++    sub C_or_E { 'Test::E' }
++
++    package Test::D;
++    use mro 'c3'; 
++    use base 'Test::O';     
++    
++    sub C_or_D { 'Test::D' }       
++      
++    package Test::C;
++    use base ('Test::D', 'Test::F');
++    use mro 'c3'; 
++    
++    sub C_or_D { 'Test::C' }
++    sub C_or_E { 'Test::C' }    
++        
++    package Test::B;    
++    use mro 'c3'; 
++    use base ('Test::D', 'Test::E');    
++        
++    package Test::A;    
++    use base ('Test::B', 'Test::C');
++    use mro 'c3';    
++}
++
++is_deeply(
++    mro::get_linear_isa('Test::F'),
++    [ qw(Test::F Test::O) ],
++    '... got the right MRO for Test::F');
++
++is_deeply(
++    mro::get_linear_isa('Test::E'),
++    [ qw(Test::E Test::O) ],
++    '... got the right MRO for Test::E');    
++
++is_deeply(
++    mro::get_linear_isa('Test::D'),
++    [ qw(Test::D Test::O) ],
++    '... got the right MRO for Test::D');       
++
++is_deeply(
++    mro::get_linear_isa('Test::C'),
++    [ qw(Test::C Test::D Test::F Test::O) ],
++    '... got the right MRO for Test::C'); 
++
++is_deeply(
++    mro::get_linear_isa('Test::B'),
++    [ qw(Test::B Test::D Test::E Test::O) ],
++    '... got the right MRO for Test::B');     
++
++is_deeply(
++    mro::get_linear_isa('Test::A'),
++    [ qw(Test::A Test::B Test::C Test::D Test::E Test::F Test::O) ],
++    '... got the right MRO for Test::A');  
++    
++is(Test::A->C_or_D, 'Test::C', '... got the expected method output');
++is(Test::A->can('C_or_D')->(), 'Test::C', '... can got the expected method output');
++is(Test::A->C_or_E, 'Test::C', '... got the expected method output');
++is(Test::A->can('C_or_E')->(), 'Test::C', '... can got the expected method output');
+=== t/mro/overload_dfs.t
+==================================================================
+--- t/mro/overload_dfs.t	(/local/perl-current)	(revision 30454)
++++ t/mro/overload_dfs.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,54 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 7;
++
++{
++    package BaseTest;
++    use strict;
++    use warnings;
++    use mro 'dfs';
++    
++    package OverloadingTest;
++    use strict;
++    use warnings;
++    use mro 'dfs';
++    use base 'BaseTest';        
++    use overload '""' => sub { ref(shift) . " stringified" },
++                 fallback => 1;
++    
++    sub new { bless {} => shift }    
++    
++    package InheritingFromOverloadedTest;
++    use strict;
++    use warnings;
++    use base 'OverloadingTest';
++    use mro 'dfs';
++}
++
++my $x = InheritingFromOverloadedTest->new();
++isa_ok($x, 'InheritingFromOverloadedTest');
++
++my $y = OverloadingTest->new();
++isa_ok($y, 'OverloadingTest');
++
++is("$x", 'InheritingFromOverloadedTest stringified', '... got the right value when stringifing');
++is("$y", 'OverloadingTest stringified', '... got the right value when stringifing');
++
++ok(($y eq 'OverloadingTest stringified'), '... eq was handled correctly');
++
++my $result;
++eval { 
++    $result = $x eq 'InheritingFromOverloadedTest stringified' 
++};
++ok(!$@, '... this should not throw an exception');
++ok($result, '... and we should get the true value');
++
+=== t/mro/basic_03_c3.t
+==================================================================
+--- t/mro/basic_03_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_03_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,107 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 4;
++
++=pod
++
++This example is take from: http://www.python.org/2.3/mro.html
++
++"My second example"
++class O: pass
++class F(O): pass
++class E(O): pass
++class D(O): pass
++class C(D,F): pass
++class B(E,D): pass
++class A(B,C): pass
++
++                           6
++                          ---
++Level 3                  | O |
++                       /  ---  \
++                      /    |    \
++                     /     |     \
++                    /      |      \
++                  ---     ---    ---
++Level 2        2 | E | 4 | D |  | F | 5
++                  ---     ---    ---
++                   \      / \     /
++                    \    /   \   /
++                     \  /     \ /
++                      ---     ---
++Level 1            1 | B |   | C | 3
++                      ---     ---
++                       \       /
++                        \     /
++                          ---
++Level 0                0 | A |
++                          ---
++
++>>> A.mro()
++(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>,
++<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>,
++<type 'object'>)
++
++=cut
++
++{
++    package Test::O;
++    use mro 'c3';
++    
++    sub O_or_D { 'Test::O' }
++    sub O_or_F { 'Test::O' }    
++    
++    package Test::F;
++    use base 'Test::O';
++    use mro 'c3';
++    
++    sub O_or_F { 'Test::F' }    
++    
++    package Test::E;
++    use base 'Test::O';
++    use mro 'c3';
++        
++    package Test::D;
++    use base 'Test::O';    
++    use mro 'c3';
++    
++    sub O_or_D { 'Test::D' }
++    sub C_or_D { 'Test::D' }
++        
++    package Test::C;
++    use base ('Test::D', 'Test::F');
++    use mro 'c3';    
++
++    sub C_or_D { 'Test::C' }
++    
++    package Test::B;
++    use base ('Test::E', 'Test::D');
++    use mro 'c3';
++        
++    package Test::A;
++    use base ('Test::B', 'Test::C');
++    use mro 'c3';
++}
++
++is_deeply(
++    mro::get_linear_isa('Test::A'),
++    [ qw(Test::A Test::B Test::E Test::C Test::D Test::F Test::O) ],
++    '... got the right MRO for Test::A');      
++    
++is(Test::A->O_or_D, 'Test::D', '... got the right method dispatch');    
++is(Test::A->O_or_F, 'Test::F', '... got the right method dispatch');   
++
++# NOTE: 
++# this test is particularly interesting because the p5 dispatch
++# would actually call Test::D before Test::C and Test::D is a
++# subclass of Test::C 
++is(Test::A->C_or_D, 'Test::C', '... got the right method dispatch');    
+=== t/mro/basic_04_c3.t
+==================================================================
+--- t/mro/basic_04_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_04_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,40 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 1;
++
++=pod 
++
++From the parrot test t/pmc/object-meths.t
++
++ A   B A   E
++  \ /   \ /
++   C     D
++    \   /
++     \ /
++      F
++
++=cut
++
++{
++    package t::lib::A; use mro 'c3';
++    package t::lib::B; use mro 'c3';
++    package t::lib::E; use mro 'c3';
++    package t::lib::C; use mro 'c3'; use base ('t::lib::A', 't::lib::B');
++    package t::lib::D; use mro 'c3'; use base ('t::lib::A', 't::lib::E');
++    package t::lib::F; use mro 'c3'; use base ('t::lib::C', 't::lib::D');
++}
++
++is_deeply(
++    mro::get_linear_isa('t::lib::F'),
++    [ qw(t::lib::F t::lib::C t::lib::D t::lib::A t::lib::B t::lib::E) ],
++    '... got the right MRO for t::lib::F');  
++
+=== t/mro/basic_05_c3.t
+==================================================================
+--- t/mro/basic_05_c3.t	(/local/perl-current)	(revision 30454)
++++ t/mro/basic_05_c3.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,61 @@
++#!./perl
++
++use strict;
++use warnings;
++BEGIN {
++    unless (-d 'blib') {
++        chdir 't' if -d 't';
++        @INC = '../lib';
++    }
++}
++
++use Test::More tests => 2;
++
++=pod
++
++This tests a strange bug found by Matt S. Trout 
++while building DBIx::Class. Thanks Matt!!!! 
++
++   <A>
++  /   \
++<C>   <B>
++  \   /
++   <D>
++
++=cut
++
++{
++    package Diamond_A;
++    use mro 'c3'; 
++
++    sub foo { 'Diamond_A::foo' }
++}
++{
++    package Diamond_B;
++    use base 'Diamond_A';
++    use mro 'c3';     
++
++    sub foo { 'Diamond_B::foo => ' . (shift)->SUPER::foo }
++}
++{
++    package Diamond_C;
++    use mro 'c3';    
++    use base 'Diamond_A';     
++
++}
++{
++    package Diamond_D;
++    use base ('Diamond_C', 'Diamond_B');
++    use mro 'c3';    
++    
++    sub foo { 'Diamond_D::foo => ' . (shift)->SUPER::foo }    
++}
++
++is_deeply(
++    mro::get_linear_isa('Diamond_D'),
++    [ qw(Diamond_D Diamond_C Diamond_B Diamond_A) ],
++    '... got the right MRO for Diamond_D');
++
++is(Diamond_D->foo, 
++   'Diamond_D::foo => Diamond_B::foo => Diamond_A::foo', 
++   '... got the right next::method dispatch path');
+=== t/mro/next_method_in_eval.t
+==================================================================
+--- t/mro/next_method_in_eval.t	(/local/perl-current)	(revision 30454)
++++ t/mro/next_method_in_eval.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,44 @@
++#!/usr/bin/perl
++
++use strict;
++use warnings;
++
++use Test::More tests => 1;
++
++=pod
++
++This tests the use of an eval{} block to wrap a next::method call.
++
++=cut
++
++{
++    package A;
++    use mro 'c3'; 
++
++    sub foo {
++      die 'A::foo died';
++      return 'A::foo succeeded';
++    }
++}
++
++{
++    package B;
++    use base 'A';
++    use mro 'c3'; 
++    
++    sub foo {
++      eval {
++        return 'B::foo => ' . (shift)->next::method();
++      };
++
++      if ($@) {
++        return $@;
++      }
++    }
++}
++
++like(B->foo, 
++   qr/^A::foo died/, 
++   'method resolved inside eval{}');
++
++
+=== t/op/magic.t
+==================================================================
+--- t/op/magic.t	(/local/perl-current)	(revision 30454)
++++ t/op/magic.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -440,7 +440,10 @@
+ if (!$Is_VMS) {
+     local @ISA;
+     local %ENV;
+-    eval { push @ISA, __PACKAGE__ };
++    # This used to be __PACKAGE__, but that causes recursive
++    #  inheritance, which is detected earlier now and broke
++    #  this test
++    eval { push @ISA, __FILE__ };
+     ok( $@ eq '', 'Push a constant on a magic array');
+     $@ and print "# $@";
+     eval { %ENV = (PATH => __PACKAGE__) };
+=== NetWare/Makefile
+==================================================================
+--- NetWare/Makefile	(/local/perl-current)	(revision 30454)
++++ NetWare/Makefile	(/local/perl-c3-subg)	(revision 30454)
+@@ -701,6 +701,7 @@
+ 		..\dump.c	\
+ 		..\globals.c	\
+ 		..\gv.c		\
++		..\mro.c	\
+ 		..\hv.c		\
+ 		..\locale.c	\
+                 ..\mathoms.c    \
+=== vms/descrip_mms.template
+==================================================================
+--- vms/descrip_mms.template	(/local/perl-current)	(revision 30454)
++++ vms/descrip_mms.template	(/local/perl-c3-subg)	(revision 30454)
+@@ -279,13 +279,13 @@
+ 
+ #### End of system configuration section. ####
+ 
+-c0 = $(MALLOC_C) $(SOCKC) av.c deb.c doio.c doop.c dump.c globals.c gv.c hv.c
++c0 = $(MALLOC_C) $(SOCKC) av.c deb.c doio.c doop.c dump.c globals.c gv.c hv.c mro.c
+ c1 = mg.c locale.c mathoms.c miniperlmain.c numeric.c op.c pad.c perl.c perlapi.c perlio.c
+ c2 = perly.c pp.c pp_ctl.c pp_hot.c pp_pack.c pp_sort.c pp_sys.c regcomp.c regexec.c reentr.c
+ c3 = run.c scope.c sv.c taint.c toke.c universal.c utf8.c util.c vms.c xsutils.c
+ c = $(c0) $(c1) $(c2) $(c3)
+ 
+-obj0 = $(MALLOC_O) $(SOCKO) av$(O) deb$(O) doio$(O) doop$(O) dump$(O)
++obj0 = $(MALLOC_O) $(SOCKO) av$(O) deb$(O) doio$(O) doop$(O) dump$(O) mro$(O)
+ obj1 = globals$(O) gv$(O) hv$(O) locale$(O) mathoms$(O) mg$(O) miniperlmain$(O) numeric$(O) op$(O) pad$(O)
+ obj2 = perl$(O) perlapi$(O) perlio$(O) perly$(O) pp$(O) pp_ctl$(O) pp_hot$(O) reentr$(O)
+ obj3 = pp_pack$(O) pp_sort$(O) pp_sys$(O) regcomp$(O) regexec$(O) run$(O) scope$(O) sv$(O) taint$(O) toke$(O)
+@@ -1619,6 +1619,8 @@
+ 	$(CC) $(CORECFLAGS) $(MMS$SOURCE)
+ gv$(O) : gv.c $(h)
+ 	$(CC) $(CORECFLAGS) $(MMS$SOURCE)
++mro$(O) : mro.c $(h)
++	$(CC) $(CORECFLAGS) $(MMS$SOURCE)
+ hv$(O) : hv.c $(h)
+ 	$(CC) $(CORECFLAGS) $(MMS$SOURCE)
+ locale$(O) : locale.c $(h)
+=== Makefile.SH
+==================================================================
+--- Makefile.SH	(/local/perl-current)	(revision 30454)
++++ Makefile.SH	(/local/perl-c3-subg)	(revision 30454)
+@@ -367,7 +367,7 @@
+ h5 = utf8.h warnings.h
+ h = $(h1) $(h2) $(h3) $(h4) $(h5)
+ 
+-c1 = av.c scope.c op.c doop.c doio.c dump.c gv.c hv.c mg.c reentr.c  perl.c
++c1 = av.c scope.c op.c doop.c doio.c dump.c gv.c hv.c mg.c reentr.c mro.c perl.c
+ c2 = perly.c pp.c pp_hot.c pp_ctl.c pp_sys.c regcomp.c regexec.c utf8.c sv.c
+ c3 = taint.c toke.c util.c deb.c run.c universal.c xsutils.c pad.c globals.c
+ c4 = perlio.c perlapi.c numeric.c mathoms.c locale.c pp_pack.c pp_sort.c
+@@ -375,7 +375,7 @@
+ 
+ c = $(c1) $(c2) $(c3) $(c4) $(c5) miniperlmain.c perlmain.c opmini.c
+ 
+-obj1 = $(madlyobj) $(mallocobj) gv$(OBJ_EXT) toke$(OBJ_EXT) perly$(OBJ_EXT) op$(OBJ_EXT) pad$(OBJ_EXT) regcomp$(OBJ_EXT) dump$(OBJ_EXT) util$(OBJ_EXT) mg$(OBJ_EXT) reentr$(OBJ_EXT)
++obj1 = $(madlyobj) $(mallocobj) gv$(OBJ_EXT) toke$(OBJ_EXT) perly$(OBJ_EXT) op$(OBJ_EXT) pad$(OBJ_EXT) regcomp$(OBJ_EXT) dump$(OBJ_EXT) util$(OBJ_EXT) mg$(OBJ_EXT) reentr$(OBJ_EXT) mro$(OBJ_EXT)
+ obj2 = hv$(OBJ_EXT) av$(OBJ_EXT) perl$(OBJ_EXT) run$(OBJ_EXT) pp_hot$(OBJ_EXT) sv$(OBJ_EXT) pp$(OBJ_EXT) scope$(OBJ_EXT) pp_ctl$(OBJ_EXT) pp_sys$(OBJ_EXT)
+ obj3 = doop$(OBJ_EXT) doio$(OBJ_EXT) regexec$(OBJ_EXT) utf8$(OBJ_EXT) taint$(OBJ_EXT) deb$(OBJ_EXT) universal$(OBJ_EXT) xsutils$(OBJ_EXT) globals$(OBJ_EXT) perlio$(OBJ_EXT) perlapi$(OBJ_EXT) numeric$(OBJ_EXT) mathoms$(OBJ_EXT) locale$(OBJ_EXT) pp_pack$(OBJ_EXT) pp_sort$(OBJ_EXT)
+ 
+=== proto.h
+==================================================================
+--- proto.h	(/local/perl-current)	(revision 30454)
++++ proto.h	(/local/perl-c3-subg)	(revision 30454)
+@@ -635,6 +635,25 @@
+ PERL_CALLCONV GV*	Perl_gv_fetchfile_flags(pTHX_ const char *const name, const STRLEN len, const U32 flags)
+ 			__attribute__nonnull__(pTHX_1);
+ 
++PERL_CALLCONV struct mro_meta*	Perl_mro_meta_init(pTHX_ HV* stash)
++			__attribute__nonnull__(pTHX_1);
++
++PERL_CALLCONV AV*	Perl_mro_get_linear_isa(pTHX_ HV* stash)
++			__attribute__nonnull__(pTHX_1);
++
++PERL_CALLCONV AV*	Perl_mro_get_linear_isa_c3(pTHX_ HV* stash, I32 level)
++			__attribute__nonnull__(pTHX_1);
++
++PERL_CALLCONV AV*	Perl_mro_get_linear_isa_dfs(pTHX_ HV* stash, I32 level)
++			__attribute__nonnull__(pTHX_1);
++
++PERL_CALLCONV void	Perl_mro_isa_changed_in(pTHX_ HV* stash)
++			__attribute__nonnull__(pTHX_1);
++
++PERL_CALLCONV void	Perl_mro_method_changed_in(pTHX_ HV* stash)
++			__attribute__nonnull__(pTHX_1);
++
++PERL_CALLCONV void	Perl_boot_core_mro(pTHX);
+ PERL_CALLCONV GV*	Perl_gv_fetchmeth(pTHX_ HV* stash, const char* name, STRLEN len, I32 level)
+ 			__attribute__nonnull__(pTHX_2);
+ 
+=== ext/B/t/b.t
+==================================================================
+--- ext/B/t/b.t	(/local/perl-current)	(revision 30454)
++++ ext/B/t/b.t	(/local/perl-c3-subg)	(revision 30454)
+@@ -169,7 +169,7 @@
+ {
+     no warnings 'once';
+     my $sg = B::sub_generation();
+-    *Whatever::hand_waving = sub { };
++    *UNIVERSAL::hand_waving = sub { };
+     ok( $sg < B::sub_generation, "sub_generation increments" );
+ }
+ 
+=== MANIFEST
+==================================================================
+--- MANIFEST	(/local/perl-current)	(revision 30454)
++++ MANIFEST	(/local/perl-c3-subg)	(revision 30454)
+@@ -2252,6 +2252,7 @@
+ lib/Module/Pluggable/t/lib/OddTest/Plugin/-Dodgy.pm	Module::Pluggable tests
+ lib/Module/Pluggable/t/lib/OddTest/Plugin/Foo.pm	Module::Pluggable tests
+ lib/Module/Pluggable/t/lib/TA/C/A/I.pm	Module::Pluggable tests
++lib/mro.pm			mro extension
+ lib/Net/Changes.libnet		libnet
+ lib/Net/Cmd.pm			libnet
+ lib/Net/Config.eg		libnet
+@@ -2953,6 +2954,7 @@
+ mpeix/mpeix_setjmp.c		MPE/iX port
+ mpeix/nm			MPE/iX port
+ mpeix/relink			MPE/iX port
++mro.c				Method Resolution Order code
+ myconfig.SH			Prints summary of the current configuration
+ NetWare/bat/Buildtype.bat	NetWare port
+ NetWare/bat/SetCodeWar.bat	NetWare port
+@@ -3619,6 +3621,35 @@
+ t/lib/warnings/universal	Tests for universal.c for warnings.t
+ t/lib/warnings/utf8		Tests for utf8.c for warnings.t
+ t/lib/warnings/util		Tests for util.c for warnings.t
++t/mro/basic_01_c3.t		mro tests
++t/mro/basic_01_dfs.t		mro tests
++t/mro/basic_02_c3.t		mro tests
++t/mro/basic_02_dfs.t		mro tests
++t/mro/basic_03_c3.t		mro tests
++t/mro/basic_03_dfs.t		mro tests
++t/mro/basic_04_c3.t		mro tests
++t/mro/basic_04_dfs.t		mro tests
++t/mro/basic_05_c3.t		mro tests
++t/mro/basic_05_dfs.t		mro tests
++t/mro/c3_with_overload.t	mro tests
++t/mro/complex_c3.t		mro tests
++t/mro/complex_dfs.t		mro tests
++t/mro/dbic_c3.t			mro tests
++t/mro/dbic_dfs.t		mro tests
++t/mro/inconsistent_c3.t		mro tests
++t/mro/next_method.t		mro tests
++t/mro/next_method_edge_cases.t	mro tests
++t/mro/next_method_in_anon.t	mro tests
++t/mro/next_method_in_eval.t	mro tests
++t/mro/next_method_skip.t	mro tests
++t/mro/next_method_used_with_NEXT.t	mro tests
++t/mro/overload_c3.t		mro tests
++t/mro/overload_dfs.t		mro tests
++t/mro/recursion_c3.t		mro tests
++t/mro/recursion_dfs.t		mro tests
++t/mro/vulcan_c3.t		mro tests
++t/mro/vulcan_dfs.t		mro tests
++t/mro/method_caching.t		mro tests
+ Todo.micro			The Wishlist for microperl
+ toke.c				The tokener
+ t/op/64bitint.t			See if 64 bit integers work
+=== mro.c
+==================================================================
+--- mro.c	(/local/perl-current)	(revision 30454)
++++ mro.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -0,0 +1,901 @@
++/*    mro.c
++ *
++ *    Copyright (c) 2007 Brandon L Black
++ *
++ *    You may distribute under the terms of either the GNU General Public
++ *    License or the Artistic License, as specified in the README file.
++ *
++ */
++
++/*
++=head1 MRO Functions
++
++These functions are related to the method resolution order of perl classes
++
++=cut
++*/
++
++#include "EXTERN.h"
++#include "perl.h"
++
++struct mro_meta*
++Perl_mro_meta_init(pTHX_ HV* stash)
++{
++    void* newmeta;
++
++    assert(stash);
++    assert(HvAUX(stash));
++    assert(!(HvAUX(stash)->xhv_mro_meta));
++    Newxz(newmeta, sizeof(struct mro_meta), char);
++    HvAUX(stash)->xhv_mro_meta = (struct mro_meta*)newmeta;
++    ((struct mro_meta*)newmeta)->sub_generation = 1;
++
++    /* Manually flag UNIVERSAL as being universal.
++       This happens early in perl booting (when universal.c
++       does the newXS calls for UNIVERSAL::*), and infects
++       other packages as they are added to UNIVERSAL's MRO
++    */
++    if(HvNAMELEN_get(stash) == 9
++       && strEQ(HEK_KEY(HvAUX(stash)->xhv_name), "UNIVERSAL")) {
++            HvMROMETA(stash)->is_universal = 1;
++    }
++
++    return newmeta;
++}
++
++/*
++=for apidoc mro_get_linear_isa_dfs
++
++Returns the Depth-First Search linearization of @ISA
++the given stash.  The return value is a read-only AV*.
++C<level> should be 0 (it is used internally in this
++function's recursion).
++
++=cut
++*/
++AV*
++Perl_mro_get_linear_isa_dfs(pTHX_ HV *stash, I32 level)
++{
++    AV* retval;
++    GV** gvp;
++    GV* gv;
++    AV* av;
++    SV** svp;
++    I32 items;
++    AV* subrv;
++    SV** subrv_p;
++    I32 subrv_items;
++    const char* stashname;
++    struct mro_meta* meta;
++
++    assert(stash);
++    assert(HvAUX(stash));
++
++    stashname = HvNAME_get(stash);
++    if (!stashname)
++      Perl_croak(aTHX_
++                 "Can't linearize anonymous symbol table");
++
++    if (level > 100)
++        Perl_croak(aTHX_ "Recursive inheritance detected in package '%s'",
++              stashname);
++
++    meta = HvMROMETA(stash);
++    if((retval = meta->mro_linear_dfs)) {
++        /* return cache if valid */
++        SvREFCNT_inc_simple_void_NN(retval);
++        return retval;
++    }
++
++    /* not in cache, make a new one */
++    retval = (AV*)sv_2mortal((SV*)newAV());
++    av_push(retval, newSVpv(stashname, 0)); /* add ourselves at the top */
++
++    gvp = (GV**)hv_fetchs(stash, "ISA", FALSE);
++    av = (gvp && (gv = *gvp) && isGV_with_GP(gv)) ? GvAV(gv) : NULL;
++
++    if(av) {
++        HV* stored = (HV*)sv_2mortal((SV*)newHV());
++        svp = AvARRAY(av);
++        items = AvFILLp(av) + 1;
++        while (items--) {
++            SV* const sv = *svp++;
++            HV* const basestash = gv_stashsv(sv, 0);
++
++            if (!basestash) {
++                if(!hv_exists_ent(stored, sv, 0)) {
++                    av_push(retval, newSVsv(sv));
++                    hv_store_ent(stored, sv, &PL_sv_undef, 0);
++                }
++            }
++            else {
++                subrv = (AV*)sv_2mortal((SV*)mro_get_linear_isa_dfs(basestash, level + 1));
++                subrv_p = AvARRAY(subrv);
++                subrv_items = AvFILLp(subrv) + 1;
++                while(subrv_items--) {
++                    SV* subsv = *subrv_p++;
++                    if(!hv_exists_ent(stored, subsv, 0)) {
++                        av_push(retval, newSVsv(subsv));
++                        hv_store_ent(stored, subsv, &PL_sv_undef, 0);
++                    }
++                }
++            }
++        }
++    }
++
++    SvREADONLY_on(retval);
++    SvREFCNT_inc_simple_void_NN(retval); /* for meta storage */
++    SvREFCNT_inc_simple_void_NN(retval); /* for return to caller */
++    meta->mro_linear_dfs = retval;
++    return retval;
++}
++
++/*
++=for apidoc mro_get_linear_isa_c3
++
++Returns the C3 linearization of @ISA
++the given stash.  The return value is a read-only AV*.
++C<level> should be 0 (it is used internally in this
++function's recursion).
++
++=cut
++*/
++
++AV*
++Perl_mro_get_linear_isa_c3(pTHX_ HV* stash, I32 level)
++{
++    AV* retval;
++    GV** gvp;
++    GV* gv;
++    AV* isa;
++    const char* stashname;
++    STRLEN stashname_len;
++    struct mro_meta* meta;
++
++    assert(stash);
++    assert(HvAUX(stash));
++
++    stashname = HvNAME_get(stash);
++    stashname_len = HvNAMELEN_get(stash);
++    if (!stashname)
++      Perl_croak(aTHX_
++                 "Can't linearize anonymous symbol table");
++
++    if (level > 100)
++        Perl_croak(aTHX_ "Recursive inheritance detected in package '%s'",
++              stashname);
++
++    meta = HvMROMETA(stash);
++    if((retval = meta->mro_linear_c3)) {
++        /* return cache if valid */
++        SvREFCNT_inc_simple_void_NN(retval);
++        return retval;
++    }
++
++    /* not in cache, make a new one */
++
++    retval = (AV*)sv_2mortal((SV*)newAV());
++    av_push(retval, newSVpvn(stashname, stashname_len)); /* us first */
++
++    gvp = (GV**)hv_fetchs(stash, "ISA", FALSE);
++    isa = (gvp && (gv = *gvp) && isGV_with_GP(gv)) ? GvAV(gv) : NULL;
++
++    if(isa && AvFILLp(isa) >= 0) {
++        SV** seqs_ptr;
++        I32 seqs_items;
++        HV* tails = (HV*)sv_2mortal((SV*)newHV());
++        AV* seqs = (AV*)sv_2mortal((SV*)newAV());
++        I32 items = AvFILLp(isa) + 1;
++        SV** isa_ptr = AvARRAY(isa);
++        while(items--) {
++            AV* isa_lin;
++            SV* isa_item = *isa_ptr++;
++            HV* isa_item_stash = gv_stashsv(isa_item, 0);
++            if(!isa_item_stash) {
++                isa_lin = newAV();
++                av_push(isa_lin, newSVsv(isa_item));
++            }
++            else {
++                isa_lin = (AV*)sv_2mortal((SV*)mro_get_linear_isa_c3(isa_item_stash, level + 1)); /* recursion */
++            }
++            av_push(seqs, (SV*)av_make(AvFILLp(isa_lin)+1, AvARRAY(isa_lin)));
++        }
++        av_push(seqs, (SV*)av_make(AvFILLp(isa)+1, AvARRAY(isa)));
++
++        seqs_ptr = AvARRAY(seqs);
++        seqs_items = AvFILLp(seqs) + 1;
++        while(seqs_items--) {
++            AV* seq = (AV*)*seqs_ptr++;
++            I32 seq_items = AvFILLp(seq);
++            if(seq_items > 0) {
++                SV** seq_ptr = AvARRAY(seq) + 1;
++                while(seq_items--) {
++                    SV* seqitem = *seq_ptr++;
++                    HE* he = hv_fetch_ent(tails, seqitem, 0, 0);
++                    if(!he) {
++                        hv_store_ent(tails, seqitem, newSViv(1), 0);
++                    }
++                    else {
++                        SV* val = HeVAL(he);
++                        sv_inc(val);
++                    }
++                }
++            }
++        }
++
++        while(1) {
++            SV* seqhead = NULL;
++            SV* cand = NULL;
++            SV* winner = NULL;
++            SV* val;
++            HE* tail_entry;
++            AV* seq;
++            SV** avptr = AvARRAY(seqs);
++            items = AvFILLp(seqs)+1;
++            while(items--) {
++                SV** svp;
++                seq = (AV*)*avptr++;
++                if(AvFILLp(seq) < 0) continue;
++                svp = av_fetch(seq, 0, 0);
++                seqhead = *svp;
++                if(!winner) {
++                    cand = seqhead;
++                    if((tail_entry = hv_fetch_ent(tails, cand, 0, 0))
++                       && (val = HeVAL(tail_entry))
++                       && (SvIVx(val) > 0))
++                           continue;
++                    winner = newSVsv(cand);
++                    av_push(retval, winner);
++                }
++                if(!sv_cmp(seqhead, winner)) {
++
++                    /* this is basically shift(@seq) in void context */
++                    SvREFCNT_dec(*AvARRAY(seq));
++                    *AvARRAY(seq) = &PL_sv_undef;
++                    AvARRAY(seq) = AvARRAY(seq) + 1;
++                    AvMAX(seq)--;
++                    AvFILLp(seq)--;
++
++                    if(AvFILLp(seq) < 0) continue;
++                    svp = av_fetch(seq, 0, 0);
++                    seqhead = *svp;
++                    tail_entry = hv_fetch_ent(tails, seqhead, 0, 0);
++                    val = HeVAL(tail_entry);
++                    sv_dec(val);
++                }
++            }
++            if(!cand) break;
++            if(!winner)
++                Perl_croak(aTHX_ "Inconsistent hierarchy during C3 merge of class '%s': "
++                    "merging failed on parent '%"SVf"'", stashname, SVfARG(cand));
++        }
++    }
++
++    SvREADONLY_on(retval);
++    SvREFCNT_inc_simple_void_NN(retval); /* for meta storage */
++    SvREFCNT_inc_simple_void_NN(retval); /* for return to caller */
++    meta->mro_linear_c3 = retval;
++    return retval;
++}
++
++/*
++=for apidoc mro_get_linear_isa
++
++Returns either C<mro_get_linear_isa_c3> or
++C<mro_get_linear_isa_dfs> for the given stash,
++dependant upon which MRO is in effect
++for that stash.  The return value is a
++read-only AV*.
++
++=cut
++*/
++AV*
++Perl_mro_get_linear_isa(pTHX_ HV *stash)
++{
++    struct mro_meta* meta;
++    assert(stash);
++    assert(HvAUX(stash));
++
++    meta = HvMROMETA(stash);
++    if(meta->mro_which == MRO_DFS) {
++        return mro_get_linear_isa_dfs(stash, 0);
++    } else if(meta->mro_which == MRO_C3) {
++        return mro_get_linear_isa_c3(stash, 0);
++    } else {
++        Perl_croak(aTHX_ "Internal error: invalid MRO!");
++    }
++}
++
++/*
++=for apidoc mro_isa_changed_in
++
++Takes the neccesary steps (cache invalidations, mostly)
++when the @ISA of the given package has changed.  Invoked
++by the C<setisa> magic, should not need to invoke directly.
++
++=cut
++*/
++void
++Perl_mro_isa_changed_in(pTHX_ HV* stash)
++{
++    dVAR;
++    HV* isarev;
++    AV* linear_mro;
++    HE* iter;
++    SV** svp;
++    I32 items;
++    struct mro_meta* meta;
++    char* stashname;
++
++    stashname = HvNAME_get(stash);
++
++    /* wipe out the cached linearizations for this stash */
++    meta = HvMROMETA(stash);
++    sv_2mortal((SV*)meta->mro_linear_dfs);
++    sv_2mortal((SV*)meta->mro_linear_c3);
++    meta->mro_linear_dfs = NULL;
++    meta->mro_linear_c3 = NULL;
++
++    /* Wipe the global method cache if this package
++       is UNIVERSAL or one of its parents */
++    if(meta->is_universal)
++        PL_sub_generation++;
++
++    /* Wipe the local method cache otherwise */
++    else
++        meta->sub_generation++;
++
++    /* wipe next::method cache too */
++    if(meta->mro_nextmethod) hv_clear(meta->mro_nextmethod);
++    
++    /* Recalcs whichever of the above two cleared linearizations
++       are in effect and gives it to us */
++    linear_mro = mro_get_linear_isa(stash);
++    isarev = meta->mro_isarev;
++
++    /* Iterate the isarev (classes that are our children),
++       wiping out their linearization and method caches */
++    if(isarev) {
++        hv_iterinit(isarev);
++        while((iter = hv_iternext(isarev))) {
++            SV* revkey = hv_iterkeysv(iter);
++            HV* revstash = gv_stashsv(revkey, 0);
++            struct mro_meta* revmeta = HvMROMETA(revstash);
++            sv_2mortal((SV*)revmeta->mro_linear_dfs);
++            sv_2mortal((SV*)revmeta->mro_linear_c3);
++            revmeta->mro_linear_dfs = NULL;
++            revmeta->mro_linear_c3 = NULL;
++            if(!meta->is_universal)
++                revmeta->sub_generation++;
++            if(revmeta->mro_nextmethod)
++                hv_clear(revmeta->mro_nextmethod);
++        }
++    }
++
++    /* we're starting at the 2nd element, skipping ourselves here */
++    svp = AvARRAY(linear_mro) + 1;
++    items = AvFILLp(linear_mro);
++    while (items--) {
++        SV* const sv = *svp++;
++        struct mro_meta* mrometa;
++        HV* mroisarev;
++
++        HV* mrostash = gv_stashsv(sv, 0);
++        if(!mrostash) {
++            mrostash = gv_stashsv(sv, GV_ADD);
++            /*
++               We created the package on the fly, so
++               that we could store isarev information.
++               This flag lets gv_fetchmeth know about it,
++               so that it can still generate the very useful
++               "Can't locate package Foo for @Bar::ISA" warning.
++            */
++            HvMROMETA(mrostash)->fake = 1;
++        }
++
++        mrometa = HvMROMETA(mrostash);
++        mroisarev = mrometa->mro_isarev;
++
++        /* is_universal is viral */
++        if(meta->is_universal)
++            mrometa->is_universal = 1;
++
++        if(!mroisarev)
++            mroisarev = mrometa->mro_isarev = newHV();
++
++        if(!hv_exists(mroisarev, stashname, strlen(stashname)))
++            hv_store(mroisarev, stashname, strlen(stashname), &PL_sv_yes, 0);
++
++        if(isarev) {
++            hv_iterinit(isarev);
++            while((iter = hv_iternext(isarev))) {
++                SV* revkey = hv_iterkeysv(iter);
++                if(!hv_exists_ent(mroisarev, revkey, 0))
++                    hv_store_ent(mroisarev, revkey, &PL_sv_yes, 0);
++            }
++        }
++    }
++}
++
++/*
++=for apidoc mro_method_changed_in
++
++Like C<mro_isa_changed_in>, but invalidates method
++caching on any child classes of the given stash, so
++that they might notice the changes in this one.
++
++Ideally, all instances of C<PL_sub_generation++> in
++the perl source should be replaced by calls to this.
++Some already are, but some are more difficult to
++replace.
++
++Perl has always had problems with method caches
++getting out of sync when one directly manipulates
++stashes via things like C<%{Foo::} = %{Bar::}> or 
++C<${Foo::}{bar} = ...> or the equivalent.  If
++you do this in core or XS code, call this afterwards
++on the destination stash to get things back in sync.
++
++If you're doing such a thing from pure perl, use
++C<mro::method_changed_in(classname)>, which
++just calls this.
++
++=cut
++*/
++void
++Perl_mro_method_changed_in(pTHX_ HV *stash)
++{
++    struct mro_meta* meta = HvMROMETA(stash);
++    HV* isarev;
++    HE* iter;
++
++    /* If stash is UNIVERSAL, or one of UNIVERSAL's parents,
++       invalidate all method caches globally */
++    if(meta->is_universal) {
++        PL_sub_generation++;
++        return;
++    }
++
++    /* else, invalidate the method caches of all child classes,
++       but not itself */
++    if((isarev = meta->mro_isarev)) {
++        hv_iterinit(isarev);
++        while((iter = hv_iternext(isarev))) {
++            SV* revkey = hv_iterkeysv(iter);
++            HV* revstash = gv_stashsv(revkey, 0);
++            struct mro_meta* mrometa = HvMROMETA(revstash);
++            mrometa->sub_generation++;
++            if(mrometa->mro_nextmethod)
++                hv_clear(mrometa->mro_nextmethod);
++        }
++    }
++}
++
++/* These two are static helpers for next::method and friends,
++   and re-implement a bunch of the code from pp_caller() in
++   a more efficient manner for this particular usage.
++*/
++
++STATIC I32
++__dopoptosub_at(const PERL_CONTEXT *cxstk, I32 startingblock) {
++    I32 i;
++    for (i = startingblock; i >= 0; i--) {
++        if(CxTYPE((PERL_CONTEXT*)(&cxstk[i])) == CXt_SUB) return i;
++    }
++    return i;
++}
++
++STATIC SV*
++__nextcan(pTHX_ SV* self, I32 throw_nomethod)
++{
++    register I32 cxix;
++    register const PERL_CONTEXT *ccstack = cxstack;
++    const PERL_SI *top_si = PL_curstackinfo;
++    HV* selfstash;
++    GV* cvgv;
++    SV *stashname;
++    const char *fq_subname;
++    const char *subname;
++    STRLEN fq_subname_len;
++    STRLEN stashname_len;
++    STRLEN subname_len;
++    SV* sv;
++    GV** gvp;
++    AV* linear_av;
++    SV** linear_svp;
++    SV* linear_sv;
++    HV* curstash;
++    GV* candidate = NULL;
++    CV* cand_cv = NULL;
++    const char *hvname;
++    I32 items;
++    struct mro_meta* selfmeta;
++    HV* nmcache;
++    HE* cache_entry;
++
++    if(sv_isobject(self))
++        selfstash = SvSTASH(SvRV(self));
++    else
++        selfstash = gv_stashsv(self, 0);
++
++    assert(selfstash);
++
++    hvname = HvNAME_get(selfstash);
++    if (!hvname)
++        croak("Can't use anonymous symbol table for method lookup");
++
++    cxix = __dopoptosub_at(cxstack, cxstack_ix);
++
++    /* This block finds the contextually-enclosing fully-qualified subname,
++       much like looking at (caller($i))[3] until you find a real sub that
++       isn't ANON, etc */
++    for (;;) {
++        /* we may be in a higher stacklevel, so dig down deeper */
++        while (cxix < 0) {
++            if(top_si->si_type == PERLSI_MAIN)
++                croak("next::method/next::can/maybe::next::method must be used in method context");
++            top_si = top_si->si_prev;
++            ccstack = top_si->si_cxstack;
++            cxix = __dopoptosub_at(ccstack, top_si->si_cxix);
++        }
++
++        if(CxTYPE((PERL_CONTEXT*)(&ccstack[cxix])) != CXt_SUB
++          || (PL_DBsub && GvCV(PL_DBsub) && ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub))) {
++            cxix = __dopoptosub_at(ccstack, cxix - 1);
++            continue;
++        }
++
++        {
++            const I32 dbcxix = __dopoptosub_at(ccstack, cxix - 1);
++            if (PL_DBsub && GvCV(PL_DBsub) && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub)) {
++                if(CxTYPE((PERL_CONTEXT*)(&ccstack[dbcxix])) != CXt_SUB) {
++                    cxix = dbcxix;
++                    continue;
++                }
++            }
++        }
++
++        cvgv = CvGV(ccstack[cxix].blk_sub.cv);
++
++        if(!isGV(cvgv)) {
++            cxix = __dopoptosub_at(ccstack, cxix - 1);
++            continue;
++        }
++
++        /* we found a real sub here */
++        sv = sv_2mortal(newSV(0));
++
++        gv_efullname3(sv, cvgv, NULL);
++
++        fq_subname = SvPVX(sv);
++        fq_subname_len = SvCUR(sv);
++
++        subname = strrchr(fq_subname, ':');
++        if(!subname)
++            croak("next::method/next::can/maybe::next::method cannot find enclosing method");
++
++        subname++;
++        subname_len = fq_subname_len - (subname - fq_subname);
++        if(subname_len == 8 && strEQ(subname, "__ANON__")) {
++            cxix = __dopoptosub_at(ccstack, cxix - 1);
++            continue;
++        }
++        break;
++    }
++
++    /* If we made it to here, we found our context */
++
++    selfmeta = HvMROMETA(selfstash);
++    if(!(nmcache = selfmeta->mro_nextmethod)) {
++        nmcache = selfmeta->mro_nextmethod = newHV();
++    }
++
++    if((cache_entry = hv_fetch_ent(nmcache, sv, 0, 0))) {
++        SV* val = HeVAL(cache_entry);
++        if(val == &PL_sv_undef) {
++            if(throw_nomethod)
++                croak("No next::method '%s' found for %s", subname, hvname);
++            return &PL_sv_undef;
++        }
++        return SvREFCNT_inc_simple_NN(val);
++    }
++
++    /* beyond here is just for cache misses, so perf isn't as critical */
++
++    stashname_len = subname - fq_subname - 2;
++    stashname = sv_2mortal(newSVpvn(fq_subname, stashname_len));
++
++    linear_av = mro_get_linear_isa_c3(selfstash, 0); /* has ourselves at the top of the list */
++    sv_2mortal((SV*)linear_av);
++
++    linear_svp = AvARRAY(linear_av);
++    items = AvFILLp(linear_av) + 1;
++
++    while (items--) {
++        linear_sv = *linear_svp++;
++        assert(linear_sv);
++        if(sv_eq(linear_sv, stashname))
++            break;
++    }
++
++    if(items > 0) {
++        while (items--) {
++            linear_sv = *linear_svp++;
++            assert(linear_sv);
++            curstash = gv_stashsv(linear_sv, FALSE);
++
++            if (!curstash || (HvMROMETA(curstash)->fake && !HvFILL(curstash))) {
++                if (ckWARN(WARN_MISC))
++                    Perl_warner(aTHX_ packWARN(WARN_MISC), "Can't locate package %"SVf" for @%s::ISA",
++                        (void*)linear_sv, hvname);
++                continue;
++            }
++
++            assert(curstash);
++
++            gvp = (GV**)hv_fetch(curstash, subname, subname_len, 0);
++            if (!gvp) continue;
++
++            candidate = *gvp;
++            assert(candidate);
++
++            if (SvTYPE(candidate) != SVt_PVGV)
++                gv_init(candidate, curstash, subname, subname_len, TRUE);
++            if (SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) {
++                SvREFCNT_inc_simple_void_NN((SV*)cand_cv);
++                hv_store_ent(nmcache, newSVsv(sv), (SV*)cand_cv, 0);
++                return (SV*)cand_cv;
++            }
++        }
++    }
++
++    hv_store_ent(nmcache, newSVsv(sv), &PL_sv_undef, 0);
++    if(throw_nomethod)
++        croak("No next::method '%s' found for %s", subname, hvname);
++    return &PL_sv_undef;
++}
++
++#include "XSUB.h"
++
++XS(XS_mro_get_linear_isa);
++XS(XS_mro_set_mro);
++XS(XS_mro_get_mro);
++XS(XS_mro_get_global_sub_generation);
++XS(XS_mro_invalidate_all_method_caches);
++XS(XS_mro_get_sub_generation);
++XS(XS_mro_method_changed_in);
++XS(XS_next_can);
++XS(XS_next_method);
++XS(XS_maybe_next_method);
++
++void
++Perl_boot_core_mro(pTHX)
++{
++    dVAR;
++    static const char file[] = __FILE__;
++
++    newXSproto("mro::get_linear_isa", XS_mro_get_linear_isa, file, "$;$");
++    newXSproto("mro::set_mro", XS_mro_set_mro, file, "$$");
++    newXSproto("mro::get_mro", XS_mro_get_mro, file, "$");
++    newXSproto("mro::get_global_sub_generation", XS_mro_get_global_sub_generation, file, "");
++    newXSproto("mro::invalidate_all_method_caches", XS_mro_invalidate_all_method_caches, file, "");
++    newXSproto("mro::get_sub_generation", XS_mro_get_sub_generation, file, "$");
++    newXSproto("mro::method_changed_in", XS_mro_method_changed_in, file, "$");
++    newXS("next::can", XS_next_can, file);
++    newXS("next::method", XS_next_method, file);
++    newXS("maybe::next::method", XS_maybe_next_method, file);
++}
++
++XS(XS_mro_get_linear_isa) {
++    dVAR;
++    dXSARGS;
++    AV* RETVAL;
++    HV* class_stash;
++    SV* classname;
++
++    if(items < 1 || items > 2)
++       croak("Usage: mro::get_linear_isa(classname [, type ])");
++
++    classname = ST(0);
++    class_stash = gv_stashsv(classname, 0);
++    if(!class_stash) croak("No such class: '%"SVf"'!", SVfARG(classname));
++
++    if(items > 1) {
++        char* which = SvPV_nolen(ST(1));
++        if(strEQ(which, "dfs"))
++            RETVAL = mro_get_linear_isa_dfs(class_stash, 0);
++        else if(strEQ(which, "c3"))
++            RETVAL = mro_get_linear_isa_c3(class_stash, 0);
++        else
++            croak("Invalid mro name: '%s'", which);
++    }
++    else {
++        RETVAL = mro_get_linear_isa(class_stash);
++    }
++
++    ST(0) = newRV_noinc((SV*)RETVAL);
++    sv_2mortal(ST(0));
++    XSRETURN(1);
++}
++
++XS(XS_mro_set_mro)
++{
++    dVAR;
++    dXSARGS;
++    SV* classname;
++    char* whichstr;
++    mro_alg which;
++    HV* class_stash;
++    struct mro_meta* meta;
++
++    if (items != 2)
++       croak("Usage: mro::set_mro(classname, type)");
++
++    classname = ST(0);
++    whichstr = SvPV_nolen(ST(1));
++    class_stash = gv_stashsv(classname, GV_ADD);
++    if(!class_stash) croak("Cannot create class: '%"SVf"'!", SVfARG(classname));
++    meta = HvMROMETA(class_stash);
++
++    if(strEQ(whichstr, "dfs"))
++        which = MRO_DFS;
++    else if(strEQ(whichstr, "c3"))
++        which = MRO_C3;
++    else
++        croak("Invalid mro name: '%s'", whichstr);
++
++    if(meta->mro_which != which) {
++        meta->mro_which = which;
++        /* Only affects local method cache, not
++           even child classes */
++        meta->sub_generation++;
++        if(meta->mro_nextmethod)
++            hv_clear(meta->mro_nextmethod);
++    }
++
++    XSRETURN_EMPTY;
++}
++
++
++XS(XS_mro_get_mro)
++{
++    dVAR;
++    dXSARGS;
++    SV* classname;
++    HV* class_stash;
++    struct mro_meta* meta;
++
++    if (items != 1)
++       croak("Usage: mro::get_mro(classname)");
++
++    classname = ST(0);
++    class_stash = gv_stashsv(classname, 0);
++    if(!class_stash) croak("No such class: '%"SVf"'!", SVfARG(classname));
++    meta = HvMROMETA(class_stash);
++
++    if(meta->mro_which == MRO_DFS)
++        ST(0) = sv_2mortal(newSVpvn("dfs", 3));
++    else
++        ST(0) = sv_2mortal(newSVpvn("c3", 2));
++
++    XSRETURN(1);
++}
++
++XS(XS_mro_get_global_sub_generation)
++{
++    dVAR;
++    dXSARGS;
++
++    if (items != 0)
++        croak("Usage: mro::get_global_sub_generation()");
++
++    ST(0) = sv_2mortal(newSViv(PL_sub_generation));
++    XSRETURN(1);
++}
++
++XS(XS_mro_invalidate_all_method_caches)
++{
++    dVAR;
++    dXSARGS;
++
++    if (items != 0)
++        croak("Usage: mro::invalidate_all_method_caches()");
++
++    PL_sub_generation++;
++
++    XSRETURN_EMPTY;
++}
++
++XS(XS_mro_get_sub_generation)
++{
++    dVAR;
++    dXSARGS;
++    SV* classname;
++    HV* class_stash;
++
++    if(items != 1)
++        croak("Usage: mro::get_sub_generation(classname)");
++
++    classname = ST(0);
++    class_stash = gv_stashsv(classname, 0);
++    if(!class_stash) croak("No such class: '%"SVf"'!", SVfARG(classname));
++
++    ST(0) = sv_2mortal(newSViv(HvMROMETA(class_stash)->sub_generation));
++    XSRETURN(1);
++}
++
++XS(XS_mro_method_changed_in)
++{
++    dVAR;
++    dXSARGS;
++    SV* classname;
++    HV* class_stash;
++
++    if(items != 1)
++        croak("Usage: mro::method_changed_in(classname)");
++    
++    classname = ST(0);
++
++    class_stash = gv_stashsv(classname, 0);
++    if(!class_stash) croak("No such class: '%"SVf"'!", SVfARG(classname));
++
++    mro_method_changed_in(class_stash);
++
++    XSRETURN_EMPTY;
++}
++
++XS(XS_next_can)
++{
++    dVAR;
++    dXSARGS;
++    SV* self = ST(0);
++    SV* methcv = __nextcan(self, 0);
++
++    PERL_UNUSED_VAR(items);
++
++    if(methcv == &PL_sv_undef) {
++        ST(0) = &PL_sv_undef;
++    }
++    else {
++        ST(0) = sv_2mortal(newRV_inc(methcv));
++    }
++
++    XSRETURN(1);
++}
++
++XS(XS_next_method)
++{
++    dMARK;
++    dAX;
++    SV* self = ST(0);
++    SV* methcv = __nextcan(self, 1);
++
++    PL_markstack_ptr++;
++    call_sv(methcv, GIMME_V);
++}
++
++XS(XS_maybe_next_method)
++{
++    dMARK;
++    dAX;
++    SV* self = ST(0);
++    SV* methcv = __nextcan(self, 0);
++
++    if(methcv == &PL_sv_undef) {
++        ST(0) = &PL_sv_undef;
++        XSRETURN(1);
++    }
++
++    PL_markstack_ptr++;
++    call_sv(methcv, GIMME_V);
++}
++
++/*
++ * Local variables:
++ * c-indentation-style: bsd
++ * c-basic-offset: 4
++ * indent-tabs-mode: t
++ * End:
++ *
++ * ex: set ts=8 sts=4 sw=4 noet:
++ */
+=== hv.c
+==================================================================
+--- hv.c	(/local/perl-current)	(revision 30454)
++++ hv.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -1531,7 +1531,7 @@
+ 	return;
+     val = HeVAL(entry);
+     if (val && isGV(val) && GvCVu(val) && HvNAME_get(hv))
+-	PL_sub_generation++;	/* may be deletion of method from stash */
++        mro_method_changed_in(hv);	/* deletion of method from stash */
+     SvREFCNT_dec(val);
+     if (HeKLEN(entry) == HEf_SVKEY) {
+ 	SvREFCNT_dec(HeKEY_sv(entry));
+@@ -1726,6 +1726,7 @@
+ 
+ 	if (SvOOK(hv)) {
+ 	    HE *entry;
++            struct mro_meta *meta;
+ 	    struct xpvhv_aux *iter = HvAUX(hv);
+ 	    /* If there are weak references to this HV, we need to avoid
+ 	       freeing them up here.  In particular we need to keep the AV
+@@ -1757,6 +1758,15 @@
+ 	    iter->xhv_riter = -1; 	/* HvRITER(hv) = -1 */
+ 	    iter->xhv_eiter = NULL;	/* HvEITER(hv) = NULL */
+ 
++            if((meta = iter->xhv_mro_meta)) {
++                if(meta->mro_linear_dfs) SvREFCNT_dec(meta->mro_linear_dfs);
++                if(meta->mro_linear_c3)  SvREFCNT_dec(meta->mro_linear_c3);
++                if(meta->mro_isarev)     SvREFCNT_dec(meta->mro_isarev);
++                if(meta->mro_nextmethod) SvREFCNT_dec(meta->mro_nextmethod);
++                Safefree(meta);
++                iter->xhv_mro_meta = NULL;
++            }
++
+ 	    /* There are now no allocated pointers in the aux structure.  */
+ 
+ 	    SvFLAGS(hv) &= ~SVf_OOK; /* Goodbye, aux structure.  */
+@@ -1878,6 +1888,7 @@
+     iter->xhv_eiter = NULL;	/* HvEITER(hv) = NULL */
+     iter->xhv_name = 0;
+     iter->xhv_backreferences = 0;
++    iter->xhv_mro_meta = NULL;
+     return iter;
+ }
+ 
+=== hv.h
+==================================================================
+--- hv.h	(/local/perl-current)	(revision 30454)
++++ hv.h	(/local/perl-c3-subg)	(revision 30454)
+@@ -38,12 +38,38 @@
+ 
+ /* Subject to change.
+    Don't access this directly.
++   Use the funcs in mro.c
+ */
++
++typedef enum {
++    MRO_DFS, /* 0 */
++    MRO_C3   /* 1 */
++} mro_alg;
++
++struct mro_meta {
++    AV          *mro_linear_dfs; /* cached dfs @ISA linearization */
++    AV          *mro_linear_c3; /* cached c3 @ISA linearization */
++    HV		*mro_isarev;    /* reverse @ISA dependencies (who depends on us?) */
++    HV		*mro_nextmethod; /* next::method caching */
++    mro_alg     mro_which;      /* which mro alg is in use? */
++    U32         sub_generation; /* Like PL_sub_generation, but stash-local */
++    I32         is_universal;   /* We are UNIVERSAL or a potentially indirect
++                                   member of @UNIVERSAL::ISA */
++    I32         fake;           /* setisa made this fake package,
++                                   gv_fetchmeth pays attention to this,
++                                   and "package" sets it back to zero */
++};
++
++/* Subject to change.
++   Don't access this directly.
++*/
++
+ struct xpvhv_aux {
+     HEK		*xhv_name;	/* name, if a symbol table */
+     AV		*xhv_backreferences; /* back references for weak references */
+     HE		*xhv_eiter;	/* current entry of iterator */
+     I32		xhv_riter;	/* current root of iterator */
++    struct mro_meta *xhv_mro_meta;
+ };
+ 
+ /* hash structure: */
+@@ -240,6 +266,7 @@
+ #define HvRITER_get(hv)	(SvOOK(hv) ? HvAUX(hv)->xhv_riter : -1)
+ #define HvEITER_get(hv)	(SvOOK(hv) ? HvAUX(hv)->xhv_eiter : 0)
+ #define HvNAME(hv)	HvNAME_get(hv)
++#define HvMROMETA(hv)	(HvAUX(hv)->xhv_mro_meta ? HvAUX(hv)->xhv_mro_meta : mro_meta_init(hv))
+ /* FIXME - all of these should use a UTF8 aware API, which should also involve
+    getting the length. */
+ /* This macro may go away without notice.  */
+=== mg.c
+==================================================================
+--- mg.c	(/local/perl-current)	(revision 30454)
++++ mg.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -1530,8 +1530,18 @@
+ {
+     dVAR;
+     PERL_UNUSED_ARG(sv);
+-    PERL_UNUSED_ARG(mg);
+-    PL_sub_generation++;
++
++    /* The first case occurs via setisa,
++       the second via setisa_elem, which
++       calls this same magic */
++    mro_isa_changed_in(
++        GvSTASH(
++            SvTYPE(mg->mg_obj) == SVt_PVGV
++                ? (GV*)mg->mg_obj
++                : (GV*)SvMAGIC(mg->mg_obj)->mg_obj
++        )
++    );
++
+     return 0;
+ }
+ 
+@@ -1541,7 +1551,6 @@
+     dVAR;
+     PERL_UNUSED_ARG(sv);
+     PERL_UNUSED_ARG(mg);
+-    /* HV_badAMAGIC_on(Sv_STASH(sv)); */
+     PL_amagic_generation++;
+ 
+     return 0;
+=== op.c
+==================================================================
+--- op.c	(/local/perl-current)	(revision 30454)
++++ op.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -3649,6 +3649,11 @@
+     save_item(PL_curstname);
+ 
+     PL_curstash = gv_stashsv(sv, GV_ADD);
++
++    /* In case mg.c:Perl_magic_setisa faked
++       this package earlier, we clear the fake flag */
++    HvMROMETA(PL_curstash)->fake = 0;
++
+     sv_setsv(PL_curstname, sv);
+ 
+     PL_hints |= HINT_BLOCK_SCOPE;
+@@ -5291,9 +5296,9 @@
+ 	    sv_setpvn((SV*)gv, ps, ps_len);
+ 	else
+ 	    sv_setiv((SV*)gv, -1);
++
+ 	SvREFCNT_dec(PL_compcv);
+ 	cv = PL_compcv = NULL;
+-	PL_sub_generation++;
+ 	goto done;
+     }
+ 
+@@ -5387,7 +5392,13 @@
+ 	    GvCV(gv) = NULL;
+ 	    cv = newCONSTSUB(NULL, name, const_sv);
+ 	}
+-	PL_sub_generation++;
++        mro_method_changed_in( /* sub Foo::Bar () { 123 } */
++            (CvGV(cv) && GvSTASH(CvGV(cv)))
++                ? GvSTASH(CvGV(cv))
++                : CvSTASH(cv)
++                    ? CvSTASH(cv)
++                    : PL_curstash
++        );
+ 	if (PL_madskills)
+ 	    goto install_block;
+ 	op_free(block);
+@@ -5470,7 +5481,7 @@
+ 		}
+ 	    }
+ 	    GvCVGEN(gv) = 0;
+-	    PL_sub_generation++;
++            mro_method_changed_in(GvSTASH(gv)); /* sub Foo::bar { (shift)+1 } */
+ 	}
+     }
+     CvGV(cv) = gv;
+@@ -5802,7 +5813,7 @@
+ 	if (name) {
+ 	    GvCV(gv) = cv;
+ 	    GvCVGEN(gv) = 0;
+-	    PL_sub_generation++;
++            mro_method_changed_in(GvSTASH(gv)); /* newXS */
+ 	}
+     }
+     CvGV(cv) = gv;
+=== sv.c
+==================================================================
+--- sv.c	(/local/perl-current)	(revision 30454)
++++ sv.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -3245,7 +3245,7 @@
+ 		    SvREFCNT_dec(GvCV(dstr));
+ 		    GvCV(dstr) = NULL;
+ 		    GvCVGEN(dstr) = 0; /* Switch off cacheness. */
+-		    PL_sub_generation++;
++		    mro_method_changed_in(GvSTASH(dstr));
+ 		}
+ 	    }
+ 	    SAVEGENERICSV(*location);
+@@ -3291,7 +3291,7 @@
+ 	    }
+ 	    GvCVGEN(dstr) = 0; /* Switch off cacheness. */
+ 	    GvASSUMECV_on(dstr);
+-	    PL_sub_generation++;
++	    mro_method_changed_in(GvSTASH(dstr)); /* sub foo { 1 } sub bar { 2 } *bar = \&foo */
+ 	}
+ 	*location = sref;
+ 	if (import_flag && !(GvFLAGS(dstr) & import_flag)
+=== pp_hot.c
+==================================================================
+--- pp_hot.c	(/local/perl-current)	(revision 30454)
++++ pp_hot.c	(/local/perl-c3-subg)	(revision 30454)
+@@ -192,7 +192,7 @@
+ 
+ 	if (strEQ(GvNAME(right),"isa")) {
+ 	    GvCVGEN(right) = 0;
+-	    ++PL_sub_generation;
++	    ++PL_sub_generation; /* I don't get this at all --blblack */
+ 	}
+     }
+     SvSetMagicSV(right, left);
+@@ -3060,7 +3060,8 @@
+ 	if (he) {
+ 	    gv = (GV*)HeVAL(he);
+ 	    if (isGV(gv) && GvCV(gv) &&
+-		(!GvCVGEN(gv) || GvCVGEN(gv) == PL_sub_generation))
++		(!GvCVGEN(gv) || GvCVGEN(gv)
++                  == (PL_sub_generation + HvMROMETA(stash)->sub_generation)))
+ 		return (SV*)GvCV(gv);
+ 	}
+     }
+=== embed.fnc
+==================================================================
+--- embed.fnc	(/local/perl-current)	(revision 30454)
++++ embed.fnc	(/local/perl-c3-subg)	(revision 30454)
+@@ -282,6 +282,13 @@
+ Ap	|GV*	|gv_fetchfile	|NN const char* name
+ Ap	|GV*	|gv_fetchfile_flags|NN const char *const name|const STRLEN len\
+ 				|const U32 flags
++ApM	|struct mro_meta*	|mro_meta_init	|NN HV* stash
++ApM	|AV*	|mro_get_linear_isa|NN HV* stash
++ApM	|AV*	|mro_get_linear_isa_c3|NN HV* stash|I32 level
++ApM	|AV*	|mro_get_linear_isa_dfs|NN HV* stash|I32 level
++ApM	|void   |mro_isa_changed_in|NN HV* stash
++ApM	|void	|mro_method_changed_in	|NN HV* stash
++ApM	|void   |boot_core_mro
+ Apd	|GV*	|gv_fetchmeth	|NULLOK HV* stash|NN const char* name|STRLEN len|I32 level
+ Apd	|GV*	|gv_fetchmeth_autoload	|NULLOK HV* stash|NN const char* name|STRLEN len|I32 level
+ Apdmb	|GV*	|gv_fetchmethod	|NULLOK HV* stash|NN const char* name
+
+Property changes on: 
+___________________________________________________________________
+Name: svk:merge
+ +bc823f99-e23a-42ae-8890-ba2193b93f74:/local/perl-c3:30450
+ +bc823f99-e23a-42ae-8890-ba2193b93f74:/local/perl-c3-isarev:29720
+ +bc823f99-e23a-42ae-8890-ba2193b93f74:/local/perl-current:30449
+
@@ -0,0 +1,106 @@
+package  # hide me from PAUSE
+    next; 
+
+use strict;
+use warnings;
+no warnings 'redefine'; # for 00load.t w/ core support
+
+use Scalar::Util 'blessed';
+
+our $VERSION = '0.06';
+
+our %METHOD_CACHE;
+
+sub method {
+    my $self     = $_[0];
+    my $class    = blessed($self) || $self;
+    my $indirect = caller() =~ /^(?:next|maybe::next)$/;
+    my $level = $indirect ? 2 : 1;
+     
+    my ($method_caller, $label, @label);
+    while ($method_caller = (caller($level++))[3]) {
+      @label = (split '::', $method_caller);
+      $label = pop @label;
+      last unless
+        $label eq '(eval)' ||
+        $label eq '__ANON__';
+    }
+
+    my $method;
+
+    my $caller   = join '::' => @label;    
+    
+    $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
+        
+        my @MRO = Class::C3::calculateMRO($class);
+        
+        my $current;
+        while ($current = shift @MRO) {
+            last if $caller eq $current;
+        }
+        
+        no strict 'refs';
+        my $found;
+        foreach my $class (@MRO) {
+            next if (defined $Class::C3::MRO{$class} && 
+                     defined $Class::C3::MRO{$class}{methods}{$label});          
+            last if (defined ($found = *{$class . '::' . $label}{CODE}));
+        }
+    
+        $found;
+    };
+
+    return $method if $indirect;
+
+    die "No next::method '$label' found for $self" if !$method;
+
+    goto &{$method};
+}
+
+sub can { method($_[0]) }
+
+package  # hide me from PAUSE
+    maybe::next; 
+
+use strict;
+use warnings;
+no warnings 'redefine'; # for 00load.t w/ core support
+
+our $VERSION = '0.02';
+
+sub method { (next::method($_[0]) || return)->(@_) }
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Class::C3::next - Pure-perl next::method and friends
+
+=head1 DESCRIPTION
+
+This module is used internally by L<Class::C3> when
+neccesary, and shouldn't be used (or required in
+distribution dependencies) directly.  It
+defines C<next::method>, C<next::can>, and
+C<maybe::next::method> in pure perl.
+
+=head1 AUTHOR
+
+Stevan Little, E<lt>stevan@iinteractive.comE<gt>
+
+Brandon L. Black, E<lt>blblack@gmail.comE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2005, 2006 by Infinity Interactive, Inc.
+
+L<http://www.iinteractive.com>
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself. 
+
+=cut
@@ -4,10 +4,29 @@ package Class::C3;
 use strict;
 use warnings;
 
-use Scalar::Util 'blessed';
-use Algorithm::C3;
-
-our $VERSION = '0.14';
+our $VERSION = '0.15_02';
+
+our $C3_IN_CORE;
+our $C3_XS;
+
+BEGIN {
+    eval "require mro"; # XXX in the future, this should be a version check
+    if($@) {
+        die $@ if $@ !~ /locate/;
+        eval "require Class::C3::XS";
+        if($@) {
+            die $@ if $@ !~ /locate/;
+            eval "require Algorithm::C3; require Class::C3::next";
+            die $@ if $@;
+        }
+        else {
+            $C3_XS = 1;
+        }
+    }
+    else {
+        $C3_IN_CORE = 1;
+    }
+}
 
 # this is our global stash of both 
 # MRO's and method dispatch tables
@@ -37,7 +56,10 @@ sub import {
     # skip if the caller is main::
     # since that is clearly not relevant
     return if $class eq 'main';
+
     return if $TURN_OFF_C3;
+    mro::set_mro($class, 'c3') if $C3_IN_CORE;
+
     # make a note to calculate $class 
     # during INIT phase
     $MRO{$class} = undef unless exists $MRO{$class};
@@ -46,24 +68,34 @@ sub import {
 ## initializers
 
 sub initialize {
+    %next::METHOD_CACHE = ();
     # why bother if we don't have anything ...
     return unless keys %MRO;
-    if($_initialized) {
-        uninitialize();
-        $MRO{$_} = undef foreach keys %MRO;
+    if($C3_IN_CORE) {
+        mro::set_mro($_, 'c3') for keys %MRO;
+    }
+    else {
+        if($_initialized) {
+            uninitialize();
+            $MRO{$_} = undef foreach keys %MRO;
+        }
+        _calculate_method_dispatch_tables();
+        _apply_method_dispatch_tables();
+        $_initialized = 1;
     }
-    _calculate_method_dispatch_tables();
-    _apply_method_dispatch_tables();
-    %next::METHOD_CACHE = ();
-    $_initialized = 1;
 }
 
 sub uninitialize {
     # why bother if we don't have anything ...
-    return unless keys %MRO;    
-    _remove_method_dispatch_tables();    
     %next::METHOD_CACHE = ();
-    $_initialized = 0;
+    return unless keys %MRO;    
+    if($C3_IN_CORE) {
+        mro::set_mro($_, 'dfs') for keys %MRO;
+    }
+    else {
+        _remove_method_dispatch_tables();    
+        $_initialized = 0;
+    }
 }
 
 sub reinitialize { goto &initialize }
@@ -71,6 +103,7 @@ sub reinitialize { goto &initialize }
 ## functions for applying C3 to classes
 
 sub _calculate_method_dispatch_tables {
+    return if $C3_IN_CORE;
     my %merge_cache;
     foreach my $class (keys %MRO) {
         _calculate_method_dispatch_table($class, \%merge_cache);
@@ -78,6 +111,7 @@ sub _calculate_method_dispatch_tables {
 }
 
 sub _calculate_method_dispatch_table {
+    return if $C3_IN_CORE;
     my ($class, $merge_cache) = @_;
     no strict 'refs';
     my @MRO = calculateMRO($class, $merge_cache);
@@ -109,28 +143,36 @@ sub _calculate_method_dispatch_table {
 }
 
 sub _apply_method_dispatch_tables {
+    return if $C3_IN_CORE;
     foreach my $class (keys %MRO) {
         _apply_method_dispatch_table($class);
     }     
 }
 
 sub _apply_method_dispatch_table {
+    return if $C3_IN_CORE;
     my $class = shift;
     no strict 'refs';
     ${"${class}::()"} = $MRO{$class}->{has_overload_fallback}
         if $MRO{$class}->{has_overload_fallback};
     foreach my $method (keys %{$MRO{$class}->{methods}}) {
+        if ( $method =~ /^\(/ ) {
+            my $orig = $MRO{$class}->{methods}->{$method}->{orig};
+            ${"${class}::$method"} = $$orig if defined $$orig;
+        }
         *{"${class}::$method"} = $MRO{$class}->{methods}->{$method}->{code};
     }    
 }
 
 sub _remove_method_dispatch_tables {
+    return if $C3_IN_CORE;
     foreach my $class (keys %MRO) {
         _remove_method_dispatch_table($class);
     }       
 }
 
 sub _remove_method_dispatch_table {
+    return if $C3_IN_CORE;
     my $class = shift;
     no strict 'refs';
     delete ${"${class}::"}{"()"} if $MRO{$class}->{has_overload_fallback};    
@@ -141,82 +183,25 @@ sub _remove_method_dispatch_table {
     }   
 }
 
-## functions for calculating C3 MRO
-
 sub calculateMRO {
     my ($class, $merge_cache) = @_;
+
     return Algorithm::C3::merge($class, sub { 
         no strict 'refs'; 
         @{$_[0] . '::ISA'};
     }, $merge_cache);
 }
 
-package  # hide me from PAUSE
-    next; 
+sub _core_calculateMRO { @{mro::get_linear_isa($_[0])} }
 
-use strict;
-use warnings;
-
-use Scalar::Util 'blessed';
-
-our $VERSION = '0.05';
-
-our %METHOD_CACHE;
-
-sub method {
-    my $indirect = caller() =~ /^(?:next|maybe::next)$/;
-    my $level = $indirect ? 2 : 1;
-     
-    my ($method_caller, $label, @label);
-    while ($method_caller = (caller($level++))[3]) {
-      @label = (split '::', $method_caller);
-      $label = pop @label;
-      last unless
-        $label eq '(eval)' ||
-        $label eq '__ANON__';
-    }
-    my $caller   = join '::' => @label;    
-    my $self     = $_[0];
-    my $class    = blessed($self) || $self;
-    
-    my $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
-        
-        my @MRO = Class::C3::calculateMRO($class);
-        
-        my $current;
-        while ($current = shift @MRO) {
-            last if $caller eq $current;
-        }
-        
-        no strict 'refs';
-        my $found;
-        foreach my $class (@MRO) {
-            next if (defined $Class::C3::MRO{$class} && 
-                     defined $Class::C3::MRO{$class}{methods}{$label});          
-            last if (defined ($found = *{$class . '::' . $label}{CODE}));
-        }
-        
-        $found;
-    };
-
-    return $method if $indirect;
-
-    die "No next::method '$label' found for $self" if !$method;
-
-    goto &{$method};
+if($C3_IN_CORE) {
+    no warnings 'redefine';
+    *Class::C3::calculateMRO = \&_core_calculateMRO;
+}
+elsif($C3_XS) {
+    no warnings 'redefine';
+    *Class::C3::calculateMRO = \&Class::C3::XS::calculateMRO;
 }
-
-sub can { method($_[0]) }
-
-package  # hide me from PAUSE
-    maybe::next; 
-
-use strict;
-use warnings;
-
-our $VERSION = '0.01';
-
-sub method { (next::method($_[0]) || return)->(@_) }
 
 1;
 
@@ -268,6 +253,19 @@ Class::C3 - A pragma to use the C3 method resolution order algortihm
     D->can('hello')->();          # can() also works correctly
     UNIVERSAL::can('D', 'hello'); # as does UNIVERSAL::can()
 
+=head1 SPECIAL NOTE FOR 0.15_01
+
+To try this with the experimental perl core c3 patch,
+download a recent copy perl-current:
+
+http://mirrors.develooper.com/perl/APC/perl-current-snap/perl-current@30943.tar.bz2
+
+apply the enclosed c3.patch, and install this perl:
+
+sh Configure -Dusedevel -Dprefix=/where/I/want/it -d -e && make && make test && make install
+
+then try your C3-using software against this perl + Class::C3 0.15_01.
+
 =head1 DESCRIPTION
 
 This is pragma to change Perl 5's standard method resolution order from depth-first left-to-right 
@@ -486,6 +484,16 @@ limitation of this module.
 
 =back
 
+=head1 COMPATIBILITY
+
+If your software requires Perl 5.9.5 or higher, you do not need L<Class::C3>, you can simple C<use mro 'c3'>, and not worry about C<initialize()>, avoid some of the above caveats, and get the best possible performance.  See L<mro> for more details.
+
+If your software is meant to work on earlier Perls, use L<Class::C3> as documented here.  L<Class::C3> will detect Perl 5.9.5+ and take advantage of the core support when available.
+
+=head1 Class::C3::XS
+
+This module will load L<Class::C3::XS> if it's installed and you are running on a Perl version older than 5.9.5.  Installing this is recommended when possible, as it results in significant performance improvements (but unlike the 5.9.5+ core support, it still has all of the same caveats as L<Class::C3>).
+
 =head1 CODE COVERAGE
 
 I use B<Devel::Cover> to test the code coverage of my tests, below is the B<Devel::Cover> report on this 
@@ -3,8 +3,9 @@
 use strict;
 use warnings;
 
-use Test::More tests => 1;
+use Test::More tests => 2;
 
 BEGIN {
     use_ok('Class::C3');
-}
\ No newline at end of file
+    use_ok('Class::C3::next');
+}
@@ -26,32 +26,32 @@ except TypeError:
 
 =cut
 
-{
-    package X;
-    use Class::C3;
-    
-    package Y;
-    use Class::C3;    
-    
-    package XY;
-    use Class::C3;
-    use base ('X', 'Y');
-    
-    package YX;
-    use Class::C3;
-    use base ('Y', 'X');
-    
-    package Z;
-    # use Class::C3; << Dont do this just yet ...
-    use base ('XY', 'YX');
-}
+eval q{ 
+    {
+        package X;
+        use Class::C3;
+
+        package Y;
+        use Class::C3;    
+
+        package XY;
+        use Class::C3;
+        use base ('X', 'Y');
+
+        package YX;
+        use Class::C3;
+        use base ('Y', 'X');
+
+        package Z;
+        eval 'use Class::C3' if $Class::C3::C3_IN_CORE;
+        use base ('XY', 'YX');
+    }
 
-Class::C3::initialize();
+    Class::C3::initialize();
 
-eval { 
     # now try to calculate the MRO
     # and watch it explode :)
-    Class::C3::calculateMRO('Z') 
+    Class::C3::calculateMRO('Z');
 };
 #diag $@;
-like($@, qr/^Inconsistent hierarchy/, '... got the right error with an inconsistent hierarchy');
+like($@, qr/Inconsistent hierarchy /, '... got the right error with an inconsistent hierarchy');
@@ -81,7 +81,13 @@ is_deeply(
     [ qw(Diamond_D Diamond_B Diamond_E Diamond_C Diamond_A) ],
     '... got the new MRO for Diamond_D');
 
-is(Diamond_D->hello, 'Diamond_C::hello', '... method still resolves with old MRO');
+# Doesn't work with core support, since reinit is not neccesary and the change
+#  takes effect immediately
+SKIP: {
+    skip "This test does not work with a c3-patched perl interpreter", 1
+        if $Class::C3::C3_IN_CORE;
+    is(Diamond_D->hello, 'Diamond_C::hello', '... method still resolves with old MRO');
+}
 
 Class::C3::reinitialize();
 
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 8;
+use Test::More tests => 9;
 
 BEGIN {
     use_ok('Class::C3');
@@ -30,6 +30,20 @@ BEGIN {
     use warnings;
     use base 'OverloadingTest';
     use Class::C3;
+
+    package BaseTwo;
+    use overload (
+        q{fallback} => 1,
+        q{""}       => 'str', ### character
+    );
+    sub str {
+        return 'BaseTwo str';
+    }
+
+    package OverloadInheritTwo;
+    use Class::C3;
+    use base qw/BaseTwo/;
+
 }
 
 Class::C3::initialize();
@@ -52,5 +66,10 @@ eval {
 ok(!$@, '... this should not throw an exception');
 ok($result, '... and we should get the true value');
 
+eval {
+    my $obj = bless {}, 'OverloadInheritTwo';
+};
+is($@, '', "Overloading to method name string");
+
 #use Data::Dumper;
 #diag Dumper { Class::C3::_dump_MRO_table }