1
0
Fork 0

Fix trait extending of supertype with constructor

Supertypes that extend constructors may now be extended by traits without
completely blowing up.  Good feature.

* lib/Trait.js (__tconstruct): Add function.
  (createVirtProxy): Use it.

* test/Trait/ClassExtendTest.js: Add test.
master
Mike Gerwitz 2017-01-02 23:32:42 -05:00
parent 92c57c8ffe
commit b841b9cc5e
Signed by: mikegerwitz
GPG Key ID: 8C917B7F5DC51BA2
2 changed files with 81 additions and 10 deletions

View File

@ -1,7 +1,7 @@
/**
* Provides system for code reuse via traits
*
* Copyright (C) 2014, 2015, 2016 Free Software Foundation, Inc.
* Copyright (C) 2014, 2015, 2016, 2017 Free Software Foundation, Inc.
*
* This file is part of GNU ease.js.
*
@ -498,14 +498,12 @@ function createConcrete( acls )
// parent ACLS has access to it (!), which is not prohibited since
// JS does not provide a strict typing mechanism...this is a kluge)
// and target supertype---that is, what __super calls should
// referene
'protected ___$$pmo$$': null,
'protected ___$$super$$': null,
__construct: function( base, pmo )
{
this.___$$super$$ = base;
this.___$$pmo$$ = pmo;
},
// reference
'protected ___$$pmo$$': null,
'protected ___$$super$$': null,
'weak virtual __construct': _fvoid,
'override __construct': __tconstruct,
// mainly for debugging; should really never see this.
__name: '#ConcreteTrait#',
@ -544,6 +542,30 @@ function createConcrete( acls )
}
/**
* Trait class __construct method
*
* This is to be used for the `__construct' method of a concrete trait
* class. This simply performs low-level trait initialization.
*
* Just below this function's definition, its `__length' property is set to
* Infinity---this avoids supertype compatibility issues based on argument
* count (see argument length check in `MemberBuilderValidator').
*
* @param {Class} base supertype
* @param {Object} pmo protected member object
*/
function __tconstruct( base, pmo )
{
this.___$$super$$ = base;
this.___$$pmo$$ = pmo;
}
// prevent any issues related to supertype compatability (__length is
// recognized by easejs to store argument count)
__tconstruct.__length = Infinity;
/**
* Create virtual method proxies for all virtual members
*
@ -567,6 +589,14 @@ function createVirtProxy( acls, dfn )
// f = `field'
for ( var f in vmembers )
{
// constructors may exist when extending a class; they require
// special treatment and it makes no sense to create a proxy for
// them
if ( f === '__construct' )
{
continue;
}
var vis = ( acls.___$$methods$$['public'][ f ] !== undefined )
? 'public'
: 'protected';

View File

@ -1,7 +1,7 @@
/**
* Tests extending traits from classes
*
* Copyright (C) 2015 Free Software Foundation, Inc.
* Copyright (C) 2015, 2017 Free Software Foundation, Inc.
*
* This file is part of GNU ease.js.
*
@ -189,6 +189,47 @@ require( 'common' ).testCase(
},
/**
* Also an implementation detail: when a constructor is present on the
* supertype, special care is needed to make sure that we have no errors
* in an override---the trait itself has its own constructor.
*
* Another subtle detail is that our constructor override needs to take
* into account that the supertype constructor could have any number of
* arguments. Since easejs enforces argument length for overrides, we
* need to make sure that the trait will handle this. (In actuality,
* the implementation just sets the argument length of the trait class
* `__construct' to Infinity.)
*/
'Trait mixin handles supertype constructor': function()
{
var ctor_called = 0;
var C = this.Class(
{
// notice that this isn't virtual (another implementation quirk
// to handle), and notice the argument count (which creates
// quite the rainbow if you have semantic coloring for your
// editor!)
__construct: function( a, b, c, d, e, f, g, h, i, j, k, l )
{
ctor_called++;
}
} );
var T = this.Sut.extend( C, {} );
this.assertDoesNotThrow( function()
{
C.use( T )();
} );
// the supertype's constructor should be invoked only _once_ (we
// were mixed into an object that should have already invoked it)
this.assertEqual( 1, ctor_called );
},
/**
* This is a corollary, but is still worth testing for assurance.
*