@@ -34,7 +34,66 @@ use rustc::ty::subst::InternalSubsts;
34
34
use rustc:: traits:: { self , ObligationCauseCode } ;
35
35
36
36
impl < ' 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 (
38
97
& self ,
39
98
expr : & ' tcx hir:: Expr ,
40
99
expected : Expectation < ' tcx > ,
0 commit comments