Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
- name: Record Rust version
run: echo "RUST=$(rustc --version)" >> "$GITHUB_ENV"
- name: Upload to codecov.io in ${{ matrix.crate }}
uses: codecov/codecov-action@v5.5.2
uses: codecov/codecov-action@v7.0.0
with:
disable_search: true
env_vars: OS,RUST
Expand Down
11 changes: 11 additions & 0 deletions crates/syn-sem-name/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,19 @@ Rust namespaces must stay separate:
Generic parameters should be represented as definitions, not recovered through
ad hoc syntax ancestry.

Definition-attached scopes should keep roles separate. `DefScopes::path` is for
path-reachable children such as enum variants, `DefScopes::generic` is for
lexical generic parameters, and `DefScopes::body` is for value-body bindings.

Name resolution should be use-site based, scope-aware, and namespace-aware.

## Future Considerations

Struct fields are not currently modeled as definitions or scopes. If field
modeling becomes necessary, add a dedicated field/member concept instead of
forcing fields into `DefScopes::path`, because fields are not path-reachable
children like enum variants.

## Primary Public Items

- `NameDb`: name-resolution database containing scopes, definitions, and
Expand Down
47 changes: 25 additions & 22 deletions crates/syn-sem-name/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ impl<'cx> NameDb<'cx> {
name,
kind,
parent_scope,
child_scope: None,
generic_scope: None,
scopes: Default::default(),
target: None,
visibility,
origin,
Expand Down Expand Up @@ -123,14 +122,19 @@ impl<'cx> NameDb<'cx> {
id
}

/// Links a definition to a child scope that contains its importable members.
pub fn set_child_scope(&mut self, def: DefId, child_scope: ScopeId) {
self.defs[def.index()].child_scope = Some(child_scope);
/// Links a definition to a path scope that contains its path-reachable members.
pub fn set_path_scope(&mut self, def: DefId, path_scope: ScopeId) {
self.defs[def.index()].scopes.path = Some(path_scope);
}

/// Links a definition to the scope containing its generic parameters.
pub fn set_generic_scope(&mut self, def: DefId, generic_scope: ScopeId) {
self.defs[def.index()].generic_scope = Some(generic_scope);
self.defs[def.index()].scopes.generic = Some(generic_scope);
}

/// Links a definition to the scope containing its value body.
pub fn set_body_scope(&mut self, def: DefId, body_scope: ScopeId) {
self.defs[def.index()].scopes.body = Some(body_scope);
}

/// Follows `DefKind::Use` alias definitions to their underlying definition.
Expand Down Expand Up @@ -208,8 +212,7 @@ impl<'cx> NameDb<'cx> {
name,
kind: DefKind::Use,
parent_scope,
child_scope: None,
generic_scope: None,
scopes: Default::default(),
target: Some(target),
visibility,
origin,
Expand Down Expand Up @@ -365,13 +368,13 @@ impl<'cx> NameDb<'cx> {
};

let glob_target = self.follow_aliases(*glob_candidate);
let Some(child_scope) = self[glob_target].child_scope else {
let Some(path_scope) = self[glob_target].scopes.path else {
return ImportResolve::Pending;
};

let mut visible = Vec::new();
for namespace in Namespace::all() {
for (&name, binding) in self[child_scope].bindings.map(namespace) {
for (&name, binding) in self[path_scope].bindings.map(namespace) {
for def in binding.iter() {
if self.is_visible_from(def, import_data.scope) {
visible.push((namespace, name, def));
Expand Down Expand Up @@ -524,10 +527,10 @@ impl<'cx> NameDb<'cx> {
};

let target = self.follow_aliases(*def);
let Some(child_scope) = self[target].child_scope else {
let Some(path_scope) = self[target].scopes.path else {
return CandidateResolution::NotFound;
};
current_scope = child_scope;
current_scope = path_scope;
current_def = Some(target);
index += 1;
}
Expand Down Expand Up @@ -764,7 +767,7 @@ mod tests {

let mut db = NameDb::default();
let root = db.root_scope();
let body = db.add_scope(ScopeKind::FunctionBody, Some(root));
let body = db.add_scope(ScopeKind::Function, Some(root));

let outer = db.add_def(
root,
Expand Down Expand Up @@ -805,12 +808,12 @@ mod tests {

let mut db = NameDb::default();
let root = db.root_scope();
let generic_scope = db.add_scope(ScopeKind::GenericParams, Some(root));
let body = db.add_scope(ScopeKind::FunctionBody, Some(generic_scope));
let generic_scope = db.add_scope(ScopeKind::Generic, Some(root));
let body = db.add_scope(ScopeKind::Function, Some(generic_scope));

let type_param = db.add_def(
generic_scope,
DefKind::TypeParam,
DefKind::GenericType,
Some(t),
Visibility::Private,
Origin::Untracked,
Expand Down Expand Up @@ -839,7 +842,7 @@ mod tests {

let mut db = NameDb::default();
let root = db.root_scope();
let body = db.add_scope(ScopeKind::FunctionBody, Some(root));
let body = db.add_scope(ScopeKind::Function, Some(root));
let block = db.add_scope(ScopeKind::Block, Some(body));

let local_struct = db.add_def(
Expand Down Expand Up @@ -878,7 +881,7 @@ mod tests {
let root = db.root_scope();
let type_param = db.add_def(
root,
DefKind::TypeParam,
DefKind::GenericType,
Some(t),
Visibility::Private,
Origin::Untracked,
Expand Down Expand Up @@ -915,11 +918,11 @@ mod tests {

let mut db = NameDb::default();
let root = db.root_scope();
let generic_scope = db.add_scope(ScopeKind::GenericParams, Some(root));
let generic_scope = db.add_scope(ScopeKind::Generic, Some(root));

let const_param = db.add_def(
generic_scope,
DefKind::ConstParam,
DefKind::GenericConst,
Some(n),
Visibility::Private,
Origin::Untracked,
Expand Down Expand Up @@ -950,7 +953,7 @@ mod tests {
Origin::Untracked,
);
let scope = db.add_scope(ScopeKind::Module, Some(parent));
db.set_child_scope(def, scope);
db.set_path_scope(def, scope);
(def, scope)
}

Expand Down Expand Up @@ -1359,7 +1362,7 @@ mod tests {
Origin::Untracked,
);
let enum_scope = db.add_scope(ScopeKind::Item, Some(a_scope));
db.set_child_scope(enum_def, enum_scope);
db.set_path_scope(enum_def, enum_scope);
db.add_def(
enum_scope,
DefKind::Variant,
Expand Down
78 changes: 54 additions & 24 deletions crates/syn-sem-name/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,8 @@ pub struct Def<'cx> {
/// Scope that owns this definition.
pub parent_scope: ScopeId,

/// Scope containing this definition's importable children.
///
/// Modules and item-like definitions such as enums can expose names through a child scope.
/// Definitions without importable children leave this unset.
pub child_scope: Option<ScopeId>,

/// Scope containing this definition's generic parameters.
///
/// Generic parameters are lexical names, not importable children. Definitions without generic
/// parameters leave this unset.
pub generic_scope: Option<ScopeId>,
/// Scopes owned by or directly attached to this definition.
pub scopes: DefScopes,

/// Definition this definition aliases.
///
Expand All @@ -39,6 +30,31 @@ pub struct Def<'cx> {
pub origin: Origin,
}

/// Scopes owned by or directly attached to a definition.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct DefScopes {
/// Scope used when path resolution descends through this definition.
///
/// This is for names reachable with paths or imports. For example, `enum E { V }` gives the
/// `E` definition a path scope containing variant `V`, so `use crate::E::V;` can descend from
/// `E` into that scope. Definitions without path-reachable children leave this unset.
pub path: Option<ScopeId>,

/// Scope containing lexical generic parameters owned by this definition.
///
/// For example, `fn f<T>() {}` gives the `f` definition a generic scope containing `T`.
/// Generic parameters are lexical names, not path-reachable children, so this is separate from
/// [`Self::path`]. Definitions without generic parameters leave this unset.
pub generic: Option<ScopeId>,

/// Scope containing the value body owned by this definition.
///
/// For example, `fn f(x: i32) { let y = x; }` gives the `f` definition a body scope containing
/// parameter binding `x`; the block inside the body then gets its own nested block scope for
/// names such as `y`. Definitions without a collected body leave this unset.
pub body: Option<ScopeId>,
}

/// Kind of definition stored in the name database.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DefKind {
Expand All @@ -60,12 +76,21 @@ pub enum DefKind {
/// A type alias item.
TypeAlias,

/// A function or method.
/// A function item.
Fn,

/// A constant item or associated constant.
/// A constant item.
Const,

/// An associated type item.
AssocType,

/// An associated function item.
AssocFn,

/// An associated constant item.
AssocConst,

/// A static item.
Static,

Expand All @@ -75,14 +100,14 @@ pub enum DefKind {
/// A local variable or pattern binding.
Local,

/// A type generic parameter.
TypeParam,
/// A generic type parameter.
GenericType,

/// A const generic parameter.
ConstParam,
/// A generic const parameter.
GenericConst,

/// A lifetime generic parameter.
LifetimeParam,
/// A generic lifetime parameter.
GenericLifetime,

/// A `use` item or imported binding.
Use,
Expand All @@ -104,18 +129,23 @@ impl DefKind {
| Self::Enum
| Self::Trait
| Self::TypeAlias
| Self::TypeParam => &[Namespace::Type],
| Self::AssocType
| Self::GenericType => &[Namespace::Type],

// Type & Value namespaces
Self::Variant => &[Namespace::Type, Namespace::Value],

// Value namespace
Self::Fn | Self::Const | Self::Static | Self::Local | Self::ConstParam => {
&[Namespace::Value]
}
Self::Fn
| Self::Const
| Self::AssocFn
| Self::AssocConst
| Self::Static
| Self::Local
| Self::GenericConst => &[Namespace::Value],

// Lifetime namespace
Self::LifetimeParam => &[Namespace::Lifetime],
Self::GenericLifetime => &[Namespace::Lifetime],

// Macro namespace
Self::Macro => &[Namespace::Macro],
Expand Down
8 changes: 4 additions & 4 deletions crates/syn-sem-name/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ pub enum ScopeKind {
/// Item body or item member scope.
Item,

/// Generic parameter scope.
GenericParams,
/// Scope containing generic type, const, and lifetime parameter bindings.
Generic,

/// Function body scope.
FunctionBody,
/// Function scope containing parameter bindings and enclosing the function block scope.
Function,

/// Block expression or statement block scope.
Block,
Expand Down
Loading