Auto merge of #35162 - canndrew:bang_type_coerced, r=nikomatsakis
Implement the `!` type This implements the never type (`!`) and hides it behind the feature gate `#[feature(never_type)]`. With the feature gate off, things should build as normal (although some error messages may be different). With the gate on, `!` is usable as a type and diverging type variables (ie. types that are unconstrained by anything in the code) will default to `!` instead of `()`.
This commit is contained in:
commit
e25542cb02
@ -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<Ordering> {
|
||||
*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")]
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -353,6 +353,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
|
||||
}
|
||||
}))
|
||||
}
|
||||
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<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
|
||||
output: match output {
|
||||
Return(ty) => Return(fld.fold_ty(ty)),
|
||||
DefaultReturn(span) => DefaultReturn(span),
|
||||
NoReturn(span) => NoReturn(span),
|
||||
},
|
||||
variadic: variadic,
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
})
|
||||
|
@ -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<Ty>),
|
||||
/// A fixed length array (`[T; n]`)
|
||||
TyFixedLengthVec(P<Ty>, P<Expr>),
|
||||
@ -1121,6 +1122,8 @@ pub enum Ty_ {
|
||||
TyRptr(Option<Lifetime>, MutTy),
|
||||
/// A bare function (e.g. `fn(usize) -> bool`)
|
||||
TyBareFn(P<BareFnTy>),
|
||||
/// The never type (`!`)
|
||||
TyNever,
|
||||
/// A tuple (`(A, B, C, D,...)`)
|
||||
TyTup(HirVec<P<Ty>>),
|
||||
/// 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,
|
||||
}
|
||||
|
@ -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)?,
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(..) |
|
||||
|
@ -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>
|
||||
|
@ -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 => {
|
||||
|
@ -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?!");
|
||||
|
@ -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<Ty<'tcx>> {
|
||||
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() => {
|
||||
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()
|
||||
});
|
||||
|
||||
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
|
||||
// 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");
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Promoted, Mir<'tcx>>,
|
||||
|
||||
/// 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<BasicBlock, BasicBlockData<'tcx>>,
|
||||
visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
|
||||
promoted: IndexVec<Promoted, Mir<'tcx>>,
|
||||
return_ty: FnOutput<'tcx>,
|
||||
return_ty: Ty<'tcx>,
|
||||
var_decls: IndexVec<Var, VarDecl<'tcx>>,
|
||||
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
|
||||
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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);
|
||||
@ -708,16 +701,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>) {
|
||||
}
|
||||
|
||||
|
@ -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(..) => {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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<A>(...)`.
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)),
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -349,6 +349,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
|
||||
ty::TyAnon(..) |
|
||||
ty::TyInfer(_) |
|
||||
ty::TyError |
|
||||
ty::TyNever |
|
||||
ty::TyFloat(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -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, .. }) |
|
||||
|
@ -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![]
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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(_), _) |
|
||||
|
@ -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<Self::Lifted> {
|
||||
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<Self::Lifted> {
|
||||
@ -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<V: TypeVisitor<'tcx>>(&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),
|
||||
|
@ -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<Ty<'tcx>> {
|
||||
match self {
|
||||
ty::FnConverging(t) => Some(t),
|
||||
ty::FnDiverging => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
|
||||
|
||||
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<Ty<'tcx>>,
|
||||
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<Ty<'tcx>> {
|
||||
self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
|
||||
}
|
||||
pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
|
||||
pub fn output(&self) -> ty::Binder<Ty<'tcx>> {
|
||||
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<FnOutput<'tcx>> {
|
||||
pub fn fn_ret(&self) -> Binder<Ty<'tcx>> {
|
||||
self.fn_sig().output()
|
||||
}
|
||||
|
||||
@ -1260,6 +1237,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||
TyArray(_, _) |
|
||||
TySlice(_) |
|
||||
TyRawPtr(_) |
|
||||
TyNever |
|
||||
TyTuple(_) |
|
||||
TyParam(_) |
|
||||
TyInfer(_) |
|
||||
|
@ -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),
|
||||
|
||||
|
@ -70,7 +70,7 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter<Ty<'tcx>> {
|
||||
fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, 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<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
|
||||
}
|
||||
|
||||
fn push_sig_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, 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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<GG>(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();
|
||||
|
@ -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<MovePathIndex> for MovePathData<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
struct MovePathDataBuilder<'a, 'tcx: 'a> {
|
||||
mir: &'a Mir<'tcx>,
|
||||
struct MovePathDataBuilder<'tcx> {
|
||||
pre_move_paths: Vec<PreMovePath<'tcx>>,
|
||||
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<MovePathIndex> {
|
||||
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),
|
||||
};
|
||||
@ -634,13 +632,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: _ } => {
|
||||
@ -751,15 +744,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<MoveOut>,
|
||||
builder: MovePathDataBuilder<'a, 'tcx>,
|
||||
builder: MovePathDataBuilder<'tcx>,
|
||||
path_map: &'b mut Vec<Vec<MoveOutIndex>>,
|
||||
loc_map_bb: &'b mut Vec<Vec<MoveOutIndex>>,
|
||||
}
|
||||
|
||||
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>,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}),
|
||||
}))
|
||||
|
@ -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));
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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, _) => {
|
||||
|
@ -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")
|
||||
})
|
||||
})
|
||||
|
@ -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})
|
||||
|
@ -74,6 +74,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, 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<Vec<u8>>, 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<Vec<u8>>, _cx: &ctxt, bs: &ty::BuiltinBounds) {
|
||||
|
@ -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 { .. } |
|
||||
|
@ -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 { .. } |
|
||||
|
@ -56,6 +56,7 @@ impl Category {
|
||||
ExprKind::LogicalOp { .. } |
|
||||
ExprKind::If { .. } |
|
||||
ExprKind::Match { .. } |
|
||||
ExprKind::NeverToAny { .. } |
|
||||
ExprKind::Call { .. } =>
|
||||
Some(Category::Rvalue(RvalueFunc::Into)),
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
|
||||
@ -256,7 +256,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> {
|
||||
@ -288,7 +288,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
fn finish(self,
|
||||
upvar_decls: Vec<UpvarDecl>,
|
||||
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
|
||||
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() {
|
||||
@ -310,7 +310,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn args_and_body<A>(&mut self,
|
||||
mut block: BasicBlock,
|
||||
return_ty: ty::FnOutput<'tcx>,
|
||||
return_ty: Ty<'tcx>,
|
||||
arguments: A,
|
||||
argument_extent: CodeExtent,
|
||||
ast_block: &'gcx hir::Block)
|
||||
@ -351,11 +351,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));
|
||||
|
||||
|
@ -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#"<br align="left"/>"#)?;
|
||||
|
||||
// User variable types (including the user's name in a comment).
|
||||
|
@ -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
|
||||
|
@ -139,6 +139,9 @@ pub enum ExprKind<'tcx> {
|
||||
Cast {
|
||||
source: ExprRef<'tcx>,
|
||||
},
|
||||
NeverToAny {
|
||||
source: ExprRef<'tcx>,
|
||||
},
|
||||
ReifyFnPointer {
|
||||
source: ExprRef<'tcx>,
|
||||
},
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
@ -303,7 +303,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())
|
||||
}
|
||||
@ -391,7 +391,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(),
|
||||
|
@ -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 {
|
||||
@ -1001,7 +1001,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();
|
||||
|
@ -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);
|
||||
@ -500,22 +491,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);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) => {}
|
||||
|
@ -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();
|
||||
|
@ -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::<Vec<_>>().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))),
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -791,6 +791,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 */
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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, _) => {
|
||||
|
@ -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<DIType> = 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),
|
||||
|
@ -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 {
|
||||
|
@ -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(..) => {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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<Ty<'tcx>>,
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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).
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
it: &hir::ForeignItem,
|
||||
n_tps: usize,
|
||||
abi: Abi,
|
||||
inputs: Vec<ty::Ty<'tcx>>,
|
||||
output: ty::FnOutput<'tcx>) {
|
||||
inputs: Vec<Ty<'tcx>>,
|
||||
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);
|
||||
@ -106,9 +106,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()),
|
||||
@ -293,7 +293,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,
|
||||
}),
|
||||
});
|
||||
@ -306,7 +306,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)
|
||||
}
|
||||
@ -379,7 +379,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 => {
|
||||
@ -392,7 +392,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
|
||||
|
@ -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<UnsafetyState>,
|
||||
|
||||
@ -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<hir::Expr>],
|
||||
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<Ty<'tcx>> {
|
||||
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);
|
||||
@ -3560,7 +3556,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);
|
||||
}
|
||||
@ -4016,7 +4012,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 {
|
||||
|
@ -349,7 +349,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(())
|
||||
|
@ -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::<hir::Expr>.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
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user