Skip to content

Commit 4f8ce9e

Browse files
authored
Rollup merge of rust-lang#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.
2 parents ca202fe + 42f3ac5 commit 4f8ce9e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+249
-106
lines changed

src/librustc/lint/builtin.rs

+8
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,13 @@ declare_lint! {
192192
"lifetimes or labels named `'_` were erroneously allowed"
193193
}
194194

195+
declare_lint! {
196+
pub RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
197+
Warn,
198+
"attempt to resolve a trait on an expression whose type cannot be inferred but which \
199+
currently defaults to ()"
200+
}
201+
195202
declare_lint! {
196203
pub SAFE_EXTERN_STATICS,
197204
Warn,
@@ -272,6 +279,7 @@ impl LintPass for HardwiredLints {
272279
SUPER_OR_SELF_IN_GLOBAL_PATH,
273280
HR_LIFETIME_IN_ASSOC_TYPE,
274281
LIFETIME_UNDERSCORE,
282+
RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
275283
SAFE_EXTERN_STATICS,
276284
PATTERNS_IN_FNS_WITHOUT_BODY,
277285
EXTRA_REQUIREMENT_IN_IMPL,

src/librustc/middle/mem_categorization.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
11991199
PatKind::Tuple(ref subpats, ddpos) => {
12001200
// (p1, ..., pN)
12011201
let expected_len = match self.pat_ty(&pat)?.sty {
1202-
ty::TyTuple(ref tys) => tys.len(),
1202+
ty::TyTuple(ref tys, _) => tys.len(),
12031203
ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
12041204
};
12051205
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {

src/librustc/mir/tcx.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ impl<'tcx> Rvalue<'tcx> {
163163
let lhs_ty = lhs.ty(mir, tcx);
164164
let rhs_ty = rhs.ty(mir, tcx);
165165
let ty = op.ty(tcx, lhs_ty, rhs_ty);
166-
let ty = tcx.intern_tup(&[ty, tcx.types.bool]);
166+
let ty = tcx.intern_tup(&[ty, tcx.types.bool], false);
167167
Some(ty)
168168
}
169169
&Rvalue::UnaryOp(_, ref operand) => {
@@ -184,7 +184,8 @@ impl<'tcx> Rvalue<'tcx> {
184184
}
185185
AggregateKind::Tuple => {
186186
Some(tcx.mk_tup(
187-
ops.iter().map(|op| op.ty(mir, tcx))
187+
ops.iter().map(|op| op.ty(mir, tcx)),
188+
false
188189
))
189190
}
190191
AggregateKind::Adt(def, _, substs, _) => {

src/librustc/traits/select.rs

+52-8
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use std::mem;
5252
use std::rc::Rc;
5353
use syntax::abi::Abi;
5454
use hir;
55+
use lint;
5556
use util::nodemap::FxHashMap;
5657

5758
struct InferredObligationsSnapshotVecDelegate<'tcx> {
@@ -407,19 +408,62 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
407408
debug!("select({:?})", obligation);
408409
assert!(!obligation.predicate.has_escaping_regions());
409410

411+
let tcx = self.tcx();
410412
let dep_node = obligation.predicate.dep_node();
411-
let _task = self.tcx().dep_graph.in_task(dep_node);
413+
let _task = tcx.dep_graph.in_task(dep_node);
412414

413415
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
414-
match self.candidate_from_obligation(&stack)? {
415-
None => Ok(None),
416+
let ret = match self.candidate_from_obligation(&stack)? {
417+
None => None,
416418
Some(candidate) => {
417419
let mut candidate = self.confirm_candidate(obligation, candidate)?;
418420
let inferred_obligations = (*self.inferred_obligations).into_iter().cloned();
419421
candidate.nested_obligations_mut().extend(inferred_obligations);
420-
Ok(Some(candidate))
422+
Some(candidate)
421423
},
424+
};
425+
426+
// Test whether this is a `()` which was produced by defaulting a
427+
// diverging type variable with `!` disabled. If so, we may need
428+
// to raise a warning.
429+
if obligation.predicate.skip_binder().self_ty().is_defaulted_unit() {
430+
let mut raise_warning = true;
431+
// Don't raise a warning if the trait is implemented for ! and only
432+
// permits a trivial implementation for !. This stops us warning
433+
// about (for example) `(): Clone` becoming `!: Clone` because such
434+
// a switch can't cause code to stop compiling or execute
435+
// differently.
436+
let mut never_obligation = obligation.clone();
437+
let def_id = never_obligation.predicate.skip_binder().trait_ref.def_id;
438+
never_obligation.predicate = never_obligation.predicate.map_bound(|mut trait_pred| {
439+
// Swap out () with ! so we can check if the trait is impld for !
440+
{
441+
let mut trait_ref = &mut trait_pred.trait_ref;
442+
let unit_substs = trait_ref.substs;
443+
let mut never_substs = Vec::with_capacity(unit_substs.len());
444+
never_substs.push(From::from(tcx.types.never));
445+
never_substs.extend(&unit_substs[1..]);
446+
trait_ref.substs = tcx.intern_substs(&never_substs);
447+
}
448+
trait_pred
449+
});
450+
if let Ok(Some(..)) = self.select(&never_obligation) {
451+
if !tcx.trait_relevant_for_never(def_id) {
452+
// The trait is also implemented for ! and the resulting
453+
// implementation cannot actually be invoked in any way.
454+
raise_warning = false;
455+
}
456+
}
457+
458+
if raise_warning {
459+
tcx.sess.add_lint(lint::builtin::RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
460+
obligation.cause.body_id,
461+
obligation.cause.span,
462+
format!("code relies on type inference rules which are likely \
463+
to change"));
464+
}
422465
}
466+
Ok(ret)
423467
}
424468

425469
///////////////////////////////////////////////////////////////////////////
@@ -1744,15 +1788,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
17441788

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

1747-
ty::TyTuple(tys) => {
1791+
ty::TyTuple(tys, _) => {
17481792
Where(ty::Binder(tys.last().into_iter().cloned().collect()))
17491793
}
17501794

17511795
ty::TyAdt(def, substs) => {
17521796
let sized_crit = def.sized_constraint(self.tcx());
17531797
// (*) binder moved here
17541798
Where(ty::Binder(match sized_crit.sty {
1755-
ty::TyTuple(tys) => tys.to_vec().subst(self.tcx(), substs),
1799+
ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs),
17561800
ty::TyBool => vec![],
17571801
_ => vec![sized_crit.subst(self.tcx(), substs)]
17581802
}))
@@ -1799,7 +1843,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
17991843
Where(ty::Binder(vec![element_ty]))
18001844
}
18011845

1802-
ty::TyTuple(tys) => {
1846+
ty::TyTuple(tys, _) => {
18031847
// (*) binder moved here
18041848
Where(ty::Binder(tys.to_vec()))
18051849
}
@@ -1874,7 +1918,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
18741918
vec![element_ty]
18751919
}
18761920

1877-
ty::TyTuple(ref tys) => {
1921+
ty::TyTuple(ref tys, _) => {
18781922
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
18791923
tys.to_vec()
18801924
}

src/librustc/traits/util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
489489
let arguments_tuple = match tuple_arguments {
490490
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
491491
TupleArgumentsFlag::Yes =>
492-
self.intern_tup(sig.skip_binder().inputs()),
492+
self.intern_tup(sig.skip_binder().inputs(), false),
493493
};
494494
let trait_ref = ty::TraitRef {
495495
def_id: fn_trait_def_id,

src/librustc/ty/contents.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
201201
|ty| tc_ty(tcx, &ty, cache))
202202
}
203203

204-
ty::TyTuple(ref tys) => {
204+
ty::TyTuple(ref tys, _) => {
205205
TypeContents::union(&tys[..],
206206
|ty| tc_ty(tcx, *ty, cache))
207207
}

src/librustc/ty/context.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1384,23 +1384,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
13841384
self.mk_ty(TySlice(ty))
13851385
}
13861386

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

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

13951396
pub fn mk_nil(self) -> Ty<'tcx> {
1396-
self.intern_tup(&[])
1397+
self.intern_tup(&[], false)
13971398
}
13981399

13991400
pub fn mk_diverging_default(self) -> Ty<'tcx> {
14001401
if self.sess.features.borrow().never_type {
14011402
self.types.never
14021403
} else {
1403-
self.mk_nil()
1404+
self.intern_tup(&[], true)
14041405
}
14051406
}
14061407

src/librustc/ty/error.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
178178
match self.sty {
179179
ty::TyBool | ty::TyChar | ty::TyInt(_) |
180180
ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(),
181-
ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(),
181+
ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),
182182

183183
ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
184184
ty::TyArray(_, n) => format!("array of {} elements", n),
@@ -209,7 +209,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
209209
|p| format!("trait {}", tcx.item_path_str(p.def_id())))
210210
}
211211
ty::TyClosure(..) => "closure".to_string(),
212-
ty::TyTuple(_) => "tuple".to_string(),
212+
ty::TyTuple(..) => "tuple".to_string(),
213213
ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
214214
ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),
215215
ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(),

src/librustc/ty/fast_reject.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
7272
Some(ClosureSimplifiedType(def_id))
7373
}
7474
ty::TyNever => Some(NeverSimplifiedType),
75-
ty::TyTuple(ref tys) => {
75+
ty::TyTuple(ref tys, _) => {
7676
Some(TupleSimplifiedType(tys.len()))
7777
}
7878
ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {

src/librustc/ty/flags.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ impl FlagComputation {
151151
self.add_ty(m.ty);
152152
}
153153

154-
&ty::TyTuple(ref ts) => {
154+
&ty::TyTuple(ref ts, _) => {
155155
self.add_tys(&ts[..]);
156156
}
157157

src/librustc/ty/inhabitedness/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
178178
},
179179

180180
TyNever => DefIdForest::full(tcx),
181-
TyTuple(ref tys) => {
181+
TyTuple(ref tys, _) => {
182182
DefIdForest::union(tcx, tys.iter().map(|ty| {
183183
ty.uninhabited_from(visited, tcx)
184184
}))

src/librustc/ty/item_path.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,9 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
319319
ty::TyRawPtr(mt) |
320320
ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty),
321321

322-
ty::TyTuple(ref tys) => tys.iter()
323-
.filter_map(|ty| characteristic_def_id_of_type(ty))
324-
.next(),
322+
ty::TyTuple(ref tys, _) => tys.iter()
323+
.filter_map(|ty| characteristic_def_id_of_type(ty))
324+
.next(),
325325

326326
ty::TyFnDef(def_id, ..) |
327327
ty::TyClosure(def_id, _) => Some(def_id),

src/librustc/ty/layout.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ impl<'a, 'gcx, 'tcx> Struct {
791791
Some(&variant.memory_index[..]))
792792
}
793793
// Can we use one of the fields in this tuple?
794-
(&Univariant { ref variant, .. }, &ty::TyTuple(tys)) => {
794+
(&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => {
795795
Struct::non_zero_field_paths(infcx, tys.iter().cloned(),
796796
Some(&variant.memory_index[..]))
797797
}
@@ -1157,7 +1157,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11571157
Univariant { variant: st, non_zero: false }
11581158
}
11591159

1160-
ty::TyTuple(tys) => {
1160+
ty::TyTuple(tys, _) => {
11611161
// FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
11621162
// See the univariant case below to learn how.
11631163
let st = Struct::new(dl,

src/librustc/ty/mod.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,17 @@ impl AssociatedItem {
197197
AssociatedKind::Type => Def::AssociatedTy(self.def_id),
198198
}
199199
}
200+
201+
/// Tests whether the associated item admits a non-trivial implementation
202+
/// for !
203+
pub fn relevant_for_never<'tcx>(&self) -> bool {
204+
match self.kind {
205+
AssociatedKind::Const => true,
206+
AssociatedKind::Type => true,
207+
// FIXME(canndrew): Be more thorough here, check if any argument is uninhabited.
208+
AssociatedKind::Method => !self.method_has_self_argument,
209+
}
210+
}
200211
}
201212

202213
#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable)]
@@ -1603,7 +1614,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16031614
_ if tys.references_error() => tcx.types.err,
16041615
0 => tcx.types.bool,
16051616
1 => tys[0],
1606-
_ => tcx.intern_tup(&tys[..])
1617+
_ => tcx.intern_tup(&tys[..], false)
16071618
};
16081619

16091620
let old = tcx.adt_sized_constraint.borrow().get(&self.did).cloned();
@@ -1638,7 +1649,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16381649
vec![ty]
16391650
}
16401651

1641-
TyTuple(ref tys) => {
1652+
TyTuple(ref tys, _) => {
16421653
match tys.last() {
16431654
None => vec![],
16441655
Some(ty) => self.sized_constraint_for_ty(tcx, stack, ty)
@@ -1652,7 +1663,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16521663
.subst(tcx, substs);
16531664
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
16541665
ty, adt_ty);
1655-
if let ty::TyTuple(ref tys) = adt_ty.sty {
1666+
if let ty::TyTuple(ref tys, _) = adt_ty.sty {
16561667
tys.iter().flat_map(|ty| {
16571668
self.sized_constraint_for_ty(tcx, stack, ty)
16581669
}).collect()
@@ -2010,6 +2021,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
20102021
}
20112022
}
20122023

2024+
pub fn trait_relevant_for_never(self, did: DefId) -> bool {
2025+
self.associated_items(did).any(|item| {
2026+
item.relevant_for_never()
2027+
})
2028+
}
2029+
20132030
pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
20142031
self.custom_coerce_unsized_kinds.memoize(did, || {
20152032
let (kind, src) = if did.krate != LOCAL_CRATE {

src/librustc/ty/relate.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -447,10 +447,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
447447
Ok(tcx.mk_slice(t))
448448
}
449449

450-
(&ty::TyTuple(as_), &ty::TyTuple(bs)) =>
450+
(&ty::TyTuple(as_, a_defaulted), &ty::TyTuple(bs, b_defaulted)) =>
451451
{
452452
if as_.len() == bs.len() {
453-
Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)))?)
453+
let defaulted = a_defaulted || b_defaulted;
454+
Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)), defaulted)?)
454455
} else if !(as_.is_empty() || bs.is_empty()) {
455456
Err(TypeError::TupleSize(
456457
expected_found(relation, &as_.len(), &bs.len())))

src/librustc/ty/structural_impls.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
474474
ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)),
475475
ty::TyDynamic(ref trait_ty, ref region) =>
476476
ty::TyDynamic(trait_ty.fold_with(folder), region.fold_with(folder)),
477-
ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)),
477+
ty::TyTuple(ts, defaulted) => ty::TyTuple(ts.fold_with(folder), defaulted),
478478
ty::TyFnDef(def_id, substs, f) => {
479479
ty::TyFnDef(def_id,
480480
substs.fold_with(folder),
@@ -511,7 +511,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
511511
ty::TyAdt(_, substs) => substs.visit_with(visitor),
512512
ty::TyDynamic(ref trait_ty, ref reg) =>
513513
trait_ty.visit_with(visitor) || reg.visit_with(visitor),
514-
ty::TyTuple(ts) => ts.visit_with(visitor),
514+
ty::TyTuple(ts, _) => ts.visit_with(visitor),
515515
ty::TyFnDef(_, substs, ref f) => {
516516
substs.visit_with(visitor) || f.visit_with(visitor)
517517
}

0 commit comments

Comments
 (0)