Skip to content
18 changes: 18 additions & 0 deletions crates/oak_db/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use aether_path::FilePath;
use camino::Utf8Component;
use camino::Utf8Path;
use camino::Utf8PathBuf;
use oak_semantic::effects_registry;
use oak_semantic::Effects;
use oak_semantic::ImportsResolver;
use oak_semantic::SourceResolution;
use url::Url;
Expand Down Expand Up @@ -83,6 +85,22 @@ impl<'db> ImportsResolver for SalsaImportsResolver<'db> {
packages,
})
}

fn resolve_effects(
&mut self,
name: &str,
_attached: &[String],
_lazy: bool,
) -> Option<Effects> {
// Base is the always-attached layer at the bottom of the search path,
// resolved through the same registry lookup as any package.
//
// TODO!: walk the rest of the search path too (flow-order attaches,
// package siblings via `who_defines`, NAMESPACE imports, re-export chase).
effects_registry::lookup("base", name)
.copied()
.map(Effects::nse)
}
}

/// Anchor directory for relative `source("path")` arguments.
Expand Down
25 changes: 25 additions & 0 deletions crates/oak_db/src/tests/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,31 @@ fn test_semantic_index_matches_oak_semantic() {
assert_eq!(via_salsa, &direct);
}

#[test]
fn test_semantic_index_recognizes_bare_base_nse() {
// Base NSE resolves through the real `SalsaImportsResolver` (base-only
// `resolve_effects`): a bare `local()` still pushes a nested NSE scope, so
// `x` lands there rather than at file scope.
use oak_semantic::semantic_index::NseScope;
use oak_semantic::semantic_index::NseTiming;
use oak_semantic::semantic_index::ScopeId;
use oak_semantic::semantic_index::ScopeKind;

let mut db = TestDb::new();
let file = new_file(&mut db, "a.R", "local({\n x <- 1\n})\n");

let index = file.semantic_index(&db);
let file_scope = ScopeId::from(0);
let local_scope = ScopeId::from(1);

assert_eq!(
index.scope(local_scope).kind(),
ScopeKind::Nse(NseScope::Nested, NseTiming::Eager)
);
assert!(index.symbols(file_scope).get("x").is_none());
assert!(index.symbols(local_scope).get("x").is_some());
}

#[test]
fn test_semantic_index_backdates_on_equivalent_content_set() {
let mut db = TestDb::new();
Expand Down
6 changes: 2 additions & 4 deletions crates/oak_db/src/tests/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,8 @@ fn test_closure_capture_with_source_before_function() {
let bindings = fn_map.bindings_at_use(use_id);
assert!(bindings.may_be_unbound());

let symbol = index.uses(fn_scope)[use_id].symbol();
let (enclosing_scope, enclosing_bindings) = index
.enclosing_bindings(fn_scope, symbol)
.enclosing_bindings(fn_scope, use_id)
.expect("`helper` should have an enclosing snapshot at the file scope");
assert_eq!(enclosing_scope, file_scope);
assert!(!enclosing_bindings.definitions().is_empty());
Expand Down Expand Up @@ -321,8 +320,7 @@ fn test_closure_capture_with_source_after_function() {
let fn_scope = ScopeId::from(1);

let use_id = oak_semantic::UseId::from(0);
let symbol = index.uses(fn_scope)[use_id].symbol();
assert!(index.enclosing_bindings(fn_scope, symbol).is_some());
assert!(index.enclosing_bindings(fn_scope, use_id).is_some());
}

#[test]
Expand Down
Loading
Loading