pub enum DefaultScopeError {
DuplicateDefaultClocking(String),
DuplicateDefaultDisable(String),
UnresolvedDefaultClockingTarget(String),
DefaultClockingTargetNotAClockingBlock(String),
}Expand description
Task 8 (sva T8, docs/superpowers/plans/2026-10-03-sva.md): LRM
1800-2023 14.12’s default clocking and 16.15’s default disable iff
– the scoping half only (which single declaration, if any, covers a
given scope): resolving the lexical-nesting/override rules both clauses
state almost verbatim (“valid only within the scope containing the
declaration … as well as any nested module[s] … It does not include
instantiated modules” – 14.12; “provides a default … to all
concurrent assertions in the scope and subscopes … the default
extends to any nested module … However, if a nested module … has a
[its own] declaration, then that … overrides any default … from
outside” – 16.15). The resolution-rule half of 16.15 (composing this
against an assertion’s own explicit disable iff clause, rules
(a)/(b)/(c)) is T27’s job, consuming default_disable_of’s result –
not reimplemented here.
§Why a syntax walk, not a sv-lang semantic accessor
The vendored C++ slang already has exactly this query
(slang::ast::Compilation::getDefaultClocking/getDefaultDisable,
include/slang/ast/Compilation.h) – but, unlike 16.13.3/16.16’s clock
flow (T7) or 16.14.6’s procedural clock inference (T6), sv-lang 0.1.9
exposes no FFI binding to either one at all (confirmed by grepping the
installed crate’s own generated ast.rs/sys surface for
default_clocking/default_disable and finding nothing – not
assumed). Per the same plan-wide posture T6/T7 already apply (“wrap
what’s exposed, reimplement only what genuinely is not”), this task
reconstructs 14.12/16.15 directly from the syntax tree, exactly as the
plan’s own Task 8 “Files”/“Steps” text asks: walking
module_or_generate_item_declaration’s default clocking clocking_identifier ;/inline [default] clocking ... endclocking/
default disable iff expr ; forms (DefaultClockingReferenceSyntax/
ClockingDeclarationSyntax/DefaultDisableDeclarationSyntax).
§Lexical nesting via Symbol::parent(), confirmed live
14.12/16.15’s “nested declaration inherits; mere instantiation does
not” distinction sounds like it needs a second, syntax-ancestry walk
independent of the elaborated instance tree – but sv_lang::Symbol:: parent() (slang_symbol_parent_scope) turns out to already encode
exactly that distinction, confirmed live against both shapes before
writing this function (not assumed from the plan’s prose): for a module
m2 declared as a nested declaration textually inside m1 and
instantiated there, m2’s elaborated InstanceBody::parent() is m1’s
own InstanceBody; for the identical textual declaration of m2
hoisted to the top level and merely instantiated inside m1, m2’s
InstanceBody::parent() is the design’s CompilationUnit root –
never m1 – even though m2 is instantiated in exactly the same
place in both cases. I.e. parent() already walks the lexical
declaration-site scope chain, not the elaborated instantiation
hierarchy, which is exactly what both clauses need told apart. The same
holds for a GenerateBlock symbol (its parent() is its lexically
enclosing module/generate scope). So [each_lexical_scope] below climbs
Symbol::parent() alone, never a second, independent Node::parent()
syntax-ancestry walk.
Variants§
DuplicateDefaultClocking(String)
14.12: “Specifying a default clocking more than once in the same module, interface, program, or checker shall result in a compiler error.” Carries the offending scope’s name.
DuplicateDefaultDisable(String)
16.15: “More than one default disable iff declaration within the same module, interface, program declaration, or generate block shall be an error.” Carries the offending scope’s name.
UnresolvedDefaultClockingTarget(String)
A default clocking clocking_identifier; reference whose name does
not resolve to any member of the scope it was declared in.
Defensive – 14.12’s own “clocking_identifier shall be the name of a
clocking block” is a semantic rule slang itself already enforces on
a fatal-error-free Design, so this should be unreachable, but a
loud named error is still required over a silent None/panic.
DefaultClockingTargetNotAClockingBlock(String)
As above, but the name resolved to a real member that is not itself a clocking block.