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

Lines changed: 8 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 3 additions & 2 deletions
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

Lines changed: 52 additions & 8 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 7 additions & 6 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

0 commit comments

Comments
 (0)