@@ -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 }
0 commit comments