Add EmptyToAny adjustment

This commit is contained in:
Andrew Cann 2016-06-25 18:42:52 +08:00
parent b0a9acd783
commit 0d863616e0
15 changed files with 69 additions and 7 deletions

View File

@ -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::AdjustEmptyToAny(..) |
adjustment::AdjustReifyFnPointer |
adjustment::AdjustUnsafeFnPointer |
adjustment::AdjustMutToConstPointer => {

View File

@ -451,6 +451,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
self.cat_expr_autoderefd(expr, autoderefs)
}
adjustment::AdjustEmptyToAny(..) |
adjustment::AdjustReifyFnPointer |
adjustment::AdjustUnsafeFnPointer |
adjustment::AdjustMutToConstPointer |

View File

@ -11,7 +11,7 @@
pub use self::AutoAdjustment::*;
pub use self::AutoRef::*;
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFoldable};
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeVariants};
use ty::LvaluePreference::{NoPreference};
use syntax::ast;
@ -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
AdjustEmptyToAny(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,10 @@ pub struct AutoDerefRef<'tcx> {
impl<'tcx> AutoAdjustment<'tcx> {
pub fn is_identity(&self) -> bool {
match *self {
AdjustEmptyToAny(ref ty) => match ty.sty {
TypeVariants::TyEmpty => true,
_ => false,
},
AdjustReifyFnPointer |
AdjustUnsafeFnPointer |
AdjustMutToConstPointer => false,
@ -154,6 +159,8 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
return match adjustment {
Some(adjustment) => {
match *adjustment {
AdjustEmptyToAny(ref ty) => ty,
AdjustReifyFnPointer => {
match self.sty {
ty::TyFnDef(_, _, f) => tcx.mk_fn_ptr(f),

View File

@ -429,6 +429,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::AdjustEmptyToAny(ref target) => {
write!(f, "AdjustEmptyToAny({:?})", target)
}
ty::adjustment::AdjustReifyFnPointer => {
write!(f, "AdjustReifyFnPointer")
}

View File

@ -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::AdjustEmptyToAny(ref ty) => {
this.emit_enum_variant("AdjustEmptyToAny", 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",
"AdjustEmptyToAny"];
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::AdjustEmptyToAny(ty)
}
_ => bug!("bad enum variant for adjustment::AutoAdjustment")
})
})

View File

@ -96,6 +96,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ExprKind::LogicalOp { .. } |
ExprKind::Box { .. } |
ExprKind::Cast { .. } |
ExprKind::EmptyToAny { .. } |
ExprKind::ReifyFnPointer { .. } |
ExprKind::UnsafeFnPointer { .. } |
ExprKind::Unsize { .. } |

View File

@ -219,6 +219,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ExprKind::Block { .. } |
ExprKind::Match { .. } |
ExprKind::If { .. } |
ExprKind::EmptyToAny { .. } |
ExprKind::Loop { .. } |
ExprKind::LogicalOp { .. } |
ExprKind::Call { .. } |

View File

@ -56,6 +56,7 @@ impl Category {
ExprKind::LogicalOp { .. } |
ExprKind::If { .. } |
ExprKind::Match { .. } |
ExprKind::EmptyToAny { .. } |
ExprKind::Call { .. } =>
Some(Category::Rvalue(RvalueFunc::Into)),

View File

@ -45,6 +45,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ExprKind::Match { discriminant, arms } => {
this.match_expr(destination, expr_span, block, discriminant, arms)
}
ExprKind::EmptyToAny { source } => {
// TODO(canndrew): Do we need to do this?
unpack!(block = this.as_rvalue(block, source));
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));

View File

@ -60,6 +60,15 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
};
}
Some(&ty::adjustment::AdjustEmptyToAny(..)) => {
let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
expr = Expr {
temp_lifetime: temp_lifetime,
ty: adjusted_ty,
span: self.span,
kind: ExprKind::EmptyToAny { source: expr.to_ref() },
};
}
Some(&ty::adjustment::AdjustMutToConstPointer) => {
let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
expr = Expr {

View File

@ -139,6 +139,9 @@ pub enum ExprKind<'tcx> {
Cast {
source: ExprRef<'tcx>,
},
EmptyToAny {
source: ExprRef<'tcx>,
},
ReifyFnPointer {
source: ExprRef<'tcx>,
},

View File

@ -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::AdjustEmptyToAny(..)) |
Some(&ty::adjustment::AdjustReifyFnPointer) |
Some(&ty::adjustment::AdjustUnsafeFnPointer) |
Some(&ty::adjustment::AdjustMutToConstPointer) => {}

View File

@ -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::{AdjustEmptyToAny, 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(AdjustEmptyToAny(..)) => span_bug!(e.span, "const expression of type ! encountered"),
Some(AdjustReifyFnPointer) => {
match ety.sty {
ty::TyFnDef(def_id, substs, _) => {

View File

@ -69,7 +69,7 @@ use tvec;
use type_of;
use value::Value;
use Disr;
use rustc::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
use rustc::ty::adjustment::{AdjustEmptyToAny, 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 {
AdjustEmptyToAny(..) => 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 {
AdjustEmptyToAny(..) => {
let const_ty = expr_ty(bcx, expr);
let llty = type_of::type_of(bcx.ccx(), const_ty);
let dummy = C_undef(llty.ptr_to());
datum = Datum::new(dummy, const_ty, Rvalue::new(ByRef)).to_expr_datum();
}
AdjustReifyFnPointer => {
match datum.ty.sty {
ty::TyFnDef(def_id, substs, _) => {

View File

@ -378,6 +378,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
Some(adjustment) => {
let resolved_adjustment = match adjustment {
adjustment::AdjustEmptyToAny(ty) => {
adjustment::AdjustEmptyToAny(self.resolve(&ty, reason))
}
adjustment::AdjustReifyFnPointer => {
adjustment::AdjustReifyFnPointer
}