diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 8764766b2ef86..bb7c971111853 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -699,6 +699,39 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + // Note: This macro is a temporary hack that can be remove once we are building with a compiler + // that supports `!` + macro_rules! not_stage0 { + () => { + #[unstable(feature = "never_type", issue = "35121")] + impl PartialEq for ! { + fn eq(&self, _: &!) -> bool { + *self + } + } + + #[unstable(feature = "never_type", issue = "35121")] + impl Eq for ! {} + + #[unstable(feature = "never_type", issue = "35121")] + impl PartialOrd for ! { + fn partial_cmp(&self, _: &!) -> Option { + *self + } + } + + #[unstable(feature = "never_type", issue = "35121")] + impl Ord for ! { + fn cmp(&self, _: &!) -> Ordering { + *self + } + } + } + } + + #[cfg(not(stage0))] + not_stage0!(); + // & pointers #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 173c55e35d51e..dbd715c722e13 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1363,6 +1363,29 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } +// Note: This macro is a temporary hack that can be remove once we are building with a compiler +// that supports `!` +macro_rules! not_stage0 { + () => { + #[unstable(feature = "never_type", issue = "35121")] + impl Debug for ! { + fn fmt(&self, _: &mut Formatter) -> Result { + *self + } + } + + #[unstable(feature = "never_type", issue = "35121")] + impl Display for ! { + fn fmt(&self, _: &mut Formatter) -> Result { + *self + } + } + } +} + +#[cfg(not(stage0))] +not_stage0!(); + #[stable(feature = "rust1", since = "1.0.0")] impl Debug for bool { fn fmt(&self, f: &mut Formatter) -> Result { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index fabb3900ec648..7831464756b94 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -88,6 +88,9 @@ #![feature(unboxed_closures)] #![feature(question_mark)] +// NOTE: remove the cfg_attr next snapshot +#![cfg_attr(not(stage0), feature(never_type))] + #[macro_use] mod macros; diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 601d3866b02d4..232db76a6d175 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -379,7 +379,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); let ret = self.straightline(call_expr, func_or_rcvr_exit, args); - if fn_ty.fn_ret().diverges() { + // FIXME(canndrew): This is_never should probably be an is_uninhabited. + if fn_ty.fn_ret().0.is_never() { self.add_unreachable_node() } else { ret diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index dd79e14f077e8..0edfd16bdfd1b 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -353,6 +353,7 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { } })) } + TyNever => node, TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))), TyPath(qself, path) => { let qself = qself.map(|QSelf { ty, position }| { @@ -515,7 +516,6 @@ pub fn noop_fold_fn_decl(decl: P, fld: &mut T) -> P { output: match output { Return(ty) => Return(fld.fold_ty(ty)), DefaultReturn(span) => DefaultReturn(span), - NoReturn(span) => NoReturn(span), }, variadic: variadic, } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 1162c290f9cfc..92b956788860e 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -403,6 +403,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { walk_list!(visitor, visit_lifetime, opt_lifetime); visitor.visit_ty(&mutable_type.ty) } + TyNever => {}, TyTup(ref tuple_element_types) => { walk_list!(visitor, visit_ty, tuple_element_types); } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index eb98ed77da703..c2b211238b2f1 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -270,6 +270,7 @@ impl<'a> LoweringContext<'a> { decl: self.lower_fn_decl(&f.decl), })) } + Never => hir::TyNever, Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()), Paren(ref ty) => { return self.lower_ty(ty); @@ -402,7 +403,6 @@ impl<'a> LoweringContext<'a> { output: match decl.output { FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)), FunctionRetTy::Default(span) => hir::DefaultReturn(span), - FunctionRetTy::None(span) => hir::NoReturn(span), }, variadic: decl.variadic, }) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 707ef987c2c06..d41cdfabdf4c0 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1112,6 +1112,7 @@ pub struct BareFnTy { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] /// The different kinds of types recognized by the compiler pub enum Ty_ { + /// A variable length array (`[T]`) TyVec(P), /// A fixed length array (`[T; n]`) TyFixedLengthVec(P, P), @@ -1121,6 +1122,8 @@ pub enum Ty_ { TyRptr(Option, MutTy), /// A bare function (e.g. `fn(usize) -> bool`) TyBareFn(P), + /// The never type (`!`) + TyNever, /// A tuple (`(A, B, C, D,...)`) TyTup(HirVec>), /// A path (`module::module::...::Type`), optionally @@ -1283,9 +1286,6 @@ impl fmt::Debug for ImplPolarity { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum FunctionRetTy { - /// Functions with return type `!`that always - /// raise an error or exit (i.e. never return to the caller) - NoReturn(Span), /// Return type is not specified. /// /// Functions default to `()` and @@ -1299,7 +1299,6 @@ pub enum FunctionRetTy { impl FunctionRetTy { pub fn span(&self) -> Span { match *self { - NoReturn(span) => span, DefaultReturn(span) => span, Return(ref ty) => ty.span, } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 6dedae5ccd75d..66c1bc7642c56 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -504,6 +504,9 @@ impl<'a> State<'a> { self.print_opt_lifetime(lifetime)?; self.print_mt(mt)?; } + hir::TyNever => { + word(&mut self.s, "!")?; + }, hir::TyTup(ref elts) => { self.popen()?; self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&ty))?; @@ -1959,10 +1962,6 @@ impl<'a> State<'a> { self.maybe_print_comment(ty.span.lo) } hir::DefaultReturn(..) => unreachable!(), - hir::NoReturn(span) => { - self.word_nbsp("!")?; - self.maybe_print_comment(span.lo) - } } } @@ -2195,7 +2194,6 @@ impl<'a> State<'a> { self.ibox(indent_unit)?; self.word_space("->")?; match decl.output { - hir::NoReturn(_) => self.word_nbsp("!")?, hir::DefaultReturn(..) => unreachable!(), hir::Return(ref ty) => self.print_type(&ty)?, } diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 3ad5ef1e0ff6d..b0dec3277a996 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1326,7 +1326,6 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names) ), hir::DefaultReturn(span) => hir::DefaultReturn(span), - hir::NoReturn(span) => hir::NoReturn(span) } } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 1fb4e59e13189..ecd9759c721b2 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -168,6 +168,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyTrait(..) | ty::TyStruct(..) | ty::TyClosure(..) | + ty::TyNever | ty::TyTuple(..) | ty::TyProjection(..) | ty::TyParam(..) | diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 697478015cb7b..24fadc549fafc 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -607,7 +607,6 @@ impl_trans_normalize!('gcx, Ty<'gcx>, &'gcx Substs<'gcx>, ty::FnSig<'gcx>, - ty::FnOutput<'gcx>, &'gcx ty::BareFnTy<'gcx>, ty::ClosureSubsts<'gcx>, ty::PolyTraitRef<'gcx> diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 18b80a9636b45..87463055a276a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -717,6 +717,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let adj = infcx.adjustments().get(&expr.id).map(|x| x.clone()); if let Some(adjustment) = adj { match adjustment { + adjustment::AdjustNeverToAny(..) | adjustment::AdjustReifyFnPointer | adjustment::AdjustUnsafeFnPointer | adjustment::AdjustMutToConstPointer => { diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 15f2f21ef2529..a1a4f15b9f78e 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -161,10 +161,9 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> { let typ = self.infcx.tcx.node_id_to_type(expr.id); match typ.sty { ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { - if let ty::FnConverging(to) = bare_fn_ty.sig.0.output { - let from = bare_fn_ty.sig.0.inputs[0]; - self.check_transmute(expr.span, from, to, expr.id); - } + let from = bare_fn_ty.sig.0.inputs[0]; + let to = bare_fn_ty.sig.0.output; + self.check_transmute(expr.span, from, to, expr.id); } _ => { span_bug!(expr.span, "transmute wasn't a bare fn?!"); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index f62c9a5d8823e..74d29b273ff2b 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -112,7 +112,7 @@ use self::VarKind::*; use dep_graph::DepNode; use hir::def::*; use hir::pat_util; -use ty::{self, TyCtxt, ParameterEnvironment}; +use ty::{self, Ty, TyCtxt, ParameterEnvironment}; use traits::{self, Reveal}; use ty::subst::Subst; use lint; @@ -1111,8 +1111,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprCall(ref f, ref args) => { + // FIXME(canndrew): This is_never should really be an is_uninhabited let diverges = !self.ir.tcx.is_method_call(expr.id) && - self.ir.tcx.expr_ty_adjusted(&f).fn_ret().diverges(); + self.ir.tcx.expr_ty_adjusted(&f).fn_ret().0.is_never(); let succ = if diverges { self.s.exit_ln } else { @@ -1125,7 +1126,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprMethodCall(_, _, ref args) => { let method_call = ty::MethodCall::expr(expr.id); let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty; - let succ = if method_ty.fn_ret().diverges() { + // FIXME(canndrew): This is_never should really be an is_uninhabited + let succ = if method_ty.fn_ret().0.is_never() { self.s.exit_ln } else { succ @@ -1454,7 +1456,7 @@ fn check_fn(_v: &Liveness, } impl<'a, 'tcx> Liveness<'a, 'tcx> { - fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> { + fn fn_ret(&self, id: NodeId) -> ty::Binder> { let fn_ty = self.ir.tcx.node_id_to_type(id); match fn_ty.sty { ty::TyClosure(closure_def_id, substs) => @@ -1477,55 +1479,44 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.ir.tcx.region_maps.call_site_extent(id, body.id), &self.fn_ret(id)); - match fn_ret { - ty::FnConverging(t_ret) - if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() => { - - let param_env = ParameterEnvironment::for_item(self.ir.tcx, id); - let t_ret_subst = t_ret.subst(self.ir.tcx, ¶m_env.free_substs); - let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env), - Reveal::All).enter(|infcx| { - let cause = traits::ObligationCause::dummy(); - traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil() - }); - - // for nil return types, it is ok to not return a value expl. - if !is_nil { - let ends_with_stmt = match body.expr { - None if !body.stmts.is_empty() => - match body.stmts.last().unwrap().node { - hir::StmtSemi(ref e, _) => { - self.ir.tcx.expr_ty(&e) == t_ret - }, - _ => false + if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { + let param_env = ParameterEnvironment::for_item(self.ir.tcx, id); + let t_ret_subst = fn_ret.subst(self.ir.tcx, ¶m_env.free_substs); + let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env), + Reveal::All).enter(|infcx| { + let cause = traits::ObligationCause::dummy(); + traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil() + }); + + // for nil return types, it is ok to not return a value expl. + if !is_nil { + let ends_with_stmt = match body.expr { + None if !body.stmts.is_empty() => + match body.stmts.last().unwrap().node { + hir::StmtSemi(ref e, _) => { + self.ir.tcx.expr_ty(&e) == fn_ret }, - _ => false + _ => false + }, + _ => false + }; + let mut err = struct_span_err!(self.ir.tcx.sess, + sp, + E0269, + "not all control paths return a value"); + if ends_with_stmt { + let last_stmt = body.stmts.last().unwrap(); + let original_span = original_sp(self.ir.tcx.sess.codemap(), + last_stmt.span, sp); + let span_semicolon = Span { + lo: original_span.hi - BytePos(1), + hi: original_span.hi, + expn_id: original_span.expn_id }; - let mut err = struct_span_err!(self.ir.tcx.sess, - sp, - E0269, - "not all control paths return a value"); - if ends_with_stmt { - let last_stmt = body.stmts.last().unwrap(); - let original_span = original_sp(self.ir.tcx.sess.codemap(), - last_stmt.span, sp); - let span_semicolon = Span { - lo: original_span.hi - BytePos(1), - hi: original_span.hi, - expn_id: original_span.expn_id - }; - err.span_help(span_semicolon, "consider removing this semicolon:"); - } - err.emit(); + err.span_help(span_semicolon, "consider removing this semicolon:"); } + err.emit(); } - ty::FnDiverging - if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() => { - span_err!(self.ir.tcx.sess, sp, E0270, - "computation may converge in a function marked as diverging"); - } - - _ => {} } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0bc3c1ae899dd..676e456dcea94 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -451,6 +451,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { self.cat_expr_autoderefd(expr, autoderefs) } + adjustment::AdjustNeverToAny(..) | adjustment::AdjustReifyFnPointer | adjustment::AdjustUnsafeFnPointer | adjustment::AdjustMutToConstPointer | @@ -922,7 +923,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let base_cmt = match method_ty { Some(method_ty) => { let ref_ty = - self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap(); + self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap(); self.cat_rvalue_node(node.id(), node.span(), ref_ty) } None => base_cmt @@ -1244,7 +1245,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // to skip past the binder. self.tcx().no_late_bound_regions(&method_ty.fn_ret()) .unwrap() - .unwrap() // overloaded ops do not diverge, either } } diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 08614ca253be5..549026290c9d5 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -17,7 +17,7 @@ use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccesso use rustc_data_structures::control_flow_graph::ControlFlowGraph; use hir::def_id::DefId; use ty::subst::Substs; -use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty}; +use ty::{self, AdtDef, ClosureSubsts, Region, Ty}; use util::ppaux; use rustc_back::slice; use hir::InlineAsm; @@ -74,7 +74,7 @@ pub struct Mir<'tcx> { pub promoted: IndexVec>, /// Return type of the function. - pub return_ty: FnOutput<'tcx>, + pub return_ty: Ty<'tcx>, /// Variables: these are stack slots corresponding to user variables. They may be /// assigned many times. @@ -107,7 +107,7 @@ impl<'tcx> Mir<'tcx> { pub fn new(basic_blocks: IndexVec>, visibility_scopes: IndexVec, promoted: IndexVec>, - return_ty: FnOutput<'tcx>, + return_ty: Ty<'tcx>, var_decls: IndexVec>, arg_decls: IndexVec>, temp_decls: IndexVec>, diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 534bb2c0b2b2a..cf91229f1c713 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -125,7 +125,7 @@ impl<'tcx> Lvalue<'tcx> { &Lvalue::Static(def_id) => LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty }, &Lvalue::ReturnPointer => - LvalueTy::Ty { ty: mir.return_ty.unwrap() }, + LvalueTy::Ty { ty: mir.return_ty }, &Lvalue::Projection(ref proj) => proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem), } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index d44f00ed2cbe2..66cdc7f156d9c 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -11,7 +11,7 @@ use middle::const_val::ConstVal; use hir::def_id::DefId; use ty::subst::Substs; -use ty::{ClosureSubsts, FnOutput, Region, Ty}; +use ty::{ClosureSubsts, Region, Ty}; use mir::repr::*; use rustc_const_math::ConstUsize; use rustc_data_structures::tuple_slice::TupleSlice; @@ -38,9 +38,7 @@ use syntax_pos::Span; // // For the most part, we do not destructure things external to the // MIR, e.g. types, spans, etc, but simply visit them and stop. This -// avoids duplication with other visitors like `TypeFoldable`. But -// there is one exception: we do destructure the `FnOutput` to reach -// the type within. Just because. +// avoids duplication with other visitors like `TypeFoldable`. // // ## Updating // @@ -192,11 +190,6 @@ macro_rules! make_mir_visitor { self.super_source_info(source_info); } - fn visit_fn_output(&mut self, - fn_output: & $($mutability)* FnOutput<'tcx>) { - self.super_fn_output(fn_output); - } - fn visit_ty(&mut self, ty: & $($mutability)* Ty<'tcx>) { self.super_ty(ty); @@ -261,7 +254,7 @@ macro_rules! make_mir_visitor { self.visit_visibility_scope_data(scope); } - self.visit_fn_output(&$($mutability)* mir.return_ty); + self.visit_ty(&$($mutability)* mir.return_ty); for var_decl in &$($mutability)* mir.var_decls { self.visit_var_decl(var_decl); @@ -702,16 +695,6 @@ macro_rules! make_mir_visitor { self.visit_visibility_scope(scope); } - fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) { - match *fn_output { - FnOutput::FnConverging(ref $($mutability)* ty) => { - self.visit_ty(ty); - } - FnOutput::FnDiverging => { - } - } - } - fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) { } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 37193d45e6885..b38f5f96de448 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -253,6 +253,7 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> ty::TySlice(..) | ty::TyRawPtr(..) | ty::TyRef(..) | + ty::TyNever | ty::TyTuple(..) | ty::TyParam(..) | ty::TyProjection(..) => { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 09b5a34fdf337..cf004767b2aac 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -212,6 +212,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyProjection(..) => Some(13), ty::TyParam(..) => Some(14), ty::TyAnon(..) => Some(15), + ty::TyNever => Some(16), ty::TyInfer(..) | ty::TyError => None } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 93c6dd09e07b8..4889895860129 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -269,10 +269,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return Some(MethodViolationCode::ReferencesSelf); } } - if let ty::FnConverging(result_type) = sig.0.output { - if self.contains_illegal_self_type_reference(trait_def_id, result_type) { - return Some(MethodViolationCode::ReferencesSelf); - } + if self.contains_illegal_self_type_reference(trait_def_id, sig.0.output) { + return Some(MethodViolationCode::ReferencesSelf); } // We can't monomorphize things like `fn foo(...)`. diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 2df492e507bdc..b61cb0d3eee72 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1388,7 +1388,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { abi: Abi::Rust, sig: ty::Binder(ty::FnSig { inputs: _, - output: ty::FnConverging(_), + output: _, variadic: false }) }) | @@ -1397,7 +1397,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { abi: Abi::Rust, sig: ty::Binder(ty::FnSig { inputs: _, - output: ty::FnConverging(_), + output: _, variadic: false }) }) => { @@ -1772,7 +1772,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) | ty::TyChar | ty::TyBox(_) | ty::TyRef(..) | - ty::TyArray(..) | ty::TyClosure(..) | + ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever | ty::TyError => { // safe for everything Where(ty::Binder(Vec::new())) @@ -1820,7 +1820,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | - ty::TyRawPtr(..) | ty::TyError | + ty::TyRawPtr(..) | ty::TyError | ty::TyNever | ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { Where(ty::Binder(Vec::new())) } @@ -1886,6 +1886,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyError | ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | + ty::TyNever | ty::TyChar => { Vec::new() } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index a097c0093b2e1..818eb4eb2fb1e 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -515,7 +515,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def_id: fn_trait_def_id, substs: self.mk_substs(trait_substs), }; - ty::Binder((trait_ref, sig.0.output.unwrap_or(self.mk_nil()))) + ty::Binder((trait_ref, sig.0.output)) } } diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 47ca7d335ab82..ae9fd5ab5bc87 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -21,9 +21,10 @@ use hir; #[derive(Copy, Clone)] pub enum AutoAdjustment<'tcx> { - AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type - AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer + AdjustNeverToAny(Ty<'tcx>), // go from ! to any type + AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type + AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer + AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer AdjustDerefRef(AutoDerefRef<'tcx>), } @@ -106,6 +107,7 @@ pub struct AutoDerefRef<'tcx> { impl<'tcx> AutoAdjustment<'tcx> { pub fn is_identity(&self) -> bool { match *self { + AdjustNeverToAny(ty) => ty.is_never(), AdjustReifyFnPointer | AdjustUnsafeFnPointer | AdjustMutToConstPointer => false, @@ -154,6 +156,8 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { return match adjustment { Some(adjustment) => { match *adjustment { + AdjustNeverToAny(ref ty) => ty, + AdjustReifyFnPointer => { match self.sty { ty::TyFnDef(_, _, f) => tcx.mk_fn_ptr(f), @@ -227,8 +231,7 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { if let Some(method_ty) = method_type(method_call) { // Method calls always have all late-bound regions // fully instantiated. - let fn_ret = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); - adjusted_ty = fn_ret.unwrap(); + adjusted_ty = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); } match adjusted_ty.builtin_deref(true, NoPreference) { Some(mt) => mt.ty, diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index 8da7568c558a7..53bf046d6b597 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -185,7 +185,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { // Scalar and unique types are sendable, and durable ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | + ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => { TC::None } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 13401e91265eb..4056fb01aa2c2 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -190,6 +190,7 @@ pub struct CommonTypes<'tcx> { pub u64: Ty<'tcx>, pub f32: Ty<'tcx>, pub f64: Ty<'tcx>, + pub never: Ty<'tcx>, pub err: Ty<'tcx>, } @@ -256,6 +257,7 @@ impl<'tcx> CommonTypes<'tcx> { CommonTypes { bool: mk(TyBool), char: mk(TyChar), + never: mk(TyNever), err: mk(TyError), isize: mk(TyInt(ast::IntTy::Is)), i8: mk(TyInt(ast::IntTy::I8)), @@ -975,7 +977,7 @@ macro_rules! sty_debug_print { for &Interned(t) in tcx.interners.type_.borrow().iter() { let variant = match t.sty { ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) | - ty::TyFloat(..) | ty::TyStr => continue, + ty::TyFloat(..) | ty::TyStr | ty::TyNever => continue, ty::TyError => /* unimportant */ continue, $(ty::$variant(..) => &mut $variant,)* }; @@ -1264,6 +1266,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_tup(Vec::new()) } + pub fn mk_diverging_default(self) -> Ty<'tcx> { + if self.sess.features.borrow().never_type { + self.types.never + } else { + self.mk_nil() + } + } + pub fn mk_bool(self) -> Ty<'tcx> { self.mk_ty(TyBool) } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 66165ec6ff7d0..dab9c246d5f1b 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -214,7 +214,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String { match self.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | - ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr => self.to_string(), + ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(), ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(), ty::TyEnum(def, _) => format!("enum `{}`", tcx.item_path_str(def.did)), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index e6f2ba8b650f1..9bf2daeb5f49b 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -26,6 +26,7 @@ pub enum SimplifiedType { StrSimplifiedType, VecSimplifiedType, PtrSimplifiedType, + NeverSimplifiedType, TupleSimplifiedType(usize), TraitSimplifiedType(DefId), StructSimplifiedType(DefId), @@ -81,6 +82,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyClosure(def_id, _) => { Some(ClosureSimplifiedType(def_id)) } + ty::TyNever => Some(NeverSimplifiedType), ty::TyTuple(ref tys) => { Some(TupleSimplifiedType(tys.len())) } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 85b7d66a2eb08..0997d6c1a7562 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -60,6 +60,7 @@ impl FlagComputation { &ty::TyInt(_) | &ty::TyFloat(_) | &ty::TyUint(_) | + &ty::TyNever | &ty::TyStr => { } @@ -171,10 +172,7 @@ impl FlagComputation { let mut computation = FlagComputation::new(); computation.add_tys(&fn_sig.0.inputs); - - if let ty::FnConverging(output) = fn_sig.0.output { - computation.add_ty(output); - } + computation.add_ty(fn_sig.0.output); self.add_bound_computation(&computation); } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 3580013c2a912..3eeff6ee5792f 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -160,12 +160,6 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { sig.super_fold_with(self) } - fn fold_output(&mut self, - output: &ty::FnOutput<'tcx>) - -> ty::FnOutput<'tcx> { - output.super_fold_with(self) - } - fn fold_bare_fn_ty(&mut self, fty: &'tcx ty::BareFnTy<'tcx>) -> &'tcx ty::BareFnTy<'tcx> diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index bfe6303d8a328..8ddd8bef36a6f 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -349,6 +349,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option { ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError | + ty::TyNever | ty::TyFloat(_) => None, } } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index d73e412f55f26..195cece6bc4e0 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -795,6 +795,9 @@ impl<'a, 'gcx, 'tcx> Layout { ty::TyFloat(FloatTy::F64) => Scalar { value: F64, non_zero: false }, ty::TyFnPtr(_) => Scalar { value: Pointer, non_zero: true }, + // The never type. + ty::TyNever => Univariant { variant: Struct::new(dl, false), non_zero: false }, + // Potentially-fat pointers. ty::TyBox(pointee) | ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8e89b3c60879f..cfc2e89f9d5a1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -55,7 +55,7 @@ use hir::intravisit::Visitor; pub use self::sty::{Binder, DebruijnIndex}; pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds}; -pub use self::sty::{BareFnTy, FnSig, PolyFnSig, FnOutput, PolyFnOutput}; +pub use self::sty::{BareFnTy, FnSig, PolyFnSig}; pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitTy}; pub use self::sty::{ClosureSubsts, TypeAndMut}; pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; @@ -63,7 +63,6 @@ pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::Issue32330; pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid}; pub use self::sty::BoundRegion::*; -pub use self::sty::FnOutput::*; pub use self::sty::InferTy::*; pub use self::sty::Region::*; pub use self::sty::TypeVariants::*; @@ -1854,7 +1853,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { let result = match ty.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | - TyArray(..) | TyClosure(..) => { + TyArray(..) | TyClosure(..) | TyNever => { vec![] } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index df907c26f7142..ee431681ad100 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -171,6 +171,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyInt(..) | // OutlivesScalar ty::TyUint(..) | // OutlivesScalar ty::TyFloat(..) | // OutlivesScalar + ty::TyNever | // ... ty::TyEnum(..) | // OutlivesNominalType ty::TyStruct(..) | // OutlivesNominalType ty::TyBox(..) | // OutlivesNominalType (ish) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index f9263947c0379..05a9b8111570d 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -256,20 +256,11 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { let inputs = relate_arg_vecs(relation, &a.inputs, &b.inputs)?; + let output = relation.relate(&a.output, &b.output)?; - let output = match (a.output, b.output) { - (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => - Ok(ty::FnConverging(relation.relate(&a_ty, &b_ty)?)), - (ty::FnDiverging, ty::FnDiverging) => - Ok(ty::FnDiverging), - (a, b) => - Err(TypeError::ConvergenceMismatch( - expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))), - }?; - - return Ok(ty::FnSig {inputs: inputs, - output: output, - variadic: a.variadic}); + Ok(ty::FnSig {inputs: inputs, + output: output, + variadic: a.variadic}) } } @@ -462,6 +453,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.types.err) } + (&ty::TyNever, _) | (&ty::TyChar, _) | (&ty::TyBool, _) | (&ty::TyInt(_), _) | diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 8c10806fda768..83413d16ffb3f 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -220,18 +220,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoRef<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for ty::FnOutput<'a> { - type Lifted = ty::FnOutput<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - match *self { - ty::FnConverging(ty) => { - tcx.lift(&ty).map(ty::FnConverging) - } - ty::FnDiverging => Some(ty::FnDiverging) - } - } -} - impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> { type Lifted = ty::FnSig<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -498,7 +486,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | - ty::TyParam(..) => self.sty.clone(), + ty::TyParam(..) | ty::TyNever => self.sty.clone(), }; folder.tcx().mk_ty(sty) } @@ -527,7 +515,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyAnon(_, ref substs) => substs.visit_with(visitor), ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) | - ty::TyParam(..) => false, + ty::TyParam(..) | ty::TyNever => false, } } @@ -587,26 +575,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - ty::FnConverging(ref ty) => ty::FnConverging(ty.fold_with(folder)), - ty::FnDiverging => ty::FnDiverging - } - } - - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_output(self) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::FnConverging(ref ty) => ty.visit_with(visitor), - ty::FnDiverging => false, - } - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::FnSig { inputs: self.inputs.fold_with(folder), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 912cb39face0a..9680632ec4dcc 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -29,7 +29,6 @@ use serialize::{Decodable, Decoder, Encodable, Encoder}; use hir; -use self::FnOutput::*; use self::InferTy::*; use self::TypeVariants::*; @@ -159,6 +158,9 @@ pub enum TypeVariants<'tcx> { /// `|a| a`. TyClosure(DefId, ClosureSubsts<'tcx>), + /// The never type `!` + TyNever, + /// A tuple type. For example, `(i32, bool)`. TyTuple(&'tcx [Ty<'tcx>]), @@ -474,47 +476,6 @@ pub struct ClosureTy<'tcx> { pub sig: PolyFnSig<'tcx>, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub enum FnOutput<'tcx> { - FnConverging(Ty<'tcx>), - FnDiverging -} - -impl<'tcx> FnOutput<'tcx> { - pub fn diverges(&self) -> bool { - *self == FnDiverging - } - - pub fn unwrap(self) -> Ty<'tcx> { - match self { - ty::FnConverging(t) => t, - ty::FnDiverging => bug!() - } - } - - pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> { - match self { - ty::FnConverging(t) => t, - ty::FnDiverging => def - } - } - - pub fn maybe_converging(self) -> Option> { - match self { - ty::FnConverging(t) => Some(t), - ty::FnDiverging => None - } - } -} - -pub type PolyFnOutput<'tcx> = Binder>; - -impl<'tcx> PolyFnOutput<'tcx> { - pub fn diverges(&self) -> bool { - self.0.diverges() - } -} - /// Signature of a function type, which I have arbitrarily /// decided to use to refer to the input/output types. /// @@ -524,7 +485,7 @@ impl<'tcx> PolyFnOutput<'tcx> { #[derive(Clone, PartialEq, Eq, Hash)] pub struct FnSig<'tcx> { pub inputs: Vec>, - pub output: FnOutput<'tcx>, + pub output: Ty<'tcx>, pub variadic: bool } @@ -537,7 +498,7 @@ impl<'tcx> PolyFnSig<'tcx> { pub fn input(&self, index: usize) -> ty::Binder> { self.map_bound_ref(|fn_sig| fn_sig.inputs[index]) } - pub fn output(&self) -> ty::Binder> { + pub fn output(&self) -> ty::Binder> { self.map_bound_ref(|fn_sig| fn_sig.output.clone()) } pub fn variadic(&self) -> bool { @@ -933,11 +894,27 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn is_empty(&self, _cx: TyCtxt) -> bool { - // FIXME(#24885): be smarter here + pub fn is_never(&self) -> bool { + match self.sty { + TyNever => true, + _ => false, + } + } + + pub fn is_uninhabited(&self, _cx: TyCtxt) -> bool { + // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made + // more complete. match self.sty { TyEnum(def, _) | TyStruct(def, _) => def.is_empty(), - _ => false + + // FIXME(canndrew): There's no reason why these can't be uncommented, they're tested + // and they don't break anything. But I'm keeping my changes small for now. + //TyNever => true, + //TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited(cx)), + + // FIXME(canndrew): this line breaks core::fmt + //TyRef(_, ref tm) => tm.ty.is_uninhabited(cx), + _ => false, } } @@ -1195,7 +1172,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { self.fn_sig().inputs() } - pub fn fn_ret(&self) -> Binder> { + pub fn fn_ret(&self) -> Binder> { self.fn_sig().output() } @@ -1260,6 +1237,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyArray(_, _) | TySlice(_) | TyRawPtr(_) | + TyNever | TyTuple(_) | TyParam(_) | TyInfer(_) | diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index e7bcfbfd82345..d7bb8ff2995aa 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -485,6 +485,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { self.def_id(data.trait_ref.def_id); self.hash(data.item_name.as_str()); } + TyNever | TyBool | TyChar | TyStr | @@ -550,7 +551,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { // Fast-path for primitive types let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyNever | TyRawPtr(..) | TyFnDef(..) | TyFnPtr(_) | TyRef(_, TypeAndMut { mutbl: hir::MutImmutable, .. }) => Some(false), @@ -596,7 +597,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { let result = match self.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | - TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), + TyArray(..) | TyTuple(..) | TyClosure(..) | TyNever => Some(true), TyStr | TyTrait(..) | TySlice(_) => Some(false), diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index ebc2642678bfd..9c1f9d9537a4f 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -70,7 +70,7 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { match parent_ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | - ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyError => { + ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => { } ty::TyBox(ty) | ty::TyArray(ty, _) | ty::TySlice(ty) => { stack.push(ty); @@ -110,10 +110,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { } fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { - match sig.0.output { - ty::FnConverging(output) => { stack.push(output); } - ty::FnDiverging => { } - } + stack.push(sig.0.output); push_reversed(stack, &sig.0.inputs); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index f6ddfe60d40e6..bfc2e11d9fbce 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -321,6 +321,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ty::TyFloat(..) | ty::TyError | ty::TyStr | + ty::TyNever | ty::TyParam(_) => { // WfScalar, WfParameter, etc } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index a17c01068139a..896ef49de6f05 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -14,7 +14,7 @@ use ty::subst::{self, Subst}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use ty::{TyBool, TyChar, TyStruct, TyEnum}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; -use ty::{TyParam, TyRawPtr, TyRef, TyTuple}; +use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::TyClosure; use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -34,7 +34,7 @@ pub fn verbose() -> bool { fn fn_sig(f: &mut fmt::Formatter, inputs: &[Ty], variadic: bool, - output: ty::FnOutput) + output: Ty) -> fmt::Result { write!(f, "(")?; let mut inputs = inputs.iter(); @@ -48,18 +48,11 @@ fn fn_sig(f: &mut fmt::Formatter, } } write!(f, ")")?; - - match output { - ty::FnConverging(ty) => { - if !ty.is_nil() { - write!(f, " -> {}", ty)?; - } - Ok(()) - } - ty::FnDiverging => { - write!(f, " -> !") - } + if !output.is_nil() { + write!(f, " -> {}", output)?; } + + Ok(()) } /// Namespace of the path given to parameterized to print. @@ -135,7 +128,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.types.get_slice(subst::TypeSpace)[0].sty { - return fn_sig(f, args, false, ty::FnConverging(projection_ty)); + return fn_sig(f, args, false, projection_ty); } } @@ -429,6 +422,9 @@ impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> { impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { + ty::adjustment::AdjustNeverToAny(ref target) => { + write!(f, "AdjustNeverToAny({:?})", target) + } ty::adjustment::AdjustReifyFnPointer => { write!(f, "AdjustReifyFnPointer") } @@ -847,6 +843,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } write!(f, "{}", tm) } + TyNever => write!(f, "!"), TyTuple(ref tys) => { write!(f, "(")?; let mut tys = tys.iter(); diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index e965dcc169c2d..b3feac2bdc5e0 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -9,7 +9,7 @@ // except according to those terms. -use rustc::ty::{FnOutput, TyCtxt}; +use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::util::nodemap::FnvHashMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; @@ -231,8 +231,7 @@ impl<'tcx> Index for MovePathData<'tcx> { } } -struct MovePathDataBuilder<'a, 'tcx: 'a> { - mir: &'a Mir<'tcx>, +struct MovePathDataBuilder<'tcx> { pre_move_paths: Vec>, rev_lookup: MovePathLookup<'tcx>, } @@ -412,7 +411,7 @@ impl<'tcx> MovePathLookup<'tcx> { } } -impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> { +impl<'tcx> MovePathDataBuilder<'tcx> { fn lookup(&mut self, lval: &Lvalue<'tcx>) -> Lookup { let proj = match *lval { Lvalue::Var(var_idx) => @@ -528,7 +527,6 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD // BlockContexts constructed on each iteration. (Moving is more // straight-forward than mutable borrows in this instance.) let mut builder = MovePathDataBuilder { - mir: mir, pre_move_paths: Vec::new(), rev_lookup: MovePathLookup::new(mir), }; @@ -632,13 +630,8 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::Return => { let source = Location { block: bb, index: bb_data.statements.len() }; - if let FnOutput::FnConverging(_) = bb_ctxt.builder.mir.return_ty { - debug!("gather_moves Return on_move_out_lval return {:?}", source); - bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source); - } else { - debug!("gather_moves Return on_move_out_lval \ - assuming unreachable return {:?}", source); - } + debug!("gather_moves Return on_move_out_lval return {:?}", source); + bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source); } TerminatorKind::If { ref cond, targets: _ } => { @@ -749,15 +742,15 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD } } -struct BlockContext<'b, 'a: 'b, 'tcx: 'a> { +struct BlockContext<'b, 'tcx: 'b> { _tcx: TyCtxt<'b, 'tcx, 'tcx>, moves: &'b mut Vec, - builder: MovePathDataBuilder<'a, 'tcx>, + builder: MovePathDataBuilder<'tcx>, path_map: &'b mut Vec>, loc_map_bb: &'b mut Vec>, } -impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> { +impl<'b, 'tcx: 'b> BlockContext<'b, 'tcx> { fn on_move_out_lval(&mut self, stmt_kind: StmtKind, lval: &Lvalue<'tcx>, diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 3e88dec8cb27a..4049a2b815d02 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -215,7 +215,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) { // Check for empty enum, because is_useful only works on inhabited types. let pat_ty = cx.tcx.node_id_to_type(scrut.id); if inlined_arms.is_empty() { - if !pat_ty.is_empty(cx.tcx) { + if !pat_ty.is_uninhabited(cx.tcx) { // We know the type is inhabited, so this must be wrong let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002, "non-exhaustive patterns: type {} is non-empty", @@ -225,7 +225,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) { possibly adding wildcards or more match arms."); err.emit(); } - // If the type *is* empty, it's vacuously exhaustive + // If the type *is* uninhabited, it's vacuously exhaustive return; } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 30fe38a0603a5..7711091685d38 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { abi: Abi::Rust, sig: ty::Binder(ty::FnSig { inputs: input_args, - output: ty::FnConverging(output_ty), + output: output_ty, variadic: false, }), })) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d8ec79fb06096..ed17f3533d49f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1110,10 +1110,9 @@ impl LateLintPass for MutableTransmutes { let typ = cx.tcx.node_id_to_type(expr.id); match typ.sty { ty::TyFnDef(_, _, ref bare_fn) if bare_fn.abi == RustIntrinsic => { - if let ty::FnConverging(to) = bare_fn.sig.0.output { - let from = bare_fn.sig.0.inputs[0]; - return Some((&from.sty, &to.sty)); - } + let from = bare_fn.sig.0.inputs[0]; + let to = bare_fn.sig.0.output; + return Some((&from.sty, &to.sty)); }, _ => () } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index b9861c309dbec..99df5c6e5f95e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -523,7 +523,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Primitive types with a stable representation. ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | - ty::TyFloat(..) => FfiSafe, + ty::TyFloat(..) | ty::TyNever => FfiSafe, ty::TyBox(..) => { FfiUnsafe("found Rust type Box<_> in foreign module, \ @@ -573,16 +573,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } let sig = cx.erase_late_bound_regions(&bare_fn.sig); - match sig.output { - ty::FnDiverging => {} - ty::FnConverging(output) => { - if !output.is_nil() { - let r = self.check_type_for_ffi(cache, output); - match r { - FfiSafe => {} - _ => { return r; } - } - } + if !sig.output.is_nil() { + let r = self.check_type_for_ffi(cache, sig.output); + match r { + FfiSafe => {} + _ => { return r; } } } for arg in sig.inputs { @@ -641,7 +636,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } if let hir::Return(ref ret_hir) = decl.output { - let ret_ty = sig.output.unwrap(); + let ret_ty = sig.output; if !ret_ty.is_nil() { self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty); } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 4dc1a5e4f5e9f..57705301aab4e 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -133,6 +133,7 @@ impl LateLintPass for UnusedResults { let t = cx.tcx.expr_ty(&expr); let warned = match t.sty { ty::TyTuple(ref tys) if tys.is_empty() => return, + ty::TyNever => return, ty::TyBool => return, ty::TyStruct(def, _) | ty::TyEnum(def, _) => { diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index f03c432c09177..b8e66530ea153 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -644,6 +644,12 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref))) }) } + + adjustment::AdjustNeverToAny(ref ty) => { + this.emit_enum_variant("AdjustNeverToAny", 5, 1, |this| { + this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, ty))) + }) + } } }); } @@ -1017,7 +1023,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { -> adjustment::AutoAdjustment<'tcx> { self.read_enum("AutoAdjustment", |this| { let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", - "AdjustMutToConstPointer", "AdjustDerefRef"]; + "AdjustMutToConstPointer", "AdjustDerefRef", + "AdjustNeverToAny"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { 1 => adjustment::AdjustReifyFnPointer, @@ -1030,6 +1037,13 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { adjustment::AdjustDerefRef(auto_deref_ref) } + 5 => { + let ty: Ty<'tcx> = this.read_enum_variant_arg(0, |this| { + Ok(this.read_ty(dcx)) + }).unwrap(); + + adjustment::AdjustNeverToAny(ty) + } _ => bug!("bad enum variant for adjustment::AutoAdjustment") }) }) diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 1dcec35adb285..7b4919bb4773b 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -311,6 +311,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { let tcx = self.tcx; match self.next() { 'b' => return tcx.types.bool, + '!' => return tcx.types.never, 'i' => { /* eat the s of is */ self.next(); return tcx.types.isize }, 'u' => { /* eat the s of us */ self.next(); return tcx.types.usize }, 'M' => { @@ -539,13 +540,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { 'N' => false, r => bug!("bad variadic: {}", r), }; - let output = match self.peek() { - 'z' => { - self.pos += 1; - ty::FnDiverging - } - _ => ty::FnConverging(self.parse_ty()) - }; + let output = self.parse_ty(); ty::Binder(ty::FnSig {inputs: inputs, output: output, variadic: variadic}) diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index c2e91eba0d252..15bafcdd3c99e 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -74,6 +74,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx match t.sty { ty::TyBool => { write!(w, "b"); } ty::TyChar => { write!(w, "c"); } + ty::TyNever => { write!(w, "!"); } ty::TyInt(t) => { match t { ast::IntTy::Is => write!(w, "is"), @@ -382,14 +383,7 @@ fn enc_fn_sig<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, } else { write!(w, "N"); } - match fsig.0.output { - ty::FnConverging(result_type) => { - enc_ty(w, cx, result_type); - } - ty::FnDiverging => { - write!(w, "z"); - } - } + enc_ty(w, cx, fsig.0.output); } pub fn enc_builtin_bounds(w: &mut Cursor>, _cx: &ctxt, bs: &ty::BuiltinBounds) { diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index dd6c9c02f5644..ae5ccbfd82099 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -96,6 +96,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::LogicalOp { .. } | ExprKind::Box { .. } | ExprKind::Cast { .. } | + ExprKind::NeverToAny { .. } | ExprKind::ReifyFnPointer { .. } | ExprKind::UnsafeFnPointer { .. } | ExprKind::Unsize { .. } | diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index f1487992cb522..dafc53d3c1542 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -219,6 +219,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Block { .. } | ExprKind::Match { .. } | ExprKind::If { .. } | + ExprKind::NeverToAny { .. } | ExprKind::Loop { .. } | ExprKind::LogicalOp { .. } | ExprKind::Call { .. } | diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 658b7779b44a9..c19ea0f445ac0 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -56,6 +56,7 @@ impl Category { ExprKind::LogicalOp { .. } | ExprKind::If { .. } | ExprKind::Match { .. } | + ExprKind::NeverToAny { .. } | ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)), diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index fd9ddc05ab5c4..e5930f5a62df6 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -45,6 +45,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Match { discriminant, arms } => { this.match_expr(destination, expr_span, block, discriminant, arms) } + ExprKind::NeverToAny { source } => { + let source = this.hir.mirror(source); + let is_call = match source.kind { + ExprKind::Call { .. } => true, + _ => false, + }; + + unpack!(block = this.as_rvalue(block, source)); + + // This is an optimization. If the expression was a call then we already have an + // unreachable block. Don't bother to terminate it and create a new one. + if is_call { + block.unit() + } else { + this.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + let end_block = this.cfg.start_new_block(); + end_block.unit() + } + } ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => { let operand = unpack!(block = this.as_operand(block, cond_expr)); @@ -190,7 +209,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Call { ty, fun, args } => { let diverges = match ty.sty { ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { - f.sig.0.output.diverges() + // FIXME(canndrew): This is_never should probably be an is_uninhabited + f.sig.0.output.is_never() } _ => false }; diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 362e1e26fdf1e..86c95db89c8a3 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -162,7 +162,7 @@ macro_rules! unpack { pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, fn_id: ast::NodeId, arguments: A, - return_ty: ty::FnOutput<'gcx>, + return_ty: Ty<'gcx>, ast_block: &'gcx hir::Block) -> (Mir<'tcx>, ScopeAuxiliaryVec) where A: Iterator, Option<&'gcx hir::Pat>)> @@ -255,7 +255,7 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, }); let ty = tcx.expr_ty_adjusted(ast_expr); - builder.finish(vec![], IndexVec::new(), ty::FnConverging(ty)) + builder.finish(vec![], IndexVec::new(), ty) } impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -287,7 +287,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, upvar_decls: Vec, arg_decls: IndexVec>, - return_ty: ty::FnOutput<'tcx>) + return_ty: Ty<'tcx>) -> (Mir<'tcx>, ScopeAuxiliaryVec) { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { if block.terminator.is_none() { @@ -309,7 +309,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn args_and_body(&mut self, mut block: BasicBlock, - return_ty: ty::FnOutput<'tcx>, + return_ty: Ty<'tcx>, arguments: A, argument_extent: CodeExtent, ast_block: &'gcx hir::Block) @@ -350,11 +350,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } // FIXME(#32959): temporary hack for the issue at hand - let return_is_unit = if let ty::FnConverging(t) = return_ty { - t.is_nil() - } else { - false - }; + let return_is_unit = return_ty.is_nil(); // start the first basic block and translate the body unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block)); diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/graphviz.rs index d986d88dafc94..72b6d7f0e5aa5 100644 --- a/src/librustc_mir/graphviz.rs +++ b/src/librustc_mir/graphviz.rs @@ -12,7 +12,7 @@ use dot; use rustc::hir::def_id::DefId; use rustc::mir::repr::*; use rustc::mir::mir_map::MirMap; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::TyCtxt; use std::fmt::Debug; use std::io::{self, Write}; use syntax::ast::NodeId; @@ -143,14 +143,7 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>, write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?; } - write!(w, ") -> ")?; - - // fn return type. - match mir.return_ty { - ty::FnOutput::FnConverging(ty) => write!(w, "{}", escape(ty))?, - ty::FnOutput::FnDiverging => write!(w, "!")?, - } - + write!(w, ") -> {}", escape(mir.return_ty))?; write!(w, r#"
"#)?; // User variable types (including the user's name in a comment). diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 88fb65d8eea03..a61fdb79df822 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -60,6 +60,14 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() }, }; } + Some(&ty::adjustment::AdjustNeverToAny(adjusted_ty)) => { + expr = Expr { + temp_lifetime: temp_lifetime, + ty: adjusted_ty, + span: self.span, + kind: ExprKind::NeverToAny { source: expr.to_ref() }, + }; + } Some(&ty::adjustment::AdjustMutToConstPointer) => { let adjusted_ty = cx.tcx.expr_ty_adjusted(self); expr = Expr { @@ -88,9 +96,9 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret()); let (region, mutbl) = match ref_ty { - Some(ty::FnConverging(&ty::TyS { + Some(&ty::TyS { sty: ty::TyRef(region, mt), .. - })) => (region, mt.mutbl), + }) => (region, mt.mutbl), _ => span_bug!(expr.span, "autoderef returned bad type") }; @@ -946,10 +954,8 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let tables = cx.tcx.tables.borrow(); let callee = &tables.method_map[&method_call]; let ref_ty = callee.ty.fn_ret(); - let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap().unwrap(); - // 1~~~~~ 2~~~~~ - // (1) callees always have all late-bound regions fully instantiated, - // (2) overloaded methods don't return `!` + let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap(); + // callees always have all late-bound regions fully instantiated, // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index a2746bf30c91f..2a5b7d0fb2902 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -139,6 +139,9 @@ pub enum ExprKind<'tcx> { Cast { source: ExprRef<'tcx>, }, + NeverToAny { + source: ExprRef<'tcx>, + }, ReifyFnPointer { source: ExprRef<'tcx>, }, diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 55e7408b0fd5d..c58491096b94f 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::repr::*; use rustc::mir::mir_map::MirMap; use rustc::mir::transform::MirSource; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; use rustc_data_structures::indexed_vec::{Idx}; use std::fmt::Display; @@ -320,16 +320,10 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?; } - write!(w, ") -> ")?; - - // fn return type. - match mir.return_ty { - ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty), - ty::FnOutput::FnDiverging => write!(w, "!"), - } + write!(w, ") -> {}", mir.return_ty) } else { assert!(mir.arg_decls.is_empty()); - write!(w, ": {} =", mir.return_ty.unwrap()) + write!(w, ": {} =", mir.return_ty) } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index eb0d8697f15d4..aaa20405b8d57 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -25,7 +25,7 @@ use rustc::mir::repr::*; use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; use rustc::mir::traversal::ReversePostorder; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::TyCtxt; use syntax_pos::Span; use build::Location; @@ -299,7 +299,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let span = self.promoted.span; let new_operand = Operand::Constant(Constant { span: span, - ty: self.promoted.return_ty.unwrap(), + ty: self.promoted.return_ty, literal: Literal::Promoted { index: Promoted::new(self.source.promoted.len()) } @@ -389,7 +389,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, parent_scope: None }).into_iter().collect(), IndexVec::new(), - ty::FnConverging(ty), + ty, IndexVec::new(), IndexVec::new(), IndexVec::new(), diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 7ebc72bcc5fca..57c0f66448d35 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -416,7 +416,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } } - let return_ty = mir.return_ty.unwrap(); + let return_ty = mir.return_ty; self.qualif = self.return_qualif.unwrap_or(Qualif::NOT_CONST); match self.mode { @@ -991,7 +991,7 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { // Statics must be Sync. if mode == Mode::Static { - let ty = mir.return_ty.unwrap(); + let ty = mir.return_ty; tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); let mut fulfillment_cx = traits::FulfillmentContext::new(); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 934357c9e1da2..a030ba17655fd 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -85,9 +85,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { } fn visit_mir(&mut self, mir: &Mir<'tcx>) { - if let ty::FnConverging(t) = mir.return_ty { - self.sanitize_type(&"return type", t); - } + self.sanitize_type(&"return type", mir.return_ty); for var_decl in &mir.var_decls { self.sanitize_type(var_decl, var_decl.ty); } @@ -135,14 +133,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { Lvalue::Static(def_id) => LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty }, Lvalue::ReturnPointer => { - if let ty::FnConverging(return_ty) = self.mir.return_ty { - LvalueTy::Ty { ty: return_ty } - } else { - LvalueTy::Ty { - ty: span_mirbug_and_err!( - self, lvalue, "return in diverging function") - } - } + LvalueTy::Ty { ty: self.mir.return_ty } } Lvalue::Projection(ref proj) => { let base_ty = self.sanitize_lvalue(&proj.base); @@ -491,22 +482,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { sig: &ty::FnSig<'tcx>, destination: &Option<(Lvalue<'tcx>, BasicBlock)>) { let tcx = self.tcx(); - match (destination, sig.output) { - (&Some(..), ty::FnDiverging) => { - span_mirbug!(self, term, "call to diverging function {:?} with dest", sig); - } - (&Some((ref dest, _)), ty::FnConverging(ty)) => { + match *destination { + Some((ref dest, _)) => { let dest_ty = dest.ty(mir, tcx).to_ty(tcx); - if let Err(terr) = self.sub_types(self.last_span, ty, dest_ty) { + if let Err(terr) = self.sub_types(self.last_span, sig.output, dest_ty) { span_mirbug!(self, term, "call dest mismatch ({:?} <- {:?}): {:?}", - dest_ty, ty, terr); + dest_ty, sig.output, terr); } - } - (&None, ty::FnDiverging) => {} - (&None, ty::FnConverging(..)) => { - span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); - } + }, + None => { + // FIXME(canndrew): This is_never should probably be an is_uninhabited + if !sig.output.is_never() { + span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); + } + }, } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 37e42cdea1bf8..0c54f20fe7667 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -632,6 +632,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) { match v.tcx.tables.borrow().adjustments.get(&e.id) { None | + Some(&ty::adjustment::AdjustNeverToAny(..)) | Some(&ty::adjustment::AdjustReifyFnPointer) | Some(&ty::adjustment::AdjustUnsafeFnPointer) | Some(&ty::adjustment::AdjustMutToConstPointer) => {} diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 7f5f09aa6b6a9..42239a7d5a4ee 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { let expr_ty = self.tcx.expr_ty(expr); let def = match expr_ty.sty { ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { - output: ty::FnConverging(ty), .. + output: ty, .. }), ..}) => ty, _ => expr_ty }.ty_adt_def().unwrap(); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 0580c51d9a17a..16cd9186ce9bb 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -671,7 +671,6 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { sig.push_str(&decl.inputs.iter().map(arg_to_string).collect::>().join(", ")); sig.push(')'); match decl.output { - ast::FunctionRetTy::None(_) => sig.push_str(" -> !"), ast::FunctionRetTy::Default(_) => {} ast::FunctionRetTy::Ty(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))), } diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 29b3f6ce52fb2..27a8c1f1df476 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -1593,7 +1593,7 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>, } let t = node_id_type(bcx, discr_expr.id); - let chk = if t.is_empty(tcx) { + let chk = if t.is_uninhabited(tcx) { Unreachable } else { Infallible diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 587c03af3abb6..3a7fde6a36bad 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -326,10 +326,7 @@ impl FnType { } }; - let ret_ty = match sig.output { - ty::FnConverging(ret_ty) => ret_ty, - ty::FnDiverging => ccx.tcx().mk_nil() - }; + let ret_ty = sig.output; let mut ret = arg_of(ret_ty, true); if !type_is_fat_ptr(ccx.tcx(), ret_ty) { @@ -470,7 +467,7 @@ impl FnType { }; // Fat pointers are returned by-value. if !self.ret.is_ignore() { - if !type_is_fat_ptr(ccx.tcx(), sig.output.unwrap()) { + if !type_is_fat_ptr(ccx.tcx(), sig.output) { fixup(&mut self.ret); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 1077cb296c1ac..70c3fdc269d68 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1972,7 +1972,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); let sig = ccx.tcx().normalize_associated_type(&sig); - let result_ty = sig.output.unwrap(); + let result_ty = sig.output; // Get location to store the result. If the user does not care about // the result, just make a stack slot @@ -2054,7 +2054,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if !fcx.fn_ty.ret.is_ignore() { let dest = fcx.get_ret_slot(bcx, "eret_slot"); let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value - let repr = adt::represent_type(ccx, sig.output.unwrap()); + let repr = adt::represent_type(ccx, sig.output); let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize; let mut arg_idx = 0; for (i, arg_ty) in sig.inputs.into_iter().enumerate() { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 983ee564c35b1..aaec2a47025a2 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -641,10 +641,7 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let opt_llretslot = dest.and_then(|dest| match dest { expr::SaveIn(dst) => Some(dst), expr::Ignore => { - let needs_drop = || match output { - ty::FnConverging(ret_ty) => bcx.fcx.type_needs_drop(ret_ty), - ty::FnDiverging => false - }; + let needs_drop = || bcx.fcx.type_needs_drop(output); if fn_ty.ret.is_indirect() || fn_ty.ret.cast.is_some() || needs_drop() { // Push the out-pointer if we use an out-pointer for this // return type, otherwise push "undef". @@ -706,16 +703,17 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // If the caller doesn't care about the result of this fn call, // drop the temporary slot we made. - match (dest, opt_llretslot, output) { - (Some(expr::Ignore), Some(llretslot), ty::FnConverging(ret_ty)) => { + match (dest, opt_llretslot) { + (Some(expr::Ignore), Some(llretslot)) => { // drop the value if it is not being saved. - bcx = glue::drop_ty(bcx, llretslot, ret_ty, debug_loc); + bcx = glue::drop_ty(bcx, llretslot, output, debug_loc); call_lifetime_end(bcx, llretslot); } _ => {} } - if output == ty::FnDiverging { + // FIXME(canndrew): This is_never should really be an is_uninhabited + if output.is_never() { Unreachable(bcx); } diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index e53a5edfc6685..77b2c43167cfd 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -201,7 +201,11 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trans_closure_expr(Dest::Ignore(ccx), &hir::FnDecl { inputs: P::new(), - output: hir::NoReturn(DUMMY_SP), + output: hir::Return(P(hir::Ty { + id: DUMMY_NODE_ID, + span: DUMMY_SP, + node: hir::Ty_::TyNever, + })), variadic: false }, &hir::Block { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 4a6dbb2bdae56..6decc48c36a3b 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -753,6 +753,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) | + ty::TyNever | ty::TyTrait(_) => { /* nothing to do */ } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index dea5a1560e15b..79cf77cd9d35d 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -558,7 +558,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { abi: Abi::C, sig: ty::Binder(ty::FnSig { inputs: vec![tcx.mk_mut_ptr(tcx.types.u8)], - output: ty::FnDiverging, + output: tcx.types.never, variadic: false }), })); @@ -1240,8 +1240,8 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, inlined_vid); let adt_def = match ctor_ty.sty { ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { - output: ty::FnConverging(ty), .. - }), ..}) => ty, + output, .. + }), ..}) => output, _ => ctor_ty }.ty_adt_def().unwrap(); let variant_def_id = if ccx.tcx().map.is_inlined_node_id(inlined_vid) { diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 769dd008af8f4..3ecba3691d279 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -34,7 +34,7 @@ use type_of; use value::Value; use Disr; use rustc::ty::subst::Substs; -use rustc::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use rustc::ty::adjustment::{AdjustNeverToAny, AdjustDerefRef, AdjustReifyFnPointer}; use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::cast::{CastTy,IntTy}; @@ -348,6 +348,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, &cx.tcx().expr_ty_adjusted(e)); let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned(); match opt_adj { + Some(AdjustNeverToAny(..)) => span_bug!(e.span, "const expression of type ! encountered"), Some(AdjustReifyFnPointer) => { match ety.sty { ty::TyFnDef(def_id, substs, _) => { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index ee13af80b2ba0..3fe8b2b66791a 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -171,6 +171,7 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push('{'); match type_.sty { + ty::TyNever | ty::TyBool | ty::TyChar | ty::TyStr | @@ -278,16 +279,9 @@ impl<'tcx> TypeMap<'tcx> { } unique_type_id.push_str(")->"); - match sig.output { - ty::FnConverging(ret_ty) => { - let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty); - let return_type_id = self.get_unique_type_id_as_string(return_type_id); - unique_type_id.push_str(&return_type_id[..]); - } - ty::FnDiverging => { - unique_type_id.push_str("!"); - } - } + let return_type_id = self.get_unique_type_id_of_type(cx, sig.output); + let return_type_id = self.get_unique_type_id_as_string(return_type_id); + unique_type_id.push_str(&return_type_id[..]); }, ty::TyClosure(_, substs) if substs.upvar_tys.is_empty() => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); @@ -595,12 +589,9 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs.len() + 1); // return type - signature_metadata.push(match signature.output { - ty::FnConverging(ret_ty) => match ret_ty.sty { - ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), - _ => type_metadata(cx, ret_ty, span) - }, - ty::FnDiverging => diverging_type_metadata(cx) + signature_metadata.push(match signature.output.sty { + ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), + _ => type_metadata(cx, signature.output, span) }); // regular arguments @@ -704,6 +695,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let sty = &t.sty; let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty { + ty::TyNever | ty::TyBool | ty::TyChar | ty::TyInt(_) | @@ -914,23 +906,13 @@ pub fn scope_metadata(fcx: &FunctionContext, } } -pub fn diverging_type_metadata(cx: &CrateContext) -> DIType { - unsafe { - llvm::LLVMRustDIBuilderCreateBasicType( - DIB(cx), - "!\0".as_ptr() as *const _, - bytes_to_bits(0), - bytes_to_bits(0), - DW_ATE_unsigned) - } -} - fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> DIType { debug!("basic_type_metadata: {:?}", t); let (name, encoding) = match t.sty { + ty::TyNever => ("!", DW_ATE_unsigned), ty::TyTuple(ref elements) if elements.is_empty() => ("()", DW_ATE_unsigned), ty::TyBool => ("bool", DW_ATE_boolean), diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index f2c7068565ee9..d6a4ce3c43a4e 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -17,8 +17,7 @@ use self::VariableKind::*; use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit}; use self::namespace::mangled_name_of_item; use self::type_names::compute_debuginfo_type_name; -use self::metadata::{type_metadata, diverging_type_metadata}; -use self::metadata::{file_metadata, TypeMap}; +use self::metadata::{type_metadata, file_metadata, TypeMap}; use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; use llvm; @@ -325,12 +324,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let mut signature = Vec::with_capacity(sig.inputs.len() + 1); // Return type -- llvm::DIBuilder wants this at index 0 - signature.push(match sig.output { - ty::FnConverging(ret_ty) => match ret_ty.sty { - ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), - _ => type_metadata(cx, ret_ty, syntax_pos::DUMMY_SP) - }, - ty::FnDiverging => diverging_type_metadata(cx) + signature.push(match sig.output.sty { + ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), + _ => type_metadata(cx, sig.output, syntax_pos::DUMMY_SP) }); let inputs = if abi == Abi::RustCall { diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index bee2667c71f9d..73b1c828663e1 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -40,6 +40,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyBool => output.push_str("bool"), ty::TyChar => output.push_str("char"), ty::TyStr => output.push_str("str"), + ty::TyNever => output.push_str("!"), ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()), ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()), ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()), @@ -133,15 +134,9 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(')'); - match sig.output { - ty::FnConverging(result_type) if result_type.is_nil() => {} - ty::FnConverging(result_type) => { - output.push_str(" -> "); - push_debuginfo_type_name(cx, result_type, true, output); - } - ty::FnDiverging => { - output.push_str(" -> !"); - } + if !sig.output.is_nil() { + output.push_str(" -> "); + push_debuginfo_type_name(cx, sig.output, true, output); } }, ty::TyClosure(..) => { diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 324e8697ecae6..4d9ee187ac50c 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -111,7 +111,8 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, let fty = FnType::new(ccx, abi, &sig, &[]); let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx)); - if sig.output == ty::FnDiverging { + // FIXME(canndrew): This is_never should really be an is_uninhabited + if sig.output.is_never() { llvm::Attribute::NoReturn.apply_llfn(Function, llfn); } diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs index 2a60dd1744671..6c894ddad1a94 100644 --- a/src/librustc_trans/expr.rs +++ b/src/librustc_trans/expr.rs @@ -69,7 +69,7 @@ use tvec; use type_of; use value::Value; use Disr; -use rustc::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer}; +use rustc::ty::adjustment::{AdjustNeverToAny, AdjustDerefRef, AdjustReifyFnPointer}; use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::ty::{self, Ty, TyCtxt}; @@ -348,6 +348,7 @@ fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } match adjustment { + AdjustNeverToAny(..) => true, AdjustReifyFnPointer => true, AdjustUnsafeFnPointer | AdjustMutToConstPointer => { // purely a type-level thing @@ -380,6 +381,12 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("unadjusted datum for expr {:?}: {:?} adjustment={:?}", expr, datum, adjustment); match adjustment { + AdjustNeverToAny(ref target) => { + let mono_target = bcx.monomorphize(target); + let llty = type_of::type_of(bcx.ccx(), mono_target); + let dummy = C_undef(llty.ptr_to()); + datum = Datum::new(dummy, mono_target, Lvalue::new("never")).to_expr_datum(); + } AdjustReifyFnPointer => { match datum.ty.sty { ty::TyFnDef(def_id, substs, _) => { @@ -796,7 +803,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ix_datum = unpack_datum!(bcx, trans(bcx, idx)); let ref_ty = // invoked methods have LB regions instantiated: - bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap(); + bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap(); let elt_ty = match ref_ty.builtin_deref(true, ty::NoPreference) { None => { span_bug!(index_expr.span, @@ -2053,7 +2060,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let ref_ty = // invoked methods have their LB regions instantiated - ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap(); + ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap(); let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref"); bcx = Callee::method(bcx, method) diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 4980fad0cc37e..7be173d17b487 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -132,7 +132,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // For `transmute` we can just trans the input expr directly into dest if name == "transmute" { - let llret_ty = type_of::type_of(ccx, ret_ty.unwrap()); + let llret_ty = type_of::type_of(ccx, ret_ty); match args { callee::ArgExprs(arg_exprs) => { assert_eq!(arg_exprs.len(), 1); @@ -315,11 +315,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, return Result::new(bcx, C_nil(ccx)); } - let ret_ty = match ret_ty { - ty::FnConverging(ret_ty) => ret_ty, - ty::FnDiverging => bug!() - }; - let llret_ty = type_of::type_of(ccx, ret_ty); // Get location to store the result. If the user does @@ -1226,7 +1221,7 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, name: &str, inputs: Vec>, - output: ty::FnOutput<'tcx>, + output: Ty<'tcx>, trans: &mut for<'b> FnMut(Block<'b, 'tcx>)) -> ValueRef { let ccx = fcx.ccx; @@ -1272,11 +1267,11 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { inputs: vec![i8p], - output: ty::FnOutput::FnConverging(tcx.mk_nil()), + output: tcx.mk_nil(), variadic: false, }), })); - let output = ty::FnOutput::FnConverging(tcx.types.i32); + let output = tcx.types.i32; let rust_try = gen_fn(fcx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans); ccx.rust_try_fn().set(Some(rust_try)); return rust_try diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index d6dbefec03467..784e4a32f9469 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -19,6 +19,7 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common::{self, Block, BlockAndBuilder}; use glue; +use std::iter; use super::rvalue; pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>, @@ -31,7 +32,7 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>, let local_types = mir.arg_decls.iter().map(|a| a.ty) .chain(mir.var_decls.iter().map(|v| v.ty)) .chain(mir.temp_decls.iter().map(|t| t.ty)) - .chain(mir.return_ty.maybe_converging()); + .chain(iter::once(mir.return_ty)); for (index, ty) in local_types.enumerate() { let ty = bcx.monomorphize(&ty); debug!("local {} has type {:?}", index, ty); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index b1fd3e88d75f0..56d02fa1fac4f 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -525,7 +525,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // Make a fake operand for store_return let op = OperandRef { val: Ref(dst), - ty: sig.output.unwrap() + ty: sig.output, }; self.store_return(&bcx, ret_dest, fn_ty.ret, op); } @@ -563,7 +563,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { debug_loc.apply_to_bcx(ret_bcx); let op = OperandRef { val: Immediate(invokeret), - ty: sig.output.unwrap() + ty: sig.output, }; self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op); }); @@ -574,7 +574,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { if let Some((_, target)) = *destination { let op = OperandRef { val: Immediate(llret), - ty: sig.output.unwrap() + ty: sig.output, }; self.store_return(&bcx, ret_dest, fn_ty.ret, op); funclet_br(self, bcx, target); diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 8f723d288c9eb..727b680541dd7 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -26,6 +26,7 @@ use syntax::parse::token::keywords; use std::ops::Deref; use std::rc::Rc; +use std::iter; use basic_block::BasicBlock; @@ -183,7 +184,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { let locals = mir.temp_decls.iter().enumerate().map(|(i, decl)| { (mir::Lvalue::Temp(mir::Temp::new(i)), decl.ty) - }).chain(mir.return_ty.maybe_converging().map(|ty| (mir::Lvalue::ReturnPointer, ty))); + }).chain(iter::once((mir::Lvalue::ReturnPointer, mir.return_ty))); args.into_iter().chain(vars).chain(locals.map(|(lvalue, ty)| { let ty = bcx.monomorphize(&ty); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 187ffe353fdcb..90058f0b8329a 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -233,7 +233,7 @@ impl<'a, 'tcx> TransItem<'tcx> { let sig = ty::FnSig { inputs: vec![tcx.mk_mut_ptr(tcx.types.i8)], - output: ty::FnOutput::FnConverging(tcx.mk_nil()), + output: tcx.mk_nil(), variadic: false, }; @@ -412,6 +412,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyBool => output.push_str("bool"), ty::TyChar => output.push_str("char"), ty::TyStr => output.push_str("str"), + ty::TyNever => output.push_str("!"), ty::TyInt(ast::IntTy::Is) => output.push_str("isize"), ty::TyInt(ast::IntTy::I8) => output.push_str("i8"), ty::TyInt(ast::IntTy::I16) => output.push_str("i16"), @@ -515,15 +516,9 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output.push(')'); - match sig.output { - ty::FnConverging(result_type) if result_type.is_nil() => {} - ty::FnConverging(result_type) => { - output.push_str(" -> "); - push_unique_type_name(tcx, result_type, output); - } - ty::FnDiverging => { - output.push_str(" -> !"); - } + if !sig.output.is_nil() { + output.push_str(" -> "); + push_unique_type_name(tcx, sig.output, output); } }, ty::TyClosure(def_id, ref closure_substs) => { diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index cde53f6fa899c..e6794149fcb3b 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -64,6 +64,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ ty::TyInt(t) => Type::int_from_ty(cx, t), ty::TyUint(t) => Type::uint_from_ty(cx, t), ty::TyFloat(t) => Type::float_from_ty(cx, t), + ty::TyNever => Type::nil(cx), ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) | @@ -249,6 +250,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ty::TyInt(t) => Type::int_from_ty(cx, t), ty::TyUint(t) => Type::uint_from_ty(cx, t), ty::TyFloat(t) => Type::float_from_ty(cx, t), + ty::TyNever => Type::nil(cx), ty::TyEnum(def, ref substs) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. This diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ad61b5b0b513e..ed67c9fbe30be 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1700,6 +1700,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let t = self.ast_ty_to_ty(rscope1, &mt.ty); tcx.mk_ref(tcx.mk_region(r), ty::TypeAndMut {ty: t, mutbl: mt.mutbl}) } + hir::TyNever => { + tcx.types.never + }, hir::TyTup(ref fields) => { let flds = fields.iter() .map(|t| self.ast_ty_to_ty(rscope, &t)) @@ -1920,11 +1923,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let output_ty = match decl.output { hir::Return(ref output) => - ty::FnConverging(self.convert_ty_with_lifetime_elision(implied_output_region, - &output, - ret_anon_scope)), - hir::DefaultReturn(..) => ty::FnConverging(self.tcx().mk_nil()), - hir::NoReturn(..) => ty::FnDiverging + self.convert_ty_with_lifetime_elision(implied_output_region, + &output, + ret_anon_scope), + hir::DefaultReturn(..) => self.tcx().mk_nil(), }; (self.tcx().mk_bare_fn(ty::BareFnTy { @@ -2067,11 +2069,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { _ if is_infer && expected_ret_ty.is_some() => expected_ret_ty.unwrap(), _ if is_infer => - ty::FnConverging(self.ty_infer(None, None, None, decl.output.span())), + self.ty_infer(None, None, None, decl.output.span()), hir::Return(ref output) => - ty::FnConverging(self.ast_ty_to_ty(&rb, &output)), + self.ast_ty_to_ty(&rb, &output), hir::DefaultReturn(..) => bug!(), - hir::NoReturn(..) => ty::FnDiverging }; debug!("ty_of_closure: input_tys={:?}", input_tys); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5f255cc1fb730..04f22b195110f 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -610,7 +610,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let scheme = tcx.lookup_item_type(def.def_id()); let scheme = if scheme.ty.is_fn() { // Replace constructor type with constructed type for tuple struct patterns. - let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap().unwrap(); + let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap(); ty::TypeScheme { ty: fn_ret, generics: scheme.generics } } else { // Leave the type as is for unit structs (backward compatibility). diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index e73c3aa352b56..985c3be149617 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -213,7 +213,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // set up all the node type bindings. error_fn_sig = ty::Binder(ty::FnSig { inputs: self.err_args(arg_exprs.len()), - output: ty::FnConverging(self.tcx.types.err), + output: self.tcx.types.err, variadic: false }); @@ -345,10 +345,9 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty); } - let nilty = fcx.tcx.mk_nil(); fcx.demand_eqtype(self.call_expr.span, - method_sig.output.unwrap_or(nilty), - self.fn_sig.output.unwrap_or(nilty)); + method_sig.output, + self.fn_sig.output); fcx.write_overloaded_call_method_map(self.call_expr, method_callee); } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d3396eb4c1baf..3acb8017eec50 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -221,7 +221,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fn_sig = ty::FnSig { inputs: input_tys, - output: ty::FnConverging(ret_param_ty), + output: ret_param_ty, variadic: false }; debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 9dd737f3a6168..4a0d529812891 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -68,6 +68,7 @@ use rustc::traits::{self, ObligationCause}; use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; use rustc::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer}; use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; +use rustc::ty::adjustment::AdjustNeverToAny; use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty}; use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; @@ -167,6 +168,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { return self.identity(b); } + if a.is_never() { + return Ok((b, AdjustNeverToAny(b))); + } + // Consider coercing the subtype to a DST let unsize = self.coerce_unsized(a, b); if unsize.is_ok() { @@ -637,7 +642,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { apply(&mut coerce, &|| Some(expr), source, target)?; if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); - assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); + match self.tables.borrow().adjustments.get(&expr.id) { + None | Some(&AdjustNeverToAny(..)) => (), + _ => bug!("expr already has an adjustment on it!"), + }; self.write_adjustment(expr.id, adjustment); } Ok(ty) @@ -741,6 +749,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } _ => false }, + Some(&AdjustNeverToAny(_)) => true, Some(_) => false, None => true }; @@ -776,7 +785,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Ok((ty, adjustment)) => { if !adjustment.is_identity() { for expr in exprs() { - self.write_adjustment(expr.id, adjustment); + let previous = self.tables.borrow().adjustments.get(&expr.id).cloned(); + if let Some(AdjustNeverToAny(_)) = previous { + self.write_adjustment(expr.id, AdjustNeverToAny(ty)); + } else { + self.write_adjustment(expr.id, adjustment); + } } } Ok(ty) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index f65e15430daf7..f3a01ef7409fa 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -433,7 +433,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( // We still need to ensure all referenced data is safe. match ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | - ty::TyFloat(_) | ty::TyStr => { + ty::TyFloat(_) | ty::TyStr | ty::TyNever => { // primitive - definitely safe Ok(()) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 9051b1c8069bd..ddc8c82c12254 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -30,8 +30,8 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::ForeignItem, n_tps: usize, abi: Abi, - inputs: Vec>, - output: ty::FnOutput<'tcx>) { + inputs: Vec>, + output: Ty<'tcx>) { let tcx = ccx.tcx; let def_id = tcx.map.local_def_id(it.id); let i_ty = tcx.lookup_item_type(def_id); @@ -104,9 +104,9 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { return; } }; - (n_tps, inputs, ty::FnConverging(output)) + (n_tps, inputs, output) } else if &name[..] == "abort" || &name[..] == "unreachable" { - (0, Vec::new(), ty::FnDiverging) + (0, Vec::new(), tcx.types.never) } else { let (n_tps, inputs, output) = match &name[..] { "breakpoint" => (0, Vec::new(), tcx.mk_nil()), @@ -291,7 +291,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { abi: Abi::Rust, sig: ty::Binder(FnSig { inputs: vec![mut_u8], - output: ty::FnOutput::FnConverging(tcx.mk_nil()), + output: tcx.mk_nil(), variadic: false, }), }); @@ -304,7 +304,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { return; } }; - (n_tps, inputs, ty::FnConverging(output)) + (n_tps, inputs, output) }; equate_intrinsic_type(ccx, it, n_tps, Abi::RustIntrinsic, inputs, output) } @@ -377,7 +377,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, } match_intrinsic_type_to_type(ccx, "return value", it.span, &mut structural_to_nomimal, - &intr.output, sig.output.unwrap()); + &intr.output, sig.output); return } None => { @@ -390,7 +390,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, }; equate_intrinsic_type(ccx, it, n_tps, Abi::PlatformIntrinsic, - inputs, ty::FnConverging(output)) + inputs, output) } // walk the expected type and the actual type in lock step, checking they're diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0c8e6d990a644..8e0f3082bae7a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -372,7 +372,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // expects the types within the function to be consistent. err_count_on_creation: usize, - ret_ty: ty::FnOutput<'tcx>, + ret_ty: Ty<'tcx>, ps: RefCell, @@ -676,14 +676,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id); *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id); - fn_sig.output = match fcx.ret_ty { - ty::FnConverging(orig_ret_ty) => { - fcx.require_type_is_sized(orig_ret_ty, decl.output.span(), traits::ReturnType); - ty::FnConverging(fcx.instantiate_anon_types(&orig_ret_ty)) - } - ty::FnDiverging => ty::FnDiverging - }; - fcx.ret_ty = fn_sig.output; + fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType); + fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty); + fn_sig.output = fcx.ret_ty; { let mut visit = GatherLocalsVisitor { fcx: &fcx, }; @@ -714,10 +709,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - fcx.check_block_with_expected(body, match fcx.ret_ty { - ty::FnConverging(result_type) => ExpectHasType(result_type), - ty::FnDiverging => NoExpectation - }); + fcx.check_block_with_expected(body, ExpectHasType(fcx.ret_ty)); fcx } @@ -1168,7 +1160,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, expected_type: Ty<'tcx>, id: ast::NodeId) { ccx.inherited(id).enter(|inh| { - let fcx = FnCtxt::new(&inh, ty::FnConverging(expected_type), expr.id); + let fcx = FnCtxt::new(&inh, expected_type, expr.id); fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized); // Gather locals in statics (because of block expressions). @@ -1465,7 +1457,7 @@ enum TupleArgumentsFlag { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, - rty: ty::FnOutput<'tcx>, + rty: Ty<'tcx>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { @@ -1559,6 +1551,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("write_ty({}, {:?}) in fcx {}", node_id, ty, self.tag()); self.tables.borrow_mut().node_types.insert(node_id, ty); + + // Add adjustments to !-expressions + if ty.is_never() { + if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) { + let adj = adjustment::AdjustNeverToAny(self.next_diverging_ty_var()); + self.write_adjustment(node_id, adj); + } + } } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -1704,7 +1704,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut type_scheme = self.tcx.lookup_item_type(did); if type_scheme.ty.is_fn() { // Tuple variants have fn type even in type namespace, extract true variant type from it - let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap().unwrap(); + let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap(); type_scheme = ty::TypeScheme { ty: fn_ret, generics: type_scheme.generics } } let type_predicates = self.tcx.lookup_predicates(did); @@ -1731,6 +1731,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn write_nil(&self, node_id: ast::NodeId) { self.write_ty(node_id, self.tcx.mk_nil()); } + + pub fn write_never(&self, node_id: ast::NodeId) { + self.write_ty(node_id, self.tcx.types.never); + } + pub fn write_error(&self, node_id: ast::NodeId) { self.write_ty(node_id, self.tcx.types.err); } @@ -1788,6 +1793,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> { + if let Some(&adjustment::AdjustNeverToAny(ref t)) + = self.tables.borrow().adjustments.get(&ex.id) { + return t; + } match self.tables.borrow().node_types.get(&ex.id) { Some(&t) => t, None => { @@ -1966,9 +1975,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for ty in &self.unsolved_variables() { let resolved = self.resolve_type_vars_if_possible(ty); if self.type_var_diverges(resolved) { - debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges", + debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil()); + self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, + self.tcx.mk_diverging_default()); } else { match self.type_is_unconstrained_numeric(resolved) { UnconstrainedInt => { @@ -2042,7 +2052,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for ty in &unsolved_variables { let resolved = self.resolve_type_vars_if_possible(ty); if self.type_var_diverges(resolved) { - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil()); + self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, + self.tcx.mk_diverging_default()); } else { match self.type_is_unconstrained_numeric(resolved) { UnconstrainedInt | UnconstrainedFloat => { @@ -2100,7 +2111,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| { for ty in &unbound_tyvars { if self.type_var_diverges(ty) { - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil()); + self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, + self.tcx.mk_diverging_default()); } else { match self.type_is_unconstrained_numeric(ty) { UnconstrainedInt => { @@ -2196,7 +2208,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // reporting for more then one conflict. for ty in &unbound_tyvars { if self.type_var_diverges(ty) { - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil()); + self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, + self.tcx.mk_diverging_default()); } else { match self.type_is_unconstrained_numeric(ty) { UnconstrainedInt => { @@ -2271,7 +2284,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // extract method return type, which will be &T; // all LB regions should have been instantiated during method lookup let ret_ty = method.ty.fn_ret(); - let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap(); + let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap(); // method returns &T, but the type as visible to user is T, so deref ret_ty.builtin_deref(true, NoPreference).unwrap() @@ -2400,7 +2413,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { args_no_rcvr: &'gcx [P], tuple_arguments: TupleArgumentsFlag, expected: Expectation<'tcx>) - -> ty::FnOutput<'tcx> { + -> Ty<'tcx> { if method_fn_ty.references_error() { let err_inputs = self.err_args(args_no_rcvr.len()); @@ -2411,7 +2424,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr, false, tuple_arguments); - ty::FnConverging(self.tcx.types.err) + self.tcx.types.err } else { match method_fn_ty.sty { ty::TyFnDef(_, _, ref fty) => { @@ -2601,7 +2614,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) { - any_diverges = any_diverges || self.type_var_diverges(arg_ty); + // FIXME(canndrew): This is_never should probably be an is_uninhabited + any_diverges = any_diverges || + self.type_var_diverges(arg_ty) || + arg_ty.is_never(); } } if any_diverges && !warned { @@ -2669,11 +2685,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn write_call(&self, call_expr: &hir::Expr, - output: ty::FnOutput<'tcx>) { - self.write_ty(call_expr.id, match output { - ty::FnConverging(output_ty) => output_ty, - ty::FnDiverging => self.next_diverging_ty_var() - }); + output: Ty<'tcx>) { + self.write_ty(call_expr.id, output); } // AST fragment checking @@ -2796,35 +2809,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn expected_types_for_fn_args(&self, call_span: Span, expected_ret: Expectation<'tcx>, - formal_ret: ty::FnOutput<'tcx>, + formal_ret: Ty<'tcx>, formal_args: &[Ty<'tcx>]) -> Vec> { let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| { - if let ty::FnConverging(formal_ret_ty) = formal_ret { - self.commit_regions_if_ok(|| { - // Attempt to apply a subtyping relationship between the formal - // return type (likely containing type variables if the function - // is polymorphic) and the expected return type. - // No argument expectations are produced if unification fails. - let origin = TypeOrigin::Misc(call_span); - let ures = self.sub_types(false, origin, formal_ret_ty, ret_ty); - // FIXME(#15760) can't use try! here, FromError doesn't default - // to identity so the resulting type is not constrained. - match ures { - // FIXME(#32730) propagate obligations - Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()), - Err(e) => return Err(e), - } + self.commit_regions_if_ok(|| { + // Attempt to apply a subtyping relationship between the formal + // return type (likely containing type variables if the function + // is polymorphic) and the expected return type. + // No argument expectations are produced if unification fails. + let origin = TypeOrigin::Misc(call_span); + let ures = self.sub_types(false, origin, formal_ret, ret_ty); + // FIXME(#15760) can't use try! here, FromError doesn't default + // to identity so the resulting type is not constrained. + match ures { + // FIXME(#32730) propagate obligations + Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()), + Err(e) => return Err(e), + } - // Record all the argument types, with the substitutions - // produced from the above subtyping unification. - Ok(formal_args.iter().map(|ty| { - self.resolve_type_vars_if_possible(ty) - }).collect()) - }).ok() - } else { - None - } + // Record all the argument types, with the substitutions + // produced from the above subtyping unification. + Ok(formal_args.iter().map(|ty| { + self.resolve_type_vars_if_possible(ty) + }).collect()) + }).ok() }).unwrap_or(vec![]); debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})", formal_args, formal_ret, @@ -3481,39 +3490,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } self.write_nil(id); } - hir::ExprBreak(_) => { self.write_ty(id, self.next_diverging_ty_var()); } - hir::ExprAgain(_) => { self.write_ty(id, self.next_diverging_ty_var()); } + hir::ExprBreak(_) => { self.write_never(id); } + hir::ExprAgain(_) => { self.write_never(id); } hir::ExprRet(ref expr_opt) => { - match self.ret_ty { - ty::FnConverging(result_type) => { - if let Some(ref e) = *expr_opt { - self.check_expr_coercable_to_type(&e, result_type); - } else { - let eq_result = self.eq_types(false, - TypeOrigin::Misc(expr.span), - result_type, - tcx.mk_nil()) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())); - if eq_result.is_err() { - struct_span_err!(tcx.sess, expr.span, E0069, - "`return;` in a function whose return type is not `()`") - .span_label(expr.span, &format!("return type is not ()")) - .emit(); - } - } - } - ty::FnDiverging => { - if let Some(ref e) = *expr_opt { - self.check_expr(&e); - } - struct_span_err!(tcx.sess, expr.span, E0166, - "`return` in a function declared as diverging") - .span_label(expr.span, &format!("diverging function cannot return")) + if let Some(ref e) = *expr_opt { + self.check_expr_coercable_to_type(&e, self.ret_ty); + } else { + let eq_result = self.eq_types(false, + TypeOrigin::Misc(expr.span), + self.ret_ty, + tcx.mk_nil()) + // FIXME(#32730) propagate obligations + .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())); + if eq_result.is_err() { + struct_span_err!(tcx.sess, expr.span, E0069, + "`return;` in a function whose return type is not `()`") + .span_label(expr.span, &format!("return type is not ()")) .emit(); } } - self.write_ty(id, self.next_diverging_ty_var()); + self.write_never(id); } hir::ExprAssign(ref lhs, ref rhs) => { self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue); @@ -3555,7 +3551,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprLoop(ref body, _) => { self.check_block_no_value(&body); if !may_break(tcx, expr.id, &body) { - self.write_ty(id, self.next_diverging_ty_var()); + self.write_never(id); } else { self.write_nil(id); } @@ -4011,7 +4007,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { "unreachable statement".to_string()); warned = true; } - any_diverges = any_diverges || self.type_var_diverges(s_ty); + // FIXME(canndrew): This is_never should probably be an is_uninhabited + any_diverges = any_diverges || + self.type_var_diverges(s_ty) || + s_ty.is_never(); any_err = any_err || s_ty.references_error(); } match blk.expr { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 63487683ec3b9..16fe1f718b921 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -343,7 +343,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // extract return type for method; all late bound regions // should have been instantiated by now let ret_ty = method_ty.fn_ret(); - Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap()) + Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap()) } None => { Err(()) diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index f3a6442f35d11..22ffcfbaae111 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -311,7 +311,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let fn_sig_tys: Vec<_> = fn_sig.inputs.iter() .cloned() - .chain(Some(fn_sig.output.unwrap_or(self.tcx.types.bool))) + .chain(Some(fn_sig.output)) .collect(); let old_body_id = self.set_body_id(body.id); @@ -708,7 +708,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { None::.iter(), true); // late-bound regions in overloaded method calls are instantiated let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret()); - fn_ret.unwrap().unwrap() + fn_ret.unwrap() } None => self.resolve_node_type(base.id) }; @@ -980,14 +980,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // Specialized version of constrain_call. self.type_must_outlive(infer::CallRcvr(deref_expr.span), self_ty, r_deref_expr); - match fn_sig.output { - ty::FnConverging(return_type) => { - self.type_must_outlive(infer::CallReturn(deref_expr.span), - return_type, r_deref_expr); - return_type - } - ty::FnDiverging => bug!() - } + self.type_must_outlive(infer::CallReturn(deref_expr.span), + fn_sig.output, r_deref_expr); + fn_sig.output } None => derefd_ty }; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index e2080906ca242..4bb9f4fd332f2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -51,7 +51,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let id = self.id; let span = self.span; self.inherited.enter(|inh| { - let fcx = FnCtxt::new(&inh, ty::FnDiverging, id); + let fcx = FnCtxt::new(&inh, inh.ccx.tcx.types.never, id); let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { ccx: fcx.ccx, code: code @@ -394,15 +394,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } implied_bounds.extend(sig.inputs); - match sig.output { - ty::FnConverging(output) => { - fcx.register_wf_obligation(output, span, self.code.clone()); + fcx.register_wf_obligation(sig.output, span, self.code.clone()); - // FIXME(#25759) return types should not be implied bounds - implied_bounds.push(output); - } - ty::FnDiverging => { } - } + // FIXME(#25759) return types should not be implied bounds + implied_bounds.push(sig.output); self.check_where_clauses(fcx, span, predicates); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 9026920e7f48a..5f8861f309948 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -378,6 +378,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { Some(adjustment) => { let resolved_adjustment = match adjustment { + adjustment::AdjustNeverToAny(ty) => { + adjustment::AdjustNeverToAny(self.resolve(&ty, reason)) + } + adjustment::AdjustReifyFnPointer => { adjustment::AdjustReifyFnPointer } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 13deac57330e3..9b26e95f7fa55 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -24,7 +24,7 @@ use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId}; use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; use rustc::ty::{TyParam, TyRawPtr}; -use rustc::ty::{TyRef, TyStruct, TyTrait, TyTuple}; +use rustc::ty::{TyRef, TyStruct, TyTrait, TyNever, TyTuple}; use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; use rustc::ty::{TyProjection, TyAnon}; @@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) | - TyTuple(..) | TyParam(..) | TyError | + TyTuple(..) | TyParam(..) | TyError | TyNever | TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => { None } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 75bfad053a328..d38065f4f1238 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -971,7 +971,7 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, abi: abi::Abi::Rust, sig: ty::Binder(ty::FnSig { inputs: inputs, - output: ty::FnConverging(scheme.ty), + output: scheme.ty, variadic: false }) })) @@ -2155,11 +2155,9 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( let output = match decl.output { hir::Return(ref ty) => - ty::FnConverging(AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty)), + AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty), hir::DefaultReturn(..) => - ty::FnConverging(ccx.tcx.mk_nil()), - hir::NoReturn(..) => - ty::FnDiverging + ccx.tcx.mk_nil(), }; // feature gate SIMD types in FFI, since I (huonw) am not sure the @@ -2180,7 +2178,7 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( check(&input.ty, ty) } if let hir::Return(ref ty) = decl.output { - check(&ty, output.unwrap()) + check(&ty, output) } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ac40708e25cde..337b87ce994ad 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1866,20 +1866,6 @@ fn bar(foo: Foo) -> u32 { ``` "##, -E0166: r##" -This error means that the compiler found a return expression in a function -marked as diverging. A function diverges if it has `!` in the place of the -return type in its signature. For example: - -```compile_fail,E0166 -fn foo() -> ! { return; } // error -``` - -For a function that diverges, every control path in the function must never -return, for example with a `loop` that never breaks or a call to another -diverging function (such as `panic!()`). -"##, - E0172: r##" This error means that an attempt was made to specify the type of a variable with a combination of a concrete type and a trait. Consider the following example: diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0dd4bc4143927..11743ade2d469 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -238,7 +238,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { inputs: Vec::new(), - output: ty::FnConverging(tcx.mk_nil()), + output: tcx.mk_nil(), variadic: false }) })); @@ -294,7 +294,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8)) ), - output: ty::FnConverging(tcx.types.isize), + output: tcx.types.isize, variadic: false, }), })); diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index b9e0b4a10ea45..a4faee8f633ed 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -322,7 +322,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { match ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | - ty::TyFloat(_) | ty::TyStr => { + ty::TyFloat(_) | ty::TyStr | ty::TyNever => { /* leaf type -- noop */ } @@ -490,9 +490,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { for &input in &sig.0.inputs { self.add_constraints_from_ty(generics, input, contra); } - if let ty::FnConverging(result_type) = sig.0.output { - self.add_constraints_from_ty(generics, result_type, variance); - } + self.add_constraints_from_ty(generics, sig.0.output, variance); } /// Adds constraints appropriate for a region appearing in a diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 73bc647fa9ffb..99d2732c4bb06 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1176,15 +1176,6 @@ impl Clean for hir::FnDecl { } } -impl<'tcx> Clean for ty::FnOutput<'tcx> { - fn clean(&self, cx: &DocContext) -> Type { - match *self { - ty::FnConverging(ty) => ty.clean(cx), - ty::FnDiverging => Bottom - } - } -} - impl<'a, 'tcx> Clean for (DefId, &'a ty::PolyFnSig<'tcx>) { fn clean(&self, cx: &DocContext) -> FnDecl { let (did, sig) = *self; @@ -1254,7 +1245,6 @@ impl Clean for hir::Arg { pub enum FunctionRetTy { Return(Type), DefaultReturn, - NoReturn } impl Clean for hir::FunctionRetTy { @@ -1262,7 +1252,6 @@ impl Clean for hir::FunctionRetTy { match *self { hir::Return(ref typ) => Return(typ.clean(cx)), hir::DefaultReturn(..) => DefaultReturn, - hir::NoReturn(..) => NoReturn } } } @@ -1470,8 +1459,7 @@ pub enum Type { Tuple(Vec), Vector(Box), FixedVector(Box, String), - /// aka TyBot - Bottom, + Never, Unique(Box), RawPointer(Mutability, Box), BorrowedRef { @@ -1682,6 +1670,7 @@ impl Clean for hir::Ty { fn clean(&self, cx: &DocContext) -> Type { use rustc::hir::*; match self.node { + TyNever => Never, TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)), TyRptr(ref l, ref m) => BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx), @@ -1790,6 +1779,7 @@ impl Clean for hir::Ty { impl<'tcx> Clean for ty::Ty<'tcx> { fn clean(&self, cx: &DocContext) -> Type { match self.sty { + ty::TyNever => Never, ty::TyBool => Primitive(Bool), ty::TyChar => Primitive(Char), ty::TyInt(ast::IntTy::Is) => Primitive(Isize), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 854ca57e8556c..2f03b235e9f67 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -492,7 +492,7 @@ impl fmt::Display for clean::Type { primitive_link(f, clean::PrimitiveType::Array, &format!("; {}]", Escape(s))) } - clean::Bottom => f.write_str("!"), + clean::Never => f.write_str("!"), clean::RawPointer(m, ref t) => { match **t { clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { @@ -634,7 +634,6 @@ impl fmt::Display for clean::FunctionRetTy { clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()), clean::Return(ref ty) => write!(f, " -> {}", ty), clean::DefaultReturn => Ok(()), - clean::NoReturn => write!(f, " -> !") } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3f929e6d23aea..f8a5cb0b04a8e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1348,6 +1348,7 @@ pub struct BareFnTy { /// The different kinds of types recognized by the compiler #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum TyKind { + /// A variable-length array (`[T]`) Vec(P), /// A fixed length array (`[T; n]`) FixedLengthVec(P, P), @@ -1357,6 +1358,8 @@ pub enum TyKind { Rptr(Option, MutTy), /// A bare function (e.g. `fn(usize) -> bool`) BareFn(P), + /// The never type (`!`) + Never, /// A tuple (`(A, B, C, D,...)`) Tup(Vec> ), /// A path (`module::module::...::Type`), optionally @@ -1564,9 +1567,6 @@ impl fmt::Debug for ImplPolarity { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum FunctionRetTy { - /// Functions with return type `!`that always - /// raise an error or exit (i.e. never return to the caller) - None(Span), /// Return type is not specified. /// /// Functions default to `()` and @@ -1580,7 +1580,6 @@ pub enum FunctionRetTy { impl FunctionRetTy { pub fn span(&self) -> Span { match *self { - FunctionRetTy::None(span) => span, FunctionRetTy::Default(span) => span, FunctionRetTy::Ty(ref ty) => ty.span, } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ad52184a6dcb0..77fd264b01d33 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -284,7 +284,10 @@ declare_features! ( // Allows tuple structs and variants in more contexts, // Permits numeric fields in struct expressions and patterns. - (active, relaxed_adts, "1.12.0", Some(35626)) + (active, relaxed_adts, "1.12.0", Some(35626)), + + // The `!` type + (active, never_type, "1.13.0", Some(35121)) ); declare_features! ( @@ -963,11 +966,25 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { gate_feature_post!(&self, conservative_impl_trait, ty.span, "`impl Trait` is experimental"); } + ast::TyKind::Never => { + gate_feature_post!(&self, never_type, ty.span, + "The `!` type is experimental"); + }, _ => {} } visit::walk_ty(self, ty) } + fn visit_fn_ret_ty(&mut self, ret_ty: &ast::FunctionRetTy) { + if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { + match output_ty.node { + ast::TyKind::Never => return, + _ => (), + }; + self.visit_ty(output_ty) + } + } + fn visit_expr(&mut self, e: &ast::Expr) { match e.node { ast::ExprKind::Box(_) => { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index afc990f498e6f..b257ab98987dc 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -373,6 +373,7 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { decl: fld.fold_fn_decl(decl) })) } + TyKind::Never => node, TyKind::Tup(tys) => TyKind::Tup(tys.move_map(|ty| fld.fold_ty(ty))), TyKind::Paren(ty) => TyKind::Paren(fld.fold_ty(ty)), TyKind::Path(qself, path) => { @@ -637,7 +638,6 @@ pub fn noop_fold_fn_decl(decl: P, fld: &mut T) -> P { output: match output { FunctionRetTy::Ty(ty) => FunctionRetTy::Ty(fld.fold_ty(ty)), FunctionRetTy::Default(span) => FunctionRetTy::Default(span), - FunctionRetTy::None(span) => FunctionRetTy::None(span), }, variadic: variadic }) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4c279b2fe4832..118096d9d4863 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1332,11 +1332,7 @@ impl<'a> Parser<'a> { /// Parse optional return type [ -> TY ] in function decl pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> { if self.eat(&token::RArrow) { - if self.eat(&token::Not) { - Ok(FunctionRetTy::None(self.last_span)) - } else { - Ok(FunctionRetTy::Ty(self.parse_ty()?)) - } + Ok(FunctionRetTy::Ty(self.parse_ty()?)) } else { let pos = self.span.lo; Ok(FunctionRetTy::Default(mk_sp(pos, pos))) @@ -1399,6 +1395,8 @@ impl<'a> Parser<'a> { } else { TyKind::Tup(ts) } + } else if self.eat(&token::Not) { + TyKind::Never } else if self.check(&token::BinOp(token::Star)) { // STAR POINTER (bare pointer?) self.bump(); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 62e55eb78b723..a77c678248b56 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -976,6 +976,9 @@ impl<'a> State<'a> { try!(self.print_opt_lifetime(lifetime)); try!(self.print_mt(mt)); } + ast::TyKind::Never => { + try!(word(&mut self.s, "!")); + }, ast::TyKind::Tup(ref elts) => { try!(self.popen()); try!(self.commasep(Inconsistent, &elts[..], @@ -2693,10 +2696,6 @@ impl<'a> State<'a> { self.maybe_print_comment(ty.span.lo) } ast::FunctionRetTy::Default(..) => unreachable!(), - ast::FunctionRetTy::None(span) => { - try!(self.word_nbsp("!")); - self.maybe_print_comment(span.lo) - } } } @@ -2952,8 +2951,6 @@ impl<'a> State<'a> { try!(self.ibox(INDENT_UNIT)); try!(self.word_space("->")); match decl.output { - ast::FunctionRetTy::None(_) => - try!(self.word_nbsp("!")), ast::FunctionRetTy::Default(..) => unreachable!(), ast::FunctionRetTy::Ty(ref ty) => try!(self.print_type(&ty)) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 6d3cdbdc6da7c..582412119caa8 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -128,6 +128,9 @@ pub trait Visitor: Sized { fn visit_vis(&mut self, vis: &Visibility) { walk_vis(self, vis) } + fn visit_fn_ret_ty(&mut self, ret_ty: &FunctionRetTy) { + walk_fn_ret_ty(self, ret_ty) + } } #[macro_export] @@ -319,6 +322,7 @@ pub fn walk_ty(visitor: &mut V, typ: &Ty) { walk_list!(visitor, visit_lifetime, opt_lifetime); visitor.visit_ty(&mutable_type.ty) } + TyKind::Never => {}, TyKind::Tup(ref tuple_element_types) => { walk_list!(visitor, visit_ty, tuple_element_types); } @@ -509,7 +513,7 @@ pub fn walk_fn_decl(visitor: &mut V, function_declaration: &FnDecl) visitor.visit_pat(&argument.pat); visitor.visit_ty(&argument.ty) } - walk_fn_ret_ty(visitor, &function_declaration.output) + visitor.visit_fn_ret_ty(&function_declaration.output) } pub fn walk_fn_kind(visitor: &mut V, function_kind: FnKind) { diff --git a/src/test/compile-fail/issue-20105.rs b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs similarity index 77% rename from src/test/compile-fail/issue-20105.rs rename to src/test/compile-fail/call-fn-never-arg-wrong-type.rs index f133a59d72297..583befed1e828 100644 --- a/src/test/compile-fail/issue-20105.rs +++ b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs @@ -8,10 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f(_: F) where F: Fn() -> R { +// Test that we can't pass other types for ! + +#![feature(never_type)] + +fn foo(x: !) -> ! { + x } fn main() { - f(|| -> ! { () }); -//~^ ERROR: computation may converge in a function marked as diverging [E0270] + foo("wow"); //~ ERROR mismatched types } + diff --git a/src/test/compile-fail/issue-897.rs b/src/test/compile-fail/issue-897.rs deleted file mode 100644 index b9cfbd695b047..0000000000000 --- a/src/test/compile-fail/issue-897.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012-2014 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(unreachable_code)] - -fn f() -> ! { - return panic!(); //~ ERROR `return` in a function declared as diverging - panic!(); // the unreachable statement error is in , at this line, there - // only is a note -} - -fn main() { f() } diff --git a/src/test/compile-fail/E0166.rs b/src/test/compile-fail/never-assign-dead-code.rs similarity index 59% rename from src/test/compile-fail/E0166.rs rename to src/test/compile-fail/never-assign-dead-code.rs index f8585d71b402a..57e0bca6a6d77 100644 --- a/src/test/compile-fail/E0166.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,9 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo() -> ! { return; } - //~^ ERROR E0166 - //~| NOTE diverging function cannot return +// Test that an assignment of type ! makes the rest of the block dead code. + +#![feature(never_type)] +#![deny(unused, unreachable_code)] fn main() { + let x: ! = panic!("aah"); //~ ERROR unused + drop(x); //~ ERROR unreachable } + diff --git a/src/test/compile-fail/loop-properly-diverging.rs b/src/test/compile-fail/never-assign-wrong-type.rs similarity index 76% rename from src/test/compile-fail/loop-properly-diverging.rs rename to src/test/compile-fail/never-assign-wrong-type.rs index 01dfbcc1b9ece..53d96aaf4fe89 100644 --- a/src/test/compile-fail/loop-properly-diverging.rs +++ b/src/test/compile-fail/never-assign-wrong-type.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn forever2() -> ! { //~ ERROR computation may converge in a function marked as diverging - loop { break } +// Test that we can't use another type in place of ! + +#![feature(never_type)] + +fn main() { + let x: ! = "hello"; //~ ERROR mismatched types } -fn main() {} + diff --git a/src/test/compile-fail/never-disabled.rs b/src/test/compile-fail/never-disabled.rs new file mode 100644 index 0000000000000..11b9f412957eb --- /dev/null +++ b/src/test/compile-fail/never-disabled.rs @@ -0,0 +1,28 @@ +// Copyright 2012 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. + +// Test that ! errors when used in illegal positions with feature(never_type) disabled + +trait Foo { + type Wub; +} + +type Ma = (u32, !, i32); //~ ERROR type is experimental +type Meeshka = Vec; //~ ERROR type is experimental +type Mow = &fn(!) -> !; //~ ERROR type is experimental +type Skwoz = &mut !; //~ ERROR type is experimental + +impl Foo for Meeshka { + type Wub = !; //~ ERROR type is experimental +} + +fn main() { +} + diff --git a/src/test/compile-fail/never-fallback.rs b/src/test/compile-fail/never-fallback.rs new file mode 100644 index 0000000000000..a43b1a45fe939 --- /dev/null +++ b/src/test/compile-fail/never-fallback.rs @@ -0,0 +1,41 @@ +// Copyright 2015 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. + +// Test that diverging types default to ! when feature(never_type) is enabled. This test is the +// same as run-pass/unit-fallback.rs except that ! is enabled. + +#![feature(never_type)] + +trait Balls: Sized { + fn smeg() -> Result; +} + +impl Balls for () { + fn smeg() -> Result<(), ()> { Ok(()) } +} + +struct Flah; + +impl Flah { + fn flah(&self) -> Result { + T::smeg() + } +} + +fn doit() -> Result<(), ()> { + // The type of _ is unconstrained here and should default to ! + let _ = try!(Flah.flah()); //~ ERROR the trait bound + Ok(()) +} + +fn main() { + let _ = doit(); +} + diff --git a/src/test/run-pass/issue-10714.rs b/src/test/compile-fail/return-from-diverging.rs similarity index 75% rename from src/test/run-pass/issue-10714.rs rename to src/test/compile-fail/return-from-diverging.rs index 795ad8fb35b82..cec59faa918bc 100644 --- a/src/test/run-pass/issue-10714.rs +++ b/src/test/compile-fail/return-from-diverging.rs @@ -8,9 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +// Test that return another type in place of ! raises a type mismatch. -enum v {} -pub fn main() { - let y: v = unsafe { ::std::mem::uninitialized() }; +fn fail() -> ! { + return "wow"; //~ ERROR mismatched types } + +fn main() { +} + diff --git a/src/test/compile-fail/return-unit-from-diverging.rs b/src/test/compile-fail/return-unit-from-diverging.rs new file mode 100644 index 0000000000000..ae2a325b24a92 --- /dev/null +++ b/src/test/compile-fail/return-unit-from-diverging.rs @@ -0,0 +1,20 @@ +// Copyright 2014 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. + +// Test that we get the usual error that we'd get for any other return type and not something about +// diverging functions not being able to return. + +fn fail() -> ! { + return; //~ ERROR in a function whose return type is not +} + +fn main() { +} + diff --git a/src/test/compile-fail/bang-tailexpr.rs b/src/test/run-fail/adjust_never.rs similarity index 73% rename from src/test/compile-fail/bang-tailexpr.rs rename to src/test/run-fail/adjust_never.rs index 7d79ea03c0245..ccdb1ca15bba0 100644 --- a/src/test/compile-fail/bang-tailexpr.rs +++ b/src/test/run-fail/adjust_never.rs @@ -8,7 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f() -> ! { //~ ERROR computation may converge in a function marked as diverging - 3 +// Test that a variable of type ! can coerce to another type. + +#![feature(never_type)] + +// error-pattern:explicit +fn main() { + let x: ! = panic!(); + let y: u32 = x; } -fn main() { } diff --git a/src/test/compile-fail/loop-does-not-diverge.rs b/src/test/run-fail/call-fn-never-arg.rs similarity index 69% rename from src/test/compile-fail/loop-does-not-diverge.rs rename to src/test/run-fail/call-fn-never-arg.rs index 451b30629b625..95101e70db951 100644 --- a/src/test/compile-fail/loop-does-not-diverge.rs +++ b/src/test/run-fail/call-fn-never-arg.rs @@ -8,14 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/* Make sure a loop{} with a break in it can't be - the tailexpr in the body of a diverging function */ -fn forever() -> ! { - loop { - break; - } - return 42; //~ ERROR `return` in a function declared as diverging +// Test that we can use a ! for an argument of type ! + +// error-pattern:wowzers! + +#![feature(never_type)] +#![allow(unreachable_code)] + +fn foo(x: !) -> ! { + x } fn main() { + foo(panic!("wowzers!")) } + diff --git a/src/test/compile-fail/liveness-bad-bang-2.rs b/src/test/run-fail/cast-never.rs similarity index 68% rename from src/test/compile-fail/liveness-bad-bang-2.rs rename to src/test/run-fail/cast-never.rs index d0bc71edf2c4c..acd002494f4ee 100644 --- a/src/test/compile-fail/liveness-bad-bang-2.rs +++ b/src/test/run-fail/cast-never.rs @@ -8,10 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that a function with a ! annotation always actually fails +// Test that we can explicitly cast ! to another type -fn bad_bang(i: usize) -> ! { //~ ERROR computation may converge in a function marked as diverging - println!("{}", 3); +#![feature(never_type)] + +// error-pattern:explicit +fn main() { + let x: ! = panic!(); + let y: u32 = x as u32; } -fn main() { bad_bang(5); } diff --git a/src/test/compile-fail/bad-bang-ann.rs b/src/test/run-fail/never-associated-type.rs similarity index 60% rename from src/test/compile-fail/bad-bang-ann.rs rename to src/test/run-fail/never-associated-type.rs index f0ecf31fd10a2..345674f3f522a 100644 --- a/src/test/compile-fail/bad-bang-ann.rs +++ b/src/test/run-fail/never-associated-type.rs @@ -8,10 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that a function with a ! annotation always actually fails +// Test that we can use ! as an associated type. -fn bad_bang(i: usize) -> ! { //~ ERROR computation may converge in a function marked as diverging - if i < 0 { } else { panic!(); } +#![feature(never_type)] + +// error-pattern:kapow! + +trait Foo { + type Wow; + + fn smeg(&self) -> Self::Wow; +} + +struct Blah; +impl Foo for Blah { + type Wow = !; + fn smeg(&self) -> ! { + panic!("kapow!"); + } +} + +fn main() { + Blah.smeg(); } -fn main() { bad_bang(5); } diff --git a/src/test/compile-fail/bad-bang-ann-3.rs b/src/test/run-fail/never-type-arg.rs similarity index 64% rename from src/test/compile-fail/bad-bang-ann-3.rs rename to src/test/run-fail/never-type-arg.rs index 1a5496f055150..826ca3a08c0e1 100644 --- a/src/test/compile-fail/bad-bang-ann-3.rs +++ b/src/test/run-fail/never-type-arg.rs @@ -8,12 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that a function with a ! annotation always actually fails +// Test that we can use ! as an argument to a trait impl. -fn bad_bang(i: usize) -> ! { - return 7; - //~^ ERROR `return` in a function declared as diverging [E0166] - //~| NOTE diverging function cannot return +// error-pattern:oh no! + +#![feature(never_type)] + +struct Wub; + +impl PartialEq for Wub { + fn eq(&self, other: &!) -> bool { + *other + } +} + +fn main() { + let _ = Wub == panic!("oh no!"); } -fn main() { bad_bang(5); } diff --git a/src/test/run-fail/return-never-coerce.rs b/src/test/run-fail/return-never-coerce.rs new file mode 100644 index 0000000000000..4cd93ac7e1a5d --- /dev/null +++ b/src/test/run-fail/return-never-coerce.rs @@ -0,0 +1,28 @@ +// Copyright 2014 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. + +// Test that ! coerces to other types. + +// error-pattern:aah! + +fn call_another_fn T>(f: F) -> T { + f() +} + +fn wub() -> ! { + panic!("aah!"); +} + +fn main() { + let x: i32 = call_another_fn(wub); + let y: u32 = wub(); +} + + diff --git a/src/test/run-pass/impl-for-never.rs b/src/test/run-pass/impl-for-never.rs new file mode 100644 index 0000000000000..794f5969bff50 --- /dev/null +++ b/src/test/run-pass/impl-for-never.rs @@ -0,0 +1,36 @@ +// Copyright 2012 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. + +// Test that we can call static methods on ! both directly and when it appears in a generic + +#![feature(never_type)] + +trait StringifyType { + fn stringify_type() -> &'static str; +} + +impl StringifyType for ! { + fn stringify_type() -> &'static str { + "!" + } +} + +fn maybe_stringify(opt: Option) -> &'static str { + match opt { + Some(_) => T::stringify_type(), + None => "none", + } +} + +fn main() { + println!("! is {}", ::stringify_type()); + println!("None is {}", maybe_stringify(None::)); +} + diff --git a/src/test/run-pass/never-result.rs b/src/test/run-pass/never-result.rs new file mode 100644 index 0000000000000..5c0af392f44df --- /dev/null +++ b/src/test/run-pass/never-result.rs @@ -0,0 +1,27 @@ +// Copyright 2015 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. + +// Test that we can extract a ! through pattern matching then use it as several different types. + +#![feature(never_type)] + +fn main() { + let x: Result = Ok(123); + match x { + Ok(z) => (), + Err(y) => { + let q: u32 = y; + let w: i32 = y; + let e: String = y; + y + }, + } +} + diff --git a/src/test/compile-fail/issue-897-2.rs b/src/test/run-pass/never_coercions.rs similarity index 64% rename from src/test/compile-fail/issue-897-2.rs rename to src/test/run-pass/never_coercions.rs index 659b1426bd3f9..dfba5d2c3da0a 100644 --- a/src/test/compile-fail/issue-897-2.rs +++ b/src/test/run-pass/never_coercions.rs @@ -8,16 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(unreachable_code)] +// Test that having something of type ! doesn't screw up type-checking and that it coerces to the +// LUB type of the other match arms. -fn g() -> ! { panic!(); } -fn f() -> ! { - return g(); //~ ERROR `return` in a function declared as diverging - g(); -} -fn h() -> ! { - loop {} - g(); +fn main() { + let v: Vec = Vec::new(); + match 0u32 { + 0 => &v, + 1 => return, + _ => &v[..], + }; } -fn main() { f() } diff --git a/src/test/run-pass/unit-fallback.rs b/src/test/run-pass/unit-fallback.rs new file mode 100644 index 0000000000000..2babc6348e107 --- /dev/null +++ b/src/test/run-pass/unit-fallback.rs @@ -0,0 +1,38 @@ +// Copyright 2015 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. + +// Test that diverging types default to () (with feature(never_type) disabled). + +trait Balls: Sized { + fn smeg() -> Result; +} + +impl Balls for () { + fn smeg() -> Result<(), ()> { Ok(()) } +} + +struct Flah; + +impl Flah { + fn flah(&self) -> Result { + T::smeg() + } +} + +fn doit() -> Result<(), ()> { + // The type of _ is unconstrained here and should default to () + let _ = try!(Flah.flah()); + Ok(()) +} + +fn main() { + let _ = doit(); +} +