Skip to content

Commit baee6b3

Browse files
committed
Auto merge of rust-lang#15406 - lowr:fix/panic-missing-impl-self-ty, r=lnicola
Don't provide `generate_default_from_new` when impl self ty is missing Also don't provide the assist when the `Default` trait can't be found. Part of rust-lang#15398
2 parents 70fa270 + 5829174 commit baee6b3

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

Diff for: crates/ide-assists/src/handlers/generate_default_from_new.rs

+33-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::{
1515
// Generates default implementation from new method.
1616
//
1717
// ```
18+
// # //- minicore: default
1819
// struct Example { _inner: () }
1920
//
2021
// impl Example {
@@ -54,6 +55,7 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
5455
}
5556

5657
let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
58+
let self_ty = impl_.self_ty()?;
5759
if is_default_implemented(ctx, &impl_) {
5860
cov_mark::hit!(default_block_is_already_present);
5961
cov_mark::hit!(struct_in_module_with_default);
@@ -70,15 +72,19 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
7072
let default_code = " fn default() -> Self {
7173
Self::new()
7274
}";
73-
let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code);
75+
let code = generate_trait_impl_text_from_impl(&impl_, self_ty, "Default", default_code);
7476
builder.insert(insert_location.end(), code);
7577
},
7678
)
7779
}
7880

7981
// FIXME: based on from utils::generate_impl_text_inner
80-
fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String {
81-
let impl_ty = impl_.self_ty().unwrap();
82+
fn generate_trait_impl_text_from_impl(
83+
impl_: &ast::Impl,
84+
self_ty: ast::Type,
85+
trait_text: &str,
86+
code: &str,
87+
) -> String {
8288
let generic_params = impl_.generic_param_list().map(|generic_params| {
8389
let lifetime_params =
8490
generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
@@ -109,7 +115,7 @@ fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code:
109115
if let Some(generic_params) = &generic_params {
110116
format_to!(buf, "{generic_params}")
111117
}
112-
format_to!(buf, " {trait_text} for {impl_ty}");
118+
format_to!(buf, " {trait_text} for {self_ty}");
113119

114120
match impl_.where_clause() {
115121
Some(where_clause) => {
@@ -136,7 +142,9 @@ fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool {
136142
let default = FamousDefs(&ctx.sema, krate).core_default_Default();
137143
let default_trait = match default {
138144
Some(value) => value,
139-
None => return false,
145+
// Return `true` to avoid providing the assist because it makes no sense
146+
// to impl `Default` when it's missing.
147+
None => return true,
140148
};
141149

142150
ty.impls_trait(db, default_trait, &[])
@@ -480,6 +488,7 @@ impl Example {
480488
check_assist_not_applicable(
481489
generate_default_from_new,
482490
r#"
491+
//- minicore: default
483492
struct Example { _inner: () }
484493
485494
impl Example {
@@ -655,4 +664,23 @@ mod test {
655664
"#,
656665
);
657666
}
667+
668+
#[test]
669+
fn not_applicable_when_default_lang_item_is_missing() {
670+
check_assist_not_applicable(
671+
generate_default_from_new,
672+
r#"
673+
struct S;
674+
impl S {
675+
fn new$0() -> Self {}
676+
}
677+
"#,
678+
);
679+
}
680+
681+
#[test]
682+
fn not_applicable_for_missing_self_ty() {
683+
// Regression test for #15398.
684+
check_assist_not_applicable(generate_default_from_new, "impl { fn new$0() -> Self {} }");
685+
}
658686
}

Diff for: crates/ide-assists/src/tests/generated.rs

+1
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,7 @@ fn doctest_generate_default_from_new() {
952952
check_doc_test(
953953
"generate_default_from_new",
954954
r#####"
955+
//- minicore: default
955956
struct Example { _inner: () }
956957
957958
impl Example {

0 commit comments

Comments
 (0)