use rustc::hir::def::{Def, PathResolution};
use rustc::hir::def_id::DefId;
use rustc::hir::pat_util::def_to_path;
-use rustc::ty::{self, Ty, TyCtxt, subst};
+use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::util::IntTypeExt;
+use rustc::ty::subst::Substs;
use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
}
fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- enum_def: DefId,
variant_def: DefId)
-> Option<&'tcx Expr> {
fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
None
}
- if let Some(enum_node_id) = tcx.map.as_local_node_id(enum_def) {
- let variant_node_id = tcx.map.as_local_node_id(variant_def).unwrap();
+ if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
+ let enum_node_id = tcx.map.get_parent(variant_node_id);
match tcx.map.find(enum_node_id) {
None => None,
Some(ast_map::NodeItem(it)) => match it.node {
/// This generally happens in late/trans const evaluation.
pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
- substs: Option<&'tcx subst::Substs<'tcx>>)
+ substs: Option<&'tcx Substs<'tcx>>)
-> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
match tcx.map.find(node_id) {
_ => None
},
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
- hir::ConstTraitItem(_, _) => {
+ hir::ConstTraitItem(..) => {
if let Some(substs) = substs {
// If we have a trait item and the substitutions for it,
// `resolve_trait_associated_const` will select an impl
// or the default.
- let trait_id = tcx.trait_of_item(def_id).unwrap();
+ let trait_id = tcx.map.get_parent(node_id);
+ let trait_id = tcx.map.local_def_id(trait_id);
resolve_trait_associated_const(tcx, ti, trait_id, substs)
} else {
// Technically, without knowing anything about the
_ => None
},
Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
- hir::ConstTraitItem(_, _) => {
+ hir::ConstTraitItem(..) => {
used_substs = true;
if let Some(substs) = substs {
// As mentioned in the comments above for in-crate
};
match fn_like.kind() {
- FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) => {
+ FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
Some(fn_like)
}
- FnKind::Method(_, m, _, _) => {
+ FnKind::Method(_, m, ..) => {
if m.constness == hir::Constness::Const {
Some(fn_like)
} else {
span,
format!("floating point constants cannot be used in patterns"));
}
- ty::TyEnum(adt_def, _) |
- ty::TyStruct(adt_def, _) => {
+ ty::TyAdt(adt_def, _) if adt_def.is_union() => {
+ // Matching on union fields is unsafe, we can't hide it in constants
+ tcx.sess.span_err(span, "cannot use unions in constant patterns");
+ }
+ ty::TyAdt(adt_def, _) => {
if !tcx.has_attr(adt_def.did, "structural_match") {
tcx.sess.add_lint(
lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
}
let pat = match expr.node {
hir::ExprTup(ref exprs) =>
- PatKind::Tuple(try!(exprs.iter()
- .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
- .collect()), None),
+ PatKind::Tuple(exprs.iter()
+ .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
+ .collect::<Result<_, _>>()?, None),
hir::ExprCall(ref callee, ref args) => {
let def = tcx.expect_def(callee.id);
}
let path = match def {
Def::Struct(def_id) => def_to_path(tcx, def_id),
- Def::Variant(_, variant_did) => def_to_path(tcx, variant_did),
+ Def::Variant(variant_did) => def_to_path(tcx, variant_did),
Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat {
id: expr.id,
node: PatKind::Lit(P(expr.clone())),
})),
_ => bug!()
};
- let pats = try!(args.iter()
- .map(|expr| const_expr_to_pat(tcx, &**expr,
- pat_id, span))
- .collect());
+ let pats = args.iter()
+ .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span))
+ .collect::<Result<_, _>>()?;
PatKind::TupleStruct(path, pats, None)
}
hir::ExprStruct(ref path, ref fields, None) => {
let field_pats =
- try!(fields.iter()
- .map(|field| Ok(codemap::Spanned {
- span: syntax_pos::DUMMY_SP,
- node: hir::FieldPat {
- name: field.name.node,
- pat: try!(const_expr_to_pat(tcx, &field.expr,
- pat_id, span)),
- is_shorthand: false,
- },
- }))
- .collect());
+ fields.iter()
+ .map(|field| Ok(codemap::Spanned {
+ span: syntax_pos::DUMMY_SP,
+ node: hir::FieldPat {
+ name: field.name.node,
+ pat: const_expr_to_pat(tcx, &field.expr, pat_id, span)?,
+ is_shorthand: false,
+ },
+ }))
+ .collect::<Result<_, _>>()?;
PatKind::Struct(path.clone(), field_pats, false)
}
hir::ExprVec(ref exprs) => {
- let pats = try!(exprs.iter()
- .map(|expr| const_expr_to_pat(tcx, &expr,
- pat_id, span))
- .collect());
+ let pats = exprs.iter()
+ .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
+ .collect::<Result<_, _>>()?;
PatKind::Vec(pats, None, hir::HirVec::new())
}
signal!(e, NonConstPath);
}
},
- Def::Variant(enum_def, variant_def) => {
- if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) {
+ Def::Variant(variant_def) => {
+ if let Some(const_expr) = lookup_variant_by_id(tcx, variant_def) {
match eval_const_expr_partial(tcx, const_expr, ty_hint, None) {
Ok(val) => val,
Err(err) => {
Def::Struct(..) => {
ConstVal::Struct(e.id)
}
- Def::Local(_, id) => {
+ Def::Local(def_id) => {
+ let id = tcx.map.as_local_node_id(def_id).unwrap();
debug!("Def::Local({:?}): {:?}", id, fn_args);
if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
val.clone()
debug!("const call({:?})", call_args);
eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
},
- hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety, lit.span) {
+ hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
Ok(val) => val,
Err(err) => signal!(e, err),
},
(&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
(&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
- (&ty::TyEnum(ref adt, _), i) => {
+ (&ty::TyAdt(adt, _), i) if adt.is_enum() => {
let hints = tcx.lookup_repr_hints(adt.did);
let int_ty = tcx.enum_repr_type(hints.iter().next());
infer(i, tcx, &int_ty.to_ty(tcx).sty)
fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ti: &'tcx hir::TraitItem,
trait_id: DefId,
- rcvr_substs: &'tcx subst::Substs<'tcx>)
+ rcvr_substs: &'tcx Substs<'tcx>)
-> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
{
- let trait_ref = ty::Binder(
- rcvr_substs.clone().erase_regions().to_trait_ref(tcx, trait_id)
- );
+ let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
debug!("resolve_trait_associated_const: trait_ref={:?}",
trait_ref);
- tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
+ tcx.populate_implementations_for_trait_if_necessary(trait_id);
tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
let mut selcx = traits::SelectionContext::new(&infcx);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
// when constructing the inference context above.
match selection {
traits::VtableImpl(ref impl_data) => {
- match tcx.associated_consts(impl_data.impl_def_id)
- .iter().find(|ic| ic.name == ti.name) {
+ let ac = tcx.impl_or_trait_items(impl_data.impl_def_id)
+ .iter().filter_map(|&def_id| {
+ match tcx.impl_or_trait_item(def_id) {
+ ty::ConstTraitItem(ic) => Some(ic),
+ _ => None
+ }
+ }).find(|ic| ic.name == ti.name);
+ match ac {
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
None => match ti.node {
hir::ConstTraitItem(ref ty, Some(ref expr)) => {
fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ty_hint: Option<Ty<'tcx>>,
- span: Span)
+ ty_hint: Option<Ty<'tcx>>)
-> Result<ConstVal, ErrKind> {
use syntax::ast::*;
use syntax::ast::LitIntType::*;
infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral)
},
None => Ok(Integral(Infer(n))),
- Some(&ty::TyEnum(ref adt, _)) => {
+ Some(&ty::TyAdt(adt, _)) => {
let hints = tcx.lookup_repr_hints(adt.did);
let int_ty = tcx.enum_repr_type(hints.iter().next());
infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
},
LitKind::Float(ref n, fty) => {
- Ok(Float(parse_float(n, Some(fty), span)))
+ parse_float(n, Some(fty)).map(Float)
}
LitKind::FloatUnsuffixed(ref n) => {
let fty_hint = match ty_hint.map(|t| &t.sty) {
Some(&ty::TyFloat(fty)) => Some(fty),
_ => None
};
- Ok(Float(parse_float(n, fty_hint, span)))
+ parse_float(n, fty_hint).map(Float)
}
LitKind::Bool(b) => Ok(Bool(b)),
LitKind::Char(c) => Ok(Char(c)),
}
}
-fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>, span: Span) -> ConstFloat {
+fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>)
+ -> Result<ConstFloat, ErrKind> {
let val = match fty_hint {
Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32),
Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64),
})
}
};
- val.unwrap_or_else(|_| {
+ val.map_err(|_| {
// FIXME(#31407) this is only necessary because float parsing is buggy
- span_bug!(span, "could not evaluate float literal (see issue #31407)");
+ UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
})
}