From 6c70a1fec542c4f843474ab84d685e7cd6848dba Mon Sep 17 00:00:00 2001 From: Yoshitomo Nakanishi Date: Wed, 19 Apr 2023 17:11:43 +0200 Subject: [PATCH] Add `DynLazySpan` --- crates/hir/src/hir_def/mod.rs | 9 ++++++++ crates/hir/src/span/expr.rs | 35 +++++++++++++++++++++++++++++++ crates/hir/src/span/mod.rs | 14 +++++++++++++ crates/hir/src/span/transition.rs | 13 ++++++++++++ 4 files changed, 71 insertions(+) diff --git a/crates/hir/src/hir_def/mod.rs b/crates/hir/src/hir_def/mod.rs index 43bbe3d95a..e2f3e0f4f6 100644 --- a/crates/hir/src/hir_def/mod.rs +++ b/crates/hir/src/hir_def/mod.rs @@ -76,6 +76,15 @@ pub enum Partial { Absent, } +impl Partial { + pub fn unwrap(&self) -> &T { + match self { + Self::Present(value) => value, + Self::Absent => panic!("unwrap called on absent value"), + } + } +} + impl Default for Partial { fn default() -> Self { Self::Absent diff --git a/crates/hir/src/span/expr.rs b/crates/hir/src/span/expr.rs index 979e1c8ed2..ae559cd313 100644 --- a/crates/hir/src/span/expr.rs +++ b/crates/hir/src/span/expr.rs @@ -175,3 +175,38 @@ impl ChainInitiator for ExprRoot { ResolvedOrigin::resolve(db, top_mod, origin) } } + +#[cfg(test)] +mod tests { + use crate::{ + hir_def::{Body, Expr, Stmt}, + test_db::TestDb, + }; + use common::Upcast; + + #[test] + fn aug_assign() { + let mut db = TestDb::default(); + + let text = r#" { + fn foo(mut x: i32) { + x += 1 + } + }"#; + + let body: Body = db.expect_item::(text); + let bin_expr = match body.stmts(db.upcast()).values().next().unwrap().unwrap() { + Stmt::Assign(_, rhs) => *rhs, + _ => unreachable!(), + }; + let (lhs, rhs) = match body.exprs(db.upcast())[bin_expr].unwrap() { + Expr::Bin(lhs, rhs, _) => (lhs, rhs), + _ => unreachable!(), + }; + + let top_mod = body.top_mod(db.upcast()); + assert_eq!("x += 1", db.text_at(top_mod, &bin_expr.lazy_span(body))); + assert_eq!("x", db.text_at(top_mod, &lhs.lazy_span(body))); + assert_eq!("1", db.text_at(top_mod, &rhs.lazy_span(body))); + } +} diff --git a/crates/hir/src/span/mod.rs b/crates/hir/src/span/mod.rs index a7d2c30aff..ee2eb55052 100644 --- a/crates/hir/src/span/mod.rs +++ b/crates/hir/src/span/mod.rs @@ -26,6 +26,18 @@ pub mod use_tree; mod transition; +/// This struct represents a dynamic lazy span, which can be converted from all +/// types that implement [`LazySpan`] in this module. We want to avoid `dyn +/// LazySpan` usage because it doesn't implement `Clone` and `Eq` which leads to +/// a lot of difficulties in salsa integration +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DynLazySpan(SpanTransitionChain); +impl LazySpan for DynLazySpan { + fn resolve(&self, db: &dyn crate::SpannedHirDb) -> Span { + self.0.resolve(db) + } +} + /// The trait provides a way to extract [`Span`](common::diagnostics::Span) from /// types which don't have a span information directly, but can be resolved into /// a span lazily. @@ -170,4 +182,6 @@ impl AugAssignDesugared { use transition::define_lazy_span_node; +use self::transition::SpanTransitionChain; + define_lazy_span_node!(LazySpanAtom); diff --git a/crates/hir/src/span/transition.rs b/crates/hir/src/span/transition.rs index 05731c2e75..2763449f3f 100644 --- a/crates/hir/src/span/transition.rs +++ b/crates/hir/src/span/transition.rs @@ -21,6 +21,13 @@ use super::{ type_alias_ast, use_ast, AugAssignDesugared, DesugaredOrigin, HirOrigin, LazySpan, }; +/// This type represents function from the hir origin to another hir origin to +/// identify the span of HIR node. `LazyTransitionFn` is regarded as a closure +/// that takes a `HirOrigin` and [`LazyArg`], `LazyArg` is considered as +/// captured variables. +/// The reason why we use `LazyTransitionFn` instead of `dyn +/// Fn` is that we want to make all types that use `LazyTransitionFn` to be +/// `Clone` and `Eq`. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub(crate) struct LazyTransitionFn { pub(super) f: fn(ResolvedOrigin, LazyArg) -> ResolvedOrigin, @@ -320,6 +327,12 @@ macro_rules! define_lazy_span_node { self.0.resolve(db) } } + + impl From<$name> for crate::span::DynLazySpan { + fn from(val: $name) -> Self { + Self(val.0) + } + } }; }