Skip to content

Commit

Permalink
rustc_typeck: correctly track "always-diverges" and "has-type-errors".
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Nov 9, 2016
1 parent ff0830d commit 6b3cc0b
Show file tree
Hide file tree
Showing 26 changed files with 345 additions and 212 deletions.
2 changes: 1 addition & 1 deletion src/libpanic_abort/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
// now hopefully.
#[no_mangle]
pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
return abort();
abort();

#[cfg(unix)]
unsafe fn abort() -> ! {
Expand Down
2 changes: 0 additions & 2 deletions src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
1 => panic!("make_input should have provided valid inputs"),
_ => early_error(sopts.error_format, "multiple input filenames provided"),
}

None
}

fn late_callback(&mut self,
Expand Down
26 changes: 18 additions & 8 deletions src/librustc_typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc::hir::def::{Def, CtorKind};
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc::infer::{self, InferOk, TypeOrigin};
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
use check::{FnCtxt, Expectation};
use check::{FnCtxt, Expectation, Diverges};
use util::nodemap::FxHashMap;

use std::collections::hash_map::Entry::{Occupied, Vacant};
Expand Down Expand Up @@ -360,9 +360,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
true
}
}

impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn check_match(&self,
expr: &'gcx hir::Expr,
discrim: &'gcx hir::Expr,
Expand Down Expand Up @@ -390,14 +388,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
discrim_ty = self.next_ty_var();
self.check_expr_has_type(discrim, discrim_ty);
};
let discrim_diverges = self.diverges.get();
self.diverges.set(Diverges::Maybe);

// Typecheck the patterns first, so that we get types for all the
// bindings.
for arm in arms {
let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| {
let mut all_pats_diverge = Diverges::WarnedAlways;
for p in &arm.pats {
self.diverges.set(Diverges::Maybe);
self.check_pat(&p, discrim_ty);
all_pats_diverge &= self.diverges.get();
}
}
all_pats_diverge
}).collect();

// Now typecheck the blocks.
//
Expand All @@ -410,6 +414,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// type in that case)
let expected = expected.adjust_for_branches(self);
let mut result_ty = self.next_diverging_ty_var();
let mut all_arms_diverge = Diverges::WarnedAlways;
let coerce_first = match expected {
// We don't coerce to `()` so that if the match expression is a
// statement it's branches can have any consistent type. That allows
Expand All @@ -422,11 +427,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => result_ty
};

for (i, arm) in arms.iter().enumerate() {
for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
if let Some(ref e) = arm.guard {
self.diverges.set(pats_diverge);
self.check_expr_has_type(e, tcx.types.bool);
}

self.diverges.set(pats_diverge);
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
all_arms_diverge &= self.diverges.get();

if result_ty.references_error() || arm_ty.references_error() {
result_ty = tcx.types.err;
Expand Down Expand Up @@ -476,11 +485,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
};
}

// We won't diverge unless the discriminant or all arms diverge.
self.diverges.set(discrim_diverges | all_arms_diverge);

result_ty
}
}

impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn check_pat_struct(&self,
pat: &'gcx hir::Pat,
path: &hir::Path,
Expand Down
Loading

0 comments on commit 6b3cc0b

Please sign in to comment.