Skip to content

Commit

Permalink
Merge pull request rust-lang#18264 from ChayimFriedman2/semi-transparent
Browse files Browse the repository at this point in the history
fix: Implement mixed site hygiene
  • Loading branch information
Veykril authored Oct 23, 2024
2 parents c8a04e3 + 8f36d1c commit 1fbaccd
Show file tree
Hide file tree
Showing 27 changed files with 671 additions and 164 deletions.
1 change: 1 addition & 0 deletions src/tools/rust-analyzer/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ dependencies = [
"syntax-bridge",
"test-fixture",
"test-utils",
"text-size",
"tracing",
"triomphe",
"tt",
Expand Down
1 change: 1 addition & 0 deletions src/tools/rust-analyzer/crates/hir-def/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ smallvec.workspace = true
hashbrown.workspace = true
triomphe.workspace = true
rustc_apfloat = "0.2.0"
text-size.workspace = true

ra-ap-rustc_parse_format.workspace = true
ra-ap-rustc_abi.workspace = true
Expand Down
84 changes: 67 additions & 17 deletions src/tools/rust-analyzer/crates/hir-def/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ use crate::{
BlockId, DefWithBodyId, HasModule, Lookup,
};

/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HygieneId(pub(crate) span::SyntaxContextId);

impl HygieneId {
pub const ROOT: Self = Self(span::SyntaxContextId::ROOT);

pub fn new(ctx: span::SyntaxContextId) -> Self {
Self(ctx)
}

pub(crate) fn is_root(self) -> bool {
self.0.is_root()
}
}

/// The body of an item (function, const etc.).
#[derive(Debug, Eq, PartialEq)]
pub struct Body {
Expand All @@ -55,6 +71,22 @@ pub struct Body {
pub body_expr: ExprId,
/// Block expressions in this body that may contain inner items.
block_scopes: Vec<BlockId>,

/// A map from binding to its hygiene ID.
///
/// Bindings that don't come from macro expansion are not allocated to save space, so not all bindings appear here.
/// If a binding does not appear here it has `SyntaxContextId::ROOT`.
///
/// Note that this may not be the direct `SyntaxContextId` of the binding's expansion, because transparent
/// expansions are attributed to their parent expansion (recursively).
binding_hygiene: FxHashMap<BindingId, HygieneId>,
/// A map from an variable usages to their hygiene ID.
///
/// Expressions that can be recorded here are single segment path, although not all single segments path refer
/// to variables and have hygiene (some refer to items, we don't know at this stage).
expr_hygiene: FxHashMap<ExprId, HygieneId>,
/// A map from a destructuring assignment possible variable usages to their hygiene ID.
pat_hygiene: FxHashMap<PatId, HygieneId>,
}

pub type ExprPtr = AstPtr<ast::Expr>;
Expand Down Expand Up @@ -107,10 +139,11 @@ pub struct BodySourceMap {
field_map_back: FxHashMap<ExprId, FieldSource>,
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,

// FIXME: Make this a sane struct.
template_map: Option<
Box<(
// format_args!
FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>,
// asm!
FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>,
)>,
Expand Down Expand Up @@ -268,13 +301,19 @@ impl Body {
pats,
bindings,
binding_owners,
binding_hygiene,
expr_hygiene,
pat_hygiene,
} = self;
block_scopes.shrink_to_fit();
exprs.shrink_to_fit();
labels.shrink_to_fit();
pats.shrink_to_fit();
bindings.shrink_to_fit();
binding_owners.shrink_to_fit();
binding_hygiene.shrink_to_fit();
expr_hygiene.shrink_to_fit();
pat_hygiene.shrink_to_fit();
}

pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
Expand Down Expand Up @@ -381,7 +420,7 @@ impl Body {
self.walk_exprs_in_pat(*pat, &mut f);
}
Statement::Expr { expr: expression, .. } => f(*expression),
Statement::Item => (),
Statement::Item(_) => (),
}
}
if let &Some(expr) = tail {
Expand Down Expand Up @@ -467,6 +506,25 @@ impl Body {
}
});
}

fn binding_hygiene(&self, binding: BindingId) -> HygieneId {
self.binding_hygiene.get(&binding).copied().unwrap_or(HygieneId::ROOT)
}

pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId {
self.expr_hygiene.get(&expr).copied().unwrap_or(HygieneId::ROOT)
}

pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId {
self.pat_hygiene.get(&pat).copied().unwrap_or(HygieneId::ROOT)
}

pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId {
match id {
ExprOrPatId::ExprId(id) => self.expr_path_hygiene(id),
ExprOrPatId::PatId(id) => self.pat_path_hygiene(id),
}
}
}

impl Default for Body {
Expand All @@ -481,6 +539,9 @@ impl Default for Body {
block_scopes: Default::default(),
binding_owners: Default::default(),
self_param: Default::default(),
binding_hygiene: Default::default(),
expr_hygiene: Default::default(),
pat_hygiene: Default::default(),
}
}
}
Expand Down Expand Up @@ -594,13 +655,11 @@ impl BodySourceMap {
pub fn implicit_format_args(
&self,
node: InFile<&ast::FormatArgsExpr>,
) -> Option<&[(syntax::TextRange, Name)]> {
) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
self.template_map
.as_ref()?
.0
.get(&self.expr_map.get(&src)?.as_expr()?)
.map(std::ops::Deref::deref)
let (hygiene, names) =
self.template_map.as_ref()?.0.get(&self.expr_map.get(&src)?.as_expr()?)?;
Some((*hygiene, &**names))
}

pub fn asm_template_args(
Expand Down Expand Up @@ -649,13 +708,4 @@ impl BodySourceMap {
diagnostics.shrink_to_fit();
binding_definitions.shrink_to_fit();
}

pub fn template_map(
&self,
) -> Option<&(
FxHashMap<Idx<Expr>, Vec<(tt::TextRange, Name)>>,
FxHashMap<Idx<Expr>, Vec<Vec<(tt::TextRange, usize)>>>,
)> {
self.template_map.as_deref()
}
}
Loading

0 comments on commit 1fbaccd

Please sign in to comment.