5
5
use crate :: cast;
6
6
use crate :: coercion:: CoerceMany ;
7
7
use crate :: coercion:: DynamicCoerceMany ;
8
+ use crate :: errors:: ReturnLikeStatementKind ;
8
9
use crate :: errors:: TypeMismatchFruTypo ;
9
10
use crate :: errors:: { AddressOfTemporaryTaken , ReturnStmtOutsideOfFnBody , StructExprNonExhaustive } ;
10
11
use crate :: errors:: {
@@ -324,6 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
324
325
}
325
326
}
326
327
ExprKind :: Ret ( ref expr_opt) => self . check_expr_return ( expr_opt. as_deref ( ) , expr) ,
328
+ ExprKind :: Become ( call) => self . check_expr_become ( call, expr) ,
327
329
ExprKind :: Let ( let_expr) => self . check_expr_let ( let_expr) ,
328
330
ExprKind :: Loop ( body, _, source, _) => {
329
331
self . check_expr_loop ( body, source, expected, expr)
@@ -735,47 +737,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
735
737
expr : & ' tcx hir:: Expr < ' tcx > ,
736
738
) -> Ty < ' tcx > {
737
739
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 ) ;
779
741
780
742
if let Some ( e) = expr_opt {
781
743
// We still have to type-check `e` (issue #86188), but calling
@@ -815,6 +777,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
815
777
self . tcx . types . never
816
778
}
817
779
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
+ ///
818
812
/// `explicit_return` is `true` if we're checking an explicit `return expr`,
819
813
/// and `false` if we're checking a trailing expression.
820
814
pub ( super ) fn check_return_expr (
@@ -831,10 +825,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
831
825
let mut span = return_expr. span ;
832
826
// Use the span of the trailing expression for our cause,
833
827
// 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
+ {
836
832
span = last_expr. span ;
837
- }
838
833
}
839
834
ret_coercion. borrow_mut ( ) . coerce (
840
835
self ,
@@ -854,6 +849,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
854
849
}
855
850
}
856
851
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
+
857
901
fn point_at_return_for_opaque_ty_error (
858
902
& self ,
859
903
errors : & mut Vec < traits:: FulfillmentError < ' tcx > > ,
0 commit comments