Support class properties shadowing type names

SystemVerilog allows a class property to have the same name as a visible
type. The lexer reports the visible type name as `TYPE_IDENTIFIER` before
the property has been installed, which made constructs such as
`typedef int T; class C; int T; endclass` fail in the class item grammar.
A class property with the same name as the class itself hits the same
problem. Member references such as `obj.T` or `obj.C` can also hit the
same tokenization problem in hierarchical names.

Parse class properties through the same declaration helper used for
variables so the first type/name pair can be disambiguated. Also let
hierarchical member names use `identifier_name`.

Stop type lookup when a class scope already has a property with the same
name. This makes method body references resolve as properties instead of
visible types, including type names found through wildcard imports.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2026-06-27 10:01:43 -07:00
parent d01efc910b
commit dc66f2fe7e
2 changed files with 15 additions and 10 deletions

15
parse.y
View File

@ -1172,11 +1172,11 @@ class_item /* IEEE1800-2005: A.1.8 */
/* IEEE1800-2017: A.1.9 Class items: Class properties... */
| property_qualifier_opt data_type list_of_variable_decl_assignments ';'
{ pform_class_property(@2, $1, $2, $3); }
| property_qualifier_opt list_of_variable_decl_assignments_with_type ';'
{ pform_class_property(@2, $1, $2.type, $2.decl_assignments); }
| K_const class_item_qualifier_opt data_type list_of_variable_decl_assignments ';'
{ pform_class_property(@1, $2 | property_qualifier_t::make_const(), $3, $4); }
| K_const class_item_qualifier_opt list_of_variable_decl_assignments_with_type ';'
{ pform_class_property(@1, $2 | property_qualifier_t::make_const(), $3.type, $3.decl_assignments); }
/* IEEEE1800-2017: A.1.9 Class items: class_item ::= { property_qualifier} data_declaration */
@ -1212,11 +1212,6 @@ class_item /* IEEE1800-2005: A.1.8 */
/* Here are some error matching rules to help recover from various
syntax errors within a class declaration. */
| property_qualifier_opt data_type error ';'
{ yyerror(@3, "error: Errors in variable names after data type.");
yyerrok;
}
| property_qualifier_opt IDENTIFIER error ';'
{ yyerror(@3, "error: %s doesn't name a type.", $2);
yyerrok;
@ -4749,7 +4744,7 @@ hierarchy_identifier
$$->push_back(name_component_t(lex_strings.make($1)));
delete[]$1;
}
| hierarchy_identifier '.' IDENTIFIER
| hierarchy_identifier '.' identifier_name
{ pform_name_t * tmp = $1;
tmp->push_back(name_component_t(lex_strings.make($3)));
delete[]$3;

View File

@ -929,6 +929,16 @@ typedef_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt)
if (sym != cur_scope->local_symbols.end())
return nullptr;
// Class properties are tracked in the class type, not in
// local_symbols, but still shadow type names before lookup falls
// through to wildcard imports.
if (auto cur_class = dynamic_cast<PClass*> (cur_scope)) {
if (cur_class->type &&
cur_class->type->properties.find(name) !=
cur_class->type->properties.end())
return nullptr;
}
PPackage*pkg = pform_find_potential_import(loc, cur_scope, name, false, false);
if (pkg) {
cur = pkg->typedefs.find(name);