@@ -34,7 +34,66 @@ use rustc::ty::subst::InternalSubsts;
3434use rustc:: traits:: { self , ObligationCauseCode } ;
3535
3636impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
37- pub ( super ) fn check_expr_kind (
37+ /// Invariant:
38+ /// If an expression has any sub-expressions that result in a type error,
39+ /// inspecting that expression's type with `ty.references_error()` will return
40+ /// true. Likewise, if an expression is known to diverge, inspecting its
41+ /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
42+ /// strict, _|_ can appear in the type of an expression that does not,
43+ /// itself, diverge: for example, fn() -> _|_.)
44+ /// Note that inspecting a type's structure *directly* may expose the fact
45+ /// that there are actually multiple representations for `Error`, so avoid
46+ /// that when err needs to be handled differently.
47+ pub ( super ) fn check_expr_with_expectation_and_needs (
48+ & self ,
49+ expr : & ' tcx hir:: Expr ,
50+ expected : Expectation < ' tcx > ,
51+ needs : Needs ,
52+ ) -> Ty < ' tcx > {
53+ debug ! ( ">> type-checking: expr={:?} expected={:?}" ,
54+ expr, expected) ;
55+
56+ // Warn for expressions after diverging siblings.
57+ self . warn_if_unreachable ( expr. hir_id , expr. span , "expression" ) ;
58+
59+ // Hide the outer diverging and has_errors flags.
60+ let old_diverges = self . diverges . get ( ) ;
61+ let old_has_errors = self . has_errors . get ( ) ;
62+ self . diverges . set ( Diverges :: Maybe ) ;
63+ self . has_errors . set ( false ) ;
64+
65+ let ty = self . check_expr_kind ( expr, expected, needs) ;
66+
67+ // Warn for non-block expressions with diverging children.
68+ match expr. node {
69+ ExprKind :: Block ( ..) |
70+ ExprKind :: Loop ( ..) | ExprKind :: While ( ..) |
71+ ExprKind :: Match ( ..) => { }
72+
73+ _ => self . warn_if_unreachable ( expr. hir_id , expr. span , "expression" )
74+ }
75+
76+ // Any expression that produces a value of type `!` must have diverged
77+ if ty. is_never ( ) {
78+ self . diverges . set ( self . diverges . get ( ) | Diverges :: Always ) ;
79+ }
80+
81+ // Record the type, which applies it effects.
82+ // We need to do this after the warning above, so that
83+ // we don't warn for the diverging expression itself.
84+ self . write_ty ( expr. hir_id , ty) ;
85+
86+ // Combine the diverging and has_error flags.
87+ self . diverges . set ( self . diverges . get ( ) | old_diverges) ;
88+ self . has_errors . set ( self . has_errors . get ( ) | old_has_errors) ;
89+
90+ debug ! ( "type of {} is..." , self . tcx. hir( ) . hir_to_string( expr. hir_id) ) ;
91+ debug ! ( "... {:?}, expected is {:?}" , ty, expected) ;
92+
93+ ty
94+ }
95+
96+ fn check_expr_kind (
3897 & self ,
3998 expr : & ' tcx hir:: Expr ,
4099 expected : Expectation < ' tcx > ,
0 commit comments