Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change the strategy for diverging types #40224

Merged
merged 36 commits into from
Mar 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
276bba9
refactor if so that the "then type" is an expression
nikomatsakis Mar 9, 2017
6c02272
update comment
nikomatsakis Mar 9, 2017
6a47fa1
remove unneeded `&` that now fails to coerce
nikomatsakis Mar 30, 2017
066d44b
refactor the `targeted_by_break` field
nikomatsakis Mar 22, 2017
4c6c26e
change the strategy for diverging types
nikomatsakis Mar 3, 2017
555b6d6
add some debug logs to type_variable.rs
nikomatsakis Mar 17, 2017
27f4b57
add a `TypeVariableOrigin` we'll use later (`DerivingFn`)
nikomatsakis Mar 17, 2017
eeb6447
add an `ObligationCauseCode` we'll use later (`ReturnNoExpression`)
nikomatsakis Mar 17, 2017
dad3140
introduce (but do not yet use) a `CoerceMany` API
nikomatsakis Mar 17, 2017
56847af
port the match code to use `CoerceMany`
nikomatsakis Mar 17, 2017
b725272
port if-then-else to use `CoerceMany`
nikomatsakis Mar 17, 2017
a6e6be5
port `return` expressions to use `CoerceMany`
nikomatsakis Mar 17, 2017
4967f1a
document the diverges flag etc
nikomatsakis Mar 17, 2017
1ae620b
do not eagerly convert `!` to a diverging variable
nikomatsakis Mar 17, 2017
16a71cc
rework how we handle the type of loops
nikomatsakis Mar 17, 2017
140165f
rewrite `ExprArray` processing to use `CoerceMany`
nikomatsakis Mar 17, 2017
cecccd9
whitespace changes, debug message
nikomatsakis Mar 17, 2017
52e524a
make `try_find_coercion_lub` private; we always use `CoerceMany`
nikomatsakis Mar 17, 2017
5cd99aa
more detailed tests around diverging type variables
nikomatsakis Mar 17, 2017
2f526cc
we now get an extra unreachable code warning in this test
nikomatsakis Mar 17, 2017
f11b7d3
add regression test for #39808
nikomatsakis Mar 18, 2017
a60e27e
pacify the mercilous tidy
nikomatsakis Mar 21, 2017
609bfe8
cherry-pick over the tests I wrote for the reachability code
nikomatsakis Mar 21, 2017
bad7948
avoid allocating a vector when the coercion sites are known upfront
nikomatsakis Mar 21, 2017
f837064
coercion now depends on whether the expression diverges
nikomatsakis Mar 24, 2017
d448329
fix handling of blocks with `CoerceMany`
nikomatsakis Mar 24, 2017
127a7d6
rename `only_has_type_or_fresh_var` to `coercion_target_type`
nikomatsakis Mar 24, 2017
d08a6da
remove `Clone` from `FnCtxt`
nikomatsakis Mar 22, 2017
8c6156e
have coercion supply back the target type
nikomatsakis Mar 23, 2017
7eeddb4
add test illustrating current "coerce to `!`" behavior
nikomatsakis Mar 24, 2017
8450add
fix `X as !` behavior
nikomatsakis Mar 24, 2017
1b5768d
document `diverges` more correctly
nikomatsakis Mar 24, 2017
e97fc52
kill the graphviz-flowgraph tests
nikomatsakis Mar 24, 2017
fb99d87
update UI test
nikomatsakis Mar 25, 2017
744f666
fix error message for issue-10176.rs
nikomatsakis Mar 26, 2017
2414222
remove comments that were tripping up pretty printer
nikomatsakis Mar 27, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/librustc/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,

impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex {
if let Some(break_to_expr_id) = blk.break_to_expr_id {
if blk.targeted_by_break {
let expr_exit = self.add_ast_node(blk.id, &[]);

self.breakable_block_scopes.push(BlockScope {
block_expr_id: break_to_expr_id,
block_expr_id: blk.id,
break_index: expr_exit,
});

Expand Down Expand Up @@ -195,7 +195,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
// [..expr..]
//
let cond_exit = self.expr(&cond, pred); // 1
let then_exit = self.block(&then, cond_exit); // 2
let then_exit = self.expr(&then, cond_exit); // 2
self.add_ast_node(expr.id, &[cond_exit, then_exit]) // 3,4
}

Expand All @@ -215,7 +215,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
// [..expr..]
//
let cond_exit = self.expr(&cond, pred); // 1
let then_exit = self.block(&then, cond_exit); // 2
let then_exit = self.expr(&then, cond_exit); // 2
let else_exit = self.expr(&otherwise, cond_exit); // 3
self.add_ast_node(expr.id, &[then_exit, else_exit]) // 4, 5
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
}
ExprIf(ref head_expression, ref if_block, ref optional_else) => {
visitor.visit_expr(head_expression);
visitor.visit_block(if_block);
visitor.visit_expr(if_block);
walk_list!(visitor, visit_expr, optional_else);
}
ExprWhile(ref subexpression, ref block, ref opt_sp_name) => {
Expand Down
39 changes: 21 additions & 18 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ impl<'a> LoweringContext<'a> {
bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect()
}

fn lower_block(&mut self, b: &Block, break_to: Option<NodeId>) -> P<hir::Block> {
fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
let mut expr = None;

let mut stmts = vec![];
Expand All @@ -1179,7 +1179,7 @@ impl<'a> LoweringContext<'a> {
expr: expr,
rules: self.lower_block_check_mode(&b.rules),
span: b.span,
break_to_expr_id: break_to,
targeted_by_break: targeted_by_break,
})
}

Expand Down Expand Up @@ -1274,7 +1274,7 @@ impl<'a> LoweringContext<'a> {
}
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
self.with_new_scopes(|this| {
let body = this.lower_block(body, None);
let body = this.lower_block(body, false);
let body = this.expr_block(body, ThinVec::new());
let body_id = this.record_body(body, Some(decl));
hir::ItemFn(this.lower_fn_decl(decl),
Expand Down Expand Up @@ -1368,7 +1368,7 @@ impl<'a> LoweringContext<'a> {
hir::TraitMethod::Required(names))
}
TraitItemKind::Method(ref sig, Some(ref body)) => {
let body = this.lower_block(body, None);
let body = this.lower_block(body, false);
let expr = this.expr_block(body, ThinVec::new());
let body_id = this.record_body(expr, Some(&sig.decl));
hir::TraitItemKind::Method(this.lower_method_sig(sig),
Expand Down Expand Up @@ -1424,7 +1424,7 @@ impl<'a> LoweringContext<'a> {
hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
}
ImplItemKind::Method(ref sig, ref body) => {
let body = this.lower_block(body, None);
let body = this.lower_block(body, false);
let expr = this.expr_block(body, ThinVec::new());
let body_id = this.record_body(expr, Some(&sig.decl));
hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
Expand Down Expand Up @@ -1848,32 +1848,35 @@ impl<'a> LoweringContext<'a> {
id: id,
rules: hir::DefaultBlock,
span: span,
break_to_expr_id: None,
targeted_by_break: false,
});
P(self.expr_block(blk, ThinVec::new()))
}
_ => P(self.lower_expr(els)),
}
});

hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt)
let then_blk = self.lower_block(blk, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());

hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt)
}
ExprKind::While(ref cond, ref body, opt_ident) => {
self.with_loop_scope(e.id, |this|
hir::ExprWhile(
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
this.lower_block(body, None),
this.lower_block(body, false),
this.lower_opt_sp_ident(opt_ident)))
}
ExprKind::Loop(ref body, opt_ident) => {
self.with_loop_scope(e.id, |this|
hir::ExprLoop(this.lower_block(body, None),
hir::ExprLoop(this.lower_block(body, false),
this.lower_opt_sp_ident(opt_ident),
hir::LoopSource::Loop))
}
ExprKind::Catch(ref body) => {
self.with_catch_scope(e.id, |this|
hir::ExprBlock(this.lower_block(body, Some(e.id))))
self.with_catch_scope(body.id, |this|
hir::ExprBlock(this.lower_block(body, true)))
}
ExprKind::Match(ref expr, ref arms) => {
hir::ExprMatch(P(self.lower_expr(expr)),
Expand All @@ -1891,7 +1894,7 @@ impl<'a> LoweringContext<'a> {
})
})
}
ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)),
ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, false)),
ExprKind::Assign(ref el, ref er) => {
hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
Expand Down Expand Up @@ -2037,7 +2040,7 @@ impl<'a> LoweringContext<'a> {

// `<pat> => <body>`
{
let body = self.lower_block(body, None);
let body = self.lower_block(body, false);
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pat = self.lower_pat(pat);
arms.push(self.arm(hir_vec![pat], body_expr));
Expand Down Expand Up @@ -2109,7 +2112,7 @@ impl<'a> LoweringContext<'a> {
let (guard, body) = if let ExprKind::If(ref cond,
ref then,
_) = else_expr.node {
let then = self.lower_block(then, None);
let then = self.lower_block(then, false);
(Some(cond),
self.expr_block(then, ThinVec::new()))
} else {
Expand Down Expand Up @@ -2159,7 +2162,7 @@ impl<'a> LoweringContext<'a> {
// Note that the block AND the condition are evaluated in the loop scope.
// This is done to allow `break` from inside the condition of the loop.
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| (
this.lower_block(body, None),
this.lower_block(body, false),
this.expr_break(e.span, ThinVec::new()),
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
));
Expand Down Expand Up @@ -2220,7 +2223,7 @@ impl<'a> LoweringContext<'a> {
// `::std::option::Option::Some(<pat>) => <body>`
let pat_arm = {
let body_block = self.with_loop_scope(e.id,
|this| this.lower_block(body, None));
|this| this.lower_block(body, false));
let body_expr = P(self.expr_block(body_block, ThinVec::new()));
let pat = self.lower_pat(pat);
let some_pat = self.pat_some(e.span, pat);
Expand Down Expand Up @@ -2652,7 +2655,7 @@ impl<'a> LoweringContext<'a> {
id: self.next_id(),
rules: hir::DefaultBlock,
span: span,
break_to_expr_id: None,
targeted_by_break: false,
}
}

Expand Down Expand Up @@ -2760,7 +2763,7 @@ impl<'a> LoweringContext<'a> {
id: id,
stmts: stmts,
expr: Some(expr),
break_to_expr_id: None,
targeted_by_break: false,
});
self.expr_block(block, attrs)
}
Expand Down
12 changes: 7 additions & 5 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,11 @@ pub struct Block {
/// Distinguishes between `unsafe { ... }` and `{ ... }`
pub rules: BlockCheckMode,
pub span: Span,
/// The id of the expression that `break` breaks to if the block can be broken out of.
/// Currently only `Some(_)` for `catch {}` blocks
pub break_to_expr_id: Option<NodeId>,
/// If true, then there may exist `break 'a` values that aim to
/// break out of this block early. As of this writing, this is not
/// currently permitted in Rust itself, but it is generated as
/// part of `catch` statements.
pub targeted_by_break: bool,
}

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
Expand Down Expand Up @@ -993,8 +995,8 @@ pub enum Expr_ {
ExprType(P<Expr>, P<Ty>),
/// An `if` block, with an optional else block
///
/// `if expr { block } else { expr }`
ExprIf(P<Expr>, P<Block>, Option<P<Expr>>),
/// `if expr { expr } else { expr }`
ExprIf(P<Expr>, P<Expr>, Option<P<Expr>>),
/// A while loop, with an optional label
///
/// `'label: while expr { block }`
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,7 @@ impl<'a> State<'a> {
word(&mut self.s, " else if ")?;
self.print_expr(&i)?;
space(&mut self.s)?;
self.print_block(&then)?;
self.print_expr(&then)?;
self.print_else(e.as_ref().map(|e| &**e))
}
// "final else"
Expand All @@ -1058,13 +1058,13 @@ impl<'a> State<'a> {

pub fn print_if(&mut self,
test: &hir::Expr,
blk: &hir::Block,
blk: &hir::Expr,
elseopt: Option<&hir::Expr>)
-> io::Result<()> {
self.head("if")?;
self.print_expr(test)?;
space(&mut self.s)?;
self.print_block(blk)?;
self.print_expr(blk)?;
self.print_else(elseopt)
}

Expand Down
5 changes: 4 additions & 1 deletion src/librustc/infer/type_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub struct TypeVariableTable<'tcx> {
}

/// Reasons to create a type inference variable
#[derive(Debug)]
pub enum TypeVariableOrigin {
MiscVariable(Span),
NormalizeProjectionType(Span),
Expand All @@ -41,6 +42,7 @@ pub enum TypeVariableOrigin {
AdjustmentType(Span),
DivergingStmt(Span),
DivergingBlockExpr(Span),
DivergingFn(Span),
LatticeVariable(Span),
}

Expand Down Expand Up @@ -196,14 +198,15 @@ impl<'tcx> TypeVariableTable<'tcx> {
diverging: bool,
origin: TypeVariableOrigin,
default: Option<Default<'tcx>>,) -> ty::TyVid {
debug!("new_var(diverging={:?}, origin={:?})", diverging, origin);
self.eq_relations.new_key(());
let index = self.values.push(TypeVariableData {
value: Bounded { relations: vec![], default: default },
origin: origin,
diverging: diverging
});
let v = ty::TyVid { index: index as u32 };
debug!("new_var() -> {:?}", v);
debug!("new_var: diverging={:?} index={:?}", diverging, v);
v
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,9 +414,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
self.consume_exprs(exprs);
}

hir::ExprIf(ref cond_expr, ref then_blk, ref opt_else_expr) => {
hir::ExprIf(ref cond_expr, ref then_expr, ref opt_else_expr) => {
self.consume_expr(&cond_expr);
self.walk_block(&then_blk);
self.walk_expr(&then_expr);
if let Some(ref else_expr) = *opt_else_expr {
self.consume_expr(&else_expr);
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -821,8 +821,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {

fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode)
-> LiveNode {
if let Some(break_to_expr_id) = blk.break_to_expr_id {
self.breakable_block_ln.insert(break_to_expr_id, succ);
if blk.targeted_by_break {
self.breakable_block_ln.insert(blk.id, succ);
}
let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ);
blk.stmts.iter().rev().fold(succ, |succ, stmt| {
Expand Down Expand Up @@ -951,7 +951,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// ( succ )
//
let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ);
let then_ln = self.propagate_through_block(&then, succ);
let then_ln = self.propagate_through_expr(&then, succ);
let ln = self.live_node(expr.id, expr.span);
self.init_from_succ(ln, else_ln);
self.merge_from_succ(ln, then_ln, false);
Expand Down
1 change: 1 addition & 0 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ObligationCauseCode::StartFunctionType |
ObligationCauseCode::IntrinsicType |
ObligationCauseCode::MethodReceiver |
ObligationCauseCode::ReturnNoExpression |
ObligationCauseCode::MiscObligation => {
}
ObligationCauseCode::SliceOrArrayElem => {
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ pub enum ObligationCauseCode<'tcx> {

// method receiver
MethodReceiver,

// `return` with no expression
ReturnNoExpression,
}

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
type Lifted = traits::ObligationCauseCode<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match *self {
super::ReturnNoExpression => Some(super::ReturnNoExpression),
super::MiscObligation => Some(super::MiscObligation),
super::SliceOrArrayElem => Some(super::SliceOrArrayElem),
super::TupleElem => Some(super::TupleElem),
Expand Down Expand Up @@ -489,6 +490,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
super::StructInitializerSized |
super::VariableType(_) |
super::ReturnType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized |
super::ConstSized |
Expand Down Expand Up @@ -533,6 +535,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
super::StructInitializerSized |
super::VariableType(_) |
super::ReturnType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized |
super::ConstSized |
Expand Down
Loading