Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/ide-assists/src/handlers/add_missing_impl_members.rs | 19 | ||||
| -rw-r--r-- | crates/ide-db/src/path_transform.rs | 6 | ||||
| -rw-r--r-- | crates/syntax/src/ast/make.rs | 3 | ||||
| -rw-r--r-- | crates/syntax/src/ast/prec.rs | 12 | ||||
| -rw-r--r-- | crates/syntax/src/ast/syntax_factory/constructors.rs | 12 |
5 files changed, 50 insertions, 2 deletions
diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 1e8fb51a3e..6e07f5f992 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -2704,4 +2704,23 @@ impl Drop for Foo { "#, ); } + + #[test] + fn issue_10326() { + check_assist( + add_missing_impl_members, + r#" +trait A<T: ?Sized> { fn a(&self) -> &T; } +trait B {} +impl<'a, T: B> A<dyn 'a + B> for T {$0}"#, + r#" +trait A<T: ?Sized> { fn a(&self) -> &T; } +trait B {} +impl<'a, T: B> A<dyn 'a + B> for T { + fn a(&self) -> &(dyn 'a + B) { + ${0:todo!()} + } +}"#, + ); + } } diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index 7cf8dff48b..101046cf54 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -415,16 +415,18 @@ impl Ctx<'_> { editor.replace(path.syntax(), qualified.clone().syntax()); } else if let Some(path_ty) = ast::PathType::cast(parent) { let old = path_ty.syntax(); + let needs_paren = old.parent().is_some_and(|it| subst.needs_parens_in(&it)); + let subst = + if needs_paren { make.ty_paren(subst.clone()) } else { subst.clone() }; if old.parent().is_some() { - editor.replace(old, subst.clone().syntax()); + editor.replace(old, subst.syntax()); } else { let start = path_ty.syntax().first_child().map(NodeOrToken::Node)?; let end = path_ty.syntax().last_child().map(NodeOrToken::Node)?; editor.replace_all( start..=end, subst - .clone() .syntax() .children() .map(NodeOrToken::Node) diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 16aa49e357..8b7f91c937 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -187,6 +187,9 @@ pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type { ty_from_text(&format!("({contents})")) } +pub fn ty_paren(ty: ast::Type) -> ast::Type { + ty_from_text(&format!("({ty})")) +} pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type { ty_from_text(&if exclusive { format!("&mut {target}") } else { format!("&{target}") }) } diff --git a/crates/syntax/src/ast/prec.rs b/crates/syntax/src/ast/prec.rs index 2a50d233c3..f473df9b15 100644 --- a/crates/syntax/src/ast/prec.rs +++ b/crates/syntax/src/ast/prec.rs @@ -575,3 +575,15 @@ impl Expr { } } } + +impl ast::Type { + pub fn needs_parens_in(&self, parent: &SyntaxNode) -> bool { + if !matches!(self, ast::Type::DynTraitType(_) | ast::Type::ImplTraitType(_)) { + return false; + } + let kind = parent.kind(); + ast::CastExpr::can_cast(kind) + || ast::RefType::can_cast(kind) + || ast::PtrType::can_cast(kind) + } +} diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs index 7f9cd1fce9..22c8c842d8 100644 --- a/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -610,6 +610,18 @@ impl SyntaxFactory { ast } + pub fn ty_paren(&self, ty: ast::Type) -> ast::Type { + let ast::Type::ParenType(paren_ty) = make::ty_paren(ty.clone()) else { unreachable!() }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(paren_ty.syntax().clone()); + builder.map_node(ty.syntax().clone(), paren_ty.ty().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + paren_ty.into() + } + pub fn path_segment_generics( &self, name_ref: ast::NameRef, |