Problem:
Various legal constructs in extended classes fail
to compile, particularly references to base class members and methods.
References to global variables in constructor code also fails.
See the test file given below.
Fix:
chuck-emit.cpp line
3303
delete
3303
< assert( v->owner_class ==
emit->env->class_def );
chuck-type.cpp line
1758
< if(
!env->class_def || env->class_scope > 0 )
>
if( !env->class_def)
Discussion:
The assert is incorrect. The reference may be to a
base-class member, (or perhaps a global variable. I'm not sure about that). It
may be better to replace the assert with something like:
assert(is_parent_type(emit->env->class_def,v->owner_class) ||
is_global_type(v->owner_class) )
(neither function currently
avaialble).
The second fix is more difficult. Generally, we
want the test to fail and go to the else clause which searches class scope for
the variable if we're in a class definition. I don't understand the purpose of
the test on class_scope, which is certainly incorrect, whatever it's supposed to
do. What I do know: class_scope is zero in constructor code, and increments for
each nested scope (function, code block &c) in the code at this point. If
the intention is to prevent references to base class or global variables in
constructure code, then it would be "env->class_scope == 0" (sense inverted);
but this seems like an arbitrary restriction on a perfectly useful
functionality, and removing the test altogether doesn't seem to cause problems
in code generation.
References to global variables and variables in the
current scope seem to be caught before this (which, thinking about it, suggests
that global variable references will take precedence over base-class references,
which is incorrect -- possibly another bug). The main issue seems to be
base-class references. Deleting the || test seems to correct the scanning pass,
and the generated code passes the test case given below.
With respect to global and base-class variables
with the same name, I wrote a test for this case (see ScopeTest-11 tests below).
The test succeeds, with the above patches applied. Both type checking and code
generation seem to work. So I'm not going to
hunt further.
Test case for the
fix:
ScopeTest.ck
/////////////////////////////
//
ScopeTest.ck
// Test Scoping of variables and virtual functions in extended
classes.
//
/////////////////////////////
function void Assert(int condition, string message)
{
if
(!condition)
{
<<< "Assert Failed: ", message
>>>;
}
}
1 => int globalVariable;
Assert(globalVariable == 1,"ScopeTest-1
Global Assignment");
string globalAndBaseclassVariable;
class Base
{
int globalAndBaseclassVariable;
2 => globalVariable;
Assert(globalVariable ==
2,"ScopeTest-2 Global Assignment from constructor.");
3 => int v;
Assert(v == 3,"ScopeTest-3 Assigment to class
variable in ctor");
function int GetV() {
return v;
}
function int GetVVirtual() {
return v;
}
}
class Super extends Base
{
4 => int v2;
Assert(v2
== 4,"ScopeTest-4 Assigment to class scope from extended class.");
5
=> v;
Assert(v == 5, "ScopeTest-5 Assignment to variable in
superclass.");
6 => v;
Assert(GetV() == 6, "ScopeTest-6
Assignment to variable in superclass.");
7 => globalVariable;
Assert(globalVariable == 7,
"ScopeTest-7 assignement to global variable in extended class");
function int Test()
{
return
GetV();
}
function int GetVVirtual() {
return
v2;
}
function int
GetglobalAndBaseclassVariable()
{
return
globalAndBaseclassVariable;
}
}
Base b;
Assert(globalVariable == 2, "ScopeTest-2.1 constructor
side-effects in global scope.");
Super s;
Assert(globalVariable == 7, "ScopeTest-7.1 superclass
constructor side-effects in global scope.");
8 => b.v;
Assert(b.v == b.GetV(),"ScopeTest-8 assigment to
class-scope variable.");
9 => s.v;
Assert(s.v == s.GetV(),"ScopeTest-9
assigment to base-class-scope variable.");
10 => s.v2;
Assert(s.v ==
s.GetV(),"ScopeTest-10 assigment to super-class-scope
variable.");
Assert(s.v2 == 10,"ScopeTest-10.1 assigment to super-class-scope
variable.");
Assert(s.v2 == s.GetVVirtual(),"ScopeTest-10.1 virtual function
resolution.");
"110" => globalAndBaseclassVariable;
111 =>
s.globalAndBaseclassVariable;
Assert(globalAndBaseclassVariable ==
"110","ScopeTest-11.1 aliased global and base-class
variable.");
Assert(s.GetglobalAndBaseclassVariable() == 111,"ScopeTest-11.2
aliased global and base-class
variable.");
Assert(s.globalAndBaseclassVariable() == 111,"ScopeTest-11.3
aliased global and base-class variable.");