mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
Auto merge of #16277 - roife:fix-issue16276, r=Veykril
Resolve panic in `generate_delegate_methods` Fixes #16276 This PR addresses two issues: 1. When using `PathTransform`, it searches for the node corresponding to the `path` in the `source_scope` during `make::fn_`. Therefore, we need to perform the transform before `make::fn_` (similar to the problem in issue #15804). Otherwise, even though the tokens are the same, their offsets (i.e., `span`) differ, resulting in the error "Can't find CONST_ARG@xxx." 2. As mentioned in the first point, `PathTransform` searches for the node corresponding to the `path` in the `source_scope`. Thus, when transforming paths, we should update nodes from right to left (i.e., use **reverse of preorder** (right -> left -> root) instead of **postorder** (left -> right -> root)). Reasons are as follows: In the red-green tree (rowan), we do not store absolute ranges but instead store the length of each node and dynamically calculate offsets (spans). Therefore, when modifying the left-side node (such as nodes are inserted or deleted), it causes all right-side nodes' spans to change. This, in turn, leads to PathTransform being unable to find nodes with the same paths (due to different spans), resulting in errors.
This commit is contained in:
commit
51ac6de6f3
2 changed files with 42 additions and 26 deletions
|
@ -3,6 +3,7 @@
|
|||
use crate::helpers::mod_path_to_ast;
|
||||
use either::Either;
|
||||
use hir::{AsAssocItem, HirDisplay, ModuleDef, SemanticsScope};
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashMap;
|
||||
use syntax::{
|
||||
ast::{self, make, AstNode},
|
||||
|
@ -227,11 +228,15 @@ struct Ctx<'a> {
|
|||
same_self_type: bool,
|
||||
}
|
||||
|
||||
fn postorder(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
|
||||
item.preorder().filter_map(|event| match event {
|
||||
syntax::WalkEvent::Enter(_) => None,
|
||||
syntax::WalkEvent::Leave(node) => Some(node),
|
||||
})
|
||||
fn preorder_rev(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
|
||||
let x = item
|
||||
.preorder()
|
||||
.filter_map(|event| match event {
|
||||
syntax::WalkEvent::Enter(node) => Some(node),
|
||||
syntax::WalkEvent::Leave(_) => None,
|
||||
})
|
||||
.collect_vec();
|
||||
x.into_iter().rev()
|
||||
}
|
||||
|
||||
impl Ctx<'_> {
|
||||
|
@ -239,12 +244,12 @@ impl Ctx<'_> {
|
|||
// `transform_path` may update a node's parent and that would break the
|
||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||
// so that such operation is safe.
|
||||
let paths = postorder(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
||||
let paths = preorder_rev(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
||||
for path in paths {
|
||||
self.transform_path(path);
|
||||
}
|
||||
|
||||
postorder(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
|
||||
preorder_rev(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
|
||||
if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
|
||||
ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
|
||||
}
|
||||
|
@ -263,7 +268,7 @@ impl Ctx<'_> {
|
|||
// `transform_path` may update a node's parent and that would break the
|
||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||
// so that such operation is safe.
|
||||
let paths = postorder(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
||||
let paths = preorder_rev(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
||||
for path in paths {
|
||||
self.transform_path(path);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue