@@ -324,6 +324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
324324 }
325325 }
326326 ExprKind :: Ret ( ref expr_opt) => self . check_expr_return ( expr_opt. as_deref ( ) , expr) ,
327+ ExprKind :: Become ( call) => self . check_expr_become ( call, expr) ,
327328 ExprKind :: Let ( let_expr) => self . check_expr_let ( let_expr) ,
328329 ExprKind :: Loop ( body, _, source, _) => {
329330 self . check_expr_loop ( body, source, expected, expr)
@@ -735,47 +736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
735736 expr : & ' tcx hir:: Expr < ' tcx > ,
736737 ) -> Ty < ' tcx > {
737738 if self . ret_coercion . is_none ( ) {
738- let mut err = ReturnStmtOutsideOfFnBody {
739- span : expr. span ,
740- encl_body_span : None ,
741- encl_fn_span : None ,
742- } ;
743-
744- let encl_item_id = self . tcx . hir ( ) . get_parent_item ( expr. hir_id ) ;
745-
746- if let Some ( hir:: Node :: Item ( hir:: Item {
747- kind : hir:: ItemKind :: Fn ( ..) ,
748- span : encl_fn_span,
749- ..
750- } ) )
751- | Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
752- kind : hir:: TraitItemKind :: Fn ( _, hir:: TraitFn :: Provided ( _) ) ,
753- span : encl_fn_span,
754- ..
755- } ) )
756- | Some ( hir:: Node :: ImplItem ( hir:: ImplItem {
757- kind : hir:: ImplItemKind :: Fn ( ..) ,
758- span : encl_fn_span,
759- ..
760- } ) ) = self . tcx . hir ( ) . find_by_def_id ( encl_item_id. def_id )
761- {
762- // We are inside a function body, so reporting "return statement
763- // outside of function body" needs an explanation.
764-
765- let encl_body_owner_id = self . tcx . hir ( ) . enclosing_body_owner ( expr. hir_id ) ;
766-
767- // If this didn't hold, we would not have to report an error in
768- // the first place.
769- assert_ne ! ( encl_item_id. def_id, encl_body_owner_id) ;
770-
771- let encl_body_id = self . tcx . hir ( ) . body_owned_by ( encl_body_owner_id) ;
772- let encl_body = self . tcx . hir ( ) . body ( encl_body_id) ;
773-
774- err. encl_body_span = Some ( encl_body. value . span ) ;
775- err. encl_fn_span = Some ( * encl_fn_span) ;
776- }
777-
778- self . tcx . sess . emit_err ( err) ;
739+ self . emit_return_outside_of_fn_body ( expr, "return" ) ;
779740
780741 if let Some ( e) = expr_opt {
781742 // We still have to type-check `e` (issue #86188), but calling
@@ -815,6 +776,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
815776 self . tcx . types . never
816777 }
817778
779+ fn check_expr_become (
780+ & self ,
781+ call : & ' tcx hir:: Expr < ' tcx > ,
782+ expr : & ' tcx hir:: Expr < ' tcx > ,
783+ ) -> Ty < ' tcx > {
784+ match & self . ret_coercion {
785+ Some ( ret_coercion) => {
786+ let ret_ty = ret_coercion. borrow ( ) . expected_ty ( ) ;
787+ let call_expr_ty = self . check_expr_with_hint ( call, ret_ty) ;
788+
789+ // N.B. don't coerce here, as tail calls can't support most/all coercions
790+ // FIXME(explicit_tail_calls): add a diagnostic note that `become` doesn't allow coercions
791+ self . demand_suptype ( expr. span , ret_ty, call_expr_ty) ;
792+ }
793+ None => {
794+ self . emit_return_outside_of_fn_body ( expr, "become" ) ;
795+
796+ // Fallback to simply type checking `call` without hint/demanding the right types.
797+ // Best effort to highlight more errors.
798+ self . check_expr ( call) ;
799+ }
800+ }
801+
802+ self . tcx . types . never
803+ }
804+
805+ /// Check an expression that _is being returned_.
806+ /// For example, this is called with `return_expr: $expr` when `return $expr`
807+ /// is encountered.
808+ ///
809+ /// Note that this function must only be called in function bodies.
810+ ///
818811 /// `explicit_return` is `true` if we're checking an explicit `return expr`,
819812 /// and `false` if we're checking a trailing expression.
820813 pub ( super ) fn check_return_expr (
@@ -831,10 +824,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
831824 let mut span = return_expr. span ;
832825 // Use the span of the trailing expression for our cause,
833826 // not the span of the entire function
834- if !explicit_return {
835- if let ExprKind :: Block ( body, _) = return_expr. kind && let Some ( last_expr) = body. expr {
827+ if !explicit_return
828+ && let ExprKind :: Block ( body, _) = return_expr. kind
829+ && let Some ( last_expr) = body. expr
830+ {
836831 span = last_expr. span ;
837- }
838832 }
839833 ret_coercion. borrow_mut ( ) . coerce (
840834 self ,
@@ -854,6 +848,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
854848 }
855849 }
856850
851+ /// Emit an error because `return` or `become` is used outside of a function body.
852+ ///
853+ /// `expr` is the `return` (`become`) "statement", `kind` is the kind of the return
854+ /// either "return" or "become"
855+ ///
856+ /// FIXME(explicit_tail_calls): come up with a better way than passing strings lol
857+ fn emit_return_outside_of_fn_body ( & self , expr : & hir:: Expr < ' _ > , kind : & ' static str ) {
858+ let mut err = ReturnStmtOutsideOfFnBody {
859+ span : expr. span ,
860+ encl_body_span : None ,
861+ encl_fn_span : None ,
862+ statement_kind : kind. to_string ( ) ,
863+ } ;
864+
865+ let encl_item_id = self . tcx . hir ( ) . get_parent_item ( expr. hir_id ) ;
866+
867+ if let Some ( hir:: Node :: Item ( hir:: Item {
868+ kind : hir:: ItemKind :: Fn ( ..) ,
869+ span : encl_fn_span,
870+ ..
871+ } ) )
872+ | Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
873+ kind : hir:: TraitItemKind :: Fn ( _, hir:: TraitFn :: Provided ( _) ) ,
874+ span : encl_fn_span,
875+ ..
876+ } ) )
877+ | Some ( hir:: Node :: ImplItem ( hir:: ImplItem {
878+ kind : hir:: ImplItemKind :: Fn ( ..) ,
879+ span : encl_fn_span,
880+ ..
881+ } ) ) = self . tcx . hir ( ) . find_by_def_id ( encl_item_id. def_id )
882+ {
883+ // We are inside a function body, so reporting "return statement
884+ // outside of function body" needs an explanation.
885+
886+ let encl_body_owner_id = self . tcx . hir ( ) . enclosing_body_owner ( expr. hir_id ) ;
887+
888+ // If this didn't hold, we would not have to report an error in
889+ // the first place.
890+ assert_ne ! ( encl_item_id. def_id, encl_body_owner_id) ;
891+
892+ let encl_body_id = self . tcx . hir ( ) . body_owned_by ( encl_body_owner_id) ;
893+ let encl_body = self . tcx . hir ( ) . body ( encl_body_id) ;
894+
895+ err. encl_body_span = Some ( encl_body. value . span ) ;
896+ err. encl_fn_span = Some ( * encl_fn_span) ;
897+ }
898+
899+ self . tcx . sess . emit_err ( err) ;
900+ }
901+
857902 fn point_at_return_for_opaque_ty_error (
858903 & self ,
859904 errors : & mut Vec < traits:: FulfillmentError < ' tcx > > ,
0 commit comments