From 47b6e912381404667bf721165707cb9d802fa8c6 Mon Sep 17 00:00:00 2001 From: Andrii Andrieiev Date: Wed, 8 Jul 2026 17:22:21 +0200 Subject: [PATCH] Fix class parameter resolution Signed-off-by: Andrii Andrieiev --- docs/CONTRIBUTORS | 1 + src/V3LinkDot.cpp | 7 +++-- test_regress/t/t_interface_typedef3.out | 5 ---- test_regress/t/t_interface_typedef3.py | 9 +++---- test_regress/t/t_interface_typedef3.v | 7 ++++- test_regress/t/t_interface_typedef_bad.out | 9 +++---- test_regress/t/t_interface_typedef_bad.v | 3 +-- test_regress/t/t_interface_typedef_bad2.out | 10 +++++++ test_regress/t/t_interface_typedef_bad2.py | 16 ++++++++++++ test_regress/t/t_interface_typedef_bad2.v | 21 +++++++++++++++ test_regress/t/t_param_type_bad.out | 2 +- test_regress/t/t_param_type_dot.py | 18 +++++++++++++ test_regress/t/t_param_type_dot.v | 29 +++++++++++++++++++++ test_regress/t/t_param_type_dot_bad.out | 14 ++++++++++ test_regress/t/t_param_type_dot_bad.py | 16 ++++++++++++ test_regress/t/t_param_type_dot_bad.v | 27 +++++++++++++++++++ 16 files changed, 169 insertions(+), 25 deletions(-) delete mode 100644 test_regress/t/t_interface_typedef3.out create mode 100644 test_regress/t/t_interface_typedef_bad2.out create mode 100755 test_regress/t/t_interface_typedef_bad2.py create mode 100644 test_regress/t/t_interface_typedef_bad2.v create mode 100755 test_regress/t/t_param_type_dot.py create mode 100644 test_regress/t/t_param_type_dot.v create mode 100644 test_regress/t/t_param_type_dot_bad.out create mode 100755 test_regress/t/t_param_type_dot_bad.py create mode 100644 test_regress/t/t_param_type_dot_bad.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 955d22e6a..954f736d2 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -26,6 +26,7 @@ Andrei Kostovski Andrew Miloradovsky Andrew Nolte Andrew Voznytsa +Andrii Andrieiev anonkey Anthony Donlon Anthony Moore diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 0bb78f8e8..3d2dc44eb 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -6126,11 +6126,10 @@ class LinkDotResolveVisitor final : public VNVisitor { // Only emit error if the child is not a type. // Do NOT unwrap valid types here - leave that to V3Width. // Unwrapping here breaks type parameter resolution during cloning. - if (nodep->lhsp() && !VN_IS(nodep->lhsp(), NodeDType)) { + if (nodep->lhsp() && !VN_IS(nodep->lhsp(), NodeDType) && !VN_IS(nodep->lhsp(), Dot)) { // Not a type - emit error - if (AstConst* const constp = VN_CAST(nodep->lhsp(), Const)) { - nodep->lhsp()->v3error( - "Expecting a data type, not a constant: " << constp->toSInt()); + if (VN_IS(nodep->lhsp(), Const)) { + nodep->lhsp()->v3error("Expecting a data type, not a constant"); } else { nodep->lhsp()->v3error("Expecting a data type, not " << nodep->lhsp()->typeName() << ": '" diff --git a/test_regress/t/t_interface_typedef3.out b/test_regress/t/t_interface_typedef3.out deleted file mode 100644 index 9895ef810..000000000 --- a/test_regress/t/t_interface_typedef3.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error: t/t_interface_typedef3.v:22:19: Expecting a data type, not DOT: '' - 22 | typedef iface_mp.choice_t tdef_t; - | ^ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: Exiting due to diff --git a/test_regress/t/t_interface_typedef3.py b/test_regress/t/t_interface_typedef3.py index 96005884d..3cc73805c 100755 --- a/test_regress/t/t_interface_typedef3.py +++ b/test_regress/t/t_interface_typedef3.py @@ -9,13 +9,10 @@ import vltest_bootstrap -test.scenarios('simulator_st') +test.scenarios('simulator') -test.compile(verilator_flags2=['--binary'], - fails=test.vlt_all, - expect_filename=test.golden_filename) +test.compile() -if not test.vlt_all: - test.execute() +test.execute() test.passes() diff --git a/test_regress/t/t_interface_typedef3.v b/test_regress/t/t_interface_typedef3.v index 9d653344e..e333fe655 100644 --- a/test_regress/t/t_interface_typedef3.v +++ b/test_regress/t/t_interface_typedef3.v @@ -20,7 +20,7 @@ module sub ( interface.mp iface_mp ); typedef iface_mp.choice_t tdef_t; - tdef_t P; + tdef_t P = '1; initial begin `checkd($bits(tdef_t), 4); end @@ -29,4 +29,9 @@ endmodule module t; ifc u_ifc (); sub u_sub (u_ifc.mp); + initial begin + if (u_sub.P != '1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end endmodule diff --git a/test_regress/t/t_interface_typedef_bad.out b/test_regress/t/t_interface_typedef_bad.out index 2a747ad1c..85d2f6437 100644 --- a/test_regress/t/t_interface_typedef_bad.out +++ b/test_regress/t/t_interface_typedef_bad.out @@ -2,13 +2,10 @@ 15 | typedef not_found.choice_t choice1_t; | ^~~~~~~~~ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_interface_typedef_bad.v:15:20: Expecting a data type, not a constant: 0 +%Error: t/t_interface_typedef_bad.v:15:20: Expecting a data type, not a constant 15 | typedef not_found.choice_t choice1_t; | ^ -%Error: t/t_interface_typedef_bad.v:16:12: Expecting a data type, not DOT: '' - 16 | typedef i.not_found_t choice2_t; - | ^ -%Error: t/t_interface_typedef_bad.v:17:19: Expecting a data type, not MEMBERSEL: 'x_t' - 17 | typedef not_ifc.x_t choice3_t; +%Error: t/t_interface_typedef_bad.v:16:19: Expecting a data type, not MEMBERSEL: 'x_t' + 16 | typedef not_ifc.x_t choice2_t; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_interface_typedef_bad.v b/test_regress/t/t_interface_typedef_bad.v index e72b45942..77c05a87c 100644 --- a/test_regress/t/t_interface_typedef_bad.v +++ b/test_regress/t/t_interface_typedef_bad.v @@ -13,8 +13,7 @@ module sub ( ); logic not_ifc; typedef not_found.choice_t choice1_t; // <--- Error: not found interface port - typedef i.not_found_t choice2_t; // <--- Error: not found typedef - typedef not_ifc.x_t choice3_t; // <--- Error: sub not interface reference + typedef not_ifc.x_t choice2_t; // <--- Error: sub not interface reference endmodule module t; diff --git a/test_regress/t/t_interface_typedef_bad2.out b/test_regress/t/t_interface_typedef_bad2.out new file mode 100644 index 000000000..96b296ea7 --- /dev/null +++ b/test_regress/t/t_interface_typedef_bad2.out @@ -0,0 +1,10 @@ +%Error: t/t_interface_typedef_bad2.v:15:13: Can't find definition of 'not_found_t' in dotted variable/method: 'i.not_found_t' + : ... note: In instance 't.u_sub' + 15 | typedef i.not_found_t choice_t; + | ^~~~~~~~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_interface_typedef_bad2.v:15:12: Expecting a data type, not a constant + : ... note: In instance 't.u_sub' + 15 | typedef i.not_found_t choice_t; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_interface_typedef_bad2.py b/test_regress/t/t_interface_typedef_bad2.py new file mode 100755 index 000000000..a00127d05 --- /dev/null +++ b/test_regress/t/t_interface_typedef_bad2.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('linter') + +test.lint(fails=test.vlt_all, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_interface_typedef_bad2.v b/test_regress/t/t_interface_typedef_bad2.v new file mode 100644 index 000000000..8973bcb81 --- /dev/null +++ b/test_regress/t/t_interface_typedef_bad2.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +interface ifc; + integer i; +endinterface + +module sub ( + interface i +); + logic not_ifc; + typedef i.not_found_t choice_t; // <--- Error: not found typedef +endmodule + +module t; + ifc u_ifc (); + sub u_sub (u_ifc); +endmodule diff --git a/test_regress/t/t_param_type_bad.out b/test_regress/t/t_param_type_bad.out index fe7834e26..d9138885d 100644 --- a/test_regress/t/t_param_type_bad.out +++ b/test_regress/t/t_param_type_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_param_type_bad.v:9:26: Expecting a data type, not a constant: 2 +%Error: t/t_param_type_bad.v:9:26: Expecting a data type, not a constant 9 | localparam type bad2 = 2; | ^ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. diff --git a/test_regress/t/t_param_type_dot.py b/test_regress/t/t_param_type_dot.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_param_type_dot.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_param_type_dot.v b/test_regress/t/t_param_type_dot.v new file mode 100644 index 000000000..a5b68d7fe --- /dev/null +++ b/test_regress/t/t_param_type_dot.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +class C; + typedef logic [1:0] T; + class nst; + typedef logic [2:0] S; + endclass +endclass: C + +class P#(type C); + localparam type C1_t = C::T; + parameter type C2_t = C::nst::S; + C1_t x = '1; + C2_t y = '1; +endclass : P + +module t(); + P#(C) P_data = new(); + initial begin + if (P_data.x != '1) $stop; + if (P_data.y != '1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_param_type_dot_bad.out b/test_regress/t/t_param_type_dot_bad.out new file mode 100644 index 000000000..58bc67ea7 --- /dev/null +++ b/test_regress/t/t_param_type_dot_bad.out @@ -0,0 +1,14 @@ +%Error: t/t_param_type_dot_bad.v:13:26: Found definition of 'C' as a PARAMTYPEDTYPE but expected a scope/variable + 13 | localparam type C1_t = C.T; + | ^ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_param_type_dot_bad.v:13:27: Expecting a data type, not a constant + 13 | localparam type C1_t = C.T; + | ^ +%Error: t/t_param_type_dot_bad.v:14:25: Found definition of 'C' as a PARAMTYPEDTYPE but expected a scope/variable + 14 | parameter type C2_t = C.y; + | ^ +%Error: t/t_param_type_dot_bad.v:14:26: Expecting a data type, not a constant + 14 | parameter type C2_t = C.y; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_param_type_dot_bad.py b/test_regress/t/t_param_type_dot_bad.py new file mode 100755 index 000000000..38cf36b43 --- /dev/null +++ b/test_regress/t/t_param_type_dot_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('linter') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_param_type_dot_bad.v b/test_regress/t/t_param_type_dot_bad.v new file mode 100644 index 000000000..7fb82e043 --- /dev/null +++ b/test_regress/t/t_param_type_dot_bad.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +class C; + typedef logic [1:0] T; + static int y = 1; +endclass: C + +class P#(type C); + localparam type C1_t = C.T; + parameter type C2_t = C.y; + C1_t x = '1; + C2_t y = 2; +endclass : P + +module t(); + P#(C) P_data = new(); + initial begin + if (P_data.x != '1) $stop; + if (P_data.y != 2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule