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