RE: [sv-ec] question about name resolution in classes

From: francoise martinolle <fm_at_.....>
Date: Fri Mar 24 2006 - 20:46:56 PST
Gordon,

Gordon,

Yes, this is what I was thinking.

A few comments below.
Francoise
    ' 

-----Original Message-----
From: owner-sv-ec@eda.org [mailto:owner-sv-ec@eda.org] On Behalf Of Gordon
Vreugdenhil
Sent: Friday, March 24, 2006 10:30 AM
To: francoise martinolle
Cc: sv-ec@eda.org
Subject: Re: [sv-ec] question about name resolution in classes



francoise martinolle wrote:
> Gordon,
> 
> Not quite, my thinking is the following. It is a little bit more complex:
>   it depends on whether the class type which encloses the symbol to
resolve 
>   is locally static (known at compile time).
> If the class type is locally static (and any enclosing class type of 
> that class is locally static), apply the normal Verilog resolution 
> rules including systemVerilog addition or walking the class type 
> hierarchy, package imports and compilation unit scope.
> In the compile time known example below, 'i' resolved to base.i.



Ok, this is more along the lines of how I was thinking about things.  The
key for something like this is to define what constitutes a "locally static"
type.  My thinking on this was to consider "elaboration types" as being the
places where one wouldn't resolve; I think that is just the complement of
the "locally static" type view that you have in mind.

I'm not quite sure that I would use "enclosing" for the inheritance aspect
since that confuses the issue of nested classes with inherited members.

Does the following get close (at least in intent)?

    When resolving a name inside a class declaration, the name
    shall first resolve using the normal scoping rules within
    the class.  If the name is not defined within the immediate
    class declaration, then if the base class is locally static the
    name shall recursively be looked up in the base class.  If it is
    not found (or if the base class is not locally static), the name
    shall be resolved using normal Verilog resolution starting
    in the scope enclosing the class.

>> Exactly that!

Since "super" and "this" are already keywords and are directives to the
search regarding where to anchor the search, any name that is prefixed by
"super." or "this." will be required to resolve within the class hierarchy
and doesn't pose an issue.  Similarly, using "base::foo" would direct a
search into the base class but require resolution to a static member.

>> You are correct about base::foo, when used outside a class but it is also
allowed to refer to a public or protected member when used within a derived
class. see section 

I think I am in agreement on some variation of the above if that is where
you are as well.

One would have to describe what constitues a locally static type.
I think the key is that you don't want to worry about parametrically
determined *sizes*, only about name resolution.  For example,
given:
      module m;
         parameter int p = 1;
         class base;
             bit[p:0] r;
         endclass
      endmodule
I wouldn't want "base" to cause problems.  So "locally static"
if taken too far is probably too strong.

>> Correct, we only care about things which can change the name space of the
scope
>> enclosing the symbol to be resolved.

Let me use the term "lexically static" rather than "locally static"
for this.  Then I think that a resonable approximation would be
that:
      A lexically static type is any type *except* the following:
         1) a type denoted by a type parameter
         2) a type denoted by a typedef whose type is
            defined by the "interface_instance_identifier . type_identifier"
            rule
         3) a type defined by a parameterized class specialization
         4) a typedef of a type that is not lexically static
         5) a class derived from a type that is not lexically static

I think that covers all of what I consider to be the "elaboration time
types" and is perhaps close to what you had in mind with the "locally
static" suggestion.

>> I like the above definition except for the terminology of lexically
static type. 
>> It seems that you chose lexical to mean that the type name space is
entirely known at parse time.
>> But I do no have a better idea at the moment.
>> The list you propose seems complete, I have reservations that any type
defined by a parameterized class specialization
>> is not lexically static. I think it depends on how the parameters are
used inside the class.
>> Just like in your example above the parameter passed as specialization
value of a class may just be used in sizing
>> a type inside the class:
>>     class vector #(int size = 1);
>>         bit [size-1:0] a;
>>     endclass

Substituting "lexically static" for "locally static" in the earlier
resolution rules allows "intuitively obvious" cases to resolve while
providing a reasonably clear set of rules for cases that might be
problematic.

