Fix of external SDK crate override bug#312
Conversation
|
In 3390c42: I'm confused by this solution. We now how have two methods, In parallel to this, this commit adds We then change |
|
@Sdoba16 could you update the description to reflect recent updates? |
|
Can you squash these commits? |
4414d2d to
438d6ff
Compare
| @@ -0,0 +1,106 @@ | |||
| use std::path::Path; | |||
There was a problem hiding this comment.
Once this file is added, let's move the CanonSourceFile struct and its implementation from driver/mod.rs into this new one
| K: Into<String>, | ||
| { | ||
| let mut dependency_map = DependencyMap::new(); | ||
| let mut builder = crate::resolution::DependencyMapBuilder::new(); |
There was a problem hiding this comment.
Use DependencyMapBuilder instead of crate::resolution::DependencyMapBuilder
| let canon_root = crate::source::CanonPath::canonicalize(&root).unwrap(); | ||
| let dependency_map = crate::resolution::DependencyMapBuilder::new() |
There was a problem hiding this comment.
Same here: use the name directly and remove the crate:: prefix
| dependency_map.insert(context, drp.into(), target).unwrap(); | ||
|
|
||
| dependency_map | ||
| crate::resolution::DependencyMapBuilder::new() |
There was a problem hiding this comment.
Found crate again. Let’s nix these everywhere else too
| /// A router for resolving dependencies across multi-file workspaces. | ||
| /// | ||
| /// Mappings are strictly sorted by the longest `context_prefix` match. | ||
| /// This mathematical guarantee ensures that if multiple nested directories | ||
| /// define the same dependency root path, the most specific (deepest) context wins. | ||
| #[derive(Debug, Clone, Default)] | ||
| pub struct DependencyMap { | ||
| /// External dependency remappings (e.g., `use math::...`) | ||
| remappings: Vec<Remapping>, | ||
| /// Package roots for resolving `crate::...` (sorted by longest path match) | ||
| package_roots: Vec<CanonPath>, | ||
| } |
There was a problem hiding this comment.
Add a bit more explanation of the architecture here. Why do we need Vec<CanonPath> here?
| pub fn with_entry_root(mut self, root: CanonPath) -> Self { | ||
| self.entry_root = Some(root); | ||
| self |
There was a problem hiding this comment.
Let’s pull this into new() and get rid of the Option for entry_root
| let resolved = Self::build_and_verify_path(&remapping.target, &parts[1..]) | ||
| .map_err(|failed_path| { | ||
| let err = if drp_name == CRATE_STR { | ||
| Error::FileNotFound(failed_path) | ||
| } else { | ||
| Error::ExternalFileNotFound(drp_name.to_string(), failed_path) | ||
| }; | ||
| RichError::new(err, *use_decl.span()) | ||
| RichError::new( | ||
| Error::ExternalFileNotFound(drp_name.to_string(), failed_path), | ||
| *use_decl.span(), | ||
| ) | ||
| })?; | ||
|
|
||
| self.check_local_file_imported_as_external( | ||
| drp_name, | ||
| current_file, | ||
| &resolved, | ||
| use_decl, | ||
| )?; | ||
| if !resolved.starts_with(&remapping.target) { | ||
| return Err(RichError::new( | ||
| Error::ExternalFileNotFound( | ||
| drp_name.to_string(), | ||
| resolved.as_path().to_path_buf(), | ||
| ), | ||
| *use_decl.span(), | ||
| )); | ||
| } | ||
|
|
||
| self.check_local_file_imported_as_external(current_file, &resolved, use_decl)?; |
There was a problem hiding this comment.
Extract this into a separate function
6ed86cb to
1836312
Compare
| self.as_path().starts_with(path.as_path()) | ||
| } | ||
| // Sort package roots by length descending to ensure longest prefix match | ||
| crate_roots.sort_by(|a, b| { |
There was a problem hiding this comment.
Should this not have a then_by sort for paths with the same length? It could probably then be used instead of the above sort at line 138
| } | ||
|
|
||
| impl DependencyMap { | ||
| pub fn new() -> Self { |
There was a problem hiding this comment.
Should this method maybe be private and add documentation to only use the builder. It seems like it is quite complicated to create this struct
| /// This mathematically guarantees that the first match we find is the most specific. | ||
| fn sort_mappings(&mut self) { | ||
| self.inner.sort_by(|a, b| { | ||
| self.remappings.sort_by(|a, b| { |
There was a problem hiding this comment.
Also feels like there should be a second sorting clause for paths with the same length
5be4511 to
7ff8fd2
Compare
|
ACK 7ff8fd2; tested locally |
| DependencyPathNotFound(String), | ||
| DependencyNotADirectory(String), | ||
| ReservedDependencyKeyword(String), | ||
| DuplicateDependencyAlias(String, String), | ||
| InvalidDependencyIdentifier(String), | ||
| Internal(String), |
There was a problem hiding this comment.
In the context of #325 (comment) should we reiterate on errors here?
@gerau what do you think? (from my PoV with this PR we are adding more work for you)
There was a problem hiding this comment.
This PR is already ACK'ed and tested. My vote is for merging as is.
There was a problem hiding this comment.
This PR is already ACK'ed and tested. My vote is for merging as is.
When possible I wanna avoid surprises for devs who are working on features
| /// This struct must always be constructed via [`DependencyMapBuilder`]. | ||
| /// Builder guarantees that the vector is never empty and contains no duplicates, so we can safely sort without worrying about edge cases. | ||
| #[derive(Debug, Clone, Default)] | ||
| pub struct DependencyMap { |
There was a problem hiding this comment.
This still derives Default, which leaves a public way to construct an invalid map without DependencyMapBuilder
There was a problem hiding this comment.
Yeah, you're right, so I will just delete deriving Default, it won't break anything
7ff8fd2 to
70cebfb
Compare
70cebfb to
f2af871
Compare
… and `TemplateProgram` in `new_with_dep` method cdaab4d Change SourceFile to CanonSourceFile in CompiledProgram and TemplateProgram to forbid passing SourceFile::anonymous (Sdoba16) Pull request description: Closes #311 Oblige user to use `CanonSourceFile` in the `CompiledProgram` and `TemplateProgram` in `new_with_dep` method to prevent passing `SourceFile::anonymous`. This PR should be merged after the #312 to prevent conflicts as it follows its implementation. ACKs for top commit: LesterEvSe: ACK cdaab4d; tested locally apoelstra: ACK cdaab4d; successfully ran local tests Tree-SHA512: 592ffa99a93851f280eed18c0a4819ef9148097d7f915ea37e0f30bb5fc14147c1fc15c1bc32c9ef7e0e4f3505bacff89df7cbbc2cefeab25cc5f6cd36c0e5b2
Closes #310
Previously, users could interact directly with the DependencyMap API in SimplicityHL, they could manually set the crate keyword to any path they want. This happened because the insert method allowed adding the crate alias without throwing any validation errors.
Fix
Was introduced
DependencyMapBuilderwhich collects dependencies and then could with build command it can be built.While building are made following validations:
Remapping was made pub(crate) to hide from external API.
resolution.rswas separated into 2 filessource.rsandresolution.rsfor readability.