}
```
-Reasonable people can disagree over whether this code is better that the code
+Reasonable people can disagree over whether this code is better than the code
that uses combinators, but if you aren't familiar with the combinator approach,
this code looks simpler to read to me. It uses explicit case analysis with
`match` and `if let`. If an error occurs, it simply stops executing the
}
```
-This prints out one through three. As we iterate through the vectors, we’re
+This prints out one through three. As we iterate through the vector, we’re
only given references to the elements. And `v` is itself borrowed as immutable,
which means we can’t change it while we’re iterating:
* `!` (`ident!(…)`, `ident!{…}`, `ident![…]`): denotes macro expansion. See [Macros].
* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`).
+* `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`).
* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`).
* `%=` (`var %= expr`): arithmetic remainder & assignment.
* `&` (`expr & expr`): bitwise and. Overloadable (`BitAnd`).
* `;` (`[…; len]`): part of fixed-size array syntax. See [Primitive Types (Arrays)].
* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`).
* `<<=` (`var <<= expr`): left-shift & assignment.
-* `<` (`expr < expr`): less-than comparison. Overloadable (`Cmp`, `PartialCmp`).
-* `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`Cmp`, `PartialCmp`).
+* `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`).
+* `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`PartialOrd`).
* `=` (`var = expr`, `ident = type`): assignment/equivalence. See [Variable Bindings], [`type` Aliases], generic parameter defaults.
-* `==` (`var == expr`): comparison. Overloadable (`Eq`, `PartialEq`).
+* `==` (`var == expr`): equality comparison. Overloadable (`PartialEq`).
* `=>` (`pat => expr`): part of match arm syntax. See [Match].
-* `>` (`expr > expr`): greater-than comparison. Overloadable (`Cmp`, `PartialCmp`).
-* `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`Cmp`, `PartialCmp`).
+* `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`).
+* `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`PartialOrd`).
* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`).
* `>>=` (`var >>= expr`): right-shift & assignment.
* `@` (`ident @ pat`): pattern binding. See [Patterns (Bindings)].
| LIT_FLOAT { $$ = mk_atom(yytext); }
| LIT_STR { $$ = mk_atom(yytext); }
| LIT_STR_RAW { $$ = mk_atom(yytext); }
-| LIT_BYTE_STR { $$ = mk_atom(yytext); }
-| LIT_BYTE_STR_RAW { $$ = mk_atom(yytext); }
+| LIT_BYTE_STR { $$ = mk_atom(yytext); }
+| LIT_BYTE_STR_RAW { $$ = mk_atom(yytext); }
| IDENT { $$ = mk_atom(yytext); }
| UNDERSCORE { $$ = mk_atom(yytext); }
| LIFETIME { $$ = mk_atom(yytext); }
}
/// Used for items loaded from external crate that are being inlined into this
-/// crate. The `path` should be the path to the item but should not include
-/// the item itself.
+/// crate.
pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
- path: Vec<PathElem>,
- def_path: DefPath,
+ parent_path: Vec<PathElem>,
+ parent_def_path: DefPath,
ii: InlinedItem,
fold_ops: F)
-> &'ast InlinedItem {
};
let ii_parent = map.forest.inlined_items.alloc(InlinedParent {
- path: path,
+ path: parent_path,
ii: ii
});
map.krate(),
ii_parent,
ii_parent_id,
- def_path,
+ parent_def_path,
mem::replace(&mut *map.map.borrow_mut(), vec![]),
mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new()));
ii_parent.ii.visit(&mut collector);
origin);
match (sub, sup) {
- (ReEarlyBound(..), ReEarlyBound(..)) => {
- // This case is used only to make sure that explicitly-specified
- // `Self` types match the real self type in implementations.
- //
- // FIXME(NDM) -- we really shouldn't be comparing bound things
- self.add_verify(VerifyRegSubReg(origin, sub, sup));
- }
(ReEarlyBound(..), _) |
(ReLateBound(..), _) |
(_, ReEarlyBound(..)) |
impl RegionParameterDef {
pub fn to_early_bound_region(&self) -> ty::Region {
ty::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: self.def_id,
space: self.space,
index: self.index,
name: self.name,
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
pub struct EarlyBoundRegion {
- pub def_id: DefId,
pub space: subst::ParamSpace,
pub index: u32,
pub name: Name,
#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum ItemKind {
Constant,
+ /// This is any sort of callable (usually those that have a type of `fn(…) -> …`). This
+ /// includes functions, constructors, but not methods which have their own ItemKind.
Function,
- Struct,
- Variant,
Method,
}
"force nonzeroing move optimization on"),
keep_mtwt_tables: bool = (false, parse_bool,
"don't clear the resolution tables after analysis"),
+ keep_ast: bool = (false, parse_bool,
+ "keep the AST after lowering it to HIR"),
}
pub fn default_lib_output() -> CrateType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ty::ReEarlyBound(ref data) => {
- write!(f, "ReEarlyBound({:?}, {:?}, {}, {})",
- data.def_id,
+ write!(f, "ReEarlyBound({:?}, {}, {})",
data.space,
data.index,
data.name)
}
let arenas = ty::CtxtArenas::new();
- let ast_map = make_map(&sess, &mut hir_forest);
+ let hir_map = make_map(&sess, &mut hir_forest);
write_out_deps(&sess, &outputs, &id);
CompileState::state_after_write_deps(input,
&sess,
outdir,
- &ast_map,
+ &hir_map,
&expanded_crate,
- &ast_map.krate(),
+ &hir_map.krate(),
&id[..],
&lcx));
"early lint checks",
|| lint::check_ast_crate(&sess, &expanded_crate));
+ let opt_crate = if sess.opts.debugging_opts.keep_ast ||
+ sess.opts.debugging_opts.save_analysis {
+ Some(&expanded_crate)
+ } else {
+ drop(expanded_crate);
+ None
+ };
+
phase_3_run_analysis_passes(&sess,
&cstore,
- ast_map,
+ hir_map,
&arenas,
&id,
control.make_glob_map,
CompileState::state_after_analysis(input,
&tcx.sess,
outdir,
- &expanded_crate,
+ opt_crate,
tcx.map.krate(),
&analysis,
&mir_map,
fn state_after_write_deps(input: &'a Input,
session: &'a Session,
out_dir: &'a Option<PathBuf>,
- ast_map: &'a hir_map::Map<'ast>,
+ hir_map: &'a hir_map::Map<'ast>,
krate: &'a ast::Crate,
hir_crate: &'a hir::Crate,
crate_name: &'a str,
-> CompileState<'a, 'ast, 'tcx> {
CompileState {
crate_name: Some(crate_name),
- ast_map: Some(ast_map),
+ ast_map: Some(hir_map),
krate: Some(krate),
hir_crate: Some(hir_crate),
lcx: Some(lcx),
fn state_after_analysis(input: &'a Input,
session: &'a Session,
out_dir: &'a Option<PathBuf>,
- krate: &'a ast::Crate,
+ krate: Option<&'a ast::Crate>,
hir_crate: &'a hir::Crate,
analysis: &'a ty::CrateAnalysis,
mir_map: &'a MirMap<'tcx>,
analysis: Some(analysis),
mir_map: Some(mir_map),
tcx: Some(tcx),
- krate: Some(krate),
+ krate: krate,
hir_crate: Some(hir_crate),
lcx: Some(lcx),
crate_name: Some(crate_name),
}
pub fn make_map<'ast>(sess: &Session,
- forest: &'ast mut front::map::Forest)
- -> front::map::Map<'ast> {
- // Construct the 'ast'-map
- let map = time(sess.time_passes(),
- "indexing hir",
- move || front::map::map_crate(forest));
-
- map
+ forest: &'ast mut hir_map::Forest)
+ -> hir_map::Map<'ast> {
+ // Construct the HIR map
+ time(sess.time_passes(),
+ "indexing hir",
+ move || hir_map::map_crate(forest))
}
/// Run the resolution, typechecking, region checking and other
/// structures carrying the results of the analysis.
pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
cstore: &CStore,
- ast_map: front::map::Map<'tcx>,
+ hir_map: hir_map::Map<'tcx>,
arenas: &'tcx ty::CtxtArenas<'tcx>,
name: &str,
make_glob_map: resolve::MakeGlobMap,
where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, MirMap<'tcx>, ty::CrateAnalysis) -> R
{
let time_passes = sess.time_passes();
- let krate = ast_map.krate();
+ let krate = hir_map.krate();
time(time_passes,
"external crate/lib resolution",
- || LocalCrateReader::new(sess, cstore, &ast_map).read_crates(krate));
+ || LocalCrateReader::new(sess, cstore, &hir_map).read_crates(krate));
let lang_items = time(time_passes,
"language item collection",
- || middle::lang_items::collect_language_items(&sess, &ast_map));
+ || middle::lang_items::collect_language_items(&sess, &hir_map));
let resolve::CrateMap {
def_map,
glob_map,
} = time(time_passes,
"resolution",
- || resolve::resolve_crate(sess, &ast_map, make_glob_map));
+ || resolve::resolve_crate(sess, &hir_map, make_glob_map));
let named_region_map = time(time_passes,
"lifetime resolution",
time(time_passes,
"looking for entry point",
- || middle::entry::find_entry_point(sess, &ast_map));
+ || middle::entry::find_entry_point(sess, &hir_map));
sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || {
plugin::build::find_plugin_registrar(sess.diagnostic(), krate)
time(time_passes,
"static item recursion checking",
- || middle::check_static_recursion::check_crate(sess, krate, &def_map.borrow(), &ast_map));
+ || middle::check_static_recursion::check_crate(sess, krate, &def_map.borrow(), &hir_map));
ty::ctxt::create_and_enter(sess,
arenas,
def_map,
named_region_map,
- ast_map,
+ hir_map,
freevars,
region_map,
lang_items,
-> ty::Region {
let name = token::intern(name);
ty::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: self.infcx.tcx.map.local_def_id(ast::DUMMY_NODE_ID),
space: space,
index: index,
name: name,
/// ast-map.
pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
tcx: &ty::ctxt<'tcx>,
- path: Vec<ast_map::PathElem>,
- def_path: ast_map::DefPath,
+ parent_path: Vec<ast_map::PathElem>,
+ parent_def_path: ast_map::DefPath,
par_doc: rbml::Doc,
orig_did: DefId)
-> Result<&'tcx InlinedItem, (Vec<ast_map::PathElem>,
ast_map::DefPath)> {
match par_doc.opt_child(c::tag_ast) {
- None => Err((path, def_path)),
+ None => Err((parent_path, parent_def_path)),
Some(ast_doc) => {
let mut path_as_str = None;
debug!("> Decoding inlined fn: {:?}::?",
{
// Do an Option dance to use the path after it is moved below.
- let s = ast_map::path_to_string(path.iter().cloned());
+ let s = ast_map::path_to_string(parent_path.iter().cloned());
path_as_str = Some(s);
path_as_str.as_ref().map(|x| &x[..])
});
last_filemap_index: Cell::new(0)
};
let raw_ii = decode_ast(ast_doc);
- let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, def_path, raw_ii, dcx);
-
+ let ii = ast_map::map_decoded_item(&dcx.tcx.map,
+ parent_path,
+ parent_def_path,
+ raw_ii,
+ dcx);
let name = match *ii {
InlinedItem::Item(ref i) => i.name,
InlinedItem::Foreign(ref i) => i.name,
pub type DecodeInlinedItem<'a> =
Box<for<'tcx> FnMut(Cmd,
&ty::ctxt<'tcx>,
- Vec<hir_map::PathElem>,
- hir_map::DefPath,
+ Vec<hir_map::PathElem>, // parent_path
+ hir_map::DefPath, // parent_def_path
rbml::Doc,
DefId)
-> Result<&'tcx InlinedItem, (Vec<hir_map::PathElem>,
hir_map::DefPath)> + 'a>;
-pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: DefIndex,
+pub fn maybe_get_item_ast<'tcx>(cdata: Cmd,
+ tcx: &ty::ctxt<'tcx>,
+ id: DefIndex,
mut decode_inlined_item: DecodeInlinedItem)
-> FoundAst<'tcx> {
debug!("Looking up item: {:?}", id);
let item_doc = cdata.lookup_item(id);
let item_did = item_def_id(item_doc, cdata);
- let path = item_path(item_doc).split_last().unwrap().1.to_vec();
- let def_path = def_path(cdata, id);
- match decode_inlined_item(cdata, tcx, path, def_path, item_doc, item_did) {
+ let parent_path = {
+ let mut path = item_path(item_doc);
+ path.pop();
+ path
+ };
+ let parent_def_path = {
+ let mut def_path = def_path(cdata, id);
+ def_path.pop();
+ def_path
+ };
+ match decode_inlined_item(cdata,
+ tcx,
+ parent_path,
+ parent_def_path,
+ item_doc,
+ item_did) {
Ok(ii) => FoundAst::Found(ii),
- Err((path, def_path)) => {
+ Err((mut parent_path, mut parent_def_path)) => {
match item_parent_item(cdata, item_doc) {
- Some(did) => {
- let parent_item = cdata.lookup_item(did.index);
- match decode_inlined_item(cdata, tcx, path, def_path, parent_item, did) {
- Ok(ii) => FoundAst::FoundParent(did, ii),
+ Some(parent_did) => {
+ // Remove the last element from the paths, since we are now
+ // trying to inline the parent.
+ parent_path.pop();
+ parent_def_path.pop();
+
+ let parent_item = cdata.lookup_item(parent_did.index);
+ match decode_inlined_item(cdata,
+ tcx,
+ parent_path,
+ parent_def_path,
+ parent_item,
+ parent_did) {
+ Ok(ii) => FoundAst::FoundParent(parent_did, ii),
Err(_) => FoundAst::NotFound
}
}
}
'B' => {
assert_eq!(self.next(), '[');
- let def_id = self.parse_def();
let space = self.parse_param_space();
assert_eq!(self.next(), '|');
let index = self.parse_u32();
assert_eq!(self.next(), '|');
let name = token::intern(&self.parse_str(']'));
ty::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: def_id,
space: space,
index: index,
name: name
mywrite!(w, "]");
}
ty::ReEarlyBound(ref data) => {
- mywrite!(w, "B[{}|{}|{}|{}]",
- (cx.ds)(data.def_id),
+ mywrite!(w, "B[{}|{}|{}]",
data.space.to_uint(),
data.index,
data.name);
let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
// Otherwise there may be def_map borrow conflicts
let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
- match def {
- def::DefVariant(_, def_id, false) |
- def::DefStruct(def_id) |
- def::DefFn(def_id, _) |
- def::DefMethod(def_id) => {
- let kind = match def {
- def::DefVariant(..) => ItemKind::Variant,
- def::DefStruct(..) => ItemKind::Struct,
- def::DefFn(..) => ItemKind::Function,
- def::DefMethod(..) => ItemKind::Method,
- _ => panic!()
- };
- ExprKind::Literal {
- literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
- }
+ let (def_id, kind) = match def {
+ // A regular function.
+ def::DefFn(def_id, _) => (def_id, ItemKind::Function),
+ def::DefMethod(def_id) => (def_id, ItemKind::Method),
+ def::DefStruct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty {
+ // A tuple-struct constructor.
+ ty::TyBareFn(..) => (def_id, ItemKind::Function),
+ // This is a special case: a unit struct which is used as a value. We return a
+ // completely different ExprKind here to account for this special case.
+ ty::TyStruct(adt_def, substs) => return ExprKind::Adt {
+ adt_def: adt_def,
+ variant_index: 0,
+ substs: substs,
+ fields: vec![],
+ base: None
+ },
+ ref sty => panic!("unexpected sty: {:?}", sty)
+ },
+ def::DefVariant(enum_id, variant_id, false) => match cx.tcx.node_id_to_type(expr.id).sty {
+ // A variant constructor.
+ ty::TyBareFn(..) => (variant_id, ItemKind::Function),
+ // A unit variant, similar special case to the struct case above.
+ ty::TyEnum(adt_def, substs) => {
+ debug_assert!(adt_def.did == enum_id);
+ let index = adt_def.variant_index_with_id(variant_id);
+ return ExprKind::Adt {
+ adt_def: adt_def,
+ substs: substs,
+ variant_index: index,
+ fields: vec![],
+ base: None
+ };
+ },
+ ref sty => panic!("unexpected sty: {:?}", sty)
},
def::DefConst(def_id) |
def::DefAssociatedConst(def_id) => {
if let Some(v) = cx.try_const_eval_literal(expr) {
- ExprKind::Literal { literal: v }
+ return ExprKind::Literal { literal: v };
} else {
- ExprKind::Literal {
- literal: Literal::Item {
- def_id: def_id,
- kind: ItemKind::Constant,
- substs: substs
- }
- }
+ (def_id, ItemKind::Constant)
}
}
-
- def::DefStatic(node_id, _) =>
- ExprKind::StaticRef {
- id: node_id,
- },
+ def::DefStatic(node_id, _) => return ExprKind::StaticRef {
+ id: node_id,
+ },
def @ def::DefLocal(..) |
- def @ def::DefUpvar(..) =>
- convert_var(cx, expr, def),
+ def @ def::DefUpvar(..) => return convert_var(cx, expr, def),
def =>
cx.tcx.sess.span_bug(
expr.span,
&format!("def `{:?}` not yet implemented", def)),
+ };
+ ExprKind::Literal {
+ literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
}
}
let referent_ty = lv_datum.ty;
let ptr_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), referent_ty);
+ // Construct the resulting datum. The right datum to return here would be an Lvalue datum,
+ // because there is cleanup scheduled and the datum doesn't own the data, but for thin pointers
+ // we microoptimize it to be an Rvalue datum to avoid the extra alloca and level of
+ // indirection and for thin pointers, this has no ill effects.
+ let kind = if type_is_sized(bcx.tcx(), referent_ty) {
+ RvalueExpr(Rvalue::new(ByValue))
+ } else {
+ LvalueExpr(lv_datum.kind)
+ };
+
// Get the pointer.
let llref = lv_datum.to_llref();
-
- // Construct the resulting datum, using what was the "by ref"
- // ValueRef of type `referent_ty` to be the "by value" ValueRef
- // of type `&referent_ty`.
- // Pointers to DST types are non-immediate, and therefore still use ByRef.
- let kind = if type_is_sized(bcx.tcx(), referent_ty) { ByValue } else { ByRef };
- DatumBlock::new(bcx, Datum::new(llref, ptr_ty, RvalueExpr(Rvalue::new(kind))))
+ DatumBlock::new(bcx, Datum::new(llref, ptr_ty, kind))
}
fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
did: DefId)
-> OperandRef<'tcx> {
match kind {
- ItemKind::Function |
- ItemKind::Struct |
- ItemKind::Variant => self.trans_fn_ref(bcx, ty, substs, did),
+ ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did),
ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
ty::TraitContainer(tdid) => self.trans_static_method(bcx, ty, did, tdid, substs)
use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr;
+use trans::adt;
use trans::machine;
use trans::type_::Type;
use trans::type_of;
use super::MirContext;
use super::operand::{OperandRef, OperandValue};
+use super::lvalue::LvalueRef;
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_rvalue(&mut self,
bcx: Block<'bcx, 'tcx>,
- lldest: ValueRef,
+ dest: LvalueRef<'tcx>,
rvalue: &mir::Rvalue<'tcx>)
-> Block<'bcx, 'tcx>
{
- debug!("trans_rvalue(lldest={}, rvalue={:?})",
- bcx.val_to_string(lldest),
+ debug!("trans_rvalue(dest.llval={}, rvalue={:?})",
+ bcx.val_to_string(dest.llval),
rvalue);
match *rvalue {
mir::Rvalue::Use(ref operand) => {
- self.trans_operand_into(bcx, lldest, operand);
+ self.trans_operand_into(bcx, dest.llval, operand);
bcx
}
// into-coerce of a thin pointer to a fat pointer - just
// use the operand path.
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
- self.store_operand(bcx, lldest, temp);
+ self.store_operand(bcx, dest.llval, temp);
return bcx;
}
base::store_ty(bcx, llval, lltemp, operand.ty);
base::coerce_unsized_into(bcx,
lltemp, operand.ty,
- lldest, cast_ty);
+ dest.llval, cast_ty);
}
OperandValue::Ref(llref) => {
base::coerce_unsized_into(bcx,
llref, operand.ty,
- lldest, cast_ty);
+ dest.llval, cast_ty);
}
}
bcx
mir::Rvalue::Repeat(ref elem, ref count) => {
let elem = self.trans_operand(bcx, elem);
let size = self.trans_constant(bcx, count).immediate();
- let base = expr::get_dataptr(bcx, lldest);
+ let base = expr::get_dataptr(bcx, dest.llval);
tvec::iter_vec_raw(bcx, base, elem.ty, size, |bcx, llslot, _| {
self.store_operand(bcx, llslot, elem);
bcx
})
}
- mir::Rvalue::Aggregate(_, ref operands) => {
- for (i, operand) in operands.iter().enumerate() {
- // Note: perhaps this should be StructGep, but
- // note that in some cases the values here will
- // not be structs but arrays.
- let lldest_i = build::GEPi(bcx, lldest, &[0, i]);
- self.trans_operand_into(bcx, lldest_i, operand);
+ mir::Rvalue::Aggregate(ref kind, ref operands) => {
+ match *kind {
+ // Unit struct or variant; both are translated very differently compared to any
+ // other aggregate
+ mir::AggregateKind::Adt(adt_def, index, _)
+ if adt_def.variants[index].kind() == ty::VariantKind::Unit => {
+ let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx()));
+ adt::trans_set_discr(bcx, &*repr, dest.llval, 0);
+ },
+ _ => {
+ for (i, operand) in operands.iter().enumerate() {
+ // Note: perhaps this should be StructGep, but
+ // note that in some cases the values here will
+ // not be structs but arrays.
+ let lldest_i = build::GEPi(bcx, dest.llval, &[0, i]);
+ self.trans_operand_into(bcx, lldest_i, operand);
+ }
+ }
}
bcx
}
let llbase1 = build::GEPi(bcx, llbase, &[from_start]);
let adj = common::C_uint(ccx, from_start + from_end);
let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None);
- let lladdrdest = expr::get_dataptr(bcx, lldest);
+ let lladdrdest = expr::get_dataptr(bcx, dest.llval);
build::Store(bcx, llbase1, lladdrdest);
- let llmetadest = expr::get_meta(bcx, lldest);
+ let llmetadest = expr::get_meta(bcx, dest.llval);
build::Store(bcx, lllen1, llmetadest);
bcx
}
_ => {
assert!(rvalue_creates_operand(rvalue));
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
- self.store_operand(bcx, lldest, temp);
+ self.store_operand(bcx, dest.llval, temp);
bcx
}
}
let index = index as usize;
match self.temps[index as usize] {
TempRef::Lvalue(tr_dest) => {
- self.trans_rvalue(bcx, tr_dest.llval, rvalue)
+ self.trans_rvalue(bcx, tr_dest, rvalue)
}
TempRef::Operand(None) => {
let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue);
}
_ => {
let tr_dest = self.trans_lvalue(bcx, lvalue);
- self.trans_rvalue(bcx, tr_dest.llval, rvalue)
+ self.trans_rvalue(bcx, tr_dest, rvalue)
}
}
}
use middle::privacy::{AllPublic, LastMod};
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
use middle::traits;
-use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags};
+use middle::ty::{self, Ty, ToPredicate, HasTypeFlags};
use middle::ty::wf::object_region_bounds;
use require_c_abi_if_variadic;
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
ty::ReLateBound(debruijn, ty::BrNamed(tcx.map.local_def_id(id), lifetime.name))
}
- Some(&rl::DefEarlyBoundRegion(space, index, id)) => {
- let def_id = tcx.map.local_def_id(id);
+ Some(&rl::DefEarlyBoundRegion(space, index, _)) => {
ty::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: def_id,
space: space,
index: index,
name: lifetime.name
// lifetime elision, we can determine it in two ways. First (determined
// here), if self is by-reference, then the implied output region is the
// region of the self parameter.
- let mut explicit_self_category_result = None;
- let (self_ty, implied_output_region) = match opt_self_info {
+ let (self_ty, explicit_self_category) = match opt_self_info {
None => (None, None),
- Some(self_info) => {
- // This type comes from an impl or trait; no late-bound
- // regions should be present.
- assert!(!self_info.untransformed_self_ty.has_escaping_regions());
-
- // Figure out and record the explicit self category.
- let explicit_self_category =
- determine_explicit_self_category(this, &rb, &self_info);
- explicit_self_category_result = Some(explicit_self_category);
- match explicit_self_category {
- ty::StaticExplicitSelfCategory => {
- (None, None)
- }
- ty::ByValueExplicitSelfCategory => {
- (Some(self_info.untransformed_self_ty), None)
- }
- ty::ByReferenceExplicitSelfCategory(region, mutability) => {
- (Some(this.tcx().mk_ref(
- this.tcx().mk_region(region),
- ty::TypeAndMut {
- ty: self_info.untransformed_self_ty,
- mutbl: mutability
- })),
- Some(region))
- }
- ty::ByBoxExplicitSelfCategory => {
- (Some(this.tcx().mk_box(self_info.untransformed_self_ty)), None)
- }
- }
- }
+ Some(self_info) => determine_self_type(this, &rb, self_info)
};
// HACK(eddyb) replace the fake self type in the AST with the actual type.
- let input_params = if self_ty.is_some() {
+ let arg_params = if self_ty.is_some() {
&decl.inputs[1..]
} else {
&decl.inputs[..]
};
- let input_tys = input_params.iter().map(|a| ty_of_arg(this, &rb, a, None));
- let input_pats: Vec<String> = input_params.iter()
- .map(|a| pprust::pat_to_string(&*a.pat))
- .collect();
- let self_and_input_tys: Vec<Ty> =
- self_ty.into_iter().chain(input_tys).collect();
-
+ let arg_tys: Vec<Ty> =
+ arg_params.iter().map(|a| ty_of_arg(this, &rb, a, None)).collect();
+ let arg_pats: Vec<String> =
+ arg_params.iter().map(|a| pprust::pat_to_string(&*a.pat)).collect();
// Second, if there was exactly one lifetime (either a substitution or a
// reference) in the arguments, then any anonymous regions in the output
// have that lifetime.
- let implied_output_region = match implied_output_region {
- Some(r) => Ok(r),
- None => {
- let input_tys = if self_ty.is_some() {
- // Skip the first argument if `self` is present.
- &self_and_input_tys[1..]
- } else {
- &self_and_input_tys[..]
- };
-
- find_implied_output_region(this.tcx(), input_tys, input_pats)
- }
+ let implied_output_region = match explicit_self_category {
+ Some(ty::ByReferenceExplicitSelfCategory(region, _)) => Ok(region),
+ _ => find_implied_output_region(this.tcx(), &arg_tys, arg_pats)
};
let output_ty = match decl.output {
- hir::Return(ref output) if output.node == hir::TyInfer =>
- ty::FnConverging(this.ty_infer(None, None, None, output.span)),
hir::Return(ref output) =>
ty::FnConverging(convert_ty_with_lifetime_elision(this,
implied_output_region,
unsafety: unsafety,
abi: abi,
sig: ty::Binder(ty::FnSig {
- inputs: self_and_input_tys,
+ inputs: self_ty.into_iter().chain(arg_tys).collect(),
output: output_ty,
variadic: decl.variadic
}),
- }, explicit_self_category_result)
+ }, explicit_self_category)
}
-fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>,
- rscope: &RegionScope,
- self_info: &SelfInfo<'a, 'tcx>)
- -> ty::ExplicitSelfCategory
+fn determine_self_type<'a, 'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ self_info: SelfInfo<'a, 'tcx>)
+ -> (Option<Ty<'tcx>>, Option<ty::ExplicitSelfCategory>)
{
+ let self_ty = self_info.untransformed_self_ty;
return match self_info.explicit_self.node {
- hir::SelfStatic => ty::StaticExplicitSelfCategory,
- hir::SelfValue(_) => ty::ByValueExplicitSelfCategory,
+ hir::SelfStatic => (None, Some(ty::StaticExplicitSelfCategory)),
+ hir::SelfValue(_) => {
+ (Some(self_ty), Some(ty::ByValueExplicitSelfCategory))
+ }
hir::SelfRegion(ref lifetime, mutability, _) => {
let region =
opt_ast_region_to_region(this,
rscope,
self_info.explicit_self.span,
lifetime);
- ty::ByReferenceExplicitSelfCategory(region, mutability)
+ (Some(this.tcx().mk_ref(
+ this.tcx().mk_region(region),
+ ty::TypeAndMut {
+ ty: self_ty,
+ mutbl: mutability
+ })),
+ Some(ty::ByReferenceExplicitSelfCategory(region, mutability)))
}
hir::SelfExplicit(ref ast_type, _) => {
let explicit_type = ast_ty_to_ty(this, rscope, &**ast_type);
impl_modifiers,
method_modifiers);
- if impl_modifiers >= method_modifiers {
+ let category = if impl_modifiers >= method_modifiers {
ty::ByValueExplicitSelfCategory
} else {
match explicit_type.sty {
ty::TyBox(_) => ty::ByBoxExplicitSelfCategory,
_ => ty::ByValueExplicitSelfCategory,
}
- }
+ };
+
+ (Some(explicit_type), Some(category))
}
};
let item = fcx.tcx().impl_or_trait_item(fcx.tcx().map.local_def_id(item_id));
- let mut implied_bounds = match item.container() {
- ty::TraitContainer(_) => vec![],
- ty::ImplContainer(def_id) => impl_implied_bounds(fcx, def_id, span)
+ let (mut implied_bounds, self_ty) = match item.container() {
+ ty::TraitContainer(_) => (vec![], fcx.tcx().mk_self_type()),
+ ty::ImplContainer(def_id) => (impl_implied_bounds(fcx, def_id, span),
+ fcx.tcx().lookup_item_type(def_id).ty)
};
match item {
let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates);
this.check_fn_or_method(fcx, span, &method_ty, &predicates,
free_id_outlive, &mut implied_bounds);
+ this.check_method_receiver(fcx, span, &method,
+ free_id_outlive, self_ty);
}
ty::TypeTraitItem(assoc_type) => {
if let Some(ref ty) = assoc_type.ty {
self.check_where_clauses(fcx, span, predicates);
}
+ fn check_method_receiver<'fcx>(&mut self,
+ fcx: &FnCtxt<'fcx,'tcx>,
+ span: Span,
+ method: &ty::Method<'tcx>,
+ free_id_outlive: CodeExtent,
+ self_ty: ty::Ty<'tcx>)
+ {
+ // check that the type of the method's receiver matches the
+ // method's first parameter.
+
+ let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
+ let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
+ let sig = fcx.tcx().liberate_late_bound_regions(free_id_outlive, &fty.sig);
+
+ debug!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})",
+ method.name, method.explicit_self, self_ty, sig);
+
+ let rcvr_ty = match method.explicit_self {
+ ty::StaticExplicitSelfCategory => return,
+ ty::ByValueExplicitSelfCategory => self_ty,
+ ty::ByReferenceExplicitSelfCategory(region, mutability) => {
+ fcx.tcx().mk_ref(fcx.tcx().mk_region(region), ty::TypeAndMut {
+ ty: self_ty,
+ mutbl: mutability
+ })
+ }
+ ty::ByBoxExplicitSelfCategory => fcx.tcx().mk_box(self_ty)
+ };
+ let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty);
+ let rcvr_ty = fcx.tcx().liberate_late_bound_regions(free_id_outlive,
+ &ty::Binder(rcvr_ty));
+
+ debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
+
+ let _ = ::require_same_types(
+ fcx.tcx(), Some(fcx.infcx()), false, span,
+ sig.inputs[0], rcvr_ty,
+ || "mismatched method receiver".to_owned()
+ );
+ }
+
fn check_variances_for_type_defn(&self,
item: &hir::Item,
ast_generics: &hir::Generics)
use middle::def_id::DefId;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
-use middle::free_region::FreeRegionMap;
-use middle::region;
use middle::resolve_lifetime;
use middle::const_eval::{self, ConstVal};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
-use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme};
+use middle::ty::{self, ToPolyTraitRef, Ty, TypeScheme};
use middle::ty::{VariantKind};
-use middle::ty::fold::{TypeFolder, TypeFoldable};
+use middle::ty::fold::{TypeFolder};
use middle::ty::util::IntTypeExt;
-use middle::infer;
use rscope::*;
use rustc::front::map as hir_map;
use util::common::{ErrorReported, memoized};
ItemCtxt { ccx: self, param_bounds: param_bounds }
}
- fn method_ty(&self, method_id: ast::NodeId) -> Rc<ty::Method<'tcx>> {
- let def_id = self.tcx.map.local_def_id(method_id);
- match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() {
- ty::MethodTraitItem(ref mty) => mty.clone(),
- _ => {
- self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id));
- }
- }
- }
-
fn cycle_check<F,R>(&self,
span: Span,
request: AstConvRequest,
fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
- sig: &hir::MethodSig,
- id: ast::NodeId,
name: ast::Name,
+ id: ast::NodeId,
vis: hir::Visibility,
+ sig: &hir::MethodSig,
untransformed_rcvr_ty: Ty<'tcx>,
rcvr_ty_generics: &ty::Generics<'tcx>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
.insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type));
}
-fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
- container: ImplOrTraitItemContainer,
- methods: I,
- untransformed_rcvr_ty: Ty<'tcx>,
- rcvr_ty_generics: &ty::Generics<'tcx>,
- rcvr_ty_predicates: &ty::GenericPredicates<'tcx>)
- where I: Iterator<Item=(&'i hir::MethodSig, ast::NodeId, ast::Name, hir::Visibility, Span)>
-{
- debug!("convert_methods(untransformed_rcvr_ty={:?}, rcvr_ty_generics={:?}, \
- rcvr_ty_predicates={:?})",
- untransformed_rcvr_ty,
- rcvr_ty_generics,
- rcvr_ty_predicates);
-
- for (sig, id, name, vis, _span) in methods {
- convert_method(ccx,
- container,
- sig,
- id,
- name,
- vis,
- untransformed_rcvr_ty,
- rcvr_ty_generics,
- rcvr_ty_predicates);
- }
-}
-
fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
span: Span,
generics: &hir::Generics,
}
}
- let methods = impl_items.iter().filter_map(|ii| {
- if let hir::ImplItemKind::Method(ref sig, _) = ii.node {
+ for impl_item in impl_items {
+ if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
// if the method specifies a visibility, use that, otherwise
// inherit the visibility from the impl (so `foo` in `pub impl
// { fn foo(); }` is public, but private in `impl { fn
// foo(); }`).
- let method_vis = ii.vis.inherit_from(parent_visibility);
- Some((sig, ii.id, ii.name, method_vis, ii.span))
- } else {
- None
- }
- });
- convert_methods(ccx,
- ImplContainer(def_id),
- methods,
- selfty,
- &ty_generics,
- &ty_predicates);
+ let method_vis = impl_item.vis.inherit_from(parent_visibility);
- for impl_item in impl_items {
- if let hir::ImplItemKind::Method(ref sig, ref body) = impl_item.node {
- let body_id = body.id;
- let body_scope = ccx.tcx.region_maps.call_site_extent(impl_item.id, body_id);
- check_method_self_type(ccx,
- &BindingRscope::new(),
- ccx.method_ty(impl_item.id),
- selfty,
- &sig.explicit_self,
- body_scope,
- body_id);
+ convert_method(ccx, ImplContainer(def_id),
+ impl_item.name, impl_item.id, method_vis,
+ sig, selfty, &ty_generics, &ty_predicates);
}
}
},
hir::ItemTrait(_, _, _, ref trait_items) => {
let trait_def = trait_def_of_item(ccx, it);
+ let def_id = trait_def.trait_ref.def_id;
let _: Result<(), ErrorReported> = // any error is already reported, can ignore
- ccx.ensure_super_predicates(it.span, ccx.tcx.map.local_def_id(it.id));
+ ccx.ensure_super_predicates(it.span, def_id);
convert_trait_predicates(ccx, it);
- let trait_predicates = tcx.lookup_predicates(ccx.tcx.map.local_def_id(it.id));
+ let trait_predicates = tcx.lookup_predicates(def_id);
debug!("convert: trait_bounds={:?}", trait_predicates);
- // Convert all the associated types.
+ // FIXME: is the ordering here important? I think it is.
+ let container = TraitContainer(def_id);
+
+ // Convert all the associated constants.
for trait_item in trait_items {
- match trait_item.node {
- hir::ConstTraitItem(ref ty, ref default) => {
- let ty = ccx.icx(&trait_predicates)
- .to_ty(&ExplicitRscope, ty);
- tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id),
- TypeScheme {
- generics: trait_def.generics.clone(),
- ty: ty,
- });
- convert_associated_const(ccx,
- TraitContainer(ccx.tcx.map.local_def_id(it.id)),
- trait_item.name,
- trait_item.id,
- hir::Public,
- ty,
- default.is_some())
- }
- _ => {}
+ if let hir::ConstTraitItem(ref ty, ref default) = trait_item.node {
+ let ty = ccx.icx(&trait_predicates)
+ .to_ty(&ExplicitRscope, ty);
+ tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id),
+ TypeScheme {
+ generics: trait_def.generics.clone(),
+ ty: ty,
+ });
+ convert_associated_const(ccx,
+ container,
+ trait_item.name,
+ trait_item.id,
+ hir::Public,
+ ty,
+ default.is_some())
}
- };
+ }
// Convert all the associated types.
for trait_item in trait_items {
- match trait_item.node {
- hir::TypeTraitItem(_, ref opt_ty) => {
- let typ = opt_ty.as_ref().map({
- |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
- });
-
- convert_associated_type(ccx,
- TraitContainer(ccx.tcx.map.local_def_id(it.id)),
- trait_item.name,
- trait_item.id,
- hir::Public,
- typ);
- }
- _ => {}
+ if let hir::TypeTraitItem(_, ref opt_ty) = trait_item.node {
+ let typ = opt_ty.as_ref().map({
+ |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
+ });
+
+ convert_associated_type(ccx,
+ container,
+ trait_item.name,
+ trait_item.id,
+ hir::Public,
+ typ);
}
- };
+ }
- let methods = trait_items.iter().filter_map(|ti| {
- let sig = match ti.node {
- hir::MethodTraitItem(ref sig, _) => sig,
- _ => return None,
- };
- Some((sig, ti.id, ti.name, hir::Inherited, ti.span))
- });
+ // Convert all the methods
+ for trait_item in trait_items {
+ if let hir::MethodTraitItem(ref sig, _) = trait_item.node {
+ convert_method(ccx,
+ container,
+ trait_item.name,
+ trait_item.id,
+ hir::Inherited,
+ sig,
+ tcx.mk_self_type(),
+ &trait_def.generics,
+ &trait_predicates);
- // Run convert_methods on the trait methods.
- convert_methods(ccx,
- TraitContainer(ccx.tcx.map.local_def_id(it.id)),
- methods,
- tcx.mk_self_type(),
- &trait_def.generics,
- &trait_predicates);
+ }
+ }
// Add an entry mapping
let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| {
let def_id = ccx.tcx.map.local_def_id(trait_item.id);
match trait_item.node {
- hir::ConstTraitItem(..) => {
- ty::ConstTraitItemId(def_id)
- }
- hir::MethodTraitItem(..) => {
- ty::MethodTraitItemId(def_id)
- }
- hir::TypeTraitItem(..) => {
- ty::TypeTraitItemId(def_id)
- }
+ hir::ConstTraitItem(..) => ty::ConstTraitItemId(def_id),
+ hir::MethodTraitItem(..) => ty::MethodTraitItemId(def_id),
+ hir::TypeTraitItem(..) => ty::TypeTraitItemId(def_id)
}
}).collect());
tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
trait_item_def_ids);
-
- // This must be done after `collect_trait_methods` so that
- // we have a method type stored for every method.
- for trait_item in trait_items {
- let (sig, the_scope, the_id) = match trait_item.node {
- hir::MethodTraitItem(ref sig, Some(ref body)) => {
- let body_scope =
- ccx.tcx.region_maps.call_site_extent(trait_item.id, body.id);
- (sig, body_scope, body.id)
- }
- hir::MethodTraitItem(ref sig, None) => {
- let item_scope = ccx.tcx.region_maps.item_extent(trait_item.id);
- (sig, item_scope, it.id)
- }
- _ => continue
- };
- check_method_self_type(ccx,
- &BindingRscope::new(),
- ccx.method_ty(trait_item.id),
- tcx.mk_self_type(),
- &sig.explicit_self,
- the_scope,
- the_id)
- }
},
hir::ItemStruct(ref struct_def, _) => {
let (scheme, predicates) = convert_typed_item(ccx, it);
.iter()
.enumerate()
.map(|(i, def)| ty::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: tcx.map.local_def_id(def.lifetime.id),
space: TypeSpace,
index: i as u32,
name: def.lifetime.name
let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics);
for (index, param) in early_lifetimes.iter().enumerate() {
let index = index as u32;
- let def_id = tcx.map.local_def_id(param.lifetime.id);
let region =
ty::ReEarlyBound(ty::EarlyBoundRegion {
- def_id: def_id,
space: space,
index: index,
name: param.lifetime.name
Substs::new(types, regions)
}
-/// Verifies that the explicit self type of a method matches the impl
-/// or trait. This is a bit weird but basically because right now we
-/// don't handle the general case, but instead map it to one of
-/// several pre-defined options using various heuristics, this method
-/// comes back to check after the fact that explicit type the user
-/// wrote actually matches what the pre-defined option said.
-fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
- ccx: &CrateCtxt<'a, 'tcx>,
- rs: &RS,
- method_type: Rc<ty::Method<'tcx>>,
- required_type: Ty<'tcx>,
- explicit_self: &hir::ExplicitSelf,
- body_scope: region::CodeExtent,
- body_id: ast::NodeId)
-{
- let tcx = ccx.tcx;
- if let hir::SelfExplicit(ref ast_type, _) = explicit_self.node {
- let typ = ccx.icx(&method_type.predicates).to_ty(rs, &**ast_type);
- let base_type = match typ.sty {
- ty::TyRef(_, tm) => tm.ty,
- ty::TyBox(typ) => typ,
- _ => typ,
- };
-
- // "Required type" comes from the trait definition. It may
- // contain late-bound regions from the method, but not the
- // trait (since traits only have early-bound region
- // parameters).
- assert!(!base_type.has_regions_escaping_depth(1));
- let required_type_free =
- liberate_early_bound_regions(
- tcx, body_scope,
- &tcx.liberate_late_bound_regions(body_scope, &ty::Binder(required_type)));
-
- // The "base type" comes from the impl. It too may have late-bound
- // regions from the method.
- assert!(!base_type.has_regions_escaping_depth(1));
- let base_type_free =
- liberate_early_bound_regions(
- tcx, body_scope,
- &tcx.liberate_late_bound_regions(body_scope, &ty::Binder(base_type)));
-
- debug!("required_type={:?} required_type_free={:?} \
- base_type={:?} base_type_free={:?}",
- required_type,
- required_type_free,
- base_type,
- base_type_free);
-
- let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
- drop(::require_same_types(tcx,
- Some(&infcx),
- false,
- explicit_self.span,
- base_type_free,
- required_type_free,
- || {
- format!("mismatched self type: expected `{}`",
- required_type)
- }));
-
- // We could conceviably add more free-region relations here,
- // but since this code is just concerned with checking that
- // the `&Self` types etc match up, it's not really necessary.
- // It would just allow people to be more approximate in some
- // cases. In any case, we can do it later as we feel the need;
- // I'd like this function to go away eventually.
- let free_regions = FreeRegionMap::new();
-
- infcx.resolve_regions_and_report_errors(&free_regions, body_id);
- }
-
- fn liberate_early_bound_regions<'tcx,T>(
- tcx: &ty::ctxt<'tcx>,
- scope: region::CodeExtent,
- value: &T)
- -> T
- where T : TypeFoldable<'tcx>
- {
- /*!
- * Convert early-bound regions into free regions; normally this is done by
- * applying the `free_substs` from the `ParameterEnvironment`, but this particular
- * method-self-type check is kind of hacky and done very early in the process,
- * before we really have a `ParameterEnvironment` to check.
- */
-
- tcx.fold_regions(value, &mut false, |region, _| {
- match region {
- ty::ReEarlyBound(data) => {
- ty::ReFree(ty::FreeRegion {
- scope: scope,
- bound_region: ty::BrNamed(data.def_id, data.name)
- })
- }
- _ => region
- }
- })
- }
-}
-
/// Checks that all the type parameters on an impl
fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
ast_generics: &hir::Generics,
.collect();
for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() {
- let def_id = tcx.map.local_def_id(lifetime_def.lifetime.id);
- let region = ty::EarlyBoundRegion { def_id: def_id,
- space: TypeSpace,
+ let region = ty::EarlyBoundRegion { space: TypeSpace,
index: index as u32,
name: lifetime_def.lifetime.name };
if
/// Adds constraints appropriate for a region appearing in a
/// context with ambient variance `variance`
fn add_constraints_from_region(&mut self,
- _generics: &ty::Generics<'tcx>,
+ generics: &ty::Generics<'tcx>,
region: ty::Region,
variance: VarianceTermPtr<'a>) {
match region {
ty::ReEarlyBound(ref data) => {
- let node_id = self.tcx().map.as_local_node_id(data.def_id).unwrap();
+ let def_id =
+ generics.regions.get(data.space, data.index as usize).def_id;
+ let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
if self.is_to_be_inferred(node_id) {
let index = self.inferred_index(node_id);
self.add_constraint(index, variance);
use sys_common::unwind;
use thread::Result;
+pub use panicking::{take_handler, set_handler, PanicInfo, Location};
+
/// A marker trait which represents "panic safe" types in Rust.
///
/// This trait is implemented by default for many types and behaves similarly in
across a recover boundary"]
pub trait RecoverSafe {}
-/// A marker trait representing types which do not contain an `UnsafeCell` by
-/// value internally.
+/// A marker trait representing types where a shared reference is considered
+/// recover safe.
+///
+/// This trait is namely not implemented by `UnsafeCell`, the root of all
+/// interior mutability.
///
/// This is a "helper marker trait" used to provide impl blocks for the
/// `RecoverSafe` trait, for more information see that documentation.
#[rustc_on_unimplemented = "the type {Self} contains interior mutability \
and a reference may not be safely transferrable \
across a recover boundary"]
-pub trait NoUnsafeCell {}
+pub trait RefRecoverSafe {}
/// A simple wrapper around a type to assert that it is panic safe.
///
// * Our custom AssertRecoverSafe wrapper is indeed recover safe
impl RecoverSafe for .. {}
impl<'a, T: ?Sized> !RecoverSafe for &'a mut T {}
-impl<'a, T: NoUnsafeCell + ?Sized> RecoverSafe for &'a T {}
-impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *const T {}
-impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *mut T {}
+impl<'a, T: RefRecoverSafe + ?Sized> RecoverSafe for &'a T {}
+impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *const T {}
+impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *mut T {}
impl<T: RecoverSafe> RecoverSafe for Unique<T> {}
-impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Shared<T> {}
+impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Shared<T> {}
impl<T: ?Sized> RecoverSafe for Mutex<T> {}
impl<T: ?Sized> RecoverSafe for RwLock<T> {}
impl<T> RecoverSafe for AssertRecoverSafe<T> {}
// not covered via the Shared impl above b/c the inner contents use
// Cell/AtomicUsize, but the usage here is recover safe so we can lift the
// impl up one level to Arc/Rc itself
-impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Rc<T> {}
-impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Arc<T> {}
+impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Rc<T> {}
+impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Arc<T> {}
-// Pretty simple implementations for the `NoUnsafeCell` marker trait, basically
-// just saying that this is a marker trait and `UnsafeCell` is the only thing
-// which doesn't implement it (which then transitively applies to everything
-// else.
-impl NoUnsafeCell for .. {}
-impl<T: ?Sized> !NoUnsafeCell for UnsafeCell<T> {}
+// Pretty simple implementations for the `RefRecoverSafe` marker trait,
+// basically just saying that this is a marker trait and `UnsafeCell` is the
+// only thing which doesn't implement it (which then transitively applies to
+// everything else.
+impl RefRecoverSafe for .. {}
+impl<T: ?Sized> !RefRecoverSafe for UnsafeCell<T> {}
+impl<T> RefRecoverSafe for AssertRecoverSafe<T> {}
impl<T> AssertRecoverSafe<T> {
/// Creates a new `AssertRecoverSafe` wrapper around the provided type.
use cell::Cell;
use cell::RefCell;
use intrinsics;
+use sync::StaticRwLock;
use sys::stdio::Stderr;
use sys_common::backtrace;
use sys_common::thread_info;
use sys_common::util;
+use thread;
thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
}
}
-fn log_panic(obj: &(Any+Send), file: &'static str, line: u32,
- log_backtrace: bool) {
- let msg = match obj.downcast_ref::<&'static str>() {
+#[derive(Copy, Clone)]
+enum Handler {
+ Default,
+ Custom(*mut (Fn(&PanicInfo) + 'static + Sync + Send)),
+}
+
+static HANDLER_LOCK: StaticRwLock = StaticRwLock::new();
+static mut HANDLER: Handler = Handler::Default;
+
+/// Registers a custom panic handler, replacing any that was previously
+/// registered.
+///
+/// The panic handler is invoked when a thread panics, but before it begins
+/// unwinding the stack. The default handler prints a message to standard error
+/// and generates a backtrace if requested, but this behavior can be customized
+/// with the `set_handler` and `take_handler` functions.
+///
+/// The handler is provided with a `PanicInfo` struct which contains information
+/// about the origin of the panic, including the payload passed to `panic!` and
+/// the source code location from which the panic originated.
+///
+/// The panic handler is a global resource.
+///
+/// # Panics
+///
+/// Panics if called from a panicking thread.
+#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+pub fn set_handler<F>(handler: F) where F: Fn(&PanicInfo) + 'static + Sync + Send {
+ if thread::panicking() {
+ panic!("cannot modify the panic handler from a panicking thread");
+ }
+
+ let handler = Box::new(handler);
+ unsafe {
+ let lock = HANDLER_LOCK.write();
+ let old_handler = HANDLER;
+ HANDLER = Handler::Custom(Box::into_raw(handler));
+ drop(lock);
+
+ if let Handler::Custom(ptr) = old_handler {
+ Box::from_raw(ptr);
+ }
+ }
+}
+
+/// Unregisters the current panic handler, returning it.
+///
+/// If no custom handler is registered, the default handler will be returned.
+///
+/// # Panics
+///
+/// Panics if called from a panicking thread.
+#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+pub fn take_handler() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
+ if thread::panicking() {
+ panic!("cannot modify the panic handler from a panicking thread");
+ }
+
+ unsafe {
+ let lock = HANDLER_LOCK.write();
+ let handler = HANDLER;
+ HANDLER = Handler::Default;
+ drop(lock);
+
+ match handler {
+ Handler::Default => Box::new(default_handler),
+ Handler::Custom(ptr) => {Box::from_raw(ptr)} // FIXME #30530
+ }
+ }
+}
+
+/// A struct providing information about a panic.
+#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+pub struct PanicInfo<'a> {
+ payload: &'a (Any + Send),
+ location: Location<'a>,
+}
+
+impl<'a> PanicInfo<'a> {
+ /// Returns the payload associated with the panic.
+ ///
+ /// This will commonly, but not always, be a `&'static str` or `String`.
+ #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+ pub fn payload(&self) -> &(Any + Send) {
+ self.payload
+ }
+
+ /// Returns information about the location from which the panic originated,
+ /// if available.
+ ///
+ /// This method will currently always return `Some`, but this may change
+ /// in future versions.
+ #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+ pub fn location(&self) -> Option<&Location> {
+ Some(&self.location)
+ }
+}
+
+/// A struct containing information about the location of a panic.
+#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+pub struct Location<'a> {
+ file: &'a str,
+ line: u32,
+}
+
+impl<'a> Location<'a> {
+ /// Returns the name of the source file from which the panic originated.
+ #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+ pub fn file(&self) -> &str {
+ self.file
+ }
+
+ /// Returns the line number from which the panic originated.
+ #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+ pub fn line(&self) -> u32 {
+ self.line
+ }
+}
+
+fn default_handler(info: &PanicInfo) {
+ let panics = PANIC_COUNT.with(|s| s.get());
+
+ // If this is a double panic, make sure that we print a backtrace
+ // for this panic. Otherwise only print it if logging is enabled.
+ let log_backtrace = panics >= 2 || backtrace::log_enabled();
+
+ let file = info.location.file;
+ let line = info.location.line;
+
+ let msg = match info.payload.downcast_ref::<&'static str>() {
Some(s) => *s,
- None => match obj.downcast_ref::<String>() {
+ None => match info.payload.downcast_ref::<String>() {
Some(s) => &s[..],
None => "Box<Any>",
}
unsafe { intrinsics::abort() }
}
- // If this is a double panic, make sure that we print a backtrace
- // for this panic. Otherwise only print it if logging is enabled.
- let log_backtrace = panics >= 2 || backtrace::log_enabled();
- log_panic(obj, file, line, log_backtrace);
+ let info = PanicInfo {
+ payload: obj,
+ location: Location {
+ file: file,
+ line: line,
+ },
+ };
+
+ unsafe {
+ let _lock = HANDLER_LOCK.read();
+ match HANDLER {
+ Handler::Default => default_handler(&info),
+ Handler::Custom(ptr) => (*ptr)(&info),
+ }
+ }
if panics >= 2 {
// If a thread panics while it's already unwinding then we
linux-x86_64 97e2a5eb8904962df8596e95d6e5d9b574d73bf4
macos-i386 ca52d2d3ba6497ed007705ee3401cf7efc136ca1
macos-x86_64 3c44ffa18f89567c2b81f8d695e711c86d81ffc7
+ openbsd-x86_64 6c8aab2c8a169274942f9a15e460069a3ff64be9
winnt-i386 f9056ebd3db9611d31c2dc6dc5f96c7208d5d227
winnt-x86_64 a85a40e535d828016181d3aa40afe34c3e36ab8c
impl <'a> Foo<'a>{
fn bar(self: &mut Foo) {
//~^ mismatched types
- //~| expected `Foo<'a>`
- //~| found `Foo<'_>`
+ //~| expected `&mut Foo<'a>`
+ //~| found `&mut Foo<'_>`
//~| lifetime mismatch
//~| mismatched types
- //~| expected `Foo<'a>`
- //~| found `Foo<'_>`
+ //~| expected `&mut Foo<'a>`
+ //~| found `&mut Foo<'_>`
//~| lifetime mismatch
}
}
isize
> {
fn say(self: &Pair<&str, isize>) {
-//~^ ERROR mismatched types
-//~| expected `Pair<&'static str, isize>`
-//~| found `Pair<&str, isize>`
-//~| lifetime mismatch
println!("{}", self);
}
}
impl S {
fn f(self: *mut S) -> String { self.0 }
- //~^ ERROR mismatched self type
+ //~^ ERROR mismatched method receiver
}
fn main() { S("".to_owned()).f(); }
}
impl Foo {
- fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched self type
+ fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched method receiver
self.f + x
}
}
}
impl<T> Bar<T> {
- fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched self type
+ fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched method receiver
x
}
- fn bar(self: &Bar<usize>, x: isize) -> isize { //~ ERROR mismatched self type
+ fn bar(self: &Bar<usize>, x: isize) -> isize { //~ ERROR mismatched method receiver
x
}
}
impl<'a, T> SomeTrait for &'a Bar<T> {
fn dummy1(self: &&'a Bar<T>) { }
- fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched self type
+ fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched types
+ //~^ ERROR mismatched types
fn dummy3(self: &&Bar<T>) {}
//~^ ERROR mismatched types
- //~| expected `&'a Bar<T>`
- //~| found `&Bar<T>`
+ //~| expected `&&'a Bar<T>`
+ //~| found `&&Bar<T>`
//~| lifetime mismatch
//~| ERROR mismatched types
- //~| expected `&'a Bar<T>`
- //~| found `&Bar<T>`
+ //~| expected `&&'a Bar<T>`
+ //~| found `&&Bar<T>`
//~| lifetime mismatch
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:greetings from the panic handler
+
+#![feature(std_panic, panic_handler)]
+use std::panic;
+use std::io::{self, Write};
+
+fn main() {
+ panic::set_handler(|i| {
+ write!(io::stderr(), "greetings from the panic handler");
+ });
+ panic!("foobar");
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'foobar'
+
+#![feature(std_panic, panic_handler)]
+use std::panic;
+use std::io::{self, Write};
+
+fn main() {
+ panic::set_handler(|i| {
+ write!(io::stderr(), "greetings from the panic handler");
+ });
+ panic::take_handler();
+ panic!("foobar");
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'foobar'
+
+#![feature(std_panic, panic_handler)]
+use std::panic;
+
+fn main() {
+ panic::take_handler();
+ panic!("foobar");
+}
fn integer(a: i32x4, b: i32x4) -> i32x4;
// vmaxq_s32
- #[cfg(any(target_arch = "arm"))]
+ #[cfg(target_arch = "arm")]
#[link_name = "llvm.arm.neon.vmaxs.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
// vmaxq_s32
- #[cfg(any(target_arch = "aarch64"))]
+ #[cfg(target_arch = "aarch64")]
#[link_name = "llvm.aarch64.neon.maxs.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
extern crate mir_external_refs as ext;
struct S(u8);
+#[derive(Debug, PartialEq, Eq)]
+struct Unit;
impl S {
fn hey() -> u8 { 42 }
<u32 as T<_, _>>::staticmeth
}
+#[rustc_mir]
+fn t21() -> Unit {
+ Unit
+}
+
+#[rustc_mir]
+fn t22() -> Option<u8> {
+ None
+}
+
fn main(){
unsafe {
assert_eq!(t1()(), regular());
assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64));
assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32));
assert_eq!(t20()(123u64, 38u32), <u32 as T<_, _>>::staticmeth(123, 38));
+ assert_eq!(t21(), Unit);
+ assert_eq!(t22(), None);
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(panic_handler, const_fn, std_panic)]
+
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::panic;
+use std::thread;
+
+static A: AtomicUsize = AtomicUsize::new(0);
+static B: AtomicUsize = AtomicUsize::new(0);
+
+fn main() {
+ panic::set_handler(|_| { A.fetch_add(1, Ordering::SeqCst); });
+ let handler = panic::take_handler();
+ panic::set_handler(move |info| {
+ B.fetch_add(1, Ordering::SeqCst);
+ handler(info);
+ });
+
+ let _ = thread::spawn(|| {
+ panic!();
+ }).join();
+
+ assert_eq!(1, A.load(Ordering::SeqCst));
+ assert_eq!(1, B.load(Ordering::SeqCst));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(panic_handler, std_panic)]
+
+use std::panic;
+use std::thread;
+
+fn a() {
+ panic::set_handler(|_| println!("hello yes this is a"));
+ panic::take_handler();
+ panic::set_handler(|_| println!("hello yes this is a part 2"));
+ panic::take_handler();
+}
+
+fn b() {
+ panic::take_handler();
+ panic::take_handler();
+ panic::take_handler();
+ panic::take_handler();
+ panic::take_handler();
+ panic!();
+}
+
+fn c() {
+ panic::set_handler(|_| ());
+ panic::set_handler(|_| ());
+ panic::set_handler(|_| ());
+ panic::set_handler(|_| ());
+ panic::set_handler(|_| ());
+ panic::set_handler(|_| ());
+ panic!();
+}
+
+fn main() {
+ for _ in 0..10 {
+ let mut handles = vec![];
+ for _ in 0..10 {
+ handles.push(thread::spawn(a));
+ }
+ for _ in 0..10 {
+ handles.push(thread::spawn(b));
+ }
+ for _ in 0..10 {
+ handles.push(thread::spawn(c));
+ }
+ for handle in handles {
+ let _ = handle.join();
+ }
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(panic_handler, const_fn, std_panic)]
+
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::panic;
+use std::thread;
+
+static A: AtomicUsize = AtomicUsize::new(0);
+
+fn main() {
+ panic::set_handler(|_| ());
+ panic::set_handler(|info| { A.fetch_add(1, Ordering::SeqCst); });
+
+ let _ = thread::spawn(|| {
+ panic!();
+ }).join();
+
+ assert_eq!(1, A.load(Ordering::SeqCst));
+}
#![allow(dead_code)]
#![feature(recover)]
-use std::panic::RecoverSafe;
+use std::panic::{RecoverSafe, AssertRecoverSafe};
use std::cell::RefCell;
use std::sync::{Mutex, RwLock, Arc};
use std::rc::Rc;
assert::<Box<T>>();
assert::<Vec<T>>();
assert::<RefCell<T>>();
+ assert::<AssertRecoverSafe<T>>();
+ assert::<&AssertRecoverSafe<T>>();
+ assert::<Rc<AssertRecoverSafe<T>>>();
+ assert::<Arc<AssertRecoverSafe<T>>>();
}
}