I recently thought again about name resolution in classes when the whole class hierarchy is not known at parse time. I think it makes sense to allow it as it is a powerful modeling mechanism. I think that you will encounter the same issues with type parameters. A type parameter could be a class type and any property/method reference of that class type will not be resolved until elaboration. parameter type T = myclass; T v; initial $display (v.i); // i may be a property of the class type, we do not know what // this property is until elaboration Symbol resolution in the elaborator becomes even more complex when we look at the effect of package imports. Here is an interesting example with import p::* package p; real i = 1.0; endpackage module top; class base_with_i; integer i; endclass class base; endclass child u1 #(base_with_i); child u2 #(base); endmodule module child; parameter type T; import p::*; class B extends PT; $display ( i ); endclass endmodule Suppose we had decided that the reference to i inside class B is not resolved until elaboration because the class B does not have a locally static name space (is not "lexically static", using Gordon's terminology). The symbol i is resolved in instance u1 to refer to the property i in class base_with_i but in instance u1, the symbol is unresolved... UNLESS the elaborator was able to look at the potential package imports (::*) and resolve i to p::i. I do not think that the elaborator should be able to look at all import ::*. The import statement is to make declarations visible for the purpose of parse time name resolution, they are used to define the visible declarations in the scope but they should not be used during elaboration. There are two main reasons: 1) i not declared in module top, you cannot refer to the package ref i as "top.i", 2) the effect of an import declaration is to provide visibility of foreign symbols for name resolution of references which follow the import, it does not affect references which precede (below example is from the LRM ). The elaborator uses an already established instance hierarchy to resolve OOMRs (XMRs). Extracted ex from LRM: module foo; import q::*; wire a = c; // This statement forces the import of q::c; import p::c; // The conflict with q::c and p::c creates an error. endmodule Imagine I have the following: module top parameter type PT; class B extends PT; $display ( i ); endclass import q::i; wire w = i; endmodule The import q::i makes the symbol i from package q visible for name resolution of i on the continuous assignment to wire w but it does not affect the name resolution of i inside class B ( at least during parsing) since the class name space is not entirely known. The question is for instance u2, during elaboration should i resolve to q::i even if it is after the class declaration? If the class was locally static, it would not and i would be undefined. Imagine I have both imports, p::* and q::i in module top (see example below), one before the class and the other after the class, we may end up with both package references used for name resolution if we decide to use the imports for the elaboration time name resolution, as a consequence either 'i' cannot be resolved, or 'i' resolves to q::i because a select import always takes precedence over an import ::* but that is at odds with the behaviour if the class was locally static. In the case where the class declaration in the example below is locally static, 'i' resolves to p::i through the import p::* during parsing. module top parameter type PT; import p::*; class B extends PT; $display ( i ); endclass import q::i; wire w = i; // this resolves to q::i at parse time. endmodule However if I replace import p::* with import p::i, module top parameter type PT; import p::i; class B extends PT; $display ( i ); endclass endmodule the symbol i from the package p is always imported and is visible in the module scope at parse time. The class does not have a locally static name space so the resolution of 'i' is postponed until elaboration. At elaboration , what does i in child instance u2 resolve to? p::i or undefined? My opinion is that potential imports and package references which have been made visible in a scope by the parser should not be considered when resolving names inside a non lexically static class or for any oomr name resolution. If we were to consider those to resolve OOMRs we would have no choice than elaborating all packages which are imported whether or not any of their declarations would be used because we do not know until oomr resolution. Besides the p::name syntax exists and could be used instead of the simple name to indicate that the symbol comes from a package in the case where the class is a non lexically static class. This name resolution is somewhat linked to a discussion we had before on whether or not packages that are imported are elaborated or not. I do not think that we need to state it in the standard. Packages should not be used for name resolution in the elaborator. The import declarations are an aid to make package symbols visible at parse time. Another issue that we also need to agree on is the order in which the class hierarchy is searched. Suppose I put the import p::* inside class B. Is the symbol 'i' lookup in p before it is looked up in the base classes of class B? Intuitively, I would think that the class B scope and the imports inside class B would be searched before attempting to search the symbol in the base class. That would make $display(i) always resolve to p::i: class B extends PT; import p::*; $display( i ); // this is p::i endclass If you want base_with_i.i, you can use "super.i" Personnally, I think we should keep name resolution in the elaborator simple and -----Original Message----- From: owner-sv-ec@eda.org [mailto:owner-sv-ec@eda.org] On Behalf Of Gordon Vreugdenhil Sent: Saturday, March 25, 2006 11:41 AM To: francoise martinolle Cc: sv-ec@eda.org Subject: Re: [sv-ec] question about name resolution in classes francoise martinolle wrote: > Gordon, > 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. Right. >>>But I do no have a better idea at the moment. I couldn't come up with anything better at the time either; if anyone has terminology suggestions here, that would be welcome. It might be more clear to go towards the term "elaboration type" but that is somewhat misleading as well. >>>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 Certainly. Including paramterized classes is primary just me being pretty conservative about where the language might go. I don't think there is any reason to include parameterized class in the list right now, but there are several directions in which I could see the language going where we might need to treat them as not lexically static. For example, if at some point we'd want to provide different implementations for particular specializations (as one can do in C++), it might be difficult to deal with the change if we require resolution. The same would be true if one wanted to have some form of conditional declarations inside a parameterized class ("only override and define these properties if the type parameter is real"). None of this is legal right now, but it is certainly possible/likely that people would make proposals along such fronts. Having a parameterized class be lexically static under some conditions and not others might be confusing and be too sensitive to design change. If we don't include parameterized classes in the list I proposed, we might be making things more difficult in the future. I think that I'd rather see the community gain a bit more experience about complex designs prior to committing to a direction. Excluding parameterized classes from being lexically static for now gives us more space to consider issues and is easy to relax later. I don't feel too strongly about this so if others are opposed to being conservative on this, I wouldn't argue too much. Gord. -- -------------------------------------------------------------------- Gordon Vreugdenhil 503-685-0808 Model Technology (Mentor Graphics) gordonv@model.comReceived on Thu Mar 30 12:03:47 2006
This archive was generated by hypermail 2.1.8 : Thu Mar 30 2006 - 12:04:09 PST