Support access to constructs inside type parameters (#3702)

This changeset brings support for accesses like:

	class Cls#(type TYPE1);
	    TYPE1::some_method();
	endclass

It is done by delaying dot resolution on type parameters until they get
resolved by V3Param, and doing a more thorough reference skip.
This commit is contained in:
Arkadiusz Kozdra 2022-10-21 15:00:40 +02:00 committed by GitHub
parent 5688d1a935
commit 627a144b83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 4 deletions

View File

@ -912,6 +912,7 @@ public:
dtypep(nullptr); // V3Width will resolve
}
ASTGEN_MEMBERS_AstParamTypeDType;
void dump(std::ostream& str = std::cout) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); }
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }

View File

@ -1719,12 +1719,25 @@ void AstTimeImport::dump(std::ostream& str) const {
void AstTypedef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (attrPublic()) str << " [PUBLIC]";
if (subDTypep()) {
str << " -> ";
subDTypep()->dump(str);
}
}
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstRange::dump(std::ostream& str) const {
this->AstNodeRange::dump(str);
if (littleEndian()) str << " [LITTLE]";
}
void AstParamTypeDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (subDTypep()) {
str << " -> ";
subDTypep()->dump(str);
} else {
str << " -> UNLINKED";
}
}
void AstRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
if (typedefp() || subDTypep()) {
@ -2095,7 +2108,8 @@ void AstClassOrPackageRef::dump(std::ostream& str) const {
}
AstNodeModule* AstClassOrPackageRef::classOrPackagep() const {
AstNode* foundp = m_classOrPackageNodep;
while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
if (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
if (auto* const anodep = VN_CAST(foundp, NodeDType)) foundp = anodep->skipRefp();
if (auto* const anodep = VN_CAST(foundp, ClassRefDType)) foundp = anodep->classp();
return VN_CAST(foundp, NodeModule);
}

View File

@ -2069,11 +2069,13 @@ private:
}
bool isParamedClassRef(const AstNode* nodep) {
// Is this a parametrized reference to a class, or a reference to class parameter
if (const auto* classRefp = VN_CAST(nodep, ClassOrPackageRef)) {
if (classRefp->paramsp()) return true;
const auto* classp = classRefp->classOrPackageNodep();
while (const auto* typedefp = VN_CAST(classp, Typedef)) classp = typedefp->subDTypep();
return VN_IS(classp, ClassRefDType) && VN_AS(classp, ClassRefDType)->paramsp();
return (VN_IS(classp, ClassRefDType) && VN_AS(classp, ClassRefDType)->paramsp())
|| VN_IS(classp, ParamTypeDType);
}
return false;
}
@ -2633,8 +2635,9 @@ private:
// Class: Recurse inside or cleanup not founds
// checkNoDot not appropriate, can be under a dot
AstNode::user5ClearTree();
UASSERT_OBJ(m_statep->forPrimary() || nodep->classOrPackagep(), nodep,
"ClassRef has unlinked class");
UASSERT_OBJ(m_statep->forPrimary() || VN_IS(nodep->classOrPackageNodep(), ParamTypeDType)
|| nodep->classOrPackagep(),
nodep, "ClassRef has unlinked class");
UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep,
"class reference parameter not removed by V3Param");
VL_RESTORER(m_ds);

View File

@ -936,11 +936,13 @@ class ParamVisitor final : public VNVisitor {
srcModp = modCellp->modp();
} else if (const auto* classRefp = VN_CAST(cellp, ClassOrPackageRef)) {
srcModp = classRefp->classOrPackagep();
if (VN_IS(classRefp->classOrPackageNodep(), ParamTypeDType)) continue;
} else if (const auto* classRefp = VN_CAST(cellp, ClassRefDType)) {
srcModp = classRefp->classp();
} else {
cellp->v3fatalSrc("Expected module parametrization");
}
UASSERT_OBJ(srcModp, cellp, "Unlinked class ref");
// Update path
string someInstanceName(modp->someInstanceName());

View File

@ -0,0 +1,21 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2020 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,32 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Arkadiusz Kozdra.
// SPDX-License-Identifier: CC0-1.0
// See also t_class_param.v
class Parcls #(type T);
static function int get_p;
return T::get_p();
endfunction
endclass
class Cls;
static function int get_p;
return 20;
endfunction
endclass
typedef Cls cls_t;
typedef cls_t cls2_t;
module t (/*AUTOARG*/);
initial begin
if (Parcls#(cls2_t)::get_p() != 20) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule