Skip to content

Commit e25542c

Browse files
authored
Auto merge of #35162 - canndrew:bang_type_coerced, r=nikomatsakis
Implement the `!` type This implements the never type (`!`) and hides it behind the feature gate `#[feature(never_type)]`. With the feature gate off, things should build as normal (although some error messages may be different). With the gate on, `!` is usable as a type and diverging type variables (ie. types that are unconstrained by anything in the code) will default to `!` instead of `()`.
2 parents 197be89 + f59f1f0 commit e25542c

File tree

128 files changed

+899
-705
lines changed

Some content is hidden

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

128 files changed

+899
-705
lines changed

src/libcore/cmp.rs

+33
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,39 @@ mod impls {
699699

700700
ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
701701

702+
// Note: This macro is a temporary hack that can be remove once we are building with a compiler
703+
// that supports `!`
704+
macro_rules! not_stage0 {
705+
() => {
706+
#[unstable(feature = "never_type", issue = "35121")]
707+
impl PartialEq for ! {
708+
fn eq(&self, _: &!) -> bool {
709+
*self
710+
}
711+
}
712+
713+
#[unstable(feature = "never_type", issue = "35121")]
714+
impl Eq for ! {}
715+
716+
#[unstable(feature = "never_type", issue = "35121")]
717+
impl PartialOrd for ! {
718+
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
719+
*self
720+
}
721+
}
722+
723+
#[unstable(feature = "never_type", issue = "35121")]
724+
impl Ord for ! {
725+
fn cmp(&self, _: &!) -> Ordering {
726+
*self
727+
}
728+
}
729+
}
730+
}
731+
732+
#[cfg(not(stage0))]
733+
not_stage0!();
734+
702735
// & pointers
703736

704737
#[stable(feature = "rust1", since = "1.0.0")]

src/libcore/fmt/mod.rs

+23
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,29 @@ macro_rules! fmt_refs {
13631363

13641364
fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
13651365

1366+
// Note: This macro is a temporary hack that can be remove once we are building with a compiler
1367+
// that supports `!`
1368+
macro_rules! not_stage0 {
1369+
() => {
1370+
#[unstable(feature = "never_type", issue = "35121")]
1371+
impl Debug for ! {
1372+
fn fmt(&self, _: &mut Formatter) -> Result {
1373+
*self
1374+
}
1375+
}
1376+
1377+
#[unstable(feature = "never_type", issue = "35121")]
1378+
impl Display for ! {
1379+
fn fmt(&self, _: &mut Formatter) -> Result {
1380+
*self
1381+
}
1382+
}
1383+
}
1384+
}
1385+
1386+
#[cfg(not(stage0))]
1387+
not_stage0!();
1388+
13661389
#[stable(feature = "rust1", since = "1.0.0")]
13671390
impl Debug for bool {
13681391
fn fmt(&self, f: &mut Formatter) -> Result {

src/libcore/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
#![feature(unboxed_closures)]
8989
#![feature(question_mark)]
9090

91+
// NOTE: remove the cfg_attr next snapshot
92+
#![cfg_attr(not(stage0), feature(never_type))]
93+
9194
#[macro_use]
9295
mod macros;
9396

src/librustc/cfg/construct.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
379379

380380
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
381381
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
382-
if fn_ty.fn_ret().diverges() {
382+
// FIXME(canndrew): This is_never should probably be an is_uninhabited.
383+
if fn_ty.fn_ret().0.is_never() {
383384
self.add_unreachable_node()
384385
} else {
385386
ret

src/librustc/hir/fold.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
353353
}
354354
}))
355355
}
356+
TyNever => node,
356357
TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))),
357358
TyPath(qself, path) => {
358359
let qself = qself.map(|QSelf { ty, position }| {
@@ -515,7 +516,6 @@ pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
515516
output: match output {
516517
Return(ty) => Return(fld.fold_ty(ty)),
517518
DefaultReturn(span) => DefaultReturn(span),
518-
NoReturn(span) => NoReturn(span),
519519
},
520520
variadic: variadic,
521521
}

src/librustc/hir/intravisit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
403403
walk_list!(visitor, visit_lifetime, opt_lifetime);
404404
visitor.visit_ty(&mutable_type.ty)
405405
}
406+
TyNever => {},
406407
TyTup(ref tuple_element_types) => {
407408
walk_list!(visitor, visit_ty, tuple_element_types);
408409
}

src/librustc/hir/lowering.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ impl<'a> LoweringContext<'a> {
270270
decl: self.lower_fn_decl(&f.decl),
271271
}))
272272
}
273+
Never => hir::TyNever,
273274
Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()),
274275
Paren(ref ty) => {
275276
return self.lower_ty(ty);
@@ -402,7 +403,6 @@ impl<'a> LoweringContext<'a> {
402403
output: match decl.output {
403404
FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
404405
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
405-
FunctionRetTy::None(span) => hir::NoReturn(span),
406406
},
407407
variadic: decl.variadic,
408408
})

