Still no break-with-value or labels, but at least we know that `loop { break; }`
doesn't diverge.
/// so it doesn't make sense.
return_ty: Ty,
diverges: Diverges,
+ breakables: Vec<BreakableContext>,
+}
+
+#[derive(Clone, Debug)]
+struct BreakableContext {
+ pub may_break: bool,
}
impl<'a> InferenceContext<'a> {
body: db.body(owner),
resolver,
diverges: Diverges::Maybe,
+ breakables: Vec::new(),
}
}
Ty, TypeCtor, Uncertain,
};
-use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch, Diverges};
+use super::{
+ BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic,
+ TypeMismatch,
+};
impl<'a> InferenceContext<'a> {
pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
Ty::Unknown
}
Expr::Loop { body } => {
+ self.breakables.push(BreakableContext { may_break: false });
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
+
+ let ctxt = self.breakables.pop().expect("breakable stack broken");
+ if ctxt.may_break {
+ self.diverges = Diverges::Maybe;
+ }
// FIXME handle break with value
- Ty::simple(TypeCtor::Never)
+ if ctxt.may_break {
+ Ty::unit()
+ } else {
+ Ty::simple(TypeCtor::Never)
+ }
}
Expr::While { condition, body } => {
+ self.breakables.push(BreakableContext { may_break: false });
// while let is desugared to a match loop, so this is always simple while
self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
+ let _ctxt = self.breakables.pop().expect("breakable stack broken");
+ // the body may not run, so it diverging doesn't mean we diverge
+ self.diverges = Diverges::Maybe;
Ty::unit()
}
Expr::For { iterable, body, pat } => {
let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
+ self.breakables.push(BreakableContext { may_break: false });
let pat_ty =
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
self.infer_pat(*pat, &pat_ty, BindingMode::default());
+
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
+ let _ctxt = self.breakables.pop().expect("breakable stack broken");
+ // the body may not run, so it diverging doesn't mean we diverge
+ self.diverges = Diverges::Maybe;
Ty::unit()
}
Expr::Lambda { body, args, ret_type, arg_types } => {
// FIXME handle break with value
self.infer_expr(*expr, &Expectation::none());
}
+ if let Some(ctxt) = self.breakables.last_mut() {
+ ctxt.may_break = true;
+ }
Ty::simple(TypeCtor::Never)
}
Expr::Return { expr } => {
// should give type mismatch
let x: u32 = { loop { break; } };
}
+fn test2() {
+ // should give type mismatch
+ let x: u32 = { for a in b { break; }; };
+ // should give type mismatch as well
+ let x: u32 = { for a in b {}; };
+ // should give type mismatch as well
+ let x: u32 = { for a in b { return; }; };
+}
+fn test3() {
+ // should give type mismatch
+ let x: u32 = { while true { break; }; };
+ // should give type mismatch as well -- there's an implicit break, even if it's never hit
+ let x: u32 = { while true {}; };
+ // should give type mismatch as well
+ let x: u32 = { while true { return; }; };
+}
"#,
true,
);
- assert_snapshot!(t, @r###""###);
+ assert_snapshot!(t, @r###"
+ 25..99 '{ ...} }; }': ()
+ 68..69 'x': u32
+ 77..96 '{ loop...k; } }': ()
+ 79..94 'loop { break; }': ()
+ 84..94 '{ break; }': ()
+ 86..91 'break': !
+ 77..96: expected u32, got ()
+ 79..94: expected u32, got ()
+ 111..357 '{ ...; }; }': ()
+ 154..155 'x': u32
+ 163..189 '{ for ...; }; }': ()
+ 165..186 'for a ...eak; }': ()
+ 169..170 'a': {unknown}
+ 174..175 'b': {unknown}
+ 176..186 '{ break; }': ()
+ 178..183 'break': !
+ 240..241 'x': u32
+ 249..267 '{ for ... {}; }': ()
+ 251..264 'for a in b {}': ()
+ 255..256 'a': {unknown}
+ 260..261 'b': {unknown}
+ 262..264 '{}': ()
+ 318..319 'x': u32
+ 327..354 '{ for ...; }; }': ()
+ 329..351 'for a ...urn; }': ()
+ 333..334 'a': {unknown}
+ 338..339 'b': {unknown}
+ 340..351 '{ return; }': ()
+ 342..348 'return': !
+ 163..189: expected u32, got ()
+ 249..267: expected u32, got ()
+ 327..354: expected u32, got ()
+ 369..668 '{ ...; }; }': ()
+ 412..413 'x': u32
+ 421..447 '{ whil...; }; }': ()
+ 423..444 'while ...eak; }': ()
+ 429..433 'true': bool
+ 434..444 '{ break; }': ()
+ 436..441 'break': !
+ 551..552 'x': u32
+ 560..578 '{ whil... {}; }': ()
+ 562..575 'while true {}': ()
+ 568..572 'true': bool
+ 573..575 '{}': ()
+ 629..630 'x': u32
+ 638..665 '{ whil...; }; }': ()
+ 640..662 'while ...urn; }': ()
+ 646..650 'true': bool
+ 651..662 '{ return; }': ()
+ 653..659 'return': !
+ 421..447: expected u32, got ()
+ 560..578: expected u32, got ()
+ 638..665: expected u32, got ()
+ "###);
}