From 6992280f0003e825ad05daf6b5aed94c63e77773 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 3 Mar 2016 14:48:08 +0100 Subject: [PATCH] simplify const path lookup for constants and associated constants --- src/librustc/middle/check_match.rs | 2 +- src/librustc/middle/const_eval.rs | 168 ++++++++++------------------ src/librustc/middle/ty/context.rs | 8 +- src/librustc_mir/hair/cx/pattern.rs | 2 +- src/librustc_passes/consts.rs | 2 +- src/librustc_trans/trans/consts.rs | 2 +- 6 files changed, 67 insertions(+), 117 deletions(-) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 1f79e76f3ac3..51985be96db5 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -476,7 +476,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { Some(Def::AssociatedConst(did)) | Some(Def::Const(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id), None) { - Some(const_expr) => { + Some((const_expr, _const_ty)) => { const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| { if let Some(ref mut renaming_map) = self.renaming_map { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index c02782b859cb..3690f0c1d664 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -98,13 +98,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, def_id: DefId, maybe_ref_id: Option, param_substs: Option<&'tcx subst::Substs<'tcx>>) - -> Option<&'tcx Expr> { + -> Option<(&'tcx Expr, Option>)> { if let Some(node_id) = tcx.map.as_local_node_id(def_id) { match tcx.map.find(node_id) { None => None, Some(ast_map::NodeItem(it)) => match it.node { - hir::ItemConst(_, ref const_expr) => { - Some(&const_expr) + hir::ItemConst(ref ty, ref const_expr) => { + Some((&const_expr, ast_ty_to_prim_ty(tcx, ty))) } _ => None }, @@ -123,8 +123,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, if let Some(param_substs) = param_substs { substs = substs.subst(tcx, param_substs); } - resolve_trait_associated_const(tcx, ti, trait_id, - substs) + resolve_trait_associated_const(tcx, ti, trait_id, substs) } // Technically, without knowing anything about the // expression that generates the obligation, we could @@ -138,8 +137,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, _ => None }, Some(ast_map::NodeImplItem(ii)) => match ii.node { - hir::ImplItemKind::Const(_, ref expr) => { - Some(&expr) + hir::ImplItemKind::Const(ref ty, ref expr) => { + Some((&expr, ast_ty_to_prim_ty(tcx, ty))) } _ => None }, @@ -147,16 +146,18 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, } } else { match tcx.extern_const_statics.borrow().get(&def_id) { - Some(&ast::DUMMY_NODE_ID) => return None, - Some(&expr_id) => { - return Some(tcx.map.expect_expr(expr_id)); + Some(&None) => return None, + Some(&Some((expr_id, ty))) => { + return Some((tcx.map.expect_expr(expr_id), ty)); } None => {} } let mut used_ref_id = false; - let expr_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { + let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node { - hir::ItemConst(_, ref const_expr) => Some(const_expr.id), + hir::ItemConst(ref ty, ref const_expr) => { + Some((&**const_expr, ast_ty_to_prim_ty(tcx, ty))) + }, _ => None }, cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node { @@ -173,8 +174,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, if let Some(param_substs) = param_substs { substs = substs.subst(tcx, param_substs); } - resolve_trait_associated_const(tcx, ti, trait_id, - substs).map(|e| e.id) + resolve_trait_associated_const(tcx, ti, trait_id, substs) } None => None } @@ -182,7 +182,9 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, _ => None }, cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node { - hir::ImplItemKind::Const(_, ref expr) => Some(expr.id), + hir::ImplItemKind::Const(ref ty, ref expr) => { + Some((&**expr, ast_ty_to_prim_ty(tcx, ty))) + }, _ => None }, _ => None @@ -192,10 +194,10 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, // lookup with the same def_id may yield a different result. if !used_ref_id { tcx.extern_const_statics - .borrow_mut().insert(def_id, - expr_id.unwrap_or(ast::DUMMY_NODE_ID)); + .borrow_mut() + .insert(def_id, expr_ty.map(|(e, t)| (e.id, t))); } - expr_id.map(|id| tcx.map.expect_expr(id)) + expr_ty } } @@ -386,7 +388,7 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P { PatKind::Path(path.clone()), Some(Def::Const(def_id)) | Some(Def::AssociatedConst(def_id)) => { - let expr = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap(); + let (expr, _ty) = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap(); return const_expr_to_pat(tcx, expr, span); }, _ => unreachable!(), @@ -778,90 +780,49 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, if def.depth != 0 { signal!(e, UnresolvedPath); } - Some(def.full_def()) + def.full_def() } else { - None + signal!(e, NonConstPath); }; - let (const_expr, const_ty) = match opt_def { - Some(Def::Const(def_id)) => { - if let Some(node_id) = tcx.map.as_local_node_id(def_id) { - match tcx.map.find(node_id) { - Some(ast_map::NodeItem(it)) => match it.node { - hir::ItemConst(ref ty, ref expr) => { - (Some(&**expr), Some(&**ty)) - } - _ => (None, None) - }, - _ => (None, None) - } + match opt_def { + Def::Const(def_id) | + Def::AssociatedConst(def_id) => { + let maybe_ref_id = if let ExprTypeChecked = ty_hint { + Some(e.id) } else { - (lookup_const_by_id(tcx, def_id, Some(e.id), None), None) + None + }; + if let Some((e, ty)) = lookup_const_by_id(tcx, def_id, maybe_ref_id, None) { + let item_hint = match ty { + Some(ty) => ty_hint.checked_or(ty), + None => ty_hint, + }; + try!(eval_const_expr_partial(tcx, e, item_hint, None)) + } else { + signal!(e, NonConstPath); + } + }, + Def::Variant(enum_def, variant_def) => { + if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) { + try!(eval_const_expr_partial(tcx, const_expr, ty_hint, None)) + } else { + signal!(e, NonConstPath); } } - Some(Def::AssociatedConst(def_id)) => { - if let Some(node_id) = tcx.map.as_local_node_id(def_id) { - match impl_or_trait_container(tcx, def_id) { - ty::TraitContainer(trait_id) => match tcx.map.find(node_id) { - Some(ast_map::NodeTraitItem(ti)) => match ti.node { - hir::ConstTraitItem(ref ty, _) => { - if let ExprTypeChecked = ty_hint { - let substs = tcx.node_id_item_substs(e.id).substs; - (resolve_trait_associated_const(tcx, - ti, - trait_id, - substs), - Some(&**ty)) - } else { - (None, None) - } - } - _ => (None, None) - }, - _ => (None, None) - }, - ty::ImplContainer(_) => match tcx.map.find(node_id) { - Some(ast_map::NodeImplItem(ii)) => match ii.node { - hir::ImplItemKind::Const(ref ty, ref expr) => { - (Some(&**expr), Some(&**ty)) - } - _ => (None, None) - }, - _ => (None, None) - }, - } - } else { - (lookup_const_by_id(tcx, def_id, Some(e.id), None), None) - } + Def::Struct(..) => { + ConstVal::Struct(e.id) } - Some(Def::Variant(enum_def, variant_def)) => { - (lookup_variant_by_id(tcx, enum_def, variant_def), None) - } - Some(Def::Struct(..)) => { - return Ok(ConstVal::Struct(e.id)) - } - Some(Def::Local(_, id)) => { + Def::Local(_, id) => { debug!("Def::Local({:?}): {:?}", id, fn_args); if let Some(val) = fn_args.and_then(|args| args.get(&id)) { - return Ok(val.clone()); + val.clone() } else { - (None, None) + signal!(e, NonConstPath); } }, - Some(Def::Method(id)) | Some(Def::Fn(id)) => return Ok(Function(id)), - _ => (None, None) - }; - let const_expr = match const_expr { - Some(actual_e) => actual_e, - None => signal!(e, NonConstPath) - }; - let item_hint = match const_ty { - Some(ty) => match ast_ty_to_prim_ty(tcx, ty) { - Some(ty) => ty_hint.checked_or(ty), - None => ty_hint.erase_hint(), - }, - None => ty_hint.erase_hint(), - }; - try!(eval_const_expr_partial(tcx, const_expr, item_hint, fn_args)) + Def::Method(id) | Def::Fn(id) => Function(id), + _ => signal!(e, NonConstPath), + } } hir::ExprCall(ref callee, ref args) => { let sub_ty_hint = ty_hint.erase_hint(); @@ -1097,28 +1058,11 @@ fn infer<'tcx>( } } -fn impl_or_trait_container(tcx: &TyCtxt, def_id: DefId) -> ty::ImplOrTraitItemContainer { - // This is intended to be equivalent to tcx.impl_or_trait_item(def_id).container() - // for local def_id, but it can be called before tcx.impl_or_trait_items is complete. - if let Some(node_id) = tcx.map.as_local_node_id(def_id) { - if let Some(ast_map::NodeItem(item)) = tcx.map.find(tcx.map.get_parent_node(node_id)) { - let container_id = tcx.map.local_def_id(item.id); - match item.node { - hir::ItemImpl(..) => return ty::ImplContainer(container_id), - hir::ItemTrait(..) => return ty::TraitContainer(container_id), - _ => () - } - } - panic!("No impl or trait container for {:?}", def_id); - } - panic!("{:?} is not local", def_id); -} - fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, ti: &'tcx hir::TraitItem, trait_id: DefId, rcvr_substs: subst::Substs<'tcx>) - -> Option<&'tcx Expr> + -> Option<(&'tcx Expr, Option>)> { let trait_ref = ty::Binder( rcvr_substs.erase_regions().to_trait_ref(tcx, trait_id) @@ -1151,7 +1095,9 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>, .iter().find(|ic| ic.name == ti.name) { Some(ic) => lookup_const_by_id(tcx, ic.def_id, None, None), None => match ti.node { - hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr), + hir::ConstTraitItem(ref ty, Some(ref expr)) => { + Some((&*expr, ast_ty_to_prim_ty(tcx, ty))) + }, _ => None, }, } diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 61a7f49f45d4..03c13115aea6 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -342,8 +342,12 @@ pub struct TyCtxt<'tcx> { /// FIXME(arielb1): why is this separate from populated_external_types? pub populated_external_primitive_impls: RefCell, - /// These caches are used by const_eval when decoding external constants. - pub extern_const_statics: RefCell>, + /// Cache used by const_eval when decoding external constants. + /// Contains `None` when the constant has been fetched but doesn't exist. + /// Constains `Some(expr_id, type)` otherwise. + /// `type` is `None` in case it's not a primitive type + pub extern_const_statics: RefCell>)>>>, + /// Cache used by const_eval when decoding extern const fns pub extern_const_fns: RefCell>, pub node_lint_levels: RefCell PatCx<'patcx, 'cx, 'tcx> { Def::Const(def_id) | Def::AssociatedConst(def_id) => match const_eval::lookup_const_by_id(self.cx.tcx, def_id, Some(pat.id), None) { - Some(const_expr) => { + Some((const_expr, _const_ty)) => { let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr, pat.span); return self.to_pattern(&pat); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 3a39a3c6dd19..a9e03bba7db8 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -604,7 +604,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } Some(Def::Const(did)) | Some(Def::AssociatedConst(did)) => { - if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did, + if let Some((expr, _ty)) = const_eval::lookup_const_by_id(v.tcx, did, Some(e.id), None) { let inner = v.global_expr(Mode::Const, expr); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index ebe19aa972ce..7d37627ad0ee 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -227,7 +227,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id), Some(param_substs)) { - Some(ref expr) => expr, + Some((ref expr, _ty)) => expr, None => { ccx.sess().span_bug(ref_expr.span, "constant item not found") }