1
0
Fork 0

Corrected virtual non-overridden trait method invocations

What a mouthful. And nightmare, having been away from the trait
implementation for so long.
protolib
Mike Gerwitz 2014-05-02 02:47:42 -04:00
parent 74b170d089
commit 779dbc37bc
2 changed files with 52 additions and 5 deletions

View File

@ -398,11 +398,12 @@ function createVirtProxy( acls, dfn )
? 'public' ? 'public'
: 'protected'; : 'protected';
var plen = acls.___$$methods$$[ vis ][ f ].__length; var srcmethod = acls.___$$methods$$[ vis ][ f ],
plen = srcmethod.__length;
// this is the aforementioned proxy method; see the docblock for // this is the aforementioned proxy method; see the docblock for
// more information // more information
dfn[ vis + ' virtual override ' + f ] = ( function() dfn[ vis + ' virtual override ' + f ] = ( function( f )
{ {
var retf = function() var retf = function()
{ {
@ -422,16 +423,16 @@ function createVirtProxy( acls, dfn )
// this guy bypasses the above virtual override check, which is // this guy bypasses the above virtual override check, which is
// necessary in certain cases to prevent infinte recursion // necessary in certain cases to prevent infinte recursion
dfn[ vis + ' virtual __$$' + f ] = ( function( f ) dfn[ vis + ' virtual __$$' + f ] = ( function( method )
{ {
var retf = function() var retf = function()
{ {
return this.___$$parent$$[ f ].apply( this, arguments ); return method.apply( this, arguments );
}; };
retf.__length = plen; retf.__length = plen;
return retf; return retf;
} )( f ); } )( srcmethod );
} }
} }

View File

@ -190,6 +190,52 @@ require( 'common' ).testCase(
}, },
/**
* This test unfortunately requires knowledge of implementation details
* to explain; it is a regression test covering a rather obnoxious bug,
* especially when the author was away from the implementation for a
* couple months.
*
* Proxying to an overridden protected method was not a problem because
* it proxies to the protected member object (PMO) which is passed into
* the ctor and, as is evident by its name, provides both the public and
* protected API. However, when not overridden, we fall back to having
* to invoke our original method, which is on our supertype---the
* abstract trait class. The problem there is that the stored supertype
* prototype provides only the public API.
*
* This test ensures that we properly access the protected API of our
* supertype. This problem existed before any general solution to this
* problem for all subtypes. We test public as well to produce a more
* general test case.
*
* The second part of this test is implicit---we're testing multiple
* virtual methods to ensure that they return distinct results, ensuring
* that we don't have any variable reassignment issues in the loop that
* generates the closures.
*/
'Properly invokes non-overridden virtual trait methods':
function()
{
var expecteda = { a: true },
expectedb = { b: true };
var T = this.Sut(
{
pub: function() { return this.vpub(); },
prot: function() { return this.vprot(); },
'virtual public vpub': function() { return expecteda; },
'virtual protected vprot': function() { return expectedb; }
} );
var inst = this.Class.use( T ).extend( {} )();
this.assertStrictEqual( inst.pub(), expecteda );
this.assertStrictEqual( inst.prot(), expectedb );
},
/** /**
* This is the same concept as the non-virtual test found in the * This is the same concept as the non-virtual test found in the
* DefinitionTest case: since a trait is mixed into a class, if it * DefinitionTest case: since a trait is mixed into a class, if it