src/librustc/hir/mod.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,7 @@ pub struct BareFnTy {
11121112
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
11131113
/// The different kinds of types recognized by the compiler
11141114
pub enum Ty_ {
1115+
/// A variable length array (`[T]`)
11151116
TyVec(P<Ty>),
11161117
/// A fixed length array (`[T; n]`)
11171118
TyFixedLengthVec(P<Ty>, P<Expr>),
@@ -1121,6 +1122,8 @@ pub enum Ty_ {
11211122
TyRptr(Option<Lifetime>, MutTy),
11221123
/// A bare function (e.g. `fn(usize) -> bool`)
11231124
TyBareFn(P<BareFnTy>),
1125+
/// The never type (`!`)
1126+
TyNever,
11241127
/// A tuple (`(A, B, C, D,...)`)
11251128
TyTup(HirVec<P<Ty>>),
11261129
/// A path (`module::module::...::Type`), optionally
@@ -1283,9 +1286,6 @@ impl fmt::Debug for ImplPolarity {
12831286

12841287
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
12851288
pub enum FunctionRetTy {
1286-
/// Functions with return type `!`that always
1287-
/// raise an error or exit (i.e. never return to the caller)
1288-
NoReturn(Span),
12891289
/// Return type is not specified.
12901290
///
12911291
/// Functions default to `()` and
@@ -1299,7 +1299,6 @@ pub enum FunctionRetTy {
12991299
impl FunctionRetTy {
13001300
pub fn span(&self) -> Span {
13011301
match *self {
1302-
NoReturn(span) => span,
13031302
DefaultReturn(span) => span,
13041303
Return(ref ty) => ty.span,
13051304
}

src/librustc/hir/print.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,9 @@ impl<'a> State<'a> {
504504
self.print_opt_lifetime(lifetime)?;
505505
self.print_mt(mt)?;
506506
}
507+
hir::TyNever => {
508+
word(&mut self.s, "!")?;
509+
},
507510
hir::TyTup(ref elts) => {
508511
self.popen()?;
509512
self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&ty))?;
@@ -1959,10 +1962,6 @@ impl<'a> State<'a> {
19591962
self.maybe_print_comment(ty.span.lo)
19601963
}
19611964
hir::DefaultReturn(..) => unreachable!(),
1962-
hir::NoReturn(span) => {
1963-
self.word_nbsp("!")?;
1964-
self.maybe_print_comment(span.lo)
1965-
}
19661965
}
19671966
}
19681967

@@ -2195,7 +2194,6 @@ impl<'a> State<'a> {
21952194
self.ibox(indent_unit)?;
21962195
self.word_space("->")?;
21972196
match decl.output {
2198-
hir::NoReturn(_) => self.word_nbsp("!")?,
21992197
hir::DefaultReturn(..) => unreachable!(),
22002198
hir::Return(ref ty) => self.print_type(&ty)?,
22012199
}

src/librustc/infer/error_reporting.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,6 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
13261326
self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names)
13271327
),
13281328
hir::DefaultReturn(span) => hir::DefaultReturn(span),
1329-
hir::NoReturn(span) => hir::NoReturn(span)
13301329
}
13311330
}
13321331

src/librustc/infer/freshen.rs

+1
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
168168
ty::TyTrait(..) |
169169
ty::TyStruct(..) |
170170
ty::TyClosure(..) |
171+
ty::TyNever |
171172
ty::TyTuple(..) |
172173
ty::TyProjection(..) |
173174
ty::TyParam(..) |

src/librustc/infer/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,6 @@ impl_trans_normalize!('gcx,
607607
Ty<'gcx>,
608608
&'gcx Substs<'gcx>,
609609
ty::FnSig<'gcx>,
610-
ty::FnOutput<'gcx>,
611610
&'gcx ty::BareFnTy<'gcx>,
612611
ty::ClosureSubsts<'gcx>,
613612
ty::PolyTraitRef<'gcx>

src/librustc/middle/expr_use_visitor.rs

+1
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
717717
let adj = infcx.adjustments().get(&expr.id).map(|x| x.clone());
718718
if let Some(adjustment) = adj {
719719
match adjustment {
720+
adjustment::AdjustNeverToAny(..) |
720721
adjustment::AdjustReifyFnPointer |
721722
adjustment::AdjustUnsafeFnPointer |
722723
adjustment::AdjustMutToConstPointer => {

src/librustc/middle/intrinsicck.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,9 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
161161
let typ = self.infcx.tcx.node_id_to_type(expr.id);
162162
match typ.sty {
163163
ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
164-
if let ty::FnConverging(to) = bare_fn_ty.sig.0.output {
165-
let from = bare_fn_ty.sig.0.inputs[0];
166-
self.check_transmute(expr.span, from, to, expr.id);
167-
}
164+
let from = bare_fn_ty.sig.0.inputs[0];
165+
let to = bare_fn_ty.sig.0.output;
166+
self.check_transmute(expr.span, from, to, expr.id);
168167
}
169168
_ => {
170169
span_bug!(expr.span, "transmute wasn't a bare fn?!");

src/librustc/middle/liveness.rs

+40-49
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ use self::VarKind::*;
112112
use dep_graph::DepNode;
113113
use hir::def::*;
114114
use hir::pat_util;
115-
use ty::{self, TyCtxt, ParameterEnvironment};
115+
use ty::{self, Ty, TyCtxt, ParameterEnvironment};
116116
use traits::{self, Reveal};
117117
use ty::subst::Subst;
118118
use lint;
@@ -1111,8 +1111,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11111111
}
11121112

11131113
hir::ExprCall(ref f, ref args) => {
1114+
// FIXME(canndrew): This is_never should really be an is_uninhabited
11141115
let diverges = !self.ir.tcx.is_method_call(expr.id) &&
1115-
self.ir.tcx.expr_ty_adjusted(&f).fn_ret().diverges();
1116+
self.ir.tcx.expr_ty_adjusted(&f).fn_ret().0.is_never();
11161117
let succ = if diverges {
11171118
self.s.exit_ln
11181119
} else {
@@ -1125,7 +1126,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11251126
hir::ExprMethodCall(_, _, ref args) => {
11261127
let method_call = ty::MethodCall::expr(expr.id);
11271128
let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty;
1128-
let succ = if method_ty.fn_ret().diverges() {
1129+
// FIXME(canndrew): This is_never should really be an is_uninhabited
1130+
let succ = if method_ty.fn_ret().0.is_never() {
11291131
self.s.exit_ln
11301132
} else {
11311133
succ
@@ -1454,7 +1456,7 @@ fn check_fn(_v: &Liveness,
14541456
}
14551457

14561458
impl<'a, 'tcx> Liveness<'a, 'tcx> {
1457-
fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
1459+
fn fn_ret(&self, id: NodeId) -> ty::Binder<Ty<'tcx>> {
14581460
let fn_ty = self.ir.tcx.node_id_to_type(id);
14591461
match fn_ty.sty {
14601462
ty::TyClosure(closure_def_id, substs) =>
@@ -1477,55 +1479,44 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
14771479
self.ir.tcx.region_maps.call_site_extent(id, body.id),
14781480
&self.fn_ret(id));
14791481

1480-
match fn_ret {
1481-
ty::FnConverging(t_ret)
1482-
if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() => {
1483-
1484-
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
1485-
let t_ret_subst = t_ret.subst(self.ir.tcx, &param_env.free_substs);
1486-
let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
1487-
Reveal::All).enter(|infcx| {
1488-
let cause = traits::ObligationCause::dummy();
1489-
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
1490-
});
1491-
1492-
// for nil return types, it is ok to not return a value expl.
1493-
if !is_nil {
1494-
let ends_with_stmt = match body.expr {
1495-
None if !body.stmts.is_empty() =>
1496-
match body.stmts.last().unwrap().node {
1497-
hir::StmtSemi(ref e, _) => {
1498-
self.ir.tcx.expr_ty(&e) == t_ret
1499-
},
1500-
_ => false
1482+
if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
1483+
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
1484+
let t_ret_subst = fn_ret.subst(self.ir.tcx, &param_env.free_substs);
1485+
let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
1486+
Reveal::All).enter(|infcx| {
1487+
let cause = traits::ObligationCause::dummy();
1488+
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
1489+
});
1490+
1491+
// for nil return types, it is ok to not return a value expl.
1492+
if !is_nil {
1493+
let ends_with_stmt = match body.expr {
1494+
None if !body.stmts.is_empty() =>
1495+
match body.stmts.last().unwrap().node {
1496+
hir::StmtSemi(ref e, _) => {
1497+
self.ir.tcx.expr_ty(&e) == fn_ret
15011498
},
1502-
_ => false
1499+
_ => false
1500+
},
1501+
_ => false
1502+
};
1503+
let mut err = struct_span_err!(self.ir.tcx.sess,
1504+
sp,
1505+
E0269,
1506+
"not all control paths return a value");
1507+
if ends_with_stmt {
1508+
let last_stmt = body.stmts.last().unwrap();
1509+
let original_span = original_sp(self.ir.tcx.sess.codemap(),
1510+
last_stmt.span, sp);
1511+
let span_semicolon = Span {
1512+
lo: original_span.hi - BytePos(1),
1513+
hi: original_span.hi,
1514+
expn_id: original_span.expn_id
15031515
};
1504-
let mut err = struct_span_err!(self.ir.tcx.sess,
1505-
sp,
1506-
E0269,
1507-
"not all control paths return a value");
1508-
if ends_with_stmt {
1509-
let last_stmt = body.stmts.last().unwrap();
1510-
let original_span = original_sp(self.ir.tcx.sess.codemap(),
1511-
last_stmt.span, sp);
1512-
let span_semicolon = Span {
1513-
lo: original_span.hi - BytePos(1),
1514-
hi: original_span.hi,
1515-
expn_id: original_span.expn_id
1516-
};
1517-
err.span_help(span_semicolon, "consider removing this semicolon:");
1518-
}
1519-
err.emit();
1516+
err.span_help(span_semicolon, "consider removing this semicolon:");
15201517
}
1518+
err.emit();
15211519
}
1522-
ty::FnDiverging
1523-
if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() => {
1524-
span_err!(self.ir.tcx.sess, sp, E0270,
1525-
"computation may converge in a function marked as diverging");
1526-
}
1527-
1528-
_ => {}
15291520
}
15301521
}
15311522

src/librustc/middle/mem_categorization.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
451451
self.cat_expr_autoderefd(expr, autoderefs)
452452
}
453453

454+
adjustment::AdjustNeverToAny(..) |
454455
adjustment::AdjustReifyFnPointer |
455456
adjustment::AdjustUnsafeFnPointer |
456457
adjustment::AdjustMutToConstPointer |
@@ -922,7 +923,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
922923
let base_cmt = match method_ty {
923924
Some(method_ty) => {
924925
let ref_ty =
925-
self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
926+
self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
926927
self.cat_rvalue_node(node.id(), node.span(), ref_ty)
927928
}
928929
None => base_cmt
@@ -1244,7 +1245,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
12441245
// to skip past the binder.
12451246
self.tcx().no_late_bound_regions(&method_ty.fn_ret())
12461247
.unwrap()
1247-
.unwrap() // overloaded ops do not diverge, either
12481248
}
12491249
}
12501250

0 commit comments

Comments
 (0)