Skip to content

Commit

Permalink
Auto merge of #47630 - canndrew:exhaustive-patterns, r=<try>
Browse files Browse the repository at this point in the history
Stabilise feature(never_type). Introduce feature(exhaustive_patterns)

This stabilizes `!`, removing the feature gate as well as the old defaulting-to-`()` behavior. The pattern exhaustiveness checks which were covered by `feature(never_type)` have been moved behind a new `feature(exhaustive_patterns)` gate.
  • Loading branch information
bors committed Jan 23, 2018
2 parents 3a39b2a + 72ce701 commit e2e6c4a
Show file tree
Hide file tree
Showing 134 changed files with 238 additions and 444 deletions.
8 changes: 4 additions & 4 deletions src/libcore/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -880,24 +880,24 @@ mod impls {

ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }

#[unstable(feature = "never_type", issue = "35121")]
#[stable(feature = "never_type", since = "1.25.0")]
impl PartialEq for ! {
fn eq(&self, _: &!) -> bool {
*self
}
}

#[unstable(feature = "never_type", issue = "35121")]
#[stable(feature = "never_type", since = "1.25.0")]
impl Eq for ! {}

#[unstable(feature = "never_type", issue = "35121")]
#[stable(feature = "never_type", since = "1.25.0")]
impl PartialOrd for ! {
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
*self
}
}

