55use crate :: cast;
66use crate :: coercion:: CoerceMany ;
77use crate :: coercion:: DynamicCoerceMany ;
8+ use crate :: errors:: ReturnLikeStatementKind ;
89use crate :: errors:: TypeMismatchFruTypo ;
910use crate :: errors:: { AddressOfTemporaryTaken , ReturnStmtOutsideOfFnBody , StructExprNonExhaustive } ;
1011use crate :: errors:: {
@@ -324,6 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
324325 }
325326 }
326327 ExprKind :: Ret ( ref expr_opt) => self . check_expr_return ( expr_opt. as_deref ( ) , expr) ,
328+ ExprKind :: Become ( call) => self . check_expr_become ( call, expr) ,
327329 ExprKind :: Let ( let_expr) => self . check_expr_let ( let_expr) ,
328330 ExprKind :: Loop ( body, _, source, _) => {
329331 self . check_expr_loop ( body, source, expected, expr)
@@ -735,47 +737,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
735737 expr : & ' tcx hir:: Expr < ' tcx > ,
736738 ) -> Ty < ' tcx > {
737739 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) ;
740+ self . emit_return_outside_of_fn_body ( expr, ReturnLikeStatementKind :: Return ) ;
779741
780742 if let Some ( e) = expr_opt {
781743 // We still have to type-check `e` (issue #86188), but calling
@@ -815,6 +777,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
815777 self . tcx . types . never
816778 }
817779
780+ fn check_expr_become (
781+ & self ,
782+ call : & ' tcx hir:: Expr < ' tcx > ,
783+ expr : & ' tcx hir:: Expr < ' tcx > ,
784+ ) -> Ty < ' tcx > {
785+ match & self . ret_coercion {
786+ Some ( ret_coercion) => {
787+ let ret_ty = ret_coercion. borrow ( ) . expected_ty ( ) ;
788+ let call_expr_ty = self . check_expr_with_hint ( call, ret_ty) ;
789+
790+ // N.B. don't coerce here, as tail calls can't support most/all coercions
791+ // FIXME(explicit_tail_calls): add a diagnostic note that `become` doesn't allow coercions
792+ self . demand_suptype ( expr. span , ret_ty, call_expr_ty) ;
793+ }
794+ None => {
795+ self . emit_return_outside_of_fn_body ( expr, ReturnLikeStatementKind :: Become ) ;
796+
797+ // Fallback to simply type checking `call` without hint/demanding the right types.
798+ // Best effort to highlight more errors.
799+ self . check_expr ( call) ;
800+ }
801+ }
802+
803+ self . tcx . types . never
804+ }
805+
806+ /// Check an expression that _is being returned_.
807+ /// For example, this is called with `return_expr: $expr` when `return $expr`
808+ /// is encountered.
809+ ///
810+ /// Note that this function must only be called in function bodies.
811+ ///
818812 /// `explicit_return` is `true` if we're checking an explicit `return expr`,
819813 /// and `false` if we're checking a trailing expression.
820814 pub ( super ) fn check_return_expr (
@@ -831,10 +825,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
831825 let mut span = return_expr. span ;
832826 // Use the span of the trailing expression for our cause,
833827 // 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 {
828+ if !explicit_return
829+ && let ExprKind :: Block ( body, _) = return_expr. kind
830+ && let Some ( last_expr) = body. expr
831+ {
836832 span = last_expr. span ;
837- }
838833 }
839834 ret_coercion. borrow_mut ( ) . coerce (
840835 self ,
@@ -854,6 +849,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
854849 }
855850 }
856851
852+ /// Emit an error because `return` or `become` is used outside of a function body.
853+ ///
854+ /// `expr` is the `return` (`become`) "statement", `kind` is the kind of the statement
855+ /// either `Return` or `Become`.
856+ fn emit_return_outside_of_fn_body ( & self , expr : & hir:: Expr < ' _ > , kind : ReturnLikeStatementKind ) {
857+ let mut err = ReturnStmtOutsideOfFnBody {
858+ span : expr. span ,
859+ encl_body_span : None ,
860+ encl_fn_span : None ,
861+ statement_kind : kind,
862+ } ;
863+
864+ let encl_item_id = self . tcx . hir ( ) . get_parent_item ( expr. hir_id ) ;
865+
866+ if let Some ( hir:: Node :: Item ( hir:: Item {
867+ kind : hir:: ItemKind :: Fn ( ..) ,
868+ span : encl_fn_span,
869+ ..
870+ } ) )
871+ | Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
872+ kind : hir:: TraitItemKind :: Fn ( _, hir:: TraitFn :: Provided ( _) ) ,
873+ span : encl_fn_span,
874+ ..
875+ } ) )
876+ | Some ( hir:: Node :: ImplItem ( hir:: ImplItem {
877+ kind : hir:: ImplItemKind :: Fn ( ..) ,
878+ span : encl_fn_span,
879+ ..
880+ } ) ) = self . tcx . hir ( ) . find_by_def_id ( encl_item_id. def_id )
881+ {
882+ // We are inside a function body, so reporting "return statement
883+ // outside of function body" needs an explanation.
884+
885+ let encl_body_owner_id = self . tcx . hir ( ) . enclosing_body_owner ( expr. hir_id ) ;
886+
887+ // If this didn't hold, we would not have to report an error in
888+ // the first place.
889+ assert_ne ! ( encl_item_id. def_id, encl_body_owner_id) ;
890+
891+ let encl_body_id = self . tcx . hir ( ) . body_owned_by ( encl_body_owner_id) ;
892+ let encl_body = self . tcx . hir ( ) . body ( encl_body_id) ;
893+
894+ err. encl_body_span = Some ( encl_body. value . span ) ;
895+ err. encl_fn_span = Some ( * encl_fn_span) ;
896+ }
897+
898+ self . tcx . sess . emit_err ( err) ;
899+ }
900+
857901 fn point_at_return_for_opaque_ty_error (
858902 & self ,
859903 errors : & mut Vec < traits:: FulfillmentError < ' tcx > > ,
0 commit comments