Auto merge of #47630 - canndrew:exhaustive-patterns, r=nikomatsakis
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.
This commit is contained in:
commit
5ebf74851d
@ -882,24 +882,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.26.0")]
|
||||
impl PartialEq for ! {
|
||||
fn eq(&self, _: &!) -> bool {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[stable(feature = "never_type", since = "1.26.0")]
|
||||
impl Eq for ! {}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[stable(feature = "never_type", since = "1.26.0")]
|
||||
impl PartialOrd for ! {
|
||||
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[stable(feature = "never_type", since = "1.26.0")]
|
||||
impl Ord for ! {
|
||||
fn cmp(&self, _: &!) -> Ordering {
|
||||
*self
|
||||
|
@ -1711,14 +1711,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.26.0")]
|
||||
impl Debug for ! {
|
||||
fn fmt(&self, _: &mut Formatter) -> Result {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[stable(feature = "never_type", since = "1.26.0")]
|
||||
impl Display for ! {
|
||||
fn fmt(&self, _: &mut Formatter) -> Result {
|
||||
*self
|
||||
|
@ -85,7 +85,7 @@
|
||||
#![feature(iterator_repeat_with)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(link_llvm_intrinsics)]
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(no_core)]
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
@ -103,6 +103,7 @@
|
||||
#![feature(unwind_attributes)]
|
||||
|
||||
#![cfg_attr(stage0, allow(unused_attributes))]
|
||||
#![cfg_attr(stage0, feature(never_type))]
|
||||
|
||||
#[prelude_import]
|
||||
#[allow(unused)]
|
||||
|
@ -886,9 +886,8 @@ for ty::TypeVariants<'gcx>
|
||||
TyGeneratorWitness(types) => {
|
||||
types.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);
|
||||
|
@ -609,12 +609,6 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
|
||||
bug!("encountered a canonical type during canonicalization")
|
||||
}
|
||||
|
||||
// Replace a `()` that "would've fallen back" to `!` with just `()`.
|
||||
ty::TyTuple(ref tys, true) => {
|
||||
assert!(tys.is_empty());
|
||||
self.tcx().mk_nil()
|
||||
}
|
||||
|
||||
ty::TyClosure(..)
|
||||
| ty::TyGenerator(..)
|
||||
| ty::TyGeneratorWitness(..)
|
||||
@ -634,7 +628,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
|
||||
| ty::TyFnPtr(_)
|
||||
| ty::TyDynamic(..)
|
||||
| ty::TyNever
|
||||
| ty::TyTuple(_, false)
|
||||
| ty::TyTuple(..)
|
||||
| ty::TyProjection(..)
|
||||
| ty::TyForeign(..)
|
||||
| ty::TyParam(..)
|
||||
|
@ -151,7 +151,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
// get solved *here*.
|
||||
match fulfill_cx.select_all_or_error(self) {
|
||||
Ok(()) => (),
|
||||
Err(errors) => self.report_fulfillment_errors(&errors, None),
|
||||
Err(errors) => self.report_fulfillment_errors(&errors, None, false),
|
||||
}
|
||||
|
||||
implied_bounds
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -60,7 +60,7 @@
|
||||
#![feature(match_default_bindings)]
|
||||
#![feature(macro_lifetime_matcher)]
|
||||
#![feature(macro_vis_matcher)]
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(non_exhaustive)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(proc_macro_internals)]
|
||||
|
@ -151,13 +151,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,
|
||||
@ -237,12 +230,6 @@ declare_lint! {
|
||||
"detect mut variables which don't need to be mutable"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub COERCE_NEVER,
|
||||
Deny,
|
||||
"detect coercion to !"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub SINGLE_USE_LIFETIME,
|
||||
Allow,
|
||||
@ -304,7 +291,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,
|
||||
@ -318,7 +304,6 @@ impl LintPass for HardwiredLints {
|
||||
DEPRECATED,
|
||||
UNUSED_UNSAFE,
|
||||
UNUSED_MUT,
|
||||
COERCE_NEVER,
|
||||
SINGLE_USE_LIFETIME,
|
||||
TYVAR_BEHIND_RAW_POINTER,
|
||||
ELIDED_LIFETIME_IN_PATH,
|
||||
|
@ -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) {
|
||||
|
@ -155,7 +155,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) => {
|
||||
@ -178,10 +178,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)
|
||||
|
@ -47,7 +47,8 @@ use syntax_pos::{DUMMY_SP, Span};
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn report_fulfillment_errors(&self,
|
||||
errors: &Vec<FulfillmentError<'tcx>>,
|
||||
body_id: Option<hir::BodyId>) {
|
||||
body_id: Option<hir::BodyId>,
|
||||
fallback_has_occurred: bool) {
|
||||
#[derive(Debug)]
|
||||
struct ErrorDescriptor<'tcx> {
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
@ -107,7 +108,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
for (error, suppressed) in errors.iter().zip(is_suppressed) {
|
||||
if !suppressed {
|
||||
self.report_fulfillment_error(error, body_id);
|
||||
self.report_fulfillment_error(error, body_id, fallback_has_occurred);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -151,11 +152,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>,
|
||||
body_id: Option<hir::BodyId>) {
|
||||
body_id: Option<hir::BodyId>,
|
||||
fallback_has_occurred: bool) {
|
||||
debug!("report_fulfillment_errors({:?})", error);
|
||||
match error.code {
|
||||
FulfillmentErrorCode::CodeSelectionError(ref e) => {
|
||||
self.report_selection_error(&error.obligation, e);
|
||||
self.report_selection_error(&error.obligation, e, fallback_has_occurred);
|
||||
}
|
||||
FulfillmentErrorCode::CodeProjectionError(ref e) => {
|
||||
self.report_projection_error(&error.obligation, e);
|
||||
@ -533,7 +535,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
pub fn report_selection_error(&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
error: &SelectionError<'tcx>)
|
||||
error: &SelectionError<'tcx>,
|
||||
fallback_has_occurred: bool)
|
||||
{
|
||||
let span = obligation.cause.span;
|
||||
|
||||
@ -619,6 +622,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
self.report_similar_impl_candidates(impl_candidates, &mut err);
|
||||
}
|
||||
|
||||
// If this error is due to `!: Trait` not implemented but `(): Trait` is
|
||||
// implemented, and fallback has occured, then it could be due to a
|
||||
// variable that used to fallback to `()` now falling back to `!`. Issue a
|
||||
// note informing about the change in behaviour.
|
||||
if trait_predicate.skip_binder().self_ty().is_never()
|
||||
&& fallback_has_occurred
|
||||
{
|
||||
let predicate = trait_predicate.map_bound(|mut trait_pred| {
|
||||
{
|
||||
let trait_ref = &mut trait_pred.trait_ref;
|
||||
let never_substs = trait_ref.substs;
|
||||
let mut unit_substs = Vec::with_capacity(never_substs.len());
|
||||
unit_substs.push(self.tcx.mk_nil().into());
|
||||
unit_substs.extend(&never_substs[1..]);
|
||||
trait_ref.substs = self.tcx.intern_substs(&unit_substs);
|
||||
}
|
||||
trait_pred
|
||||
});
|
||||
let unit_obligation = Obligation {
|
||||
predicate: ty::Predicate::Trait(predicate),
|
||||
.. obligation.clone()
|
||||
};
|
||||
let mut selcx = SelectionContext::new(self);
|
||||
if selcx.evaluate_obligation(&unit_obligation) {
|
||||
err.note("the trait is implemented for `()`. \
|
||||
Possibly this error has been caused by changes to \
|
||||
Rust's type-inference algorithm \
|
||||
(see: https://github.com/rust-lang/rust/issues/48950 \
|
||||
for more info). Consider whether you meant to use the \
|
||||
type `()` here instead.");
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
@ -729,14 +765,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(
|
||||
Some(span),
|
||||
tys.iter()
|
||||
.map(|ty| ("_".to_owned(), format!("{}", ty.sty)))
|
||||
@ -986,7 +1022,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 })),
|
||||
@ -1422,7 +1458,7 @@ impl ArgKind {
|
||||
/// argument. This has no name (`_`) and no source spans..
|
||||
pub fn from_expected_ty(t: Ty<'_>) -> ArgKind {
|
||||
match t.sty {
|
||||
ty::TyTuple(ref tys, _) => ArgKind::Tuple(
|
||||
ty::TyTuple(ref tys) => ArgKind::Tuple(
|
||||
None,
|
||||
tys.iter()
|
||||
.map(|ty| ("_".to_owned(), format!("{}", ty.sty)))
|
||||
|
@ -330,11 +330,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![]))
|
||||
|
@ -580,7 +580,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
) {
|
||||
Ok(predicates) => predicates,
|
||||
Err(errors) => {
|
||||
infcx.report_fulfillment_errors(&errors, None);
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
// An unnormalized env is better than nothing.
|
||||
return elaborated_env;
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ fn trivial_dropck_outlives<'cx, 'tcx>(tcx: TyCtxt<'cx, '_, 'tcx>, ty: Ty<'tcx>)
|
||||
|
||||
// (T1..Tn) and closures have same properties as T1..Tn --
|
||||
// check if *any* of those are trivial.
|
||||
ty::TyTuple(ref tys, _) => tys.iter().cloned().all(|t| trivial_dropck_outlives(tcx, t)),
|
||||
ty::TyTuple(ref tys) => tys.iter().cloned().all(|t| trivial_dropck_outlives(tcx, t)),
|
||||
ty::TyClosure(def_id, ref substs) => substs
|
||||
.upvar_tys(def_id, tcx)
|
||||
.all(|t| trivial_dropck_outlives(tcx, t)),
|
||||
|
@ -53,7 +53,6 @@ use std::mem;
|
||||
use std::rc::Rc;
|
||||
use syntax::abi::Abi;
|
||||
use hir;
|
||||
use lint;
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
||||
|
||||
@ -526,54 +525,12 @@ 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,
|
||||
Some(candidate) => Some(self.confirm_candidate(obligation, candidate)?)
|
||||
};
|
||||
|
||||
// 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(tcx.types.never.into());
|
||||
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)
|
||||
}
|
||||
|
||||
@ -1929,7 +1886,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()
|
||||
}
|
||||
|
||||
@ -2068,7 +2025,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()))
|
||||
}
|
||||
|
||||
@ -2122,7 +2079,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()))
|
||||
}
|
||||
@ -2215,7 +2172,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()
|
||||
}
|
||||
@ -3004,7 +2961,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.
|
||||
@ -3017,7 +2974,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)
|
||||
|
@ -503,7 +503,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,
|
||||
|
@ -2014,7 +2014,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!(),
|
||||
@ -2134,25 +2134,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.features().never_type {
|
||||
self.types.never
|
||||
} else {
|
||||
self.intern_tup(&[], true)
|
||||
}
|
||||
self.intern_tup(&[])
|
||||
}
|
||||
|
||||
pub fn mk_bool(self) -> Ty<'tcx> {
|
||||
|
@ -177,7 +177,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)),
|
||||
|
@ -97,7 +97,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len()))
|
||||
}
|
||||
ty::TyNever => Some(NeverSimplifiedType),
|
||||
ty::TyTuple(ref tys, _) => {
|
||||
ty::TyTuple(ref tys) => {
|
||||
Some(TupleSimplifiedType(tys.len()))
|
||||
}
|
||||
ty::TyFnPtr(ref f) => {
|
||||
|
@ -179,10 +179,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[..]);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}))
|
||||
|
@ -355,9 +355,9 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
|
||||
ty::TyRawPtr(mt) |
|
||||
ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty),
|
||||
|
||||
ty::TyTuple(ref tys, _) => tys.iter()
|
||||
.filter_map(|ty| characteristic_def_id_of_type(ty))
|
||||
.next(),
|
||||
ty::TyTuple(ref tys) => tys.iter()
|
||||
.filter_map(|ty| characteristic_def_id_of_type(ty))
|
||||
.next(),
|
||||
|
||||
ty::TyFnDef(def_id, _) |
|
||||
ty::TyClosure(def_id, _) |
|
||||
|
@ -1318,7 +1318,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
||||
StructKind::AlwaysSized)?
|
||||
}
|
||||
|
||||
ty::TyTuple(tys, _) => {
|
||||
ty::TyTuple(tys) => {
|
||||
let kind = if tys.len() == 0 {
|
||||
StructKind::AlwaysSized
|
||||
} else {
|
||||
@ -2243,7 +2243,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||
substs.field_tys(def_id, tcx).nth(i).unwrap()
|
||||
}
|
||||
|
||||
ty::TyTuple(tys, _) => tys[i],
|
||||
ty::TyTuple(tys) => tys[i],
|
||||
|
||||
// SIMD vector types.
|
||||
ty::TyAdt(def, ..) if def.repr.simd() => {
|
||||
|
@ -2046,7 +2046,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
vec![ty]
|
||||
}
|
||||
|
||||
TyTuple(ref tys, _) => {
|
||||
TyTuple(ref tys) => {
|
||||
match tys.last() {
|
||||
None => vec![],
|
||||
Some(ty) => self.sized_constraint_for_ty(tcx, ty)
|
||||
|
@ -529,11 +529,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||
Ok(tcx.mk_slice(t))
|
||||
}
|
||||
|
||||
(&ty::TyTuple(as_, a_defaulted), &ty::TyTuple(bs, b_defaulted)) =>
|
||||
(&ty::TyTuple(as_), &ty::TyTuple(bs)) =>
|
||||
{
|
||||
if as_.len() == bs.len() {
|
||||
let defaulted = a_defaulted || b_defaulted;
|
||||
Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)), defaulted)?)
|
||||
Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)))?)
|
||||
} else if !(as_.is_empty() || bs.is_empty()) {
|
||||
Err(TypeError::TupleSize(
|
||||
expected_found(relation, &as_.len(), &bs.len())))
|
||||
|
@ -869,7 +869,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
|
||||
ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)),
|
||||
ty::TyDynamic(ref trait_ty, ref region) =>
|
||||
ty::TyDynamic(trait_ty.fold_with(folder), region.fold_with(folder)),
|
||||
ty::TyTuple(ts, defaulted) => ty::TyTuple(ts.fold_with(folder), defaulted),
|
||||
ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)),
|
||||
ty::TyFnDef(def_id, substs) => {
|
||||
ty::TyFnDef(def_id, substs.fold_with(folder))
|
||||
}
|
||||
@ -908,7 +908,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
|
||||
ty::TyAdt(_, substs) => substs.visit_with(visitor),
|
||||
ty::TyDynamic(ref trait_ty, ref reg) =>
|
||||
trait_ty.visit_with(visitor) || reg.visit_with(visitor),
|
||||
ty::TyTuple(ts, _) => ts.visit_with(visitor),
|
||||
ty::TyTuple(ts) => ts.visit_with(visitor),
|
||||
ty::TyFnDef(_, substs) => substs.visit_with(visitor),
|
||||
ty::TyFnPtr(ref f) => f.visit_with(visitor),
|
||||
ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor),
|
||||
|
@ -148,11 +148,7 @@ pub enum TypeVariants<'tcx> {
|
||||
TyNever,
|
||||
|
||||
/// A tuple type. For example, `(i32, bool)`.
|
||||
/// The bool indicates whether this is a unit tuple and was created by
|
||||
/// defaulting a diverging type variable with feature(never_type) disabled.
|
||||
/// It's only purpose is for raising future-compatibility warnings for when
|
||||
/// diverging type variables start defaulting to ! instead of ().
|
||||
TyTuple(&'tcx Slice<Ty<'tcx>>, bool),
|
||||
TyTuple(&'tcx Slice<Ty<'tcx>>),
|
||||
|
||||
/// The projection of an associated type. For example,
|
||||
/// `<T as Trait<..>>::N`.
|
||||
@ -1274,7 +1270,7 @@ impl RegionKind {
|
||||
impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||
pub fn is_nil(&self) -> bool {
|
||||
match self.sty {
|
||||
TyTuple(ref tys, _) => tys.is_empty(),
|
||||
TyTuple(ref tys) => tys.is_empty(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -1286,15 +1282,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Test whether this is a `()` which was produced by defaulting a
|
||||
/// diverging type variable with feature(never_type) disabled.
|
||||
pub fn is_defaulted_unit(&self) -> bool {
|
||||
match self.sty {
|
||||
TyTuple(_, true) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_primitive(&self) -> bool {
|
||||
match self.sty {
|
||||
TyBool | TyChar | TyInt(_) | TyUint(_) | TyFloat(_) => true,
|
||||
|
@ -269,7 +269,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
// Don't use `non_enum_variant`, this may be a univariant enum.
|
||||
adt.variants[0].fields.get(i).map(|f| f.ty(self, substs))
|
||||
}
|
||||
(&TyTuple(ref v, _), None) => v.get(i).cloned(),
|
||||
(&TyTuple(ref v), None) => v.get(i).cloned(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -307,7 +307,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
ty::TyTuple(tys, _) => {
|
||||
ty::TyTuple(tys) => {
|
||||
if let Some((&last_ty, _)) = tys.split_last() {
|
||||
ty = last_ty;
|
||||
} else {
|
||||
@ -344,7 +344,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
break;
|
||||
}
|
||||
},
|
||||
(&TyTuple(a_tys, _), &TyTuple(b_tys, _))
|
||||
(&TyTuple(a_tys), &TyTuple(b_tys))
|
||||
if a_tys.len() == b_tys.len() => {
|
||||
if let Some(a_last) = a_tys.last() {
|
||||
a = a_last;
|
||||
@ -709,9 +709,8 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
|
||||
TyGeneratorWitness(tys) => {
|
||||
self.hash(tys.skip_binder().len());
|
||||
}
|
||||
TyTuple(tys, defaulted) => {
|
||||
TyTuple(tys) => {
|
||||
self.hash(tys.len());
|
||||
self.hash(defaulted);
|
||||
}
|
||||
TyParam(p) => {
|
||||
self.hash(p.idx);
|
||||
@ -838,7 +837,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
-> Representability
|
||||
{
|
||||
match ty.sty {
|
||||
TyTuple(ref ts, _) => {
|
||||
TyTuple(ref ts) => {
|
||||
// Find non representable
|
||||
fold_repr(ts.iter().map(|ty| {
|
||||
is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty)
|
||||
@ -1106,7 +1105,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
// state transformation pass
|
||||
ty::TyGenerator(..) => true,
|
||||
|
||||
ty::TyTuple(ref tys, _) => tys.iter().cloned().any(needs_drop),
|
||||
ty::TyTuple(ref tys) => tys.iter().cloned().any(needs_drop),
|
||||
|
||||
// unions don't have destructors regardless of the child types
|
||||
ty::TyAdt(def, _) if def.is_union() => false,
|
||||
|
@ -125,7 +125,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
|
||||
ty::TyGeneratorWitness(ts) => {
|
||||
stack.extend(ts.skip_binder().iter().cloned().rev());
|
||||
}
|
||||
ty::TyTuple(ts, _) => {
|
||||
ty::TyTuple(ts) => {
|
||||
stack.extend(ts.iter().cloned().rev());
|
||||
}
|
||||
ty::TyFnDef(_, substs) => {
|
||||
|
@ -275,7 +275,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
|
||||
self.compute_const(len);
|
||||
}
|
||||
|
||||
ty::TyTuple(ref tys, _) => {
|
||||
ty::TyTuple(ref tys) => {
|
||||
if let Some((_last, rest)) = tys.split_last() {
|
||||
for elem in rest {
|
||||
self.require_sized(elem, traits::TupleElem);
|
||||
|
@ -340,7 +340,7 @@ impl PrintContext {
|
||||
|
||||
if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
|
||||
let projection_ty = projections[0].ty;
|
||||
if let TyTuple(ref args, _) = substs.type_at(1).sty {
|
||||
if let TyTuple(ref args) = substs.type_at(1).sty {
|
||||
return self.fn_sig(f, args, false, projection_ty);
|
||||
}
|
||||
}
|
||||
@ -1013,7 +1013,7 @@ define_print! {
|
||||
tm.print(f, cx)
|
||||
}
|
||||
TyNever => write!(f, "!"),
|
||||
TyTuple(ref tys, _) => {
|
||||
TyTuple(ref tys) => {
|
||||
write!(f, "(")?;
|
||||
let mut tys = tys.iter();
|
||||
if let Some(&ty) = tys.next() {
|
||||
|
@ -298,7 +298,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> {
|
||||
self.infcx.tcx.intern_tup(&[ty1, ty2], false)
|
||||
self.infcx.tcx.intern_tup(&[ty1, ty2])
|
||||
}
|
||||
|
||||
pub fn t_param(&self, index: u32) -> Ty<'tcx> {
|
||||
@ -604,8 +604,8 @@ fn walk_ty() {
|
||||
let tcx = env.infcx.tcx;
|
||||
let int_ty = tcx.types.isize;
|
||||
let usize_ty = tcx.types.usize;
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false);
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty]);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty]);
|
||||
let walked: Vec<_> = tup2_ty.walk().collect();
|
||||
assert_eq!(walked,
|
||||
[tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty,
|
||||
@ -619,8 +619,8 @@ fn walk_ty_skip_subtree() {
|
||||
let tcx = env.infcx.tcx;
|
||||
let int_ty = tcx.types.isize;
|
||||
let usize_ty = tcx.types.usize;
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false);
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty]);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty]);
|
||||
|
||||
// types we expect to see (in order), plus a boolean saying
|
||||
// whether to skip the subtree.
|
||||
|
@ -32,6 +32,7 @@
|
||||
#![feature(quote)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(slice_patterns)]
|
||||
#![cfg_attr(stage0, feature(never_type))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate syntax;
|
||||
@ -234,11 +235,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||
reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
|
||||
epoch: None,
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(RESOLVE_TRAIT_ON_DEFAULTED_UNIT),
|
||||
reference: "issue #39216 <https://github.com/rust-lang/rust/issues/39216>",
|
||||
epoch: None,
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(MISSING_FRAGMENT_SPECIFIER),
|
||||
reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
|
||||
@ -274,11 +270,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||
reference: "issue #46205 <https://github.com/rust-lang/rust/issues/46205>",
|
||||
epoch: None,
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(COERCE_NEVER),
|
||||
reference: "issue #46325 <https://github.com/rust-lang/rust/issues/46325>",
|
||||
epoch: None,
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(TYVAR_BEHIND_RAW_POINTER),
|
||||
reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
|
||||
@ -315,4 +306,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||
"converted into hard error, see https://github.com/rust-lang/rust/issues/36892");
|
||||
store.register_removed("extra_requirement_in_impl",
|
||||
"converted into hard error, see https://github.com/rust-lang/rust/issues/37166");
|
||||
store.register_removed("coerce_never",
|
||||
"converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
|
||||
store.register_removed("resolve_trait_on_defaulted_unit",
|
||||
"converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
||||
|
||||
let t = cx.tables.expr_ty(&expr);
|
||||
let ty_warned = match t.sty {
|
||||
ty::TyTuple(ref tys, _) if tys.is_empty() => return,
|
||||
ty::TyTuple(ref tys) if tys.is_empty() => return,
|
||||
ty::TyNever => return,
|
||||
ty::TyAdt(def, _) => {
|
||||
if def.variants.is_empty() {
|
||||
|
@ -789,7 +789,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
} else {
|
||||
format!("{}", def.non_enum_variant().fields[field.index()].name)
|
||||
},
|
||||
ty::TyTuple(_, _) => format!("{}", field.index()),
|
||||
ty::TyTuple(_) => format!("{}", field.index()),
|
||||
ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => {
|
||||
self.describe_field_from_ty(&tnm.ty, field)
|
||||
}
|
||||
|
@ -542,7 +542,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||
}),
|
||||
};
|
||||
}
|
||||
ty::TyTuple(tys, _) => {
|
||||
ty::TyTuple(tys) => {
|
||||
return match tys.get(field.index()) {
|
||||
Some(&ty) => Ok(ty),
|
||||
None => Err(FieldAccessError::OutOfRange {
|
||||
|
@ -635,7 +635,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||
let (&output, tuplized_inputs) = inputs_and_output.split_last().unwrap();
|
||||
assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs");
|
||||
let inputs = match tuplized_inputs[0].sty {
|
||||
ty::TyTuple(inputs, _) => inputs,
|
||||
ty::TyTuple(inputs) => inputs,
|
||||
_ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]),
|
||||
};
|
||||
|
||||
|
@ -298,7 +298,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let source_info = self.source_info(span);
|
||||
let bool_ty = self.hir.bool_ty();
|
||||
if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
|
||||
let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty], false);
|
||||
let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
|
||||
let result_value = self.temp(result_tup, span);
|
||||
|
||||
self.cfg.push_assign(block, source_info,
|
||||
|
@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
|
||||
let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
|
||||
i == variant_index || {
|
||||
self.hir.tcx().features().never_type &&
|
||||
self.hir.tcx().features().exhaustive_patterns &&
|
||||
self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
|
||||
}
|
||||
});
|
||||
|
@ -227,7 +227,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
|
||||
let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
|
||||
let tupled_args = Expr {
|
||||
ty: cx.tcx.mk_tup(arg_tys, false),
|
||||
ty: cx.tcx.mk_tup(arg_tys),
|
||||
temp_lifetime,
|
||||
span: expr.span,
|
||||
kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() },
|
||||
|
@ -219,7 +219,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
|
||||
if self.tcx.features().never_type {
|
||||
if self.tcx.features().exhaustive_patterns {
|
||||
self.tcx.is_ty_uninhabited_from(self.module, ty)
|
||||
} else {
|
||||
false
|
||||
@ -245,7 +245,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
||||
substs: &'tcx ty::subst::Substs<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
if self.tcx.features().never_type {
|
||||
if self.tcx.features().exhaustive_patterns {
|
||||
self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs)
|
||||
} else {
|
||||
false
|
||||
@ -694,7 +694,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
// test for details.
|
||||
//
|
||||
// FIXME: currently the only way I know of something can
|
||||
// be a privately-empty enum is when the never_type
|
||||
// be a privately-empty enum is when the exhaustive_patterns
|
||||
// feature flag is not present, so this is only
|
||||
// needed for that case.
|
||||
|
||||
@ -877,7 +877,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
|
||||
fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
|
||||
debug!("constructor_arity({:#?}, {:?})", ctor, ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs, _) => fs.len() as u64,
|
||||
ty::TyTuple(ref fs) => fs.len() as u64,
|
||||
ty::TySlice(..) | ty::TyArray(..) => match *ctor {
|
||||
Slice(length) => length,
|
||||
ConstantValue(_) => 0,
|
||||
@ -901,7 +901,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
{
|
||||
debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
|
||||
ty::TyTuple(ref fs) => fs.into_iter().map(|t| *t).collect(),
|
||||
ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
|
||||
Slice(length) => (0..length).map(|_| ty).collect(),
|
||||
ConstantValue(_) => vec![],
|
||||
|
@ -222,7 +222,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
let pat_ty = self.tables.node_id_to_type(scrut.hir_id);
|
||||
let module = self.tcx.hir.get_module_parent(scrut.id);
|
||||
if inlined_arms.is_empty() {
|
||||
let scrutinee_is_uninhabited = if self.tcx.features().never_type {
|
||||
let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
|
||||
self.tcx.is_ty_uninhabited_from(module, pat_ty)
|
||||
} else {
|
||||
self.conservative_is_uninhabited(pat_ty)
|
||||
|
@ -449,7 +449,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
PatKind::Tuple(ref subpatterns, ddpos) => {
|
||||
let ty = self.tables.node_id_to_type(pat.hir_id);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref tys, _) => {
|
||||
ty::TyTuple(ref tys) => {
|
||||
let subpatterns =
|
||||
subpatterns.iter()
|
||||
.enumerate_and_adjust(tys.len(), ddpos)
|
||||
@ -879,7 +879,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
subpatterns: adt_subpatterns(struct_var.fields.len(), None),
|
||||
}
|
||||
}
|
||||
ty::TyTuple(fields, _) => {
|
||||
ty::TyTuple(fields) => {
|
||||
PatternKind::Leaf {
|
||||
subpatterns: adt_subpatterns(fields.len(), None),
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
// Second argument must be a tuple matching the argument list of sig
|
||||
let snd_ty = real_sig.inputs_and_output[1];
|
||||
match snd_ty.sty {
|
||||
ty::TyTuple(tys, _) if sig.inputs().len() == tys.len() =>
|
||||
ty::TyTuple(tys) if sig.inputs().len() == tys.len() =>
|
||||
if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
|
||||
return Ok(true)
|
||||
},
|
||||
|
@ -32,13 +32,14 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||
#![feature(inclusive_range)]
|
||||
#![feature(macro_vis_matcher)]
|
||||
#![feature(match_default_bindings)]
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(range_contains)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(collection_placement)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(underscore_lifetimes)]
|
||||
#![cfg_attr(stage0, feature(never_type))]
|
||||
|
||||
extern crate arena;
|
||||
#[macro_use]
|
||||
|
@ -281,7 +281,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
self.push_def_path(adt_def.did, output);
|
||||
self.push_type_params(substs, iter::empty(), output);
|
||||
},
|
||||
ty::TyTuple(component_types, _) => {
|
||||
ty::TyTuple(component_types) => {
|
||||
output.push('(');
|
||||
for &component_type in component_types {
|
||||
self.push_type_name(component_type, output);
|
||||
|
@ -312,7 +312,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
substs.upvar_tys(def_id, tcx)
|
||||
)
|
||||
}
|
||||
ty::TyTuple(tys, _) => builder.tuple_like_shim(dest, src, tys.iter().cloned()),
|
||||
ty::TyTuple(tys) => builder.tuple_like_shim(dest, src, tys.iter().cloned()),
|
||||
_ => {
|
||||
bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty)
|
||||
}
|
||||
|
@ -599,7 +599,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
assert!(args.next().is_none());
|
||||
|
||||
let tuple = Place::Local(tuple);
|
||||
let tuple_tys = if let ty::TyTuple(s, _) = tuple.ty(caller_mir, tcx).to_ty(tcx).sty {
|
||||
let tuple_tys = if let ty::TyTuple(s) = tuple.ty(caller_mir, tcx).to_ty(tcx).sty {
|
||||
s
|
||||
} else {
|
||||
bug!("Closure arguments are not passed as a tuple");
|
||||
|
@ -1246,7 +1246,7 @@ impl MirPass for QualifyAndPromoteConstants {
|
||||
tcx.require_lang_item(lang_items::SyncTraitLangItem),
|
||||
cause);
|
||||
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(&err, None);
|
||||
infcx.report_fulfillment_errors(&err, None, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -788,7 +788,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect();
|
||||
self.open_drop_for_tuple(&tys)
|
||||
}
|
||||
ty::TyTuple(tys, _) => {
|
||||
ty::TyTuple(tys) => {
|
||||
self.open_drop_for_tuple(tys)
|
||||
}
|
||||
ty::TyAdt(def, _) if def.is_box() => {
|
||||
|
@ -184,7 +184,7 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>(
|
||||
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety)
|
||||
}
|
||||
|
||||
ty::TyTuple(tys, _) => tys.iter()
|
||||
ty::TyTuple(tys) => tys.iter()
|
||||
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
|
||||
.collect(),
|
||||
|
||||
|
@ -722,7 +722,7 @@ impl<'a, 'tcx> FnType<'tcx> {
|
||||
assert!(!sig.variadic && extra_args.is_empty());
|
||||
|
||||
match sig.inputs().last().unwrap().sty {
|
||||
ty::TyTuple(ref tupled_arguments, _) => {
|
||||
ty::TyTuple(ref tupled_arguments) => {
|
||||
inputs = &sig.inputs()[0..sig.inputs().len() - 1];
|
||||
tupled_arguments
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
|
||||
// return type
|
||||
signature_metadata.push(match signature.output().sty {
|
||||
ty::TyTuple(ref tys, _) if tys.is_empty() => ptr::null_mut(),
|
||||
ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
|
||||
_ => type_metadata(cx, signature.output(), span)
|
||||
});
|
||||
|
||||
@ -533,7 +533,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
ty::TyFloat(_) => {
|
||||
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
|
||||
}
|
||||
ty::TyTuple(ref elements, _) if elements.is_empty() => {
|
||||
ty::TyTuple(ref elements) if elements.is_empty() => {
|
||||
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
|
||||
}
|
||||
ty::TyArray(typ, _) |
|
||||
@ -621,7 +621,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
usage_site_span).finalize(cx)
|
||||
}
|
||||
},
|
||||
ty::TyTuple(ref elements, _) => {
|
||||
ty::TyTuple(ref elements) => {
|
||||
prepare_tuple_metadata(cx,
|
||||
t,
|
||||
&elements[..],
|
||||
@ -731,7 +731,7 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
|
||||
let (name, encoding) = match t.sty {
|
||||
ty::TyNever => ("!", DW_ATE_unsigned),
|
||||
ty::TyTuple(ref elements, _) if elements.is_empty() =>
|
||||
ty::TyTuple(ref elements) if elements.is_empty() =>
|
||||
("()", DW_ATE_unsigned),
|
||||
ty::TyBool => ("bool", DW_ATE_boolean),
|
||||
ty::TyChar => ("char", DW_ATE_unsigned_char),
|
||||
|
@ -312,7 +312,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
|
||||
// Return type -- llvm::DIBuilder wants this at index 0
|
||||
signature.push(match sig.output().sty {
|
||||
ty::TyTuple(ref tys, _) if tys.is_empty() => ptr::null_mut(),
|
||||
ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
|
||||
_ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)
|
||||
});
|
||||
|
||||
@ -351,7 +351,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
}
|
||||
|
||||
if sig.abi == Abi::RustCall && !sig.inputs().is_empty() {
|
||||
if let ty::TyTuple(args, _) = sig.inputs()[sig.inputs().len() - 1].sty {
|
||||
if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty {
|
||||
for &argument_type in args {
|
||||
signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
push_item_name(cx, def.did, qualified, output);
|
||||
push_type_params(cx, substs, output);
|
||||
},
|
||||
ty::TyTuple(component_types, _) => {
|
||||
ty::TyTuple(component_types) => {
|
||||
output.push('(');
|
||||
for &component_type in component_types {
|
||||
push_debuginfo_type_name(cx, component_type, true, output);
|
||||
|
@ -710,7 +710,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
let layout = cx.layout_of(cx.tcx.intern_tup(&[
|
||||
cx.tcx.mk_mut_ptr(cx.tcx.types.u8),
|
||||
cx.tcx.types.i32
|
||||
], false));
|
||||
]));
|
||||
let slot = PlaceRef::alloca(bx, layout, "personalityslot");
|
||||
self.personality_slot = Some(slot);
|
||||
slot
|
||||
|
@ -448,7 +448,7 @@ fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
|
||||
|
||||
let arg_ty = fx.monomorphize(&arg_decl.ty);
|
||||
let tupled_arg_tys = match arg_ty.sty {
|
||||
ty::TyTuple(ref tys, _) => tys,
|
||||
ty::TyTuple(ref tys) => tys,
|
||||
_ => bug!("spread argument isn't a tuple?!")
|
||||
};
|
||||
|
||||
|
@ -399,7 +399,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
lhs.immediate(), rhs.immediate(),
|
||||
lhs.layout.ty);
|
||||
let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
|
||||
let operand_ty = bx.tcx().intern_tup(&[val_ty, bx.tcx().types.bool], false);
|
||||
let operand_ty = bx.tcx().intern_tup(&[val_ty, bx.tcx().types.bool]);
|
||||
let operand = OperandRef {
|
||||
val: result,
|
||||
layout: bx.cx.layout_of(operand_ty)
|
||||
|
@ -1050,7 +1050,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
tcx.types.never
|
||||
},
|
||||
hir::TyTup(ref fields) => {
|
||||
tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t)), false)
|
||||
tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t)))
|
||||
}
|
||||
hir::TyBareFn(ref bf) => {
|
||||
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
|
||||
|
@ -319,7 +319,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let mut expected_len = elements.len();
|
||||
if ddpos.is_some() {
|
||||
// Require known type only when `..` is present
|
||||
if let ty::TyTuple(ref tys, _) =
|
||||
if let ty::TyTuple(ref tys) =
|
||||
self.structurally_resolved_type(pat.span, expected).sty {
|
||||
expected_len = tys.len();
|
||||
}
|
||||
@ -332,7 +332,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
ty::UniverseIndex::ROOT,
|
||||
TypeVariableOrigin::TypeInference(pat.span)));
|
||||
let element_tys = tcx.mk_type_list(element_tys_iter);
|
||||
let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys, false));
|
||||
let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys));
|
||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
||||
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
||||
self.check_pat_walk(elem, &element_tys[i], def_bm, true);
|
||||
|
@ -38,7 +38,7 @@
|
||||
//! expression, `e as U2` is not necessarily so (in fact it will only be valid if
|
||||
//! `U1` coerces to `U2`).
|
||||
|
||||
use super::{Diverges, FnCtxt};
|
||||
use super::FnCtxt;
|
||||
|
||||
use errors::DiagnosticBuilder;
|
||||
use hir::def_id::DefId;
|
||||
@ -59,7 +59,6 @@ use util::common::ErrorReported;
|
||||
pub struct CastCheck<'tcx> {
|
||||
expr: &'tcx hir::Expr,
|
||||
expr_ty: Ty<'tcx>,
|
||||
expr_diverges: Diverges,
|
||||
cast_ty: Ty<'tcx>,
|
||||
cast_span: Span,
|
||||
span: Span,
|
||||
@ -115,7 +114,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::TyTuple(fields, _) => match fields.last() {
|
||||
ty::TyTuple(fields) => match fields.last() {
|
||||
None => Some(PointerKind::Thin),
|
||||
Some(f) => self.pointer_kind(f, span)?
|
||||
},
|
||||
@ -183,7 +182,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||
pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
expr_ty: Ty<'tcx>,
|
||||
expr_diverges: Diverges,
|
||||
cast_ty: Ty<'tcx>,
|
||||
cast_span: Span,
|
||||
span: Span)
|
||||
@ -191,7 +189,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||
let check = CastCheck {
|
||||
expr,
|
||||
expr_ty,
|
||||
expr_diverges,
|
||||
cast_ty,
|
||||
cast_span,
|
||||
span,
|
||||
@ -437,7 +434,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||
let f = self.expr_ty.fn_sig(fcx.tcx);
|
||||
let res = fcx.try_coerce(self.expr,
|
||||
self.expr_ty,
|
||||
self.expr_diverges,
|
||||
fcx.tcx.mk_fn_ptr(f));
|
||||
if !res.is_ok() {
|
||||
return Err(CastError::NonScalar);
|
||||
@ -620,7 +616,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
||||
}
|
||||
|
||||
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
|
||||
fcx.try_coerce(self.expr, self.expr_ty, self.expr_diverges, self.cast_ty).is_ok()
|
||||
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// the `closures` table.
|
||||
let sig = bound_sig.map_bound(|sig| {
|
||||
self.tcx.mk_fn_sig(
|
||||
iter::once(self.tcx.intern_tup(sig.inputs(), false)),
|
||||
iter::once(self.tcx.intern_tup(sig.inputs())),
|
||||
sig.output(),
|
||||
sig.variadic,
|
||||
sig.unsafety,
|
||||
@ -312,7 +312,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
);
|
||||
|
||||
let input_tys = match arg_param_ty.sty {
|
||||
ty::TyTuple(tys, _) => tys.into_iter(),
|
||||
ty::TyTuple(tys) => tys.into_iter(),
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::{Coercion, InferResult, InferOk};
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc::lint;
|
||||
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts};
|
||||
@ -572,7 +571,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
|
||||
// Object safety violations or miscellaneous.
|
||||
Err(err) => {
|
||||
self.report_selection_error(&obligation, &err);
|
||||
self.report_selection_error(&obligation, &err, false);
|
||||
// Treat this like an obligation and follow through
|
||||
// with the unsizing - the lack of a coercion should
|
||||
// be silent, as it causes a type mismatch later.
|
||||
@ -752,27 +751,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn try_coerce(&self,
|
||||
expr: &hir::Expr,
|
||||
expr_ty: Ty<'tcx>,
|
||||
expr_diverges: Diverges,
|
||||
target: Ty<'tcx>)
|
||||
-> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let source = self.resolve_type_vars_with_obligations(expr_ty);
|
||||
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
|
||||
|
||||
// Special-ish case: we can coerce any type `T` into the `!`
|
||||
// type, but only if the source expression diverges.
|
||||
if target.is_never() && expr_diverges.always() {
|
||||
debug!("permit coercion to `!` because expr diverges");
|
||||
if self.can_eq(self.param_env, source, target).is_err() {
|
||||
self.tcx.lint_node(
|
||||
lint::builtin::COERCE_NEVER,
|
||||
expr.id,
|
||||
expr.span,
|
||||
&format!("cannot coerce `{}` to !", source)
|
||||
);
|
||||
return Ok(target);
|
||||
}
|
||||
}
|
||||
|
||||
let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
|
||||
let coerce = Coerce::new(self, cause);
|
||||
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
|
||||
@ -1123,7 +1106,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
|
||||
if self.pushed == 0 {
|
||||
// Special-case the first expression we are coercing.
|
||||
// To be honest, I'm not entirely sure why we do this.
|
||||
fcx.try_coerce(expression, expression_ty, expression_diverges, self.expected_ty)
|
||||
fcx.try_coerce(expression, expression_ty, self.expected_ty)
|
||||
} else {
|
||||
match self.expressions {
|
||||
Expressions::Dynamic(ref exprs) =>
|
||||
|
@ -334,7 +334,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(errors, None);
|
||||
infcx.report_fulfillment_errors(errors, None, false);
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
@ -839,7 +839,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(errors, None);
|
||||
infcx.report_fulfillment_errors(errors, None, false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
-> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
|
||||
let expected = self.resolve_type_vars_with_obligations(expected);
|
||||
|
||||
let e = match self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
|
||||
let e = match self.try_coerce(expr, checked_ty, expected) {
|
||||
Ok(ty) => return (ty, None),
|
||||
Err(e) => e
|
||||
};
|
||||
|
@ -112,7 +112,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
||||
|
||||
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
|
||||
// this could be reached when we get lazy normalization
|
||||
infcx.report_fulfillment_errors(errors, None);
|
||||
infcx.report_fulfillment_errors(errors, None, false);
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
"cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(0)),
|
||||
param(0),
|
||||
param(0)],
|
||||
tcx.intern_tup(&[param(0), tcx.types.bool], false)),
|
||||
tcx.intern_tup(&[param(0), tcx.types.bool])),
|
||||
"load" => (1, vec![tcx.mk_imm_ptr(param(0))],
|
||||
param(0)),
|
||||
"store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
|
||||
@ -281,7 +281,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" =>
|
||||
(1, vec![param(0), param(0)],
|
||||
tcx.intern_tup(&[param(0), tcx.types.bool], false)),
|
||||
tcx.intern_tup(&[param(0), tcx.types.bool])),
|
||||
|
||||
"unchecked_div" | "unchecked_rem" =>
|
||||
(1, vec![param(0), param(0)], param(0)),
|
||||
@ -441,7 +441,7 @@ fn match_intrinsic_type_to_type<'a, 'tcx>(
|
||||
|
||||
match *expected {
|
||||
Void => match t.sty {
|
||||
ty::TyTuple(ref v, _) if v.is_empty() => {},
|
||||
ty::TyTuple(ref v) if v.is_empty() => {},
|
||||
_ => simple_error(&format!("`{}`", t), "()"),
|
||||
},
|
||||
// (The width we pass to LLVM doesn't concern the type checker.)
|
||||
@ -515,7 +515,7 @@ fn match_intrinsic_type_to_type<'a, 'tcx>(
|
||||
}
|
||||
Aggregate(_flatten, ref expected_contents) => {
|
||||
match t.sty {
|
||||
ty::TyTuple(contents, _) => {
|
||||
ty::TyTuple(contents) => {
|
||||
if contents.len() != expected_contents.len() {
|
||||
simple_error(&format!("tuple with length {}", contents.len()),
|
||||
&format!("tuple with length {}", expected_contents.len()));
|
||||
|
@ -873,11 +873,12 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
};
|
||||
|
||||
// All type checking constraints were added, try to fallback unsolved variables.
|
||||
fcx.select_obligations_where_possible();
|
||||
fcx.select_obligations_where_possible(false);
|
||||
let mut fallback_has_occurred = false;
|
||||
for ty in &fcx.unsolved_variables() {
|
||||
fcx.fallback_if_possible(ty);
|
||||
fallback_has_occurred |= fcx.fallback_if_possible(ty);
|
||||
}
|
||||
fcx.select_obligations_where_possible();
|
||||
fcx.select_obligations_where_possible(fallback_has_occurred);
|
||||
|
||||
// Even though coercion casts provide type hints, we check casts after fallback for
|
||||
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
|
||||
@ -1837,7 +1838,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// possible. This can help substantially when there are
|
||||
// indirect dependencies that don't seem worth tracking
|
||||
// precisely.
|
||||
self.select_obligations_where_possible();
|
||||
self.select_obligations_where_possible(false);
|
||||
ty = self.resolve_type_vars_if_possible(&ty);
|
||||
|
||||
debug!("resolve_type_vars_with_obligations: ty={:?}", ty);
|
||||
@ -2154,18 +2155,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
fn resolve_generator_interiors(&self, def_id: DefId) {
|
||||
let mut generators = self.deferred_generator_interiors.borrow_mut();
|
||||
for (body_id, interior) in generators.drain(..) {
|
||||
self.select_obligations_where_possible();
|
||||
self.select_obligations_where_possible(false);
|
||||
generator_interior::resolve_interior(self, def_id, body_id, interior);
|
||||
}
|
||||
}
|
||||
|
||||
// Tries to apply a fallback to `ty` if it is an unsolved variable.
|
||||
// Non-numerics get replaced with ! or () (depending on whether
|
||||
// feature(never_type) is enabled), unconstrained ints with i32,
|
||||
// Non-numerics get replaced with !, unconstrained ints with i32,
|
||||
// unconstrained floats with f64.
|
||||
// Fallback becomes very dubious if we have encountered type-checking errors.
|
||||
// In that case, fallback to TyError.
|
||||
fn fallback_if_possible(&self, ty: Ty<'tcx>) {
|
||||
// The return value indicates whether fallback has occured.
|
||||
fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
|
||||
use rustc::ty::error::UnconstrainedNumeric::Neither;
|
||||
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
|
||||
|
||||
@ -2174,25 +2175,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
_ if self.is_tainted_by_errors() => self.tcx().types.err,
|
||||
UnconstrainedInt => self.tcx.types.i32,
|
||||
UnconstrainedFloat => self.tcx.types.f64,
|
||||
Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
|
||||
Neither => return
|
||||
Neither if self.type_var_diverges(ty) => self.tcx.types.never,
|
||||
Neither => return false,
|
||||
};
|
||||
debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback);
|
||||
self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback);
|
||||
true
|
||||
}
|
||||
|
||||
fn select_all_obligations_or_error(&self) {
|
||||
debug!("select_all_obligations_or_error");
|
||||
if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
|
||||
self.report_fulfillment_errors(&errors, self.inh.body_id);
|
||||
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Select as many obligations as we can at present.
|
||||
fn select_obligations_where_possible(&self) {
|
||||
fn select_obligations_where_possible(&self, fallback_has_occurred: bool) {
|
||||
match self.fulfillment_cx.borrow_mut().select_where_possible(self) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); }
|
||||
Err(errors) => {
|
||||
self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -2438,7 +2442,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
let err_inputs = match tuple_arguments {
|
||||
DontTupleArguments => err_inputs,
|
||||
TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..], false)],
|
||||
TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
|
||||
};
|
||||
|
||||
self.check_argument_types(sp, expr_sp, &err_inputs[..], &[], args_no_rcvr,
|
||||
@ -2531,16 +2535,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let formal_tys = if tuple_arguments == TupleArguments {
|
||||
let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
|
||||
match tuple_type.sty {
|
||||
ty::TyTuple(arg_types, _) if arg_types.len() != args.len() => {
|
||||
ty::TyTuple(arg_types) if arg_types.len() != args.len() => {
|
||||
parameter_count_error(tcx.sess, sp, expr_sp, arg_types.len(), args.len(),
|
||||
"E0057", false, def_span, false);
|
||||
expected_arg_tys = &[];
|
||||
self.err_args(args.len())
|
||||
}
|
||||
ty::TyTuple(arg_types, _) => {
|
||||
ty::TyTuple(arg_types) => {
|
||||
expected_arg_tys = match expected_arg_tys.get(0) {
|
||||
Some(&ty) => match ty.sty {
|
||||
ty::TyTuple(ref tys, _) => &tys,
|
||||
ty::TyTuple(ref tys) => &tys,
|
||||
_ => &[]
|
||||
},
|
||||
None => &[]
|
||||
@ -2596,7 +2600,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// an "opportunistic" vtable resolution of any trait bounds on
|
||||
// the call. This helps coercions.
|
||||
if check_closures {
|
||||
self.select_obligations_where_possible();
|
||||
self.select_obligations_where_possible(false);
|
||||
}
|
||||
|
||||
// For variadic functions, we don't have a declared type for all of
|
||||
@ -3193,7 +3197,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
None
|
||||
}
|
||||
}
|
||||
ty::TyTuple(ref v, _) => {
|
||||
ty::TyTuple(ref v) => {
|
||||
tuple_like = true;
|
||||
v.get(idx.node).cloned()
|
||||
}
|
||||
@ -3945,7 +3949,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let t_cast = self.resolve_type_vars_if_possible(&t_cast);
|
||||
let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
|
||||
let t_cast = self.resolve_type_vars_if_possible(&t_cast);
|
||||
let diverges = self.diverges.get();
|
||||
|
||||
// Eagerly check for some obvious errors.
|
||||
if t_expr.references_error() || t_cast.references_error() {
|
||||
@ -3953,7 +3956,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
} else {
|
||||
// Defer other checks until we're done type checking.
|
||||
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
|
||||
match cast::CastCheck::new(self, e, t_expr, diverges, t_cast, t.span, expr.span) {
|
||||
match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
|
||||
Ok(cast_check) => {
|
||||
deferred_cast_checks.push(cast_check);
|
||||
t_cast
|
||||
@ -4060,7 +4063,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let flds = expected.only_has_type(self).and_then(|ty| {
|
||||
let ty = self.resolve_type_vars_with_obligations(ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref flds, _) => Some(&flds[..]),
|
||||
ty::TyTuple(ref flds) => Some(&flds[..]),
|
||||
_ => None
|
||||
}
|
||||
});
|
||||
@ -4078,7 +4081,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
t
|
||||
});
|
||||
let tuple = tcx.mk_tup(elt_ts_iter, false);
|
||||
let tuple = tcx.mk_tup(elt_ts_iter);
|
||||
if tuple.references_error() {
|
||||
tcx.types.err
|
||||
} else {
|
||||
|
@ -479,7 +479,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
match method {
|
||||
Some(ok) => {
|
||||
let method = self.register_infer_ok_obligations(ok);
|
||||
self.select_obligations_where_possible();
|
||||
self.select_obligations_where_possible(false);
|
||||
|
||||
Ok(method)
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
// Check that all transitive obligations are satisfied.
|
||||
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(&errors, None);
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
}
|
||||
|
||||
// Finally, resolve all regions.
|
||||
|
@ -80,13 +80,14 @@ This API is completely unstable and subject to change.
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(from_ref)]
|
||||
#![feature(match_default_bindings)]
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(option_filter)]
|
||||
#![feature(quote)]
|
||||
#![feature(refcell_replace_swap)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(i128_type)]
|
||||
#![cfg_attr(stage0, feature(never_type))]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate syntax;
|
||||
@ -173,7 +174,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
match fulfill_cx.select_all_or_error(infcx) {
|
||||
Ok(()) => true,
|
||||
Err(errors) => {
|
||||
infcx.report_fulfillment_errors(&errors, None);
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
self.add_constraints_from_mt(current, mt, variance);
|
||||
}
|
||||
|
||||
ty::TyTuple(subtys, _) => {
|
||||
ty::TyTuple(subtys) => {
|
||||
for &subty in subtys {
|
||||
self.add_constraints_from_ty(current, subty, variance);
|
||||
}
|
||||
|
@ -1322,7 +1322,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: boo
|
||||
Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => {
|
||||
assert_eq!(types.len(), 1);
|
||||
let inputs = match types[0].sty {
|
||||
ty::TyTuple(ref tys, _) => tys.iter().map(|t| t.clean(cx)).collect(),
|
||||
ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
|
||||
_ => {
|
||||
return PathParameters::AngleBracketed {
|
||||
lifetimes,
|
||||
@ -1334,7 +1334,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: boo
|
||||
let output = None;
|
||||
// FIXME(#20299) return type comes from a projection now
|
||||
// match types[1].sty {
|
||||
// ty::TyTuple(ref v, _) if v.is_empty() => None, // -> ()
|
||||
// ty::TyTuple(ref v) if v.is_empty() => None, // -> ()
|
||||
// _ => Some(types[1].clean(cx))
|
||||
// };
|
||||
PathParameters::Parenthesized {
|
||||
@ -1377,7 +1377,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
|
||||
// collect any late bound regions
|
||||
let mut late_bounds = vec![];
|
||||
for ty_s in self.input_types().skip(1) {
|
||||
if let ty::TyTuple(ts, _) = ty_s.sty {
|
||||
if let ty::TyTuple(ts) = ty_s.sty {
|
||||
for &ty_s in ts {
|
||||
if let ty::TyRef(ref reg, _) = ty_s.sty {
|
||||
if let &ty::RegionKind::ReLateBound(..) = *reg {
|
||||
@ -2731,7 +2731,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||
Never
|
||||
}
|
||||
}
|
||||
ty::TyTuple(ref t, _) => Tuple(t.clean(cx)),
|
||||
ty::TyTuple(ref t) => Tuple(t.clean(cx)),
|
||||
|
||||
ty::TyProjection(ref data) => data.clean(cx),
|
||||
|
||||
|
@ -234,7 +234,7 @@ impl<'a> From<Cow<'a, str>> for Box<Error> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[stable(feature = "never_type", since = "1.26.0")]
|
||||
impl Error for ! {
|
||||
fn description(&self) -> &str { *self }
|
||||
}
|
||||
|
@ -282,7 +282,7 @@
|
||||
#![feature(macro_reexport)]
|
||||
#![feature(macro_vis_matcher)]
|
||||
#![feature(needs_panic_runtime)]
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(num_bits_bytes)]
|
||||
#![feature(old_wrapping)]
|
||||
#![feature(on_unimplemented)]
|
||||
@ -324,6 +324,7 @@
|
||||
#![feature(doc_spotlight)]
|
||||
#![cfg_attr(test, feature(update_panic_count))]
|
||||
#![cfg_attr(windows, feature(used))]
|
||||
#![cfg_attr(stage0, feature(never_type))]
|
||||
|
||||
#![default_lib_allocator]
|
||||
|
||||
|
@ -79,7 +79,6 @@ mod prim_bool { }
|
||||
/// write:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(never_type)]
|
||||
/// # fn foo() -> u32 {
|
||||
/// let x: ! = {
|
||||
/// return 123
|
||||
@ -131,13 +130,15 @@ mod prim_bool { }
|
||||
/// [`Result<String, !>`] which we can unpack like this:
|
||||
///
|
||||
/// ```ignore (string-from-str-error-type-is-not-never-yet)
|
||||
/// #[feature(exhaustive_patterns)]
|
||||
/// // NOTE: This does not work today!
|
||||
/// let Ok(s) = String::from_str("hello");
|
||||
/// ```
|
||||
///
|
||||
/// Since the [`Err`] variant contains a `!`, it can never occur. So we can exhaustively match on
|
||||
/// [`Result<T, !>`] by just taking the [`Ok`] variant. This illustrates another behaviour of `!` -
|
||||
/// it can be used to "delete" certain enum variants from generic types like `Result`.
|
||||
/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns`
|
||||
/// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the
|
||||
/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain
|
||||
/// enum variants from generic types like `Result`.
|
||||
///
|
||||
/// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str
|
||||
/// [`Result<String, !>`]: result/enum.Result.html
|
||||
@ -154,7 +155,6 @@ mod prim_bool { }
|
||||
/// for example:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(never_type)]
|
||||
/// # use std::fmt;
|
||||
/// # trait Debug {
|
||||
/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result;
|
||||
@ -192,7 +192,6 @@ mod prim_bool { }
|
||||
/// [`Default`]: default/trait.Default.html
|
||||
/// [`default()`]: default/trait.Default.html#tymethod.default
|
||||
///
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
mod prim_never { }
|
||||
|
||||
#[doc(primitive = "char")]
|
||||
|
@ -286,8 +286,8 @@ declare_features! (
|
||||
// Allows `impl Trait` in function arguments.
|
||||
(active, universal_impl_trait, "1.23.0", Some(34511), None),
|
||||
|
||||
// The `!` type
|
||||
(active, never_type, "1.13.0", Some(35121), None),
|
||||
// Allows exhaustive pattern matching on types that contain uninhabited types.
|
||||
(active, exhaustive_patterns, "1.13.0", None, None),
|
||||
|
||||
// Allows all literals in attribute lists and values of key-value pairs.
|
||||
(active, attr_literals, "1.13.0", Some(34981), None),
|
||||
@ -1566,10 +1566,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
ast::TyKind::BareFn(ref bare_fn_ty) => {
|
||||
self.check_abi(bare_fn_ty.abi, ty.span);
|
||||
}
|
||||
ast::TyKind::Never => {
|
||||
gate_feature_post!(&self, never_type, ty.span,
|
||||
"The `!` type is experimental");
|
||||
},
|
||||
ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => {
|
||||
gate_feature_post!(&self, dyn_trait, ty.span,
|
||||
"`dyn Trait` syntax is unstable");
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
// Test that we can't pass other types for !
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
fn foo(x: !) -> ! {
|
||||
x
|
||||
}
|
||||
|
@ -8,15 +8,11 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
fn foo(x: usize, y: !, z: usize) { }
|
||||
|
||||
#[deny(coerce_never)]
|
||||
fn cast_a() {
|
||||
let y = {return; 22} as !;
|
||||
//~^ ERROR cannot coerce `i32` to !
|
||||
//~| hard error
|
||||
//~^ ERROR non-primitive cast
|
||||
}
|
||||
|
||||
fn cast_b() {
|
||||
|
@ -8,18 +8,11 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![deny(coerce_never)]
|
||||
|
||||
fn foo(x: usize, y: !, z: usize) { }
|
||||
|
||||
fn call_foo_a() {
|
||||
// FIXME(#40800) -- accepted because divergence happens **before**
|
||||
// the coercion to `!`, but within same expression. Not clear that
|
||||
// these are the rules we want.
|
||||
foo(return, 22, 44);
|
||||
//~^ ERROR cannot coerce `{integer}` to !
|
||||
//~| hard error
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn call_foo_b() {
|
||||
@ -39,8 +32,7 @@ fn call_foo_d() {
|
||||
let b = 22;
|
||||
let c = 44;
|
||||
foo(a, b, c); // ... and hence a reference to `a` is expected to diverge.
|
||||
//~^ ERROR cannot coerce `{integer}` to !
|
||||
//~| hard error
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn call_foo_e() {
|
||||
@ -80,8 +72,7 @@ fn tuple_a() {
|
||||
fn tuple_b() {
|
||||
// Divergence happens before coercion: OK
|
||||
let x: (usize, !, usize) = (return, 44, 66);
|
||||
//~^ ERROR cannot coerce `{integer}` to !
|
||||
//~| hard error
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn tuple_c() {
|
||||
|
@ -25,14 +25,17 @@ trait ImplementedForUnitButNotNever {}
|
||||
impl ImplementedForUnitButNotNever for () {}
|
||||
|
||||
fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
|
||||
//~^ NOTE required by `foo`
|
||||
|
||||
fn smeg() {
|
||||
let _x = return;
|
||||
foo(_x);
|
||||
//~^ ERROR code relies on type
|
||||
//~| WARNING previously accepted
|
||||
//~^ ERROR the trait bound
|
||||
//~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented
|
||||
//~| NOTE the trait is implemented for `()`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
smeg();
|
||||
}
|
||||
|
@ -8,12 +8,10 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deny(coerce_never)]
|
||||
fn assert_sizeof() -> ! {
|
||||
unsafe {
|
||||
::std::mem::transmute::<f64, [u8; 8]>(panic!())
|
||||
//~^ ERROR cannot coerce `[u8; 8]` to !
|
||||
//~| hard error
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
// error-pattern:reached recursion limit
|
||||
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
|
||||
struct Foo<'a, T: 'a> {
|
||||
ph: std::marker::PhantomData<T>,
|
||||
|
@ -8,8 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
fn main() {
|
||||
let val: ! = loop { break break; };
|
||||
//~^ ERROR mismatched types
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
|
||||
mod private {
|
||||
pub struct Private {
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
// Test that an assignment of type ! makes the rest of the block dead code.
|
||||
|
||||
#![feature(never_type, rustc_attrs)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![warn(unused)]
|
||||
|
||||
#[rustc_error]
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
// Test that we can't use another type in place of !
|
||||
|
||||
#![feature(never_type)]
|
||||
#![deny(warnings)]
|
||||
|
||||
fn main() {
|
||||
|
@ -8,8 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//#![feature(never_type)]
|
||||
|
||||
struct R<'a> {
|
||||
r: &'a R<'a>,
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
|
||||
mod foo {
|
||||
pub struct SecretlyEmpty {
|
||||
|
@ -11,7 +11,7 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
mod foo {
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
fn main() {
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(never_type, rustc_attrs)]
|
||||
#![feature(exhaustive_patterns, rustc_attrs)]
|
||||
#![warn(unreachable_code)]
|
||||
#![warn(unreachable_patterns)]
|
||||
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
// Test that a variable of type ! can coerce to another type.
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
// error-pattern:explicit
|
||||
fn main() {
|
||||
let x: ! = panic!();
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
// error-pattern:wowzers!
|
||||
|
||||
#![feature(never_type)]
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
fn foo(x: !) -> ! {
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
// Test that we can explicitly cast ! to another type
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
// error-pattern:explicit
|
||||
fn main() {
|
||||
let x: ! = panic!();
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
// Test that we can use ! as an associated type.
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
// error-pattern:kapow!
|
||||
|
||||
trait Foo {
|
||||
|
@ -12,8 +12,6 @@
|
||||
|
||||
// error-pattern:oh no!
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
struct Wub;
|
||||
|
||||
impl PartialEq<!> for Wub {
|
||||
|
@ -14,8 +14,6 @@
|
||||
// These represent current behavior, but are pretty dubious. I would
|
||||
// like to revisit these and potentially change them. --nmatsakis
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
trait BadDefault {
|
||||
fn default() -> Self;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(slice_patterns)]
|
||||
#![allow(unreachable_patterns)]
|
||||
#![allow(unreachable_code)]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user