Gord.



> 
> If the class declaration in which the symbol appears is not completely 
> known at parsing time (like in your previous example), we
> either:
>    a) requires that the user disambiguate the symbol as to whether it 
> refers to the class type hierarchy (this., super. BASE:: ) BASE:: can 
> only be used for public or protected properties within the derived 
> classes. There could be a potential oomr for super.i or BASE::i.
> In that case if a simple name like 'i' is given, it can never be an 
> oomr and needs to be resolved at compile time.
>    b) we allow simple name oomrs like 'i' to occur and be resolved at 
> elaboration when the type is entirely known.
> 
> With case a) and with your previous example, 'i' resolved to child.i 
> With case b) 'i' resolution postponed to elaboration resolves to 
> base.i for instance c1 and c2.i for instance c2.
> 
> I prefer approach a) because in b) we are adding simple name oomrs to 
> Verilog (with the existing exception of function/task names). We have 
> plenty of lexical ways to disambiguate what 'i' is and I think that we 
> should require the user to use them.
> It certainly enforces the intent and minimizes the risk of user error.
> 
> In summary, if the enclosing type is not known at compile time, 
> requires that the symbols appearing in that type are fully qualified 
> otherwise normal parsing name resolution will occur.
> The advantage of this approach is that for a simple name symbols 
> inside a class type which is either locally static or not, that simple 
> name is resolved at parsed time.
> 
> 
> Francoise
>     '
> -----Original Message-----
> From: owner-sv-ec@eda.org [mailto:owner-sv-ec@eda.org] On Behalf Of 
> Gordon Vreugdenhil
> Sent: Friday, March 24, 2006 1:28 AM
> To: francoise martinolle
> Cc: sv-ec@eda.org
> Subject: Re: [sv-ec] question about name resolution in classes
> 
> Fancoise,
> 
> I'd like to make sure that I understand your thinking here -- I think 
> that you are suggesting that normal lexical and package name binding 
> should occur
> *before* class hierarchical resolution, is that correct?
> 
> In particular, given a simpler example of my example:
> 
>     module child;
>        int i;
>        class base;
>            int i;
>        endclass
>        class derived extends base;
>            function void dump;
>                $display(i);
>            endfunction
>        endclass
>     endmodule
> 
> your view would be that the reference to "i" inside derived::dump 
> would refer to child.i and not to the property in base.  If the user 
> wanted to refer to the property in base, they would have to use 
> super.i (or possibly this.i).  Is that a correct understanding of your
description?
> 
> Gord
> 
> 
> 
> francoise martinolle wrote:
> 
>> 
>>Gordon,
>>
>>That is an interesting sophisticated example where the base class is 
>>not known until elaboration.
>>I agree that there are some lexical ways for removing ambiguity in 
>>which scope to resolve a symbol (this, super). If we follow the normal 
>>verilog name resolution rules, in your example, since there is a 
>>child.i, i would resolve to child.i
>>
>>My opinion is that if there was an import p::*, then the parser needs 
>>to attempt to resolve the symbol by looking up in the package. The 
>>package look up is now part of name resolution as I had pointed out 
>>before.
>>If the user needs to specify that i is a property of the class 
>>hierarchy, super.i needs to be used. If the symbol is not resolved at 
>>that point (no import and no static i), I would think that in your 
>>case we ought to consider 'i' as an oomr which may be resolved at 
>>elaboration. We should only consider this last resort because type of 
>>the immediate scope containing the symbol 'i' is not known until 
>>elaboration and i because it is a simple name needs to be resolved in 
>>that scope.
>>That scope is not *complete* until elaboration.
>>This is a new case of oomrs. Usually (with the exceptions of functions 
>>and
>>tasks) an oomr
>>consists of more than 1 token separated by '.'
>>
>>In summary, I expect the following:
>>
>>During parsing, normal Verilog name resolution rules (augmented by 
>>systemVerilog package look up) apply, then if the symbol is still 
>>undefined and the scope in which it appears is a type which is not 
>>known until elaboration, then the symbol is an oomr which is resolved 
>>at elaboration when the type is known.
>>
>>Another approach is to avoid the oomr for simple name and require that 
>>i be resolved at parsing time.
>>However if super.i is used, allow the oomr to be resolved at elaboration.
>>
>>Francoise
>>    '
>>
>>-----Original Message-----
>>From: owner-sv-ec@eda.org [mailto:owner-sv-ec@eda.org] On Behalf Of 
>>Gordon Vreugdenhil
>>Sent: Thursday, March 23, 2006 6:40 PM
>>To: francoise martinolle
>>Cc: sv-ec@eda.org
>>Subject: Re: [sv-ec] question about name resolution in classes
>>
>>Francoise,
>>
>>This is an area that is quite a bit more interesting than even your
> 
> example.
> 
>>The basic question is how to align lexical (and package) search rules 
>>with class member and property lookup.
>>
>>In the package case (such as yours), since the package is required to 
>>exist, the resolution of the base type is required to be known, so I 
>>think the intuitive answer is that "i" is the member reference and 
>>needs to be resolved as such.  It isn't clear to me however that this 
>>is going  to end up being the answer.
>>
>>There are other contexts which are far more difficult since there are 
>>separate compilation issues that come into play.
>>
>>Consider:
>>
>>    module child;
>>       parameter type T = int;
>>
>>       int i;
>>       class derived extends T;
>>           function void dump;
>>               $display(i);
>>           endfunction
>>       endclass
>>    endmodule
>>
>>    package p;
>>       class base;
>>           bit b;
>>       endclass
>>    endpackage
>>
>>    module top;
>>       class base;
>>          int i;
>>       endclas
>>
>>       child #(base) c1();
>>       child #(p::base) c2();
>>    endmodule
>>
>>In this scenario, what does "i" mean in class derived?  You can't 
>>possibly know what it is or whether it is even lexically resolved to 
>>child.i or resolved in the context of the class hierarchy.
>>In my example, the answer changes in the different module instances.
>>
>>Since module child is a valid module for separate compilation there is 
>>no way to determine the answer at compilation; elaboration time is the 
>>earliest at which this can be resolved.
>>
>>This is complicated by the package import rules.
>>If you didn't have "i" declared in "child" but it was potentially 
>>visible, would you do the import and make it actually visible?
>>
>>One reasonable approach to the general problem is to require a "this." 
>>or "super." prefix for references to inherited members in at least 
>>some situations.
>>
>>I don't think there is any ideal solution to the naming issue since 
>>you either have to deal with syntax requirements or have to try to 
>>define some reasonable rules for when an implementation is required to 
>>know things about the inheritance structure and when the user is 
>>required
> 
> to disambiguate.
> 
>>This is loosely related to the issues with randomize() that Ray and I 
>>have been working on a proposal to address.
>>
>>Gord.
>>
>>
>>francoise martinolle wrote:
>>
>>
>>>Supposed I have a base class in a package and I create a derived 
>>>class of that class in a module. I do not import the package but I 
>>>use the package scope syntax to indicate the base class. Does this 
>>>cause all the class item declaration of the BASE class to be visible 
>>>in the derived class?
>>>
>>>I think it should.
>>>
>>>
>>>package p;
>>>class BASE;
>>> rand logic i;
>>>endclass
>>>endpackage
>>>
>>>
>>>module top;
>>>class derived extends p::BASE;
>>>      constraint c1 { i == 1'b1};
>>>endclass
>>>endmodule
>>>
>>
>>
>>--
>>--------------------------------------------------------------------
>>Gordon Vreugdenhil                                503-685-0808
>>Model Technology (Mentor Graphics)                gordonv@model.com
>>
> 
> 
> --
> --------------------------------------------------------------------
> Gordon Vreugdenhil                                503-685-0808
> Model Technology (Mentor Graphics)                gordonv@model.com
> 

--
--------------------------------------------------------------------
Gordon Vreugdenhil                                503-685-0808
Model Technology (Mentor Graphics)                gordonv@model.com
Received on Fri Mar 24 20:47:43 2006

This archive was generated by hypermail 2.1.8 : Fri Mar 24 2006 - 20:47:59 PST