#[unstable(feature = "never_type", issue = "35121")]
#[stable(feature = "never_type", since = "1.25.0")]
impl Ord for ! {
fn cmp(&self, _: &!) -> Ordering {
*self
Expand Down
4 changes: 2 additions & 2 deletions src/libcore/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1570,14 +1570,14 @@ macro_rules! fmt_refs {

fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }

#[unstable(feature = "never_type", issue = "35121")]
#[stable(feature = "never_type", since = "1.25.0")]
impl Debug for ! {
fn fmt(&self, _: &mut Formatter) -> Result {
*self
}
}

#[unstable(feature = "never_type", issue = "35121")]
#[stable(feature = "never_type", since = "1.25.0")]
impl Display for ! {
fn fmt(&self, _: &mut Formatter) -> Result {
*self
Expand Down
3 changes: 2 additions & 1 deletion src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
#![feature(inclusive_range_syntax)]
#![feature(intrinsics)]
#![feature(lang_items)]
#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(no_core)]
#![feature(on_unimplemented)]
#![feature(optin_builtin_traits)]
Expand All @@ -91,6 +91,7 @@
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(doc_spotlight)]
#![cfg_attr(stage0, feature(never_type))]

#[prelude_import]
#[allow(unused)]
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,9 +656,8 @@ for ty::TypeVariants<'gcx>
closure_substs.hash_stable(hcx, hasher);
interior.hash_stable(hcx, hasher);
}
TyTuple(inner_tys, from_diverging_type_var) => {
TyTuple(inner_tys) => {
inner_tys.hash_stable(hcx, hasher);
from_diverging_type_var.hash_stable(hcx, hasher);
}
TyProjection(ref projection_ty) => {
projection_ty.hash_stable(hcx, hasher);
Expand Down
6 changes: 0 additions & 6 deletions src/librustc/infer/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx>
ty::TyInfer(_) => {
bug!("Unexpected type in full type resolver: {:?}", t);
}
ty::TyTuple(tys, true) => {
// Un-default defaulted tuples - we are going to a
// different infcx, and the default will just cause
// pollution.
self.tcx().intern_tup(tys, false)
}
_ => {
t.super_fold_with(self)
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
#![cfg_attr(windows, feature(libc))]
#![feature(macro_vis_matcher)]
#![feature(match_default_bindings)]
#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(nonzero)]
#![feature(quote)]
#![feature(refcell_replace_swap)]
Expand Down
8 changes: 0 additions & 8 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,6 @@ declare_lint! {
"lints that have been renamed or removed"
}

declare_lint! {
pub RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
Deny,
"attempt to resolve a trait on an expression whose type cannot be inferred but which \
currently defaults to ()"
}

declare_lint! {
pub SAFE_EXTERN_STATICS,
Deny,
Expand Down Expand Up @@ -275,7 +268,6 @@ impl LintPass for HardwiredLints {
INVALID_TYPE_PARAM_DEFAULT,
CONST_ERR,
RENAMED_AND_REMOVED_LINTS,
RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
SAFE_EXTERN_STATICS,
SAFE_PACKED_BORROWS,
PATTERNS_IN_FNS_WITHOUT_BODY,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
PatKind::Tuple(ref subpats, ddpos) => {
// (p1, ..., pN)
let expected_len = match self.pat_ty(&pat)?.sty {
ty::TyTuple(ref tys, _) => tys.len(),
ty::TyTuple(ref tys) => tys.len(),
ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
Expand Down
7 changes: 2 additions & 5 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl<'tcx> Rvalue<'tcx> {
let lhs_ty = lhs.ty(local_decls, tcx);
let rhs_ty = rhs.ty(local_decls, tcx);
let ty = op.ty(tcx, lhs_ty, rhs_ty);
tcx.intern_tup(&[ty, tcx.types.bool], false)
tcx.intern_tup(&[ty, tcx.types.bool])
}
Rvalue::UnaryOp(UnOp::Not, ref operand) |
Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
Expand All @@ -195,10 +195,7 @@ impl<'tcx> Rvalue<'tcx> {
tcx.mk_array(ty, ops.len() as u64)
}
AggregateKind::Tuple => {
tcx.mk_tup(
ops.iter().map(|op| op.ty(local_decls, tcx)),
false
)
tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
}
AggregateKind::Adt(def, _, substs, _) => {
tcx.type_of(def.did).subst(tcx, substs)
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,14 +718,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}).map(|sp| self.tcx.sess.codemap().def_span(sp)); // the sp could be an fn def

let found = match found_trait_ref.skip_binder().substs.type_at(1).sty {
ty::TyTuple(ref tys, _) => tys.iter()
ty::TyTuple(ref tys) => tys.iter()
.map(|_| ArgKind::empty()).collect::<Vec<_>>(),
_ => vec![ArgKind::empty()],
};
let expected = match expected_trait_ref.skip_binder().substs.type_at(1).sty {
ty::TyTuple(ref tys, _) => tys.iter()
ty::TyTuple(ref tys) => tys.iter()
.map(|t| match t.sty {
ty::TypeVariants::TyTuple(ref tys, _) => ArgKind::Tuple(
ty::TypeVariants::TyTuple(ref tys) => ArgKind::Tuple(
span,
tys.iter()
.map(|ty| ("_".to_owned(), format!("{}", ty.sty)))
Expand Down Expand Up @@ -937,7 +937,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn build_fn_sig_string<'a, 'gcx, 'tcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>,
trait_ref: &ty::TraitRef<'tcx>) -> String {
let inputs = trait_ref.substs.type_at(1);
let sig = if let ty::TyTuple(inputs, _) = inputs.sty {
let sig = if let ty::TyTuple(inputs) = inputs.sty {
tcx.mk_fn_sig(
inputs.iter().map(|&x| x),
tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })),
Expand Down
6 changes: 1 addition & 5 deletions src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,11 +328,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
if data.is_global() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if
// make defaulted unit go through the slow path for better warnings,
// please remove this when the warnings are removed.
!trait_obligation.predicate.skip_binder().self_ty().is_defaulted_unit() &&
selcx.evaluate_obligation_conservatively(&obligation) {
if selcx.evaluate_obligation_conservatively(&obligation) {
debug!("selecting trait `{:?}` at depth {} evaluated to holds",
data, obligation.recursion_depth);
return Ok(Some(vec![]))
Expand Down
55 changes: 6 additions & 49 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ use std::mem;
use std::rc::Rc;
use syntax::abi::Abi;
use hir;
use lint;
use util::nodemap::FxHashMap;

struct InferredObligationsSnapshotVecDelegate<'tcx> {
Expand Down Expand Up @@ -517,8 +516,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("select({:?})", obligation);
assert!(!obligation.predicate.has_escaping_regions());

let tcx = self.tcx();

let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
let ret = match self.candidate_from_obligation(&stack)? {
None => None,
Expand All @@ -530,46 +527,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
},
};

// Test whether this is a `()` which was produced by defaulting a
// diverging type variable with `!` disabled. If so, we may need
// to raise a warning.
if obligation.predicate.skip_binder().self_ty().is_defaulted_unit() {
let mut raise_warning = true;
// Don't raise a warning if the trait is implemented for ! and only
// permits a trivial implementation for !. This stops us warning
// about (for example) `(): Clone` becoming `!: Clone` because such
// a switch can't cause code to stop compiling or execute
// differently.
let mut never_obligation = obligation.clone();
let def_id = never_obligation.predicate.skip_binder().trait_ref.def_id;
never_obligation.predicate = never_obligation.predicate.map_bound(|mut trait_pred| {
// Swap out () with ! so we can check if the trait is impld for !
{
let trait_ref = &mut trait_pred.trait_ref;
let unit_substs = trait_ref.substs;
let mut never_substs = Vec::with_capacity(unit_substs.len());
never_substs.push(From::from(tcx.types.never));
never_substs.extend(&unit_substs[1..]);
trait_ref.substs = tcx.intern_substs(&never_substs);
}
trait_pred
});
if let Ok(Some(..)) = self.select(&never_obligation) {
if !tcx.trait_relevant_for_never(def_id) {
// The trait is also implemented for ! and the resulting
// implementation cannot actually be invoked in any way.
raise_warning = false;
}
}

if raise_warning {
tcx.lint_node(lint::builtin::RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
obligation.cause.body_id,
obligation.cause.span,
&format!("code relies on type inference rules which are likely \
to change"));
}
}
Ok(ret)
}

Expand Down Expand Up @@ -1913,7 +1870,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}

// (.., T) -> (.., U).
(&ty::TyTuple(tys_a, _), &ty::TyTuple(tys_b, _)) => {
(&ty::TyTuple(tys_a), &ty::TyTuple(tys_b)) => {
tys_a.len() == tys_b.len()
}

Expand Down Expand Up @@ -2052,7 +2009,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {

ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never,

ty::TyTuple(tys, _) => {
ty::TyTuple(tys) => {
Where(ty::Binder(tys.last().into_iter().cloned().collect()))
}

Expand Down Expand Up @@ -2105,7 +2062,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
Where(ty::Binder(vec![element_ty]))
}

ty::TyTuple(tys, _) => {
ty::TyTuple(tys) => {
// (*) binder moved here
Where(ty::Binder(tys.to_vec()))
}
Expand Down Expand Up @@ -2196,7 +2153,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
vec![element_ty]
}

ty::TyTuple(ref tys, _) => {
ty::TyTuple(ref tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
tys.to_vec()
}
Expand Down Expand Up @@ -2969,7 +2926,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}

// (.., T) -> (.., U).
(&ty::TyTuple(tys_a, _), &ty::TyTuple(tys_b, _)) => {
(&ty::TyTuple(tys_a), &ty::TyTuple(tys_b)) => {
assert_eq!(tys_a.len(), tys_b.len());

// The last field of the tuple has to exist.
Expand All @@ -2982,7 +2939,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {

// Check that the source tuple with the target's
// last element is equal to the target.
let new_tuple = tcx.mk_tup(a_mid.iter().chain(Some(b_last)), false);
let new_tuple = tcx.mk_tup(a_mid.iter().chain(Some(b_last)));
let InferOk { obligations, .. } =
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(target, new_tuple)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let arguments_tuple = match tuple_arguments {
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
TupleArgumentsFlag::Yes =>
self.intern_tup(sig.skip_binder().inputs(), false),
self.intern_tup(sig.skip_binder().inputs()),
};
let trait_ref = ty::TraitRef {
def_id: fn_trait_def_id,
Expand Down
21 changes: 6 additions & 15 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
let converted_sig = sig.map_bound(|s| {
let params_iter = match s.inputs()[0].sty {
ty::TyTuple(params, _) => {
ty::TyTuple(params) => {
params.into_iter().cloned()
}
_ => bug!(),
Expand Down Expand Up @@ -2005,25 +2005,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.mk_ty(TySlice(ty))
}

pub fn intern_tup(self, ts: &[Ty<'tcx>], defaulted: bool) -> Ty<'tcx> {
self.mk_ty(TyTuple(self.intern_type_list(ts), defaulted))
pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
self.mk_ty(TyTuple(self.intern_type_list(ts)))
}

pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I,
defaulted: bool) -> I::Output {
iter.intern_with(|ts| self.mk_ty(TyTuple(self.intern_type_list(ts), defaulted)))
pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I) -> I::Output {
iter.intern_with(|ts| self.mk_ty(TyTuple(self.intern_type_list(ts))))
}

pub fn mk_nil(self) -> Ty<'tcx> {
self.intern_tup(&[], false)
}

pub fn mk_diverging_default(self) -> Ty<'tcx> {
if self.sess.features.borrow().never_type {
self.types.never
} else {
self.intern_tup(&[], true)
}
self.intern_tup(&[])
}

pub fn mk_bool(self) -> Ty<'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
match self.sty {
ty::TyBool | ty::TyChar | ty::TyInt(_) |
ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(),
ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),
ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(),

ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/fast_reject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
Some(GeneratorSimplifiedType(def_id))
}
ty::TyNever => Some(NeverSimplifiedType),
ty::TyTuple(ref tys, _) => {
ty::TyTuple(ref tys) => {
Some(TupleSimplifiedType(tys.len()))
}
ty::TyFnPtr(ref f) => {
Expand Down
5 changes: 1 addition & 4 deletions src/librustc/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,7 @@ impl FlagComputation {
self.add_ty(m.ty);
}

&ty::TyTuple(ref ts, is_default) => {
if is_default {
self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX);
}
&ty::TyTuple(ref ts) => {
self.add_tys(&ts[..]);
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/inhabitedness/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
},

TyNever => DefIdForest::full(tcx),
TyTuple(ref tys, _) => {
TyTuple(ref tys) => {
DefIdForest::union(tcx, tys.iter().map(|ty| {
ty.uninhabited_from(visited, tcx)
}))
Expand Down
Loading

0 comments on commit e2e6c4a

Please sign in to comment.