-
Notifications
You must be signed in to change notification settings - Fork 29
Resolve symbols from attached and imported packages #1258
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
Changes from all commits
b8e49c9
6ae5496
560713a
1abab5e
e7425f2
277ade9
44c0075
27ac5d4
b2eabe0
d95d493
67a0e8b
3209b47
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| use crate::Db; | ||
| use crate::Definition; | ||
| use crate::Name; | ||
| use crate::Package; | ||
|
|
||
| /// Visibility filter for [`Package::resolve`]. | ||
| /// | ||
| /// Mirrors R's `::` vs `:::` distinction. `Exported` requires `name` to | ||
| /// appear in the package's NAMESPACE `export()` directives. `Internal` | ||
| /// returns any top-level binding the package's files define, exported | ||
| /// or not. | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
| pub enum PackageVisibility { | ||
| Exported, | ||
| Internal, | ||
| } | ||
|
|
||
| #[salsa::tracked] | ||
| impl<'db> Package { | ||
| /// Resolve `name` against this package's top-level bindings. | ||
| /// | ||
| /// - `Exported` (R's `pkg::name`) gates on the package's NAMESPACE `export()` | ||
| /// directives: an internal binding is invisible even if it exists. | ||
| /// - `Internal` (R's `pkg:::name`) returns any top-level binding regardless | ||
| /// of NAMESPACE. | ||
| /// | ||
| /// Iterates [`Package::files`] and aggregates each file's | ||
| /// [`File::resolve_export`] for `name`. | ||
| /// | ||
| /// Returns a `Vec` because a package's namespace can carry more than one | ||
| /// binding per name. A common pattern is a top-level stub overridden from | ||
| /// an `.onLoad` hook via `<<-`: | ||
|
Comment on lines
+30
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But overwriting via
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, or is it that
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right |
||
| /// | ||
| /// ```r | ||
| /// # R/foo.R | ||
| /// foo <- function() stop("not loaded yet") | ||
| /// | ||
| /// # R/zzz.R | ||
| /// .onLoad <- function(libname, pkgname) { | ||
| /// foo <<- function() "real implementation" | ||
| /// } | ||
| /// ``` | ||
| /// | ||
| /// Both bindings live in the package namespace; both come back as | ||
| /// candidates. Conditional fan-out within a single file (e.g. | ||
| /// `if cond x <- 1 else x <- 2`) surfaces here the same way. | ||
| /// | ||
| /// Returns an empty Vec when the name isn't bound anywhere in the package, | ||
| /// or when `Exported` is requested for a name absent from | ||
| /// `namespace.exports`. | ||
| #[salsa::tracked] | ||
| pub fn resolve( | ||
| self, | ||
| db: &'db dyn Db, | ||
| name: Name<'db>, | ||
| visibility: PackageVisibility, | ||
| ) -> Vec<Definition<'db>> { | ||
| if visibility == PackageVisibility::Exported && | ||
| !self | ||
| .namespace(db) | ||
| .exports | ||
| .contains_str(name.text(db).as_str()) | ||
| { | ||
| return Vec::new(); | ||
| } | ||
|
|
||
| let mut results = Vec::new(); | ||
| for &file in self.files(db) { | ||
| results.extend(file.resolve_export(db, name)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do re-exports work? i.e. does
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They did not! Now done, good catch |
||
| } | ||
|
|
||
| // Re-exports. A name brought in by `importFrom()` and surfaced again by | ||
| // `export()` has no binding in this package's own files, so the loop | ||
| // above returns empty. Follow the import to the source package and | ||
| // resolve the name among its exports instead. | ||
| if results.is_empty() { | ||
| let name_str = name.text(db).as_str(); | ||
| if let Some(import) = self | ||
| .namespace(db) | ||
| .imports | ||
| .iter() | ||
| .find(|import| import.name == name_str) | ||
| { | ||
| if let Some(source) = db.package_by_name(&import.package) { | ||
| results = source.resolve(db, name, PackageVisibility::Exported); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| results | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,5 +8,6 @@ mod file_resolve_at; | |
| mod file_root; | ||
| mod identifier; | ||
| mod inputs; | ||
| mod package_resolve; | ||
| mod resolver; | ||
| mod test_db; | ||
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.
These use
next()and only take the first hit, should this function returnVec<Definition>?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.
And if so, should there be corresponding tests somewhere that ensure that multiple definitions work?
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.
ha, resolved by #1259