Skip to content

Commit 2cc84df

Browse files
committed
Add warning for () to ! switch
1 parent 57ecd7a commit 2cc84df

Some content is hidden

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

53 files changed

+178
-105
lines changed

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: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -407,19 +407,66 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
407407
debug!("select({:?})", obligation);
408408
assert!(!obligation.predicate.has_escaping_regions());
409409

410+
let tcx = self.tcx();
410411
let dep_node = obligation.predicate.dep_node();
411-
let _task = self.tcx().dep_graph.in_task(dep_node);
412+
let _task = tcx.dep_graph.in_task(dep_node);
412413

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

425472
///////////////////////////////////////////////////////////////////////////
@@ -1744,15 +1791,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
17441791

17451792
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) => Never,
17461793

1747-
ty::TyTuple(tys) => {
1794+
ty::TyTuple(tys, _) => {
17481795
Where(ty::Binder(tys.last().into_iter().cloned().collect()))
17491796
}
17501797

17511798
ty::TyAdt(def, substs) => {
17521799
let sized_crit = def.sized_constraint(self.tcx());
17531800
// (*) binder moved here
17541801
Where(ty::Binder(match sized_crit.sty {
1755-
ty::TyTuple(tys) => tys.to_vec().subst(self.tcx(), substs),
1802+
ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs),
17561803
ty::TyBool => vec![],
17571804
_ => vec![sized_crit.subst(self.tcx(), substs)]
17581805
}))
@@ -1799,7 +1846,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
17991846
Where(ty::Binder(vec![element_ty]))
18001847
}
18011848

1802-
ty::TyTuple(tys) => {
1849+
ty::TyTuple(tys, _) => {
18031850
// (*) binder moved here
18041851
Where(ty::Binder(tys.to_vec()))
18051852
}
@@ -1874,7 +1921,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
18741921
vec![element_ty]
18751922
}
18761923

1877-
ty::TyTuple(ref tys) => {
1924+
ty::TyTuple(ref tys, _) => {
18781925
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
18791926
tys.to_vec()
18801927
}

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
@@ -1379,23 +1379,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
13791379
self.mk_ty(TySlice(ty))
13801380
}
13811381

1382-
pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
1383-
self.mk_ty(TyTuple(self.intern_type_list(ts)))
1382+
pub fn intern_tup(self, ts: &[Ty<'tcx>], defaulted: bool) -> Ty<'tcx> {
1383+
self.mk_ty(TyTuple(self.intern_type_list(ts), defaulted))
13841384
}
13851385

1386-
pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I) -> I::Output {
1387-
iter.intern_with(|ts| self.mk_ty(TyTuple(self.intern_type_list(ts))))
1386+
pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I,
1387+
defaulted: bool) -> I::Output {
1388+
iter.intern_with(|ts| self.mk_ty(TyTuple(self.intern_type_list(ts), defaulted)))
13881389
}
13891390

13901391
pub fn mk_nil(self) -> Ty<'tcx> {
1391-
self.intern_tup(&[])
1392+
self.intern_tup(&[], false)
13921393
}
13931394

13941395
pub fn mk_diverging_default(self) -> Ty<'tcx> {
13951396
if self.sess.features.borrow().never_type {
13961397
self.types.never
13971398
} else {
1398-
self.mk_nil()
1399+
self.intern_tup(&[], true)
13991400
}
14001401
}
14011402

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

src/librustc/ty/inhabitedness/mod.rs

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

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

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

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

src/librustc/ty/mod.rs

Lines changed: 20 additions & 3 deletions
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+
// TODO(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

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

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

src/librustc/ty/sty.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@ pub enum TypeVariants<'tcx> {
151151
TyNever,
152152

153153
/// A tuple type. For example, `(i32, bool)`.
154-
TyTuple(&'tcx Slice<Ty<'tcx>>),
154+
/// The bool indicates whether this is a unit tuple and was created by
155+
/// defaulting a diverging type variable with feature(never_type) disabled.
156+
/// It's only purpose is for raising future-compatibility warnings for when
157+
/// diverging type variables start defaulting to ! instead of ().
158+
TyTuple(&'tcx Slice<Ty<'tcx>>, bool),
155159

156160
/// The projection of an associated type. For example,
157161
/// `<T as Trait<..>>::N`.
@@ -961,7 +965,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
961965

962966
pub fn is_nil(&self) -> bool {
963967
match self.sty {
964-
TyTuple(ref tys) => tys.is_empty(),
968+
TyTuple(ref tys, _) => tys.is_empty(),
965969
_ => false
966970
}
967971
}
@@ -1355,7 +1359,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
13551359
TySlice(_) |
13561360
TyRawPtr(_) |
13571361
TyNever |
1358-
TyTuple(_) |
1362+
TyTuple(..) |
13591363
TyParam(_) |
13601364
TyInfer(_) |
13611365
TyError => {

0 commit comments

Comments
 (0)