There are some corner cases around class constructor chaining that can
result in chained constructors not being called, or being called multiple
times.
This is primarily related to that a class can have either an explicit
constructor called `new` and an implicit constructor called `new@` and how
the lookup of them is done.
Lookup is currently done independently for the implicit and explicit
constructor using the `method_from_name()` method. `method_from_name()`
will search the whole class hierarchy for a class method. If a class
doesn't have a method by that name it will look in the parent class and so
on.
As a result the lookup for the explicit constructor can return the explicit
constructor of a parent class if the class itself only has an implicit
constructor and vice versa.
E.g. in the following example the constructor of D will not be called
because the implicit constructor for C is found when looking for a implicit
constructor in D.
```
class C;
int x = 10;
endclass
class D extends C;
function new;
$display("D");
endfunction
endclass
class E extends D;
int y;
function new;
y = 20;
endfunction
endclass
E e = new;
```
There is a similar case where the constructor of a base class can be called
multiple times if the base class has an explicit constructor and the
derived class has an implicit constructor. In that case the derived class
constructor will call the base class constructor, but the code that is
emitted for the `new` statement will call both of them.
To mitigate this introduce a new method to lookup the constructor that will
search for either the explicit or implicit constructor in the current class
and only continue to search in the base class if neither is found.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows objects to be assigned to a variable that is a base
type of the objects type.
E.g.
```
class B; endclass
Class C extends B; endclass
C c = new
B b = c;
```
Add a type_compatibility() method for netclass_t that allows these kinds of
assignments.
This already works fine in vvp since, as SystemVerilog does not support
multiple inheritance, properties will always be at the same offset in the
base class and the inheriting class.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is not allowed to create objects of virtual classes. Currently the
virtual keyword is accepted by the parser, but otherwise ignored.
Keep track of whether a class is virtual and generate an error when the
class new operator is used for a virtual type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The base class type is not owned by a class and is shared. For this reason
it must not be modified. To ensure this mark the base class pointer as
const.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For some data types the value returned by the `elaborate_type()` method is
shared among different signals of that type. E.g. all string or real types
get elaborated to the same ivl_type_s. This means the returned value must
not be modified, otherwise the data type for unrelated signals might get
changed.
To enforce this and protect against accidental breakage make the return
type of the `elaborate_type()` and the related `elaborate_type_raw()`
methods const.
Note that `ivl_type_t` is used for the new return type which is a typedef
for `const ivl_type_s*`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is allowed to access a constant declared in a class scope, such as a
enum value or parameter, on an object of that class type. This is described
in section 8.5 ("Object properties and object parameter data") of the LRM
(1800-2017).
E.g.
```
class C
enum { A } e;
endclass
C c = new;
c.e = c.A;
```
Support this by in addition of searching for class properties on the object
also search for constants in the class scope.
A bit of refactoring is needed around the parameter elaboration functions
since they expect a non-const NetScope, but for classes we only have a
const scope available.
The non-const scope is needed to be able to mark specparams as
non-annotatable. Since classes can't have specparams this part is factored
out into a separate function the NetScope parameter for the shared
functions is made const.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This adds the runtime support for class properties that are classes
to be arrayed. Add a means to define the dimensions of a property
in the vvp format, and add functions for setting/extracting elements
of a property.
We need the scope where the class is defined so that it can find
types in that containing scope. Note that most definitions cannot
escape into the the lexical scope of the class, but some can.
It is better to leave the handling of PChainConstructor calls to
the elaboration, instead of stripping them out early. This allows
for handling the arguments of the chain constructor in the correct
scope.
Static properties are like variables in a named scope.
Detect these variables during elaboration so that the
code generator just sees them as variables.
This implementation works by detecting assignments
to constant properties in elaboration. Allow initializer
assignments to assign to the constant, error all other
assignments, and otherwise treat the constant like any
other property.
Emit the elaborated class methods. Also generate root scopes to
represent the classes in order to hold the methods. These scopes
can also in the future be used to implement static properties.
This provides the ivl_target.h interface for class definitions
and expressions, the vvp code generator support for class objects
and properties, and the vvp run time support. Trivial class objects
now seem to work.
Add properties to the classes, and elaborate expressions that
have class properties. Describe class object property references
all the way down to the stub target.