11use super :: FnCtxt ;
22
3+ use crate :: coercion:: CollectRetsVisitor ;
34use crate :: errors;
45use crate :: fluent_generated as fluent;
56use crate :: fn_ctxt:: rustc_span:: BytePos ;
@@ -16,6 +17,7 @@ use rustc_errors::{Applicability, Diagnostic, MultiSpan};
1617use rustc_hir as hir;
1718use rustc_hir:: def:: Res ;
1819use rustc_hir:: def:: { CtorKind , CtorOf , DefKind } ;
20+ use rustc_hir:: intravisit:: { Map , Visitor } ;
1921use rustc_hir:: lang_items:: LangItem ;
2022use rustc_hir:: {
2123 CoroutineDesugaring , CoroutineKind , CoroutineSource , Expr , ExprKind , GenericBound , HirId , Node ,
@@ -827,6 +829,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
827829 }
828830 hir:: FnRetTy :: Return ( hir_ty) => {
829831 if let hir:: TyKind :: OpaqueDef ( item_id, ..) = hir_ty. kind
832+ // FIXME: account for RPITIT.
830833 && let hir:: Node :: Item ( hir:: Item {
831834 kind : hir:: ItemKind :: OpaqueTy ( op_ty) , ..
832835 } ) = self . tcx . hir_node ( item_id. hir_id ( ) )
@@ -1038,33 +1041,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10381041 return ;
10391042 }
10401043
1041- if let hir:: FnRetTy :: Return ( ty) = fn_decl. output {
1042- let ty = self . astconv ( ) . ast_ty_to_ty ( ty) ;
1043- let bound_vars = self . tcx . late_bound_vars ( fn_id) ;
1044- let ty = self
1045- . tcx
1046- . instantiate_bound_regions_with_erased ( Binder :: bind_with_vars ( ty, bound_vars) ) ;
1047- let ty = match self . tcx . asyncness ( fn_id. owner ) {
1048- ty:: Asyncness :: Yes => self . get_impl_future_output_ty ( ty) . unwrap_or_else ( || {
1049- span_bug ! ( fn_decl. output. span( ) , "failed to get output type of async function" )
1050- } ) ,
1051- ty:: Asyncness :: No => ty,
1052- } ;
1053- let ty = self . normalize ( expr. span , ty) ;
1054- if self . can_coerce ( found, ty) {
1055- if let Some ( owner_node) = self . tcx . hir_node ( fn_id) . as_owner ( )
1056- && let Some ( span) = expr. span . find_ancestor_inside ( * owner_node. span ( ) )
1044+ let in_closure = matches ! (
1045+ self . tcx
1046+ . hir( )
1047+ . parent_iter( id)
1048+ . filter( |( _, node) | {
1049+ matches!(
1050+ node,
1051+ Node :: Expr ( Expr { kind: ExprKind :: Closure ( ..) , .. } )
1052+ | Node :: Item ( _)
1053+ | Node :: TraitItem ( _)
1054+ | Node :: ImplItem ( _)
1055+ )
1056+ } )
1057+ . next( ) ,
1058+ Some ( ( _, Node :: Expr ( Expr { kind: ExprKind :: Closure ( ..) , .. } ) ) )
1059+ ) ;
1060+
1061+ let can_return = match fn_decl. output {
1062+ hir:: FnRetTy :: Return ( ty) => {
1063+ let ty = self . astconv ( ) . ast_ty_to_ty ( ty) ;
1064+ let bound_vars = self . tcx . late_bound_vars ( fn_id) ;
1065+ let ty = self
1066+ . tcx
1067+ . instantiate_bound_regions_with_erased ( Binder :: bind_with_vars ( ty, bound_vars) ) ;
1068+ let ty = match self . tcx . asyncness ( fn_id. owner ) {
1069+ ty:: Asyncness :: Yes => self . get_impl_future_output_ty ( ty) . unwrap_or_else ( || {
1070+ span_bug ! (
1071+ fn_decl. output. span( ) ,
1072+ "failed to get output type of async function"
1073+ )
1074+ } ) ,
1075+ ty:: Asyncness :: No => ty,
1076+ } ;
1077+ let ty = self . normalize ( expr. span , ty) ;
1078+ self . can_coerce ( found, ty)
1079+ }
1080+ hir:: FnRetTy :: DefaultReturn ( _) if in_closure => {
1081+ let mut rets = vec ! [ ] ;
1082+ if let Some ( ret_coercion) = self . ret_coercion . as_ref ( ) {
1083+ let ret_ty = ret_coercion. borrow ( ) . expected_ty ( ) ;
1084+ rets. push ( ret_ty) ;
1085+ }
1086+ let mut visitor = CollectRetsVisitor { ret_exprs : vec ! [ ] } ;
1087+ if let Some ( item) = self . tcx . hir ( ) . find ( id)
1088+ && let Node :: Expr ( expr) = item
10571089 {
1058- err. multipart_suggestion (
1059- "you might have meant to return this value" ,
1060- vec ! [
1061- ( span. shrink_to_lo( ) , "return " . to_string( ) ) ,
1062- ( span. shrink_to_hi( ) , ";" . to_string( ) ) ,
1063- ] ,
1064- Applicability :: MaybeIncorrect ,
1065- ) ;
1090+ visitor. visit_expr ( expr) ;
1091+ for expr in visitor. ret_exprs {
1092+ if let Some ( ty) = self . typeck_results . borrow ( ) . node_type_opt ( expr. hir_id ) {
1093+ rets. push ( ty) ;
1094+ }
1095+ }
1096+ if let hir:: ExprKind :: Block ( hir:: Block { expr : Some ( expr) , .. } , _) = expr. kind
1097+ {
1098+ if let Some ( ty) = self . typeck_results . borrow ( ) . node_type_opt ( expr. hir_id ) {
1099+ rets. push ( ty) ;
1100+ }
1101+ }
10661102 }
1103+ rets. into_iter ( ) . all ( |ty| self . can_coerce ( found, ty) )
10671104 }
1105+ _ => false ,
1106+ } ;
1107+ if can_return
1108+ && let Some ( owner_node) = self . tcx . hir_node ( fn_id) . as_owner ( )
1109+ && let Some ( span) = expr. span . find_ancestor_inside ( owner_node. span ( ) )
1110+ {
1111+ err. multipart_suggestion (
1112+ "you might have meant to return this value" ,
1113+ vec ! [
1114+ ( span. shrink_to_lo( ) , "return " . to_string( ) ) ,
1115+ ( span. shrink_to_hi( ) , ";" . to_string( ) ) ,
1116+ ] ,
1117+ Applicability :: MaybeIncorrect ,
1118+ ) ;
10681119 }
10691120 }
10701121
0 commit comments