Rollup merge of #39009 - canndrew:default-unit-warnings, r=nikomatsakis
Add warning for () to ! switch With feature(never_type) enabled diverging type variables will default to `!` instead of `()`. This can cause breakages where a trait is resolved on such a type. This PR emits a future-compatibility warning when it sees this happen.
This commit is contained in:
commit
4f8ce9efb9
@ -192,6 +192,13 @@ declare_lint! {
|
||||
"lifetimes or labels named `'_` were erroneously allowed"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
|
||||
Warn,
|
||||
"attempt to resolve a trait on an expression whose type cannot be inferred but which \
|
||||
currently defaults to ()"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub SAFE_EXTERN_STATICS,
|
||||
Warn,
|
||||
@ -272,6 +279,7 @@ impl LintPass for HardwiredLints {
|
||||
SUPER_OR_SELF_IN_GLOBAL_PATH,
|
||||
HR_LIFETIME_IN_ASSOC_TYPE,
|
||||
LIFETIME_UNDERSCORE,
|
||||
RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
|
||||
SAFE_EXTERN_STATICS,
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
EXTRA_REQUIREMENT_IN_IMPL,
|
||||
|
@ -1199,7 +1199,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) {
|
||||
|
@ -163,7 +163,7 @@ impl<'tcx> Rvalue<'tcx> {
|
||||
let lhs_ty = lhs.ty(mir, tcx);
|
||||
let rhs_ty = rhs.ty(mir, tcx);
|
||||
let ty = op.ty(tcx, lhs_ty, rhs_ty);
|
||||
let ty = tcx.intern_tup(&[ty, tcx.types.bool]);
|
||||
let ty = tcx.intern_tup(&[ty, tcx.types.bool], false);
|
||||
Some(ty)
|
||||
}
|
||||
&Rvalue::UnaryOp(_, ref operand) => {
|
||||
@ -184,7 +184,8 @@ impl<'tcx> Rvalue<'tcx> {
|
||||
}
|
||||
AggregateKind::Tuple => {
|
||||
Some(tcx.mk_tup(
|
||||
ops.iter().map(|op| op.ty(mir, tcx))
|
||||
ops.iter().map(|op| op.ty(mir, tcx)),
|
||||
false
|
||||
))
|
||||
}
|
||||
AggregateKind::Adt(def, _, substs, _) => {
|
||||
|
@ -52,6 +52,7 @@ use std::mem;
|
||||
use std::rc::Rc;
|
||||
use syntax::abi::Abi;
|
||||
use hir;
|
||||
use lint;
|
||||
use util::nodemap::FxHashMap;
|
||||
|
||||
struct InferredObligationsSnapshotVecDelegate<'tcx> {
|
||||
@ -407,19 +408,62 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
debug!("select({:?})", obligation);
|
||||
assert!(!obligation.predicate.has_escaping_regions());
|
||||
|
||||
let tcx = self.tcx();
|
||||
let dep_node = obligation.predicate.dep_node();
|
||||
let _task = self.tcx().dep_graph.in_task(dep_node);
|
||||
let _task = tcx.dep_graph.in_task(dep_node);
|
||||
|
||||
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
|
||||
match self.candidate_from_obligation(&stack)? {
|
||||
None => Ok(None),
|
||||
let ret = match self.candidate_from_obligation(&stack)? {
|
||||
None => None,
|
||||
Some(candidate) => {
|
||||
let mut candidate = self.confirm_candidate(obligation, candidate)?;
|
||||
let inferred_obligations = (*self.inferred_obligations).into_iter().cloned();
|
||||
candidate.nested_obligations_mut().extend(inferred_obligations);
|
||||
Ok(Some(candidate))
|
||||
Some(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 mut 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.sess.add_lint(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)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -1744,7 +1788,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
|
||||
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) => Never,
|
||||
|
||||
ty::TyTuple(tys) => {
|
||||
ty::TyTuple(tys, _) => {
|
||||
Where(ty::Binder(tys.last().into_iter().cloned().collect()))
|
||||
}
|
||||
|
||||
@ -1752,7 +1796,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
let sized_crit = def.sized_constraint(self.tcx());
|
||||
// (*) binder moved here
|
||||
Where(ty::Binder(match sized_crit.sty {
|
||||
ty::TyTuple(tys) => tys.to_vec().subst(self.tcx(), substs),
|
||||
ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs),
|
||||
ty::TyBool => vec![],
|
||||
_ => vec![sized_crit.subst(self.tcx(), substs)]
|
||||
}))
|
||||
@ -1799,7 +1843,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()))
|
||||
}
|
||||
@ -1874,7 +1918,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()
|
||||
}
|
||||
|
@ -489,7 +489,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()),
|
||||
self.intern_tup(sig.skip_binder().inputs(), false),
|
||||
};
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: fn_trait_def_id,
|
||||
|
@ -201,7 +201,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
|ty| tc_ty(tcx, &ty, cache))
|
||||
}
|
||||
|
||||
ty::TyTuple(ref tys) => {
|
||||
ty::TyTuple(ref tys, _) => {
|
||||
TypeContents::union(&tys[..],
|
||||
|ty| tc_ty(tcx, *ty, cache))
|
||||
}
|
||||
|
@ -1384,23 +1384,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
self.mk_ty(TySlice(ty))
|
||||
}
|
||||
|
||||
pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
|
||||
self.mk_ty(TyTuple(self.intern_type_list(ts)))
|
||||
pub fn intern_tup(self, ts: &[Ty<'tcx>], defaulted: bool) -> Ty<'tcx> {
|
||||
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_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_nil(self) -> Ty<'tcx> {
|
||||
self.intern_tup(&[])
|
||||
self.intern_tup(&[], false)
|
||||
}
|
||||
|
||||
pub fn mk_diverging_default(self) -> Ty<'tcx> {
|
||||
if self.sess.features.borrow().never_type {
|
||||
self.types.never
|
||||
} else {
|
||||
self.mk_nil()
|
||||
self.intern_tup(&[], true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,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::TyArray(_, n) => format!("array of {} elements", n),
|
||||
@ -209,7 +209,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
|
||||
|p| format!("trait {}", tcx.item_path_str(p.def_id())))
|
||||
}
|
||||
ty::TyClosure(..) => "closure".to_string(),
|
||||
ty::TyTuple(_) => "tuple".to_string(),
|
||||
ty::TyTuple(..) => "tuple".to_string(),
|
||||
ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
|
||||
ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),
|
||||
ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(),
|
||||
|
@ -72,7 +72,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
Some(ClosureSimplifiedType(def_id))
|
||||
}
|
||||
ty::TyNever => Some(NeverSimplifiedType),
|
||||
ty::TyTuple(ref tys) => {
|
||||
ty::TyTuple(ref tys, _) => {
|
||||
Some(TupleSimplifiedType(tys.len()))
|
||||
}
|
||||
ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {
|
||||
|
@ -151,7 +151,7 @@ impl FlagComputation {
|
||||
self.add_ty(m.ty);
|
||||
}
|
||||
|
||||
&ty::TyTuple(ref ts) => {
|
||||
&ty::TyTuple(ref ts, _) => {
|
||||
self.add_tys(&ts[..]);
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,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)
|
||||
}))
|
||||
|
@ -319,9 +319,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, _) => Some(def_id),
|
||||
|
@ -791,7 +791,7 @@ impl<'a, 'gcx, 'tcx> Struct {
|
||||
Some(&variant.memory_index[..]))
|
||||
}
|
||||
// Can we use one of the fields in this tuple?
|
||||
(&Univariant { ref variant, .. }, &ty::TyTuple(tys)) => {
|
||||
(&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => {
|
||||
Struct::non_zero_field_paths(infcx, tys.iter().cloned(),
|
||||
Some(&variant.memory_index[..]))
|
||||
}
|
||||
@ -1157,7 +1157,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
Univariant { variant: st, non_zero: false }
|
||||
}
|
||||
|
||||
ty::TyTuple(tys) => {
|
||||
ty::TyTuple(tys, _) => {
|
||||
// FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
|
||||
// See the univariant case below to learn how.
|
||||
let st = Struct::new(dl,
|
||||
|
@ -197,6 +197,17 @@ impl AssociatedItem {
|
||||
AssociatedKind::Type => Def::AssociatedTy(self.def_id),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests whether the associated item admits a non-trivial implementation
|
||||
/// for !
|
||||
pub fn relevant_for_never<'tcx>(&self) -> bool {
|
||||
match self.kind {
|
||||
AssociatedKind::Const => true,
|
||||
AssociatedKind::Type => true,
|
||||
// FIXME(canndrew): Be more thorough here, check if any argument is uninhabited.
|
||||
AssociatedKind::Method => !self.method_has_self_argument,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable)]
|
||||
@ -1603,7 +1614,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
_ if tys.references_error() => tcx.types.err,
|
||||
0 => tcx.types.bool,
|
||||
1 => tys[0],
|
||||
_ => tcx.intern_tup(&tys[..])
|
||||
_ => tcx.intern_tup(&tys[..], false)
|
||||
};
|
||||
|
||||
let old = tcx.adt_sized_constraint.borrow().get(&self.did).cloned();
|
||||
@ -1638,7 +1649,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, stack, ty)
|
||||
@ -1652,7 +1663,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
.subst(tcx, substs);
|
||||
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
|
||||
ty, adt_ty);
|
||||
if let ty::TyTuple(ref tys) = adt_ty.sty {
|
||||
if let ty::TyTuple(ref tys, _) = adt_ty.sty {
|
||||
tys.iter().flat_map(|ty| {
|
||||
self.sized_constraint_for_ty(tcx, stack, ty)
|
||||
}).collect()
|
||||
@ -2010,6 +2021,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_relevant_for_never(self, did: DefId) -> bool {
|
||||
self.associated_items(did).any(|item| {
|
||||
item.relevant_for_never()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
|
||||
self.custom_coerce_unsized_kinds.memoize(did, || {
|
||||
let (kind, src) = if did.krate != LOCAL_CRATE {
|
||||
|
@ -447,10 +447,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||
Ok(tcx.mk_slice(t))
|
||||
}
|
||||
|
||||
(&ty::TyTuple(as_), &ty::TyTuple(bs)) =>
|
||||
(&ty::TyTuple(as_, a_defaulted), &ty::TyTuple(bs, b_defaulted)) =>
|
||||
{
|
||||
if as_.len() == bs.len() {
|
||||
Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)))?)
|
||||
let defaulted = a_defaulted || b_defaulted;
|
||||
Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)), defaulted)?)
|
||||
} else if !(as_.is_empty() || bs.is_empty()) {
|
||||
Err(TypeError::TupleSize(
|
||||
expected_found(relation, &as_.len(), &bs.len())))
|
||||
|
@ -474,7 +474,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) => ty::TyTuple(ts.fold_with(folder)),
|
||||
ty::TyTuple(ts, defaulted) => ty::TyTuple(ts.fold_with(folder), defaulted),
|
||||
ty::TyFnDef(def_id, substs, f) => {
|
||||
ty::TyFnDef(def_id,
|
||||
substs.fold_with(folder),
|
||||
@ -511,7 +511,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, ref f) => {
|
||||
substs.visit_with(visitor) || f.visit_with(visitor)
|
||||
}
|
||||
|
@ -151,7 +151,11 @@ pub enum TypeVariants<'tcx> {
|
||||
TyNever,
|
||||
|
||||
/// A tuple type. For example, `(i32, bool)`.
|
||||
TyTuple(&'tcx Slice<Ty<'tcx>>),
|
||||
/// 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),
|
||||
|
||||
/// The projection of an associated type. For example,
|
||||
/// `<T as Trait<..>>::N`.
|
||||
@ -961,7 +965,7 @@ 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
|
||||
}
|
||||
}
|
||||
@ -973,6 +977,15 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether a type is visibly uninhabited from a particular module.
|
||||
/// # Example
|
||||
/// ```rust
|
||||
@ -1355,7 +1368,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||
TySlice(_) |
|
||||
TyRawPtr(_) |
|
||||
TyNever |
|
||||
TyTuple(_) |
|
||||
TyTuple(..) |
|
||||
TyParam(_) |
|
||||
TyInfer(_) |
|
||||
TyError => {
|
||||
|
@ -207,7 +207,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
// Don't use `struct_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
|
||||
}
|
||||
}
|
||||
@ -466,8 +466,9 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
|
||||
self.def_id(d);
|
||||
}
|
||||
}
|
||||
TyTuple(tys) => {
|
||||
TyTuple(tys, defaulted) => {
|
||||
self.hash(tys.len());
|
||||
self.hash(defaulted);
|
||||
}
|
||||
TyParam(p) => {
|
||||
self.hash(p.idx);
|
||||
@ -675,7 +676,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
seen: &mut Vec<Ty<'tcx>>, ty: Ty<'tcx>)
|
||||
-> Representability {
|
||||
match ty.sty {
|
||||
TyTuple(ref ts) => {
|
||||
TyTuple(ref ts, _) => {
|
||||
find_nonrepresentable(tcx, sp, seen, ts.iter().cloned())
|
||||
}
|
||||
// Fixed-length vectors.
|
||||
|
@ -112,7 +112,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
|
||||
ty::TyClosure(_, ref substs) => {
|
||||
stack.extend(substs.substs.types().rev());
|
||||
}
|
||||
ty::TyTuple(ts) => {
|
||||
ty::TyTuple(ts, _) => {
|
||||
stack.extend(ts.iter().cloned().rev());
|
||||
}
|
||||
ty::TyFnDef(_, substs, ref ft) => {
|
||||
|
@ -315,7 +315,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
|
||||
self.require_sized(subty, traits::SliceOrArrayElem);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -156,7 +156,7 @@ pub fn parameterized(f: &mut fmt::Formatter,
|
||||
|
||||
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 fn_sig(f, args, false, projection_ty);
|
||||
}
|
||||
}
|
||||
@ -724,7 +724,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
|
||||
write!(f, "{}", tm)
|
||||
}
|
||||
TyNever => write!(f, "!"),
|
||||
TyTuple(ref tys) => {
|
||||
TyTuple(ref tys, _) => {
|
||||
write!(f, "(")?;
|
||||
let mut tys = tys.iter();
|
||||
if let Some(&ty) = tys.next() {
|
||||
|
@ -423,7 +423,7 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>,
|
||||
};
|
||||
|
||||
match parent_ty.sty {
|
||||
ty::TyTuple(ref v) => {
|
||||
ty::TyTuple(ref v, _) => {
|
||||
let tuple_idx = match *origin_field_name {
|
||||
mc::PositionalField(tuple_idx) => tuple_idx,
|
||||
mc::NamedField(_) =>
|
||||
|
@ -713,7 +713,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx).collect();
|
||||
self.open_drop_for_tuple(c, &tys)
|
||||
}
|
||||
ty::TyTuple(tys) => {
|
||||
ty::TyTuple(tys, _) => {
|
||||
self.open_drop_for_tuple(c, tys)
|
||||
}
|
||||
ty::TyAdt(def, _) if def.is_box() => {
|
||||
|
@ -721,7 +721,7 @@ fn pat_constructors(_cx: &mut MatchCheckCtxt,
|
||||
fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize {
|
||||
debug!("constructor_arity({:?}, {:?})", ctor, ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs) => fs.len(),
|
||||
ty::TyTuple(ref fs, _) => fs.len(),
|
||||
ty::TySlice(..) | ty::TyArray(..) => match *ctor {
|
||||
Slice(length) => length,
|
||||
ConstantValue(_) => 0,
|
||||
@ -745,7 +745,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) => repeat(ty).take(length).collect(),
|
||||
ConstantValue(_) => vec![],
|
||||
|
@ -342,7 +342,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
|
||||
PatKind::Tuple(ref subpatterns, ddpos) => {
|
||||
let ty = self.tables.node_id_to_type(pat.id);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref tys) => {
|
||||
ty::TyTuple(ref tys, _) => {
|
||||
let subpatterns =
|
||||
subpatterns.iter()
|
||||
.enumerate_and_adjust(tys.len(), ddpos)
|
||||
|
@ -280,7 +280,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])
|
||||
self.infcx.tcx.intern_tup(&[ty1, ty2], false)
|
||||
}
|
||||
|
||||
pub fn t_param(&self, index: u32) -> Ty<'tcx> {
|
||||
@ -803,8 +803,8 @@ fn walk_ty() {
|
||||
let tcx = env.infcx.tcx;
|
||||
let int_ty = tcx.types.isize;
|
||||
let uint_ty = tcx.types.usize;
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]);
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false);
|
||||
let walked: Vec<_> = tup2_ty.walk().collect();
|
||||
assert_eq!(walked,
|
||||
[tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty,
|
||||
@ -818,8 +818,8 @@ fn walk_ty_skip_subtree() {
|
||||
let tcx = env.infcx.tcx;
|
||||
let int_ty = tcx.types.isize;
|
||||
let uint_ty = tcx.types.usize;
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]);
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false);
|
||||
|
||||
// types we expect to see (in order), plus a boolean saying
|
||||
// whether to skip the subtree.
|
||||
|
@ -219,6 +219,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||
id: LintId::of(LIFETIME_UNDERSCORE),
|
||||
reference: "issue #36892 <https://github.com/rust-lang/rust/issues/36892>",
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(RESOLVE_TRAIT_ON_DEFAULTED_UNIT),
|
||||
reference: "issue #39216 <https://github.com/rust-lang/rust/issues/39216>",
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(SAFE_EXTERN_STATICS),
|
||||
reference: "issue #36247 <https://github.com/rust-lang/rust/issues/35112>",
|
||||
|
@ -532,7 +532,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
consider using a `*const libc::c_char`")
|
||||
}
|
||||
|
||||
ty::TyTuple(_) => {
|
||||
ty::TyTuple(..) => {
|
||||
FfiUnsafe("found Rust tuple type in foreign module; \
|
||||
consider using a struct instead")
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
||||
|
||||
let t = cx.tables.expr_ty(&expr);
|
||||
let 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::TyBool => return,
|
||||
ty::TyAdt(def, _) => {
|
||||
|
@ -257,7 +257,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]);
|
||||
let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty], false);
|
||||
let result_value = self.temp(result_tup);
|
||||
|
||||
self.cfg.push_assign(block, source_info,
|
||||
|
@ -282,7 +282,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 {
|
||||
|
@ -1440,7 +1440,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
|
||||
}.lower(self.tcx));
|
||||
}
|
||||
}
|
||||
ty::TyTuple(_) => {}
|
||||
ty::TyTuple(..) => {}
|
||||
_ => span_bug!(ex.span,
|
||||
"Expected struct or tuple type, found {:?}",
|
||||
ty),
|
||||
|
@ -367,7 +367,7 @@ impl FnType {
|
||||
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[..]
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
|
||||
monomorphize::field_ty(cx.tcx(), substs, f)
|
||||
}).collect::<Vec<_>>()
|
||||
},
|
||||
ty::TyTuple(fields) => fields.to_vec(),
|
||||
ty::TyTuple(fields, _) => fields.to_vec(),
|
||||
ty::TyClosure(def_id, substs) => {
|
||||
if variant_index > 0 { bug!("{} is a closure, which only has one variant", t);}
|
||||
substs.upvar_tys(def_id, cx.tcx()).collect()
|
||||
|
@ -485,7 +485,7 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||
}
|
||||
};
|
||||
let sig = tcx.erase_late_bound_regions_and_normalize(sig);
|
||||
let tuple_input_ty = tcx.intern_tup(sig.inputs());
|
||||
let tuple_input_ty = tcx.intern_tup(sig.inputs(), false);
|
||||
let sig = tcx.mk_fn_sig(
|
||||
[bare_fn_ty_maybe_ref, tuple_input_ty].iter().cloned(),
|
||||
sig.output(),
|
||||
|
@ -823,7 +823,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
||||
output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type)));
|
||||
}
|
||||
}
|
||||
ty::TyTuple(args) => {
|
||||
ty::TyTuple(args, _) => {
|
||||
for arg in args {
|
||||
let arg = glue::get_drop_glue_type(scx, arg);
|
||||
if scx.type_needs_drop(arg) {
|
||||
|
@ -93,7 +93,7 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
|
||||
}
|
||||
}))
|
||||
}
|
||||
ty::TyTuple(tys) => {
|
||||
ty::TyTuple(tys, _) => {
|
||||
if tys.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'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)
|
||||
});
|
||||
|
||||
@ -528,7 +528,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'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, len) => {
|
||||
@ -603,7 +603,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
usage_site_span).finalize(cx)
|
||||
}
|
||||
},
|
||||
ty::TyTuple(ref elements) => {
|
||||
ty::TyTuple(ref elements, _) => {
|
||||
prepare_tuple_metadata(cx,
|
||||
t,
|
||||
&elements[..],
|
||||
@ -706,7 +706,7 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'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),
|
||||
|
@ -295,7 +295,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'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)
|
||||
});
|
||||
|
||||
@ -311,7 +311,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
if 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));
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'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);
|
||||
|
@ -442,7 +442,7 @@ fn drop_structural_ty<'a, 'tcx>(
|
||||
cx = tvec::slice_for_each(&cx, ptr.llval, unit_ty, ptr.llextra,
|
||||
|bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty)));
|
||||
}
|
||||
ty::TyTuple(ref args) => {
|
||||
ty::TyTuple(ref args, _) => {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
let llfld_a = ptr.trans_field_ptr(&cx, i);
|
||||
drop_ty(&cx, LvalueRef::new_sized_ty(llfld_a, *arg));
|
||||
|
@ -695,7 +695,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
let tuple = self.trans_operand(bcx, operand);
|
||||
|
||||
let arg_types = match tuple.ty.sty {
|
||||
ty::TyTuple(ref tys) => tys,
|
||||
ty::TyTuple(ref tys, _) => tys,
|
||||
_ => span_bug!(self.mir.span,
|
||||
"bad final argument to \"rust-call\" fn {:?}", tuple.ty)
|
||||
};
|
||||
|
@ -735,7 +735,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
let rhs = self.const_operand(rhs, span)?;
|
||||
let ty = lhs.ty;
|
||||
let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
|
||||
let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool]);
|
||||
let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
|
||||
let (lhs, rhs) = (lhs.llval, rhs.llval);
|
||||
assert!(!ty.is_fp());
|
||||
|
||||
|
@ -384,7 +384,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
||||
// individual LLVM function arguments.
|
||||
|
||||
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?!")
|
||||
};
|
||||
|
||||
|
@ -402,7 +402,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
lhs.immediate(), rhs.immediate(),
|
||||
lhs.ty);
|
||||
let val_ty = op.ty(bcx.tcx(), lhs.ty, rhs.ty);
|
||||
let operand_ty = bcx.tcx().intern_tup(&[val_ty, bcx.tcx().types.bool]);
|
||||
let operand_ty = bcx.tcx().intern_tup(&[val_ty, bcx.tcx().types.bool], false);
|
||||
let operand = OperandRef {
|
||||
val: result,
|
||||
ty: operand_ty
|
||||
|
@ -409,7 +409,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);
|
||||
|
@ -74,7 +74,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
|
||||
Type::array(&llty, size)
|
||||
}
|
||||
|
||||
ty::TyTuple(ref tys) if tys.is_empty() => {
|
||||
ty::TyTuple(ref tys, _) if tys.is_empty() => {
|
||||
Type::nil(cx)
|
||||
}
|
||||
|
||||
@ -276,7 +276,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
|
||||
let sig = cx.tcx().erase_late_bound_regions_and_normalize(&f.sig);
|
||||
FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
|
||||
}
|
||||
ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
|
||||
ty::TyTuple(ref tys, _) if tys.is_empty() => Type::nil(cx),
|
||||
ty::TyTuple(..) => {
|
||||
adt::type_of(cx, t)
|
||||
}
|
||||
|
@ -421,7 +421,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
span: output_span
|
||||
};
|
||||
|
||||
(self.tcx().mk_ty(ty::TyTuple(inputs)), output_binding)
|
||||
(self.tcx().mk_ty(ty::TyTuple(inputs, false)), output_binding)
|
||||
}
|
||||
|
||||
/// Instantiates the path for the given trait reference, assuming that it's
|
||||
@ -1170,7 +1170,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)))
|
||||
tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t)), false)
|
||||
}
|
||||
hir::TyBareFn(ref bf) => {
|
||||
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
|
||||
|
@ -164,7 +164,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();
|
||||
}
|
||||
@ -176,7 +176,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// from all tuple elements isn't trivial.
|
||||
TypeVariableOrigin::TypeInference(pat.span)));
|
||||
let element_tys = tcx.mk_type_list(element_tys_iter);
|
||||
let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys));
|
||||
let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys, false));
|
||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
||||
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
||||
self.check_pat(elem, &element_tys[i]);
|
||||
|
@ -89,7 +89,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// Tuple up the arguments and insert the resulting function type into
|
||||
// the `closures` table.
|
||||
fn_ty.sig.0 = self.tcx.mk_fn_sig(
|
||||
iter::once(self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs())),
|
||||
iter::once(self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs(), false)),
|
||||
fn_ty.sig.skip_binder().output(),
|
||||
fn_ty.sig.variadic()
|
||||
);
|
||||
@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
arg_param_ty);
|
||||
|
||||
let input_tys = match arg_param_ty.sty {
|
||||
ty::TyTuple(tys) => tys.into_iter(),
|
||||
ty::TyTuple(tys, _) => tys.into_iter(),
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
ty::TyTuple(tys) => {
|
||||
ty::TyTuple(tys, _) => {
|
||||
for ty in tys {
|
||||
iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
|
||||
"cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)),
|
||||
param(ccx, 0),
|
||||
param(ccx, 0)],
|
||||
tcx.intern_tup(&[param(ccx, 0), tcx.types.bool])),
|
||||
tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
|
||||
"load" => (1, vec![tcx.mk_imm_ptr(param(ccx, 0))],
|
||||
param(ccx, 0)),
|
||||
"store" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)],
|
||||
@ -272,7 +272,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
|
||||
|
||||
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" =>
|
||||
(1, vec![param(ccx, 0), param(ccx, 0)],
|
||||
tcx.intern_tup(&[param(ccx, 0), tcx.types.bool])),
|
||||
tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
|
||||
|
||||
"unchecked_div" | "unchecked_rem" =>
|
||||
(1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
|
||||
@ -420,7 +420,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
|
||||
|
||||
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.)
|
||||
@ -494,7 +494,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
|
||||
}
|
||||
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()));
|
||||
|
@ -1947,7 +1947,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
/// Apply "fallbacks" to some types
|
||||
/// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64.
|
||||
/// unconstrained types get replaced with ! or () (depending on whether
|
||||
/// feature(never_type) is enabled), unconstrained ints with i32, and
|
||||
/// unconstrained floats with f64.
|
||||
fn default_type_parameters(&self) {
|
||||
use rustc::ty::error::UnconstrainedNumeric::Neither;
|
||||
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
|
||||
@ -2408,7 +2410,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[..])],
|
||||
TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..], false)],
|
||||
};
|
||||
|
||||
self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
|
||||
@ -2505,16 +2507,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_args, arg_types.len(), args.len(),
|
||||
"E0057", false, def_span);
|
||||
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 => &[]
|
||||
@ -3072,7 +3074,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
})
|
||||
}
|
||||
ty::TyTuple(ref v) => {
|
||||
ty::TyTuple(ref v, _) => {
|
||||
tuple_like = true;
|
||||
v.get(idx.node).cloned()
|
||||
}
|
||||
@ -3864,7 +3866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
hir::ExprTup(ref elts) => {
|
||||
let flds = expected.only_has_type(self).and_then(|ty| {
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref flds) => Some(&flds[..]),
|
||||
ty::TyTuple(ref flds, _) => Some(&flds[..]),
|
||||
_ => None
|
||||
}
|
||||
});
|
||||
@ -3882,7 +3884,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
t
|
||||
});
|
||||
let tuple = tcx.mk_tup(elt_ts_iter);
|
||||
let tuple = tcx.mk_tup(elt_ts_iter, false);
|
||||
if tuple.references_error() {
|
||||
tcx.types.err
|
||||
} else {
|
||||
@ -3923,7 +3925,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
},
|
||||
base_t);
|
||||
// Try to give some advice about indexing tuples.
|
||||
if let ty::TyTuple(_) = base_t.sty {
|
||||
if let ty::TyTuple(..) = base_t.sty {
|
||||
let mut needs_note = true;
|
||||
// If the index is an integer, we can show the actual
|
||||
// fixed expression:
|
||||
|
@ -338,7 +338,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
self.add_constraints_from_mt(generics, mt, variance);
|
||||
}
|
||||
|
||||
ty::TyTuple(subtys) => {
|
||||
ty::TyTuple(subtys, _) => {
|
||||
for &subty in subtys {
|
||||
self.add_constraints_from_ty(generics, subty, variance);
|
||||
}
|
||||
|
@ -655,7 +655,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: lifetimes,
|
||||
@ -667,7 +667,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 {
|
||||
@ -710,7 +710,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::Region::ReLateBound(..) = *reg {
|
||||
@ -1895,7 +1895,7 @@ impl<'tcx> Clean<Type> for ty::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),
|
||||
|
||||
|
51
src/test/compile-fail/defaulted-unit-warning.rs
Normal file
51
src/test/compile-fail/defaulted-unit-warning.rs
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unreachable_code)]
|
||||
#![deny(resolve_trait_on_defaulted_unit)]
|
||||
|
||||
trait Deserialize: Sized {
|
||||
fn deserialize() -> Result<Self, String>;
|
||||
}
|
||||
|
||||
impl Deserialize for () {
|
||||
fn deserialize() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn doit() -> Result<(), String> {
|
||||
let _ = match Deserialize::deserialize() {
|
||||
//~^ ERROR code relies on type
|
||||
//~| WARNING previously accepted
|
||||
Ok(x) => x,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
trait ImplementedForUnitButNotNever {}
|
||||
|
||||
impl ImplementedForUnitButNotNever for () {}
|
||||
|
||||
fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
|
||||
|
||||
fn smeg() {
|
||||
let _x = return;
|
||||
foo(_x);
|
||||
//~^ ERROR code relies on type
|
||||
//~| WARNING previously accepted
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = doit();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user