Skip to content

Commit 08f634b

Browse files
committed
Resolve package reexports
1 parent 2f5916c commit 08f634b

2 files changed

Lines changed: 85 additions & 0 deletions

File tree

crates/oak_db/src/package_resolve.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,24 @@ impl<'db> Package {
6969
results.extend(file.resolve_export(db, name));
7070
}
7171

72+
// Re-exports. A name brought in by `importFrom()` and surfaced again by
73+
// `export()` has no binding in this package's own files, so the loop
74+
// above returns empty. Follow the import to the source package and
75+
// resolve the name among its exports instead.
76+
if results.is_empty() {
77+
let name_str = name.text(db).as_str();
78+
if let Some(import) = self
79+
.namespace(db)
80+
.imports
81+
.iter()
82+
.find(|import| import.name == name_str)
83+
{
84+
if let Some(source) = db.package_by_name(&import.package) {
85+
results = source.resolve(db, name, PackageVisibility::Exported);
86+
}
87+
}
88+
}
89+
7290
results
7391
}
7492
}

crates/oak_db/src/tests/package_resolve.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use oak_package_metadata::namespace::Import;
12
use oak_package_metadata::namespace::Namespace;
23
use salsa::Setter;
34
use stdext::SortedVec;
@@ -180,6 +181,72 @@ fn test_stub_and_onload_override_both_returned() {
180181
assert!(target_files.contains(&files[1]));
181182
}
182183

184+
#[test]
185+
fn test_reexport_via_import_from_resolves_to_source() {
186+
// dplyr re-exports tibble's `tibble`: NAMESPACE carries `export(tibble)`
187+
// plus `importFrom(tibble, tibble)`, and the only R source is a bare
188+
// `tibble::tibble` expression (not an assignment). The binding lives in
189+
// tibble, so `dplyr::tibble` must follow the import and resolve there.
190+
let mut db = TestDb::new();
191+
let root = workspace_root(&db, "workspace");
192+
193+
let tibble_ns = Namespace {
194+
exports: SortedVec::from_vec(vec!["tibble".to_string()]),
195+
..Default::default()
196+
};
197+
let tibble = Package::new(
198+
&db,
199+
file_path("workspace/tibble/DESCRIPTION"),
200+
"tibble".to_string(),
201+
None,
202+
tibble_ns,
203+
Vec::new(),
204+
Vec::new(),
205+
None,
206+
);
207+
let tibble_file = File::new(
208+
&db,
209+
file_path("workspace/tibble/R/tibble.R"),
210+
"tibble <- function() 1\n".to_string(),
211+
Some(tibble),
212+
);
213+
tibble.set_files(&mut db).to(vec![tibble_file]);
214+
215+
let dplyr_ns = Namespace {
216+
exports: SortedVec::from_vec(vec!["tibble".to_string()]),
217+
imports: vec![Import {
218+
name: "tibble".to_string(),
219+
package: "tibble".to_string(),
220+
}],
221+
..Default::default()
222+
};
223+
let dplyr = Package::new(
224+
&db,
225+
file_path("workspace/dplyr/DESCRIPTION"),
226+
"dplyr".to_string(),
227+
None,
228+
dplyr_ns,
229+
Vec::new(),
230+
Vec::new(),
231+
None,
232+
);
233+
let dplyr_file = File::new(
234+
&db,
235+
file_path("workspace/dplyr/R/reexport.R"),
236+
"tibble::tibble\n".to_string(),
237+
Some(dplyr),
238+
);
239+
dplyr.set_files(&mut db).to(vec![dplyr_file]);
240+
241+
root.set_packages(&mut db).to(vec![tibble, dplyr]);
242+
db.workspace_roots().set_roots(&mut db).to(vec![root]);
243+
244+
let defs = dplyr.resolve(&db, name(&db, "tibble"), PackageVisibility::Exported);
245+
assert_eq!(defs.len(), 1);
246+
assert_eq!(defs[0].file(&db), tibble_file);
247+
assert_eq!(defs[0].name(&db).text(&db).as_str(), "tibble");
248+
}
249+
183250
#[test]
184251
fn test_same_name_defined_in_multiple_files_returns_each() {
185252
// Two files in the package both define `foo`. `Package::resolve`

0 commit comments

Comments
 (0)