Skip to content

Commit 9a3a89e

Browse files
Revert "Fix late-bound ICE in unsized return suggestion"
This reverts commit b899251.
1 parent f262ca1 commit 9a3a89e

10 files changed

+84
-242
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 55 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,8 +1129,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11291129
}
11301130

11311131
let hir = self.tcx.hir();
1132-
let fn_hir_id = hir.get_parent_node(obligation.cause.body_id);
1133-
let node = hir.find(fn_hir_id);
1132+
let parent_node = hir.get_parent_node(obligation.cause.body_id);
1133+
let node = hir.find(parent_node);
11341134
let Some(hir::Node::Item(hir::Item {
11351135
kind: hir::ItemKind::Fn(sig, _, body_id),
11361136
..
@@ -1168,17 +1168,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11681168
visitor.visit_body(&body);
11691169

11701170
let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
1171-
let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id) else { return false; };
11721171

1173-
let ret_types = visitor
1172+
let mut ret_types = visitor
11741173
.returns
11751174
.iter()
1176-
.filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?)))
1177-
.map(|(expr_span, ty)| (expr_span, self.resolve_vars_if_possible(ty)));
1175+
.filter_map(|expr| typeck_results.node_type_opt(expr.hir_id))
1176+
.map(|ty| self.resolve_vars_if_possible(ty));
11781177
let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold(
11791178
(None, true, true),
11801179
|(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool),
1181-
(_, ty)| {
1180+
ty| {
11821181
let ty = self.resolve_vars_if_possible(ty);
11831182
same &=
11841183
!matches!(ty.kind(), ty::Error(_))
@@ -1199,60 +1198,39 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11991198
(Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never))
12001199
},
12011200
);
1202-
let mut spans_and_needs_box = vec![];
1203-
1204-
match liberated_sig.output().kind() {
1205-
ty::Dynamic(predicates, _) => {
1206-
let cause = ObligationCause::misc(ret_ty.span, fn_hir_id);
1207-
let param_env = ty::ParamEnv::empty();
1208-
1209-
if !only_never_return {
1210-
for (expr_span, return_ty) in ret_types {
1211-
let self_ty_satisfies_dyn_predicates = |self_ty| {
1212-
predicates.iter().all(|predicate| {
1213-
let pred = predicate.with_self_ty(self.tcx, self_ty);
1214-
let obl = Obligation::new(cause.clone(), param_env, pred);
1215-
self.predicate_may_hold(&obl)
1201+
let all_returns_conform_to_trait =
1202+
if let Some(ty_ret_ty) = typeck_results.node_type_opt(ret_ty.hir_id) {
1203+
match ty_ret_ty.kind() {
1204+
ty::Dynamic(predicates, _) => {
1205+
let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
1206+
let param_env = ty::ParamEnv::empty();
1207+
only_never_return
1208+
|| ret_types.all(|returned_ty| {
1209+
predicates.iter().all(|predicate| {
1210+
let pred = predicate.with_self_ty(self.tcx, returned_ty);
1211+
let obl = Obligation::new(cause.clone(), param_env, pred);
1212+
self.predicate_may_hold(&obl)
1213+
})
12161214
})
1217-
};
1218-
1219-
if let ty::Adt(def, substs) = return_ty.kind()
1220-
&& def.is_box()
1221-
&& self_ty_satisfies_dyn_predicates(substs.type_at(0))
1222-
{
1223-
spans_and_needs_box.push((expr_span, false));
1224-
} else if self_ty_satisfies_dyn_predicates(return_ty) {
1225-
spans_and_needs_box.push((expr_span, true));
1226-
} else {
1227-
return false;
1228-
}
12291215
}
1216+
_ => false,
12301217
}
1231-
}
1232-
_ => return false,
1233-
};
1218+
} else {
1219+
true
1220+
};
12341221

12351222
let sm = self.tcx.sess.source_map();
1236-
if !ret_ty.span.overlaps(span) {
1223+
let (true, hir::TyKind::TraitObject(..), Ok(snippet), true) = (
1224+
// Verify that we're dealing with a return `dyn Trait`
1225+
ret_ty.span.overlaps(span),
1226+
&ret_ty.kind,
1227+
sm.span_to_snippet(ret_ty.span),
1228+
// If any of the return types does not conform to the trait, then we can't
1229+
// suggest `impl Trait` nor trait objects: it is a type mismatch error.
1230+
all_returns_conform_to_trait,
1231+
) else {
12371232
return false;
1238-
}
1239-
let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind {
1240-
if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) {
1241-
snippet
1242-
} else {
1243-
return false;
1244-
}
1245-
} else {
1246-
// Substitute the type, so we can print a fixup given `type Alias = dyn Trait`
1247-
let name = liberated_sig.output().to_string();
1248-
let name =
1249-
name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name);
1250-
if !name.starts_with("dyn ") {
1251-
return false;
1252-
}
1253-
name.to_owned()
12541233
};
1255-
12561234
err.code(error_code!(E0746));
12571235
err.set_primary_message("return type cannot have an unboxed trait object");
12581236
err.children.clear();
@@ -1262,7 +1240,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12621240
let trait_obj_msg = "for information on trait objects, see \
12631241
<https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
12641242
#using-trait-objects-that-allow-for-values-of-different-types>";
1265-
12661243
let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
12671244
let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
12681245
if only_never_return {
@@ -1290,25 +1267,26 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12901267
} else {
12911268
if is_object_safe {
12921269
// Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
1293-
err.multipart_suggestion(
1294-
"return a boxed trait object instead",
1295-
vec![
1296-
(ret_ty.span.shrink_to_lo(), "Box<".to_string()),
1297-
(span.shrink_to_hi(), ">".to_string()),
1298-
],
1299-
Applicability::MaybeIncorrect,
1300-
);
1301-
for (span, needs_box) in spans_and_needs_box {
1302-
if needs_box {
1303-
err.multipart_suggestion(
1304-
"... and box this value",
1305-
vec![
1306-
(span.shrink_to_lo(), "Box::new(".to_string()),
1307-
(span.shrink_to_hi(), ")".to_string()),
1308-
],
1309-
Applicability::MaybeIncorrect,
1310-
);
1311-
}
1270+
// Get all the return values and collect their span and suggestion.
1271+
let mut suggestions: Vec<_> = visitor
1272+
.returns
1273+
.iter()
1274+
.flat_map(|expr| {
1275+
[
1276+
(expr.span.shrink_to_lo(), "Box::new(".to_string()),
1277+
(expr.span.shrink_to_hi(), ")".to_string()),
1278+
]
1279+
.into_iter()
1280+
})
1281+
.collect();
1282+
if !suggestions.is_empty() {
1283+
// Add the suggestion for the return type.
1284+
suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj)));
1285+
err.multipart_suggestion(
1286+
"return a boxed trait object instead",
1287+
suggestions,
1288+
Applicability::MaybeIncorrect,
1289+
);
13121290
}
13131291
} else {
13141292
// This is currently not possible to trigger because E0038 takes precedence, but
@@ -2845,15 +2823,13 @@ fn suggest_trait_object_return_type_alternatives(
28452823
Applicability::MaybeIncorrect,
28462824
);
28472825
if is_object_safe {
2848-
err.multipart_suggestion(
2826+
err.span_suggestion(
2827+
ret_ty,
28492828
&format!(
28502829
"use a boxed trait object if all return paths implement trait `{}`",
28512830
trait_obj,
28522831
),
2853-
vec![
2854-
(ret_ty.shrink_to_lo(), "Box<".to_string()),
2855-
(ret_ty.shrink_to_hi(), ">".to_string()),
2856-
],
2832+
format!("Box<dyn {}>", trait_obj),
28572833
Applicability::MaybeIncorrect,
28582834
);
28592835
}

src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ LL | fn bak() -> impl Trait { unimplemented!() }
8181
help: use a boxed trait object if all return paths implement trait `Trait`
8282
|
8383
LL | fn bak() -> Box<dyn Trait> { unimplemented!() }
84-
| ++++ +
84+
| ~~~~~~~~~~~~~~
8585

8686
error[E0746]: return type cannot have an unboxed trait object
8787
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13
@@ -95,16 +95,12 @@ LL | fn bal() -> dyn Trait {
9595
= note: you can create a new `enum` with a variant for each returned type
9696
help: return a boxed trait object instead
9797
|
98-
LL | fn bal() -> Box<dyn Trait> {
99-
| ++++ +
100-
help: ... and box this value
101-
|
102-
LL | return Box::new(Struct);
103-
| +++++++++ +
104-
help: ... and box this value
98+
LL ~ fn bal() -> Box<dyn Trait> {
99+
LL | if true {
100+
LL ~ return Box::new(Struct);
101+
LL | }
102+
LL ~ Box::new(42)
105103
|
106-
LL | Box::new(42)
107-
| +++++++++ +
108104

109105
error[E0308]: `if` and `else` have incompatible types
110106
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:29:9
@@ -130,16 +126,12 @@ LL | fn bax() -> dyn Trait {
130126
= note: you can create a new `enum` with a variant for each returned type
131127
help: return a boxed trait object instead
132128
|
133-
LL | fn bax() -> Box<dyn Trait> {
134-
| ++++ +
135-
help: ... and box this value
136-
|
137-
LL | Box::new(Struct)
138-
| +++++++++ +
139-
help: ... and box this value
129+
LL ~ fn bax() -> Box<dyn Trait> {
130+
LL | if true {
131+
LL ~ Box::new(Struct)
132+
LL | } else {
133+
LL ~ Box::new(42)
140134
|
141-
LL | Box::new(42)
142-
| +++++++++ +
143135

144136
error[E0308]: mismatched types
145137
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:34:16

src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,13 @@ LL | fn hat() -> dyn std::fmt::Display {
103103
= note: you can create a new `enum` with a variant for each returned type
104104
help: return a boxed trait object instead
105105
|
106-
LL | fn hat() -> Box<dyn std::fmt::Display> {
107-
| ++++ +
108-
help: ... and box this value
109-
|
110-
LL | return Box::new(0i32);
111-
| +++++++++ +
112-
help: ... and box this value
113-
|
114-
LL | Box::new(1u32)
115-
| +++++++++ +
106+
LL ~ fn hat() -> Box<dyn std::fmt::Display> {
107+
LL | match 13 {
108+
LL | 0 => {
109+
LL ~ return Box::new(0i32);
110+
LL | }
111+
LL | _ => {
112+
...
116113

117114
error[E0308]: `match` arms have incompatible types
118115
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14
@@ -138,20 +135,12 @@ LL | fn pug() -> dyn std::fmt::Display {
138135
= note: you can create a new `enum` with a variant for each returned type
139136
help: return a boxed trait object instead
140137
|
141-
LL | fn pug() -> Box<dyn std::fmt::Display> {
142-
| ++++ +
143-
help: ... and box this value
144-
|
145-
LL | 0 => Box::new(0i32),
146-
| +++++++++ +
147-
help: ... and box this value
138+
LL ~ fn pug() -> Box<dyn std::fmt::Display> {
139+
LL | match 13 {
140+
LL ~ 0 => Box::new(0i32),
141+
LL ~ 1 => Box::new(1u32),
142+
LL ~ _ => Box::new(2u32),
148143
|
149-
LL | 1 => Box::new(1u32),
150-
| +++++++++ +
151-
help: ... and box this value
152-
|
153-
LL | _ => Box::new(2u32),
154-
| +++++++++ +
155144

156145
error[E0308]: `if` and `else` have incompatible types
157146
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9
@@ -177,16 +166,12 @@ LL | fn man() -> dyn std::fmt::Display {
177166
= note: you can create a new `enum` with a variant for each returned type
178167
help: return a boxed trait object instead
179168
|
180-
LL | fn man() -> Box<dyn std::fmt::Display> {
181-
| ++++ +
182-
help: ... and box this value
183-
|
184-
LL | Box::new(0i32)
185-
| +++++++++ +
186-
help: ... and box this value
169+
LL ~ fn man() -> Box<dyn std::fmt::Display> {
170+
LL | if false {
171+
LL ~ Box::new(0i32)
172+
LL | } else {
173+
LL ~ Box::new(1u32)
187174
|
188-
LL | Box::new(1u32)
189-
| +++++++++ +
190175

191176
error: aborting due to 14 previous errors
192177

src/test/ui/issues/issue-18107.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ LL | impl AbstractRenderer
1515
help: use a boxed trait object if all return paths implement trait `AbstractRenderer`
1616
|
1717
LL | Box<dyn AbstractRenderer>
18-
| ++++ +
18+
|
1919

2020
error: aborting due to previous error
2121

src/test/ui/unsized/box-instead-of-dyn-fn.rs

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/test/ui/unsized/box-instead-of-dyn-fn.stderr

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)