Infer return type of loops with value breaks.
This commit is contained in:
parent
38e8f35855
commit
0fe876925e
@ -218,6 +218,7 @@ struct InferenceContext<'a> {
|
||||
#[derive(Clone, Debug)]
|
||||
struct BreakableContext {
|
||||
pub may_break: bool,
|
||||
pub break_ty: Ty,
|
||||
}
|
||||
|
||||
impl<'a> InferenceContext<'a> {
|
||||
|
@ -93,7 +93,7 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||
Ty::Unknown
|
||||
}
|
||||
Expr::Loop { body } => {
|
||||
self.breakables.push(BreakableContext { may_break: false });
|
||||
self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown });
|
||||
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
|
||||
|
||||
let ctxt = self.breakables.pop().expect("breakable stack broken");
|
||||
@ -102,13 +102,13 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||
}
|
||||
// FIXME handle break with value
|
||||
if ctxt.may_break {
|
||||
Ty::unit()
|
||||
ctxt.break_ty
|
||||
} else {
|
||||
Ty::simple(TypeCtor::Never)
|
||||
}
|
||||
}
|
||||
Expr::While { condition, body } => {
|
||||
self.breakables.push(BreakableContext { may_break: false });
|
||||
self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown });
|
||||
// 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()));
|
||||
@ -120,7 +120,7 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||
Expr::For { iterable, body, pat } => {
|
||||
let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
|
||||
|
||||
self.breakables.push(BreakableContext { may_break: false });
|
||||
self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown });
|
||||
let pat_ty =
|
||||
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
|
||||
|
||||
@ -229,12 +229,21 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||
}
|
||||
Expr::Continue => Ty::simple(TypeCtor::Never),
|
||||
Expr::Break { expr } => {
|
||||
let mut has_val_ty = None;
|
||||
|
||||
if let Some(expr) = expr {
|
||||
// FIXME handle break with value
|
||||
self.infer_expr(*expr, &Expectation::none());
|
||||
has_val_ty = Some(self.infer_expr(*expr, &Expectation::none()));
|
||||
}
|
||||
|
||||
if let Some(ctxt) = self.breakables.last_mut() {
|
||||
ctxt.may_break = true;
|
||||
if let Some(val_ty) = has_val_ty {
|
||||
if ctxt.break_ty == Ty::Unknown {
|
||||
ctxt.break_ty = val_ty;
|
||||
} else if ctxt.break_ty != val_ty {
|
||||
// TODO: Unify partially matching type information (Option<{unknown}> + Option<i32> => Option<i32>)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
|
||||
expr: tgt_expr,
|
||||
|
Loading…
Reference in New Issue
Block a user