From 2cc84df44cca1b6ab4b1f4d01a7680c72d7f20d9 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Wed, 11 Jan 2017 15:58:37 +0800 Subject: [PATCH 1/9] Add warning for () to ! switch --- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/mir/tcx.rs | 5 +- src/librustc/traits/select.rs | 63 ++++++++++++++++--- src/librustc/traits/util.rs | 2 +- src/librustc/ty/contents.rs | 2 +- src/librustc/ty/context.rs | 13 ++-- src/librustc/ty/error.rs | 4 +- src/librustc/ty/fast_reject.rs | 2 +- src/librustc/ty/flags.rs | 2 +- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc/ty/item_path.rs | 6 +- src/librustc/ty/layout.rs | 4 +- src/librustc/ty/mod.rs | 23 ++++++- src/librustc/ty/relate.rs | 5 +- src/librustc/ty/structural_impls.rs | 4 +- src/librustc/ty/sty.rs | 10 ++- src/librustc/ty/util.rs | 6 +- src/librustc/ty/walk.rs | 2 +- src/librustc/ty/wf.rs | 2 +- src/librustc/util/ppaux.rs | 4 +- src/librustc_borrowck/borrowck/fragments.rs | 2 +- .../borrowck/mir/elaborate_drops.rs | 2 +- src/librustc_const_eval/_match.rs | 4 +- src/librustc_const_eval/pattern.rs | 2 +- src/librustc_driver/test.rs | 8 +-- src/librustc_lint/types.rs | 2 +- src/librustc_lint/unused.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/transform/type_check.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/adt.rs | 2 +- src/librustc_trans/callee.rs | 2 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/common.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 8 +-- src/librustc_trans/debuginfo/mod.rs | 4 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/glue.rs | 2 +- src/librustc_trans/mir/block.rs | 2 +- src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/mir/mod.rs | 2 +- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans/trans_item.rs | 2 +- src/librustc_trans/type_of.rs | 4 +- src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/_match.rs | 4 +- src/librustc_typeck/check/closure.rs | 4 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 8 +-- src/librustc_typeck/check/mod.rs | 20 +++--- src/librustc_typeck/variance/constraints.rs | 2 +- src/librustdoc/clean/mod.rs | 8 +-- 53 files changed, 178 insertions(+), 105 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0e8e1921de700..9d1bcb8164a9e 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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) { diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 03530945e046d..f1268521d6708 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -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, _) => { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index d51332f833d77..451f075dfeed7 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -407,19 +407,66 @@ 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 let ty::TyTuple(_, true) = obligation.predicate.skip_binder() + .self_ty().sty { + + 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 { + let sess = tcx.sess; + let span = obligation.cause.span; + let mut warn = sess.struct_span_warn(span, "code relies on type inference rules \ + which are likely to change"); + warn.span_label(span, &"the type of this expression may change from () \ + to ! in a future version of Rust"); + warn.emit(); + } } + Ok(ret) } /////////////////////////////////////////////////////////////////////////// @@ -1744,7 +1791,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 +1799,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 +1846,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 +1921,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() } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index cebd8bf87d736..7b2882bb64f2c 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -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, diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index 00c6dca21b1ef..56621c57eb8f7 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -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)) } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ce4a6a3182635..95751346908ec 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1379,23 +1379,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], Ty<'tcx>>>(self, iter: I) -> I::Output { - iter.intern_with(|ts| self.mk_ty(TyTuple(self.intern_type_list(ts)))) + pub fn mk_tup], 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) } } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 29d855a7fcb78..3ab3fc899e78c 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -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(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 94b9abc72025f..981cf0897a034 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -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) => { diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 0de77526b5a46..2012917f93a87 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -151,7 +151,7 @@ impl FlagComputation { self.add_ty(m.ty); } - &ty::TyTuple(ref ts) => { + &ty::TyTuple(ref ts, _) => { self.add_tys(&ts[..]); } diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 6c49493a65559..18a3f1a218d85 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -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) })) diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index b719911d18cf8..f45f00b4dec96 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -319,9 +319,9 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option { 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), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 78364abdaecba..a7351943dd7c4 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -792,7 +792,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[..])) } @@ -1158,7 +1158,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, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5ab45e746e7f2..978a8aa0fffee 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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, + // TODO(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 { diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 89514085e1c78..adedf78bba7c0 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -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()))) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 05f4abad46921..aa74e7cc0d043 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -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) } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 113534e4529cd..62b70d4420180 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -151,7 +151,11 @@ pub enum TypeVariants<'tcx> { TyNever, /// A tuple type. For example, `(i32, bool)`. - TyTuple(&'tcx Slice>), + /// 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>, bool), /// The projection of an associated type. For example, /// `>::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 } } @@ -1355,7 +1359,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TySlice(_) | TyRawPtr(_) | TyNever | - TyTuple(_) | + TyTuple(..) | TyParam(_) | TyInfer(_) | TyError => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index ba49aa1ef4866..f667100465dac 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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,7 +466,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> self.def_id(d); } } - TyTuple(tys) => { + TyTuple(tys, _) => { self.hash(tys.len()); } TyParam(p) => { @@ -675,7 +675,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { seen: &mut Vec>, ty: Ty<'tcx>) -> Representability { match ty.sty { - TyTuple(ref ts) => { + TyTuple(ref ts, _) => { find_nonrepresentable(tcx, sp, seen, ts.iter().cloned()) } // Fixed-length vectors. diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 0d1dc2e4d7c21..01f31e5024c0d 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -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) => { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 33b70b09dcb7b..8a5bd6862cf45 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -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); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index aa2eb2955debe..5d6ee1a277a5f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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() { diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 285f3ab9047c8..dbab3bca52b4e 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -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(_) => diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 9e89a3689c7ac..d2f744bde2d63 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -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() => { diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 94b2ba58c9aa5..7a64ff7114a7e 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -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![], diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index c6272613f4d09..609fb3e39d62c 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -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) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 1086d75f02cb4..41e5a4d53122f 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -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,7 +818,7 @@ 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 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]); // types we expect to see (in order), plus a boolean saying diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 9669efa2d86b3..dc3fd3328a648 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -534,7 +534,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") } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index a85b47c8ada7a..28ce9126019eb 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -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, _) => { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 48690a275c205..c212054205da5 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -258,7 +258,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, diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index c9195f29f1784..529fe564af02b 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -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 { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f128167bbf621..41f91a1d2acc1 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -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), diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index d392ebaa33d42..a476b1d29e5fb 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -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[..] } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index c3b9a56ac9778..bc1e07e708c24 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -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::>() }, - 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() diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 58d0c46850353..c6b86c6ba48de 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -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(), diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 392c270c130a8..89f5c00e9c11a 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -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) { diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 0ba94fdfe635c..98ea06c4cb278 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -95,7 +95,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; } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index b7e319f2de434..c83e2f4854bf5 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -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), diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index e9468e56637d2..501f891befa8d 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -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)); } diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 8e11bf6b8976a..018bbb6e97d34 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -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); diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 1415ca6029f53..fdefd37549ced 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -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)); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 7d4a1ab5ae70e..027779aca63e4 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -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) }; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 9ac2bea3b82fb..d28133d982549 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -737,7 +737,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()); diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 30c138310da9c..8a0a97a563439 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -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?!") }; diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 1b97a8d010cfe..81b241b485175 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -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 diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index d58a93e3cb71c..04a6cb27501b3 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -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); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 4df0e989ada99..87af3b6c5e153 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -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) } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index bb9a487802e7b..a3373f6da2852 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 932e7ae1dd426..feed5752cf8fb 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -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]); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 2e6592b550179..7979edbf5e27a 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -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; } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 34aa4eda772ad..f701bc3220848 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -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)? } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 7ead7ada893d7..cb4e85e842c2a 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -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())); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c435f9341253e..0f429bd0c3aaa 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1940,7 +1940,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}; @@ -2401,7 +2403,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, @@ -2498,16 +2500,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 => &[] @@ -3065,7 +3067,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() } @@ -3857,7 +3859,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 } }); @@ -3875,7 +3877,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 { @@ -3916,7 +3918,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: diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 40e82959336de..860f6d98370ad 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -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); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cdb24a56367fc..fea92d9517c24 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -649,7 +649,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option, 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, @@ -661,7 +661,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option, 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 { @@ -704,7 +704,7 @@ impl<'tcx> Clean 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 { @@ -1889,7 +1889,7 @@ impl<'tcx> Clean 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), From c570cd663601694b017bc3c739bb9c260c88324b Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 12 Jan 2017 15:36:37 +0800 Subject: [PATCH 2/9] Fix make tidy --- src/librustc/ty/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 978a8aa0fffee..c9ae3b3df028c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -204,7 +204,7 @@ impl AssociatedItem { match self.kind { AssociatedKind::Const => true, AssociatedKind::Type => true, - // TODO(canndrew): Be more thorough here, check if any argument is uninhabited. + // FIXME(canndrew): Be more thorough here, check if any argument is uninhabited. AssociatedKind::Method => !self.method_has_self_argument, } } From 5dbaefb608ac71afedadd9810e0bba6348e27c6a Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Fri, 13 Jan 2017 00:50:15 +0800 Subject: [PATCH 3/9] Hash TyTuple's defaulted flag --- src/librustc/ty/util.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index f667100465dac..b01b77bbcf8a5 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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); From 085f046c280639ce2f545108740d02c8a470cdd6 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sat, 21 Jan 2017 14:02:43 +0800 Subject: [PATCH 4/9] Add is_defaulted_unit helper method --- src/librustc/traits/select.rs | 4 +--- src/librustc/ty/sty.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 451f075dfeed7..d5efc8f18939e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -425,9 +425,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Test whether this is a `()` which was produced by defaulting a // diverging type variable with `!` disabled. If so, we may need // to raise a warning. - if let ty::TyTuple(_, true) = obligation.predicate.skip_binder() - .self_ty().sty { - + 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 diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 62b70d4420180..9bba4c6e37a69 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -977,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 From 5c90dd797883ad2084e8bbc92420b42b9f7fb7d7 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sat, 21 Jan 2017 15:15:23 +0800 Subject: [PATCH 5/9] Use a proper future-compatibility lint --- src/librustc/lint/builtin.rs | 8 ++++++ src/librustc/traits/select.rs | 13 +++++----- src/librustc_lint/lib.rs | 4 +++ .../compile-fail/defaulted-unit-warning.rs | 26 +++++++++++++++++++ 4 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/defaulted-unit-warning.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index e1605959922c0..70f03e02f46d9 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index d5efc8f18939e..41f3f825c3d19 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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> { @@ -455,13 +456,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } if raise_warning { - let sess = tcx.sess; - let span = obligation.cause.span; - let mut warn = sess.struct_span_warn(span, "code relies on type inference rules \ - which are likely to change"); - warn.span_label(span, &"the type of this expression may change from () \ - to ! in a future version of Rust"); - warn.emit(); + 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) diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 18067cb86739b..81ba49f56f050 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -220,6 +220,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(LIFETIME_UNDERSCORE), reference: "issue #36892 ", }, + FutureIncompatibleInfo { + id: LintId::of(RESOLVE_TRAIT_ON_DEFAULTED_UNIT), + reference: "issue #39216 ", + }, FutureIncompatibleInfo { id: LintId::of(SAFE_EXTERN_STATICS), reference: "issue #36247 ", diff --git a/src/test/compile-fail/defaulted-unit-warning.rs b/src/test/compile-fail/defaulted-unit-warning.rs new file mode 100644 index 0000000000000..7a15ac025ef85 --- /dev/null +++ b/src/test/compile-fail/defaulted-unit-warning.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(resolve_trait_on_defaulted_unit)] + +trait Deserialize { + fn deserialize() -> Result +} + +fn doit() -> Result<(), String> { + let _ = Deserialize::deserialize()?; + //~^ ERROR attempt to resolve a trait + Ok(()) +} + +fn main() { + doit(); +} + From 6a99573513054ec3839a75174e084351e2da87fc Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sat, 21 Jan 2017 16:03:28 +0800 Subject: [PATCH 6/9] Fix test --- src/test/compile-fail/defaulted-unit-warning.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/test/compile-fail/defaulted-unit-warning.rs b/src/test/compile-fail/defaulted-unit-warning.rs index 7a15ac025ef85..e48ff2bbcdb42 100644 --- a/src/test/compile-fail/defaulted-unit-warning.rs +++ b/src/test/compile-fail/defaulted-unit-warning.rs @@ -10,17 +10,24 @@ #![deny(resolve_trait_on_defaulted_unit)] -trait Deserialize { - fn deserialize() -> Result +trait Deserialize: Sized { + fn deserialize() -> Result; +} + +impl Deserialize for () { + fn deserialize() -> Result<(), String> { + Ok(()) + } } fn doit() -> Result<(), String> { let _ = Deserialize::deserialize()?; - //~^ ERROR attempt to resolve a trait + //~^ ERROR code relies on type + //~| WARNING previously accepted Ok(()) } fn main() { - doit(); + let _ = doit(); } From 40c9538d2cb391e6be11cb7c9ede9f302bef3d59 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 29 Jan 2017 23:49:01 +0800 Subject: [PATCH 7/9] Fix test --- src/test/compile-fail/defaulted-unit-warning.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail/defaulted-unit-warning.rs b/src/test/compile-fail/defaulted-unit-warning.rs index e48ff2bbcdb42..2b6bd01f907c1 100644 --- a/src/test/compile-fail/defaulted-unit-warning.rs +++ b/src/test/compile-fail/defaulted-unit-warning.rs @@ -21,9 +21,12 @@ impl Deserialize for () { } fn doit() -> Result<(), String> { - let _ = Deserialize::deserialize()?; - //~^ ERROR code relies on type - //~| WARNING previously accepted + let _ = match Deserialize::deserialize() { + //~^ ERROR code relies on type + //~| WARNING previously accepted + Ok(x) => x, + Err(e) => return Err(e), + }; Ok(()) } From 7444d07154652c4d7a3e91e645eaa604a8bc4c84 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sat, 4 Feb 2017 14:03:28 +0800 Subject: [PATCH 8/9] Fix test --- src/librustc_driver/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 41e5a4d53122f..5481de1811d78 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -819,7 +819,7 @@ fn walk_ty_skip_subtree() { 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], false); - let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]); + 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. From 42f3ac5ea610b351e404dd30199d13ffc91617d5 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sat, 4 Feb 2017 14:17:58 +0800 Subject: [PATCH 9/9] Expand defaulted unit test --- src/test/compile-fail/defaulted-unit-warning.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/compile-fail/defaulted-unit-warning.rs b/src/test/compile-fail/defaulted-unit-warning.rs index 2b6bd01f907c1..5213a189714dd 100644 --- a/src/test/compile-fail/defaulted-unit-warning.rs +++ b/src/test/compile-fail/defaulted-unit-warning.rs @@ -8,6 +8,8 @@ // 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 { @@ -30,6 +32,19 @@ fn doit() -> Result<(), String> { Ok(()) } +trait ImplementedForUnitButNotNever {} + +impl ImplementedForUnitButNotNever for () {} + +fn foo(_t: T) {} + +fn smeg() { + let _x = return; + foo(_x); + //~^ ERROR code relies on type + //~| WARNING previously accepted +} + fn main() { let _ = doit(); }