Unnamed repository; edit this file 'description' to name the repository.
fix: add parens in transformed dyn type in ref type
Example
---
```rust
trait A<T: ?Sized> { fn a(&self) -> &T; }
trait B {}
impl<'a, T: B> A<dyn 'a + B> for T {$0}
```
**Before this PR**
```rust
impl<'a, T: B> A<dyn 'a + B> for T {
fn a(&self) -> &dyn 'a + B {
// ^^^^^^^^^^ ambiguous `+` in a type
${0:todo!()}
}
}
```
**After this PR**
```rust
impl<'a, T: B> A<dyn 'a + B> for T {
fn a(&self) -> &(dyn 'a + B) {
${0:todo!()}
}
}
```
| -rw-r--r-- | crates/ide-assists/src/handlers/add_missing_impl_members.rs | 19 | ||||
| -rw-r--r-- | crates/ide-db/src/path_transform.rs | 18 |
2 files changed, 35 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..1f4d5c4020 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -415,16 +415,21 @@ 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 = type_needs_parens(old.parent(), subst); + let subst = if needs_paren { + make.ty(&format!("({subst})")) + } 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) @@ -598,6 +603,15 @@ impl Ctx<'_> { } } +fn type_needs_parens(parent: Option<SyntaxNode>, new: &ast::Type) -> bool { + if !matches!(new, ast::Type::DynTraitType(_)) { + return false; + } + let Some(parent) = parent else { return false }; + let kind = parent.kind(); + ast::CastExpr::can_cast(kind) || ast::RefType::can_cast(kind) || ast::PtrType::can_cast(kind) +} + // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the // trait ref, and then go from the types in the substs back to the syntax). fn get_syntactic_substs(impl_def: ast::Impl) -> Option<AstSubsts> { |