-
Notifications
You must be signed in to change notification settings - Fork 14
feat: Scoping rules and utilities for symbols, links and variables #1754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1754 +/- ##
==========================================
+ Coverage 86.50% 86.66% +0.16%
==========================================
Files 188 191 +3
Lines 34400 34692 +292
Branches 31257 31549 +292
==========================================
+ Hits 29757 30066 +309
+ Misses 2948 2928 -20
- Partials 1695 1698 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
c50ca26
to
f6f5cea
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks much nicer than before thanks
678ec93
to
5d50273
Compare
This PR contains breaking changes to the public Rust API. cargo-semver-checks summary
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with 33 comments, that might be a record ;-) ;-)
Like the direction. Mostly this is nice stuff - I haven't looked at export.rs
and import.rs
because after looking through parse.rs
I realized it was mostly github + reindenting ;).
There are a few places where I'm not quite clear how scopes/regions work hence a few requests for comments etc. but generally I like it :-)
--- | ||
(hugr 0) | ||
|
||
(import prelude.Array) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super-nit: inconsistent capitalization with prelude.json
and indeed most other things (arithmetic.int.types.int
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. Before we actually stabilise on this, there needs to be a pass through to get consistent names.
ports @1 :UInt32; | ||
} | ||
|
||
# Either `0` for an open scope, or the number of links in the closed scope incremented by `1`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand what the scope of a link is? Is this for e.g. nonlocal edges? Would "the number of links in the closed scope" be the number of steps up/down the hierarchy, then, say?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Links don't have a global index space, but every closed region defines an index space. There can't be non-local edges across closed regions. This is a first step to simplify upcoming work on consts and nested hugrs, so that ideally closed regions can be loaded as Hugr
s themselves.
} | ||
|
||
struct RegionScope { | ||
links @0 :UInt32; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to have some comment here. Is this the number of links/ports in the region? Some distance up/down the hierarchy? etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps you could just cross-link to RegionScope
in mod.rs
let meta = read_list!(bump, reader, get_meta, read_meta_item); | ||
let signature = reader.get_signature().checked_sub(1).map(model::TermId); | ||
|
||
let scope = if reader.has_scope() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let scope = if reader.has_scope() { | |
let scope = reader.get_scope().map(read_region_scope) |
as read_region_scope
does not need need to return a ReadResult (it always produces Ok
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The if
checks if the field is set to see if the region is open (field absent) or closed (field present). I'm not entirely sure if get_scope
on an absent scope would be an error or return a default value, but either would not be desirable: An error would be undesirable since we want to distinguish between an open region and a corrupted file. A default value would make every region closed.
write_operation(builder.reborrow().init_operation(), &node.operation); | ||
write_list!(builder, init_inputs, write_link_ref, node.inputs); | ||
write_list!(builder, init_outputs, write_link_ref, node.outputs); | ||
let _ = builder.set_inputs(model::LinkIndex::unwrap_slice(node.inputs)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No way to indicate failure here? If you're planning to introduce one in a later PR, might be worth a comment to that effect. Or if this write_node
just works on a best-effort basis, could comment that too.
I note that write_term
just discards the Result, so +1 to taking steps towards passing lint ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ignore the Result
here since it can not fail given the type of argument that we pass to it. This is a bit of wonkyness in the capnp API.
Specifically set_inputs
takes an impl capnp::traits::SetterInput<capnp::primitive_list::Owned<u32>>
and we call it on a &[u32]
slice, which means that ultimately https://docs.rs/capnp/latest/src/capnp/primitive_list.rs.html#291-308 will run. This always returns Ok
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the reason for the API to be able to return an error is as follows: you can pass a capnp reader object to a setter. The reader can point to invalid data, in which case the setter attempts to read that invalid data and must forward the error.
hugr-model/src/v0/scope/vars.rs
Outdated
let scope = self.scopes.last().unwrap(); | ||
let (set_index, _) = self | ||
.vars | ||
.get_full(&(scope.node, name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does get_full
return the pair? Can you do .get
and then not have to discard the second element (as in let (set_index, _) = ...
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code was written before I knew of get_index_of
. I replaced it with get_index_of
now.
#[display("{_0}#{_1}")] | ||
pub struct LinkId(pub RegionId, pub LinkIndex); | ||
|
||
/// The id of a variable consisting of its node and the variable index. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be overkill but consider ultra-explicitness "The id of a variable being the node declaring the variable and the index within the variables declared by that node"
self.symbols.enter(self.module.root); | ||
self.links.enter(self.module.root); | ||
|
||
// TODO: What scope does the metadata live in? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd guess that metadata attached to a node lives just outside the scope of that node itself (e.g. cannot refer to variables defined by that node, or stuff inside it), but can refer to anything outside it. That's a bit of a guess, though, happy to leave this as TODO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is the indended scoping for metadata and it is implemented as such for almost all nodes. However this is the root node: everything, including imports, lives within the root node. So the metadata on the root node can not refer to anything...
let explicit_children = self.parse_nodes(&mut inner)?; | ||
|
||
let children = self.parse_nodes(&mut inner)?; | ||
let mut children = BumpVec::with_capacity_in( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this be something like from_slice(explicit_children.into_iter().chain(self.implicit_imports.drain().....))
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afaik chain
does not implement ExactSizeIterator
...
hugr-model/src/v0/text/parse.rs
Outdated
fn parse_regions( | ||
&mut self, | ||
pairs: &mut Pairs<'a, Rule>, | ||
closed: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be worth defining an enum RegionType {Open, Closed}
## 🤖 New release * `hugr`: 0.14.0 -> 0.14.1 (✓ API compatible changes) * `hugr-core`: 0.14.0 -> 0.14.1 (✓ API compatible changes) * `hugr-model`: 0.15.0 -> 0.16.0 (⚠️ API breaking changes) * `hugr-llvm`: 0.14.0 -> 0.14.1 (✓ API compatible changes) * `hugr-passes`: 0.14.0 -> 0.14.1 (✓ API compatible changes) * `hugr-cli`: 0.14.0 -> 0.14.1 (✓ API compatible changes) ###⚠️ `hugr-model` breaking changes ``` --- failure constructible_struct_adds_field: externally-constructible struct adds field --- Description: A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field. ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.37.0/src/lints/constructible_struct_adds_field.ron Failed in: field Region.scope in /tmp/.tmpN5f4vM/hugr/hugr-model/src/v0/mod.rs:414 field LinkId.1 in /tmp/.tmpN5f4vM/hugr/hugr-model/src/v0/mod.rs:162 --- failure enum_missing: pub enum removed or renamed --- Description: A publicly-visible enum cannot be imported by its prior path. A `pub use` may have been removed, or the enum itself may have been renamed or removed entirely. ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.37.0/src/lints/enum_missing.ron Failed in: enum hugr_model::v0::GlobalRef, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:456 enum hugr_model::v0::LocalRef, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:476 enum hugr_model::v0::LinkRef, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:494 --- failure enum_struct_variant_field_added: pub enum struct variant field added --- Description: An enum's exhaustive struct variant has a new field, which has to be included when constructing or matching on this variant. ref: https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.37.0/src/lints/enum_struct_variant_field_added.ron Failed in: field symbol of variant Term::Apply in /tmp/.tmpN5f4vM/hugr/hugr-model/src/v0/mod.rs:544 field symbol of variant Term::ApplyFull in /tmp/.tmpN5f4vM/hugr/hugr-model/src/v0/mod.rs:557 --- failure enum_struct_variant_field_missing: pub enum struct variant's field removed or renamed --- Description: A publicly-visible enum has a struct variant whose field is no longer available under its prior name. It may have been renamed or removed entirely. ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.37.0/src/lints/enum_struct_variant_field_missing.ron Failed in: field global of variant Term::Apply, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:544 field global of variant Term::ApplyFull, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:557 --- failure enum_variant_added: enum variant added on exhaustive enum --- Description: A publicly-visible enum without #[non_exhaustive] has a new variant. ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.37.0/src/lints/enum_variant_added.ron Failed in: variant ModelError:InvalidVar in /tmp/.tmpN5f4vM/hugr/hugr-model/src/v0/mod.rs:723 variant ModelError:InvalidSymbol in /tmp/.tmpN5f4vM/hugr/hugr-model/src/v0/mod.rs:726 variant Operation:Import in /tmp/.tmpN5f4vM/hugr/hugr-model/src/v0/mod.rs:374 --- failure enum_variant_missing: pub enum variant removed or renamed --- Description: A publicly-visible enum has at least one variant that is no longer available under its prior name. It may have been renamed or removed entirely. ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.37.0/src/lints/enum_variant_missing.ron Failed in: variant ModelError::InvalidLocal, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:723 variant ModelError::InvalidGlobal, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:727 --- failure inherent_method_missing: pub method removed or renamed --- Description: A publicly-visible method or associated fn is no longer available under its prior name. It may have been renamed or removed entirely. ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.37.0/src/lints/inherent_method_missing.ron Failed in: LinkId::new, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:140 LinkId::index, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:140 LinkId::unwrap_slice, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:140 LinkId::wrap_slice, previously in file /tmp/.tmp2gotdW/hugr-model/src/v0/mod.rs:140 --- failure struct_repr_transparent_removed: struct repr(transparent) removed --- Description: repr(transparent) was removed from a struct whose layout was part of the public ABI. This can cause its memory layout to change, breaking FFI use cases. ref: https://doc.rust-lang.org/cargo/reference/semver.html#repr-transparent-remove impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.37.0/src/lints/struct_repr_transparent_removed.ron Failed in: struct LinkId in /tmp/.tmpN5f4vM/hugr/hugr-model/src/v0/mod.rs:162 ``` <details><summary><i><b>Changelog</b></i></summary><p> ## `hugr` <blockquote> ## [0.14.1](hugr-v0.14.0...hugr-v0.14.1) - 2024-12-18 ### Bug Fixes - Constant folding now tolerates root nodes without input/output nodes (#1799) - `Call` ops not tracking their parameter extensions (#1805) ### New Features - add MonomorphizePass and deprecate monomorphize (#1809) - Lower LoadNat to LLVM (#1801) - Cleanup `Display` of types and arguments (#1802) - add ArrayValue to python, rust and lowering (#1773) - Scoping rules and utilities for symbols, links and variables (#1754) </blockquote> ## `hugr-core` <blockquote> ## [0.14.1](hugr-core-v0.14.0...hugr-core-v0.14.1) - 2024-12-18 ### Bug Fixes - `Call` ops not tracking their parameter extensions (#1805) ### New Features - Lower LoadNat to LLVM (#1801) - Cleanup `Display` of types and arguments (#1802) - add ArrayValue to python, rust and lowering (#1773) - Scoping rules and utilities for symbols, links and variables (#1754) </blockquote> ## `hugr-model` <blockquote> ## [0.16.0](hugr-model-v0.15.0...hugr-model-v0.16.0) - 2024-12-18 ### New Features - Scoping rules and utilities for symbols, links and variables (#1754) </blockquote> ## `hugr-llvm` <blockquote> ## [0.14.1](hugr-llvm-v0.14.0...hugr-llvm-v0.14.1) - 2024-12-18 ### Bug Fixes - Add LLVM lowering for `logic.Not` (#1812) ### New Features - Lower LoadNat to LLVM (#1801) - add ArrayValue to python, rust and lowering (#1773) </blockquote> ## `hugr-passes` <blockquote> ## [0.14.1](hugr-passes-v0.14.0...hugr-passes-v0.14.1) - 2024-12-18 ### Bug Fixes - Constant folding now tolerates root nodes without input/output nodes (#1799) ### New Features - Cleanup `Display` of types and arguments (#1802) - add MonomorphizePass and deprecate monomorphize (#1809) </blockquote> ## `hugr-cli` <blockquote> ## [0.14.1](hugr-cli-v0.14.0...hugr-cli-v0.14.1) - 2024-12-18 ### New Features - Print `hugr-cli`'s correct version when using '--version' (#1790) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/).
This PR introduces scoping for symbols, links and variables. It comes with utilities that can be used to resolve names appropriately. Moreover the model data structures are changed so that they always use direct references by indices instead of names in order to streamline the serialisation format.