-
Notifications
You must be signed in to change notification settings - Fork 187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hir #860
Hir #860
Conversation
f61edbd
to
e11d401
Compare
d168f1f
to
689720d
Compare
0881acf
to
c983488
Compare
A potential issue with types implementing the LazySpan is that they are not coupled with the items defined in hir_def. For example, the following code is clearly redundant: // Perform name resolution for function parameters
for (i, param) in func.params(..).enumerate() {
if !resolve_type(param.type()) {
// Construct the corresponding LazySpan
let span = func.lazy_span().params().param(i).ty();
Diagnostics::new(span, ...)
}
} To solve this issue, we could create a thin wrapper like the following that includes both the Hir Item and LazySpan: pub struct SpannedItem<Item, Span> {
item: Item,
span: Span,
}
impl SpannedItem {
pub fn name(db: &dyn HirDb) -> SpanendItem<ItentId, LazySpanAtom> {
...
}
pub fn params(db: &dyn HirDb) -> Spanneditem<FnParamListId, LazyFnParamList> {
...
}
}
impl<Item, Span: LazySpan> LazySpan for Spanneditem<Item, LazySpan> {
fn resolve(&self, db: &dyn SpannedHirDb) -> Span {
self.span.resolve(db)
}
} However, at the moment, it is unclear whether |
744195e
to
c74bb85
Compare
/// The root node of the tree is the top level module, which corresponds to the | ||
/// `module_tree::TopLevelModule`. | ||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
pub struct ItemTree { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ItemTree
will be replaced with ScopeGraph
in the next PR.
@sbillig #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) struct LazyTransitionFn {
pub(super) f: fn(ResolvedOrigin, LazyArg) -> ResolvedOrigin,
pub(super) arg: LazyArg,
} By explicitly holding a function pointer and captured variables as Furthermore, I defined |
Also, I added more precise support to track the node by changing the argument of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nice. I haven't verified that everything is correct, but I suspect that any issues will become apparent as the analyzer is implemented. The lazy span stuff is clever, if perhaps a bit complicated (though I can't think of a way to avoid such complication of course).
Define HIR, implement lowering from AST, and add helper structs to evaluate span lazily.
Architecture
Hir items
The
hir_def
module is a collection ofHIR
node definitions.All items that correspond to the Rust items are defined as a salsa tracked struct so that they can work as a granularity of analysis.
Below is all item's definition.
TopMod
is the top-level module that corresponds to each file.Mod
is an internal module that is defined inside aTopMod
bymod my_mod {...}
.ExternFunc
is a desugared function that is defined insideextern
block.extern
block doesn't create a scope, so theHIR
item definition doesn't containextern
block explicitly.Body
represents a function body or nameless body that appears in a constant expression context, e.g.,10
in[u32; 10]
orLEN
in[1; LEN]
. Expressions, statements, and patterns are always stored inside the body's arena, not in the salsa database. Thus a body is a minimum granularity for analysis of the expressions, statements, and patterns.Three different databases
HirDb
HirDb
is the core database for analysis and integration with LSP implementation.HirDb
works mainly as a container for Hir nodes. But it also contains some private tracked functions for lowering.HirDb can be considered a completely span-agnostic database from the perspective of external crates. In reality, the tracked structs stored in HirDb do contain span information, but they are designed so that they cannot be accessed through HirDb (all fields dependent on spans have private visibility). Furthermore, since lowering from AST (or source file) to HIR can also be considered span-dependent, the visibility of tracked functions that perform lowering is defined as private. However, functions that depend on HirDb may internally call the lowering function. These calls are unavoidable for HIR construction and do not unnecessarily invalidate the cache. Additionally, from external crates, the fact that these internal functions are being called is completely hidden.
It is possible to embed span information in diagnostics without directly depending on spans by using types that implement the
LazySpan
trait, which will be described later. This allows for each analysis phase to be span-agnostic.LowerHirDb
LowerHirDb
is a marker trait used for lowering source files or ASTs to HIR. All public functions related to lowering takeLowerHirDb
as an argument. All analysis passes must NOT depend on the db.SpannedHieDb
SpannedHirDb
is a marker trait used for evaluating theLazySpan
trait lazily, which will be described later. All public functions related to span information take SpannedHirDb as an argument. All analysis passes must NOT depend on the db.LazySpan
Types implementing the
LazySpan
trait provide the ability to extract span information lazily, but types themselves don't directly depend on it. These types are implemented underhir/span
and basically correspond one-to-one with each HIR node. For example,LazyFuncSpan
corresponds to theFunc
item. Please see the tests inspan/item.rs
for more examples. To construct these types, there is no need to depend onSpannedHirDb
, but when "evaluating" the types to extract the actual span, you need to useSpannedHirDb
. Types implementingLazySpan
internally hold aSpanTransitionChain
. This chain has a span-independent starting point of the chain and a transition function from the starting point. To evaluate the chain,SpannedHirDb
first converts the starting point to a span-dependent structure, then applies the transition function to extract the specific span information.