make `const_expr_to_pat` fallible (but never have it actually fail)

This commit is contained in:
Niko Matsakis 2016-02-03 16:38:48 -05:00
parent 40deb279a8
commit 5bc2868060
3 changed files with 52 additions and 26 deletions

View File

@ -478,15 +478,25 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
Some(Def::Const(did)) => {
let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
if let Some((const_expr, _)) = lookup_const_by_id(self.tcx, did, substs) {
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
if let Some(ref mut renaming_map) = self.renaming_map {
// Record any renamings we do here
record_renamings(const_expr, &pat, renaming_map);
match const_expr_to_pat(self.tcx, const_expr, pat.span) {
Ok(new_pat) => {
if let Some(ref mut map) = self.renaming_map {
// Record any renamings we do here
record_renamings(const_expr, &pat, map);
}
new_pat
}
new_pat
})
Err(def_id) => {
// TODO back-compat
self.failed = true;
self.tcx.sess.span_err(
pat.span,
&format!("constants of the type `{}` \
cannot be used in patterns",
self.tcx.item_path_str(def_id)));
pat
}
}
} else {
self.failed = true;
span_err!(self.tcx.sess, pat.span, E0158,

View File

@ -323,10 +323,13 @@ impl ConstVal {
}
}
pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
pub fn const_expr_to_pat(tcx: &ty::TyCtxt, expr: &Expr, span: Span)
-> Result<P<hir::Pat>, DefId> {
let pat = match expr.node {
hir::ExprTup(ref exprs) =>
PatKind::Tup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect()),
PatKind::Tup(try!(exprs.iter()
.map(|expr| const_expr_to_pat(tcx, &expr, span))
.collect())),
hir::ExprCall(ref callee, ref args) => {
let def = *tcx.def_map.borrow().get(&callee.id).unwrap();
@ -336,31 +339,38 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
let path = match def.full_def() {
Def::Struct(def_id) => def_to_path(tcx, def_id),
Def::Variant(_, variant_did) => def_to_path(tcx, variant_did),
Def::Fn(..) => return P(hir::Pat {
Def::Fn(..) => return Ok(P(hir::Pat {
id: expr.id,
node: PatKind::Lit(P(expr.clone())),
span: span,
}),
})),
_ => unreachable!()
};
let pats = args.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect();
let pats = try!(args.iter()
.map(|expr| const_expr_to_pat(tcx, &**expr, span))
.collect());
PatKind::TupleStruct(path, Some(pats))
}
hir::ExprStruct(ref path, ref fields, None) => {
let field_pats = fields.iter().map(|field| codemap::Spanned {
span: codemap::DUMMY_SP,
node: hir::FieldPat {
name: field.name.node,
pat: const_expr_to_pat(tcx, &field.expr, span),
is_shorthand: false,
},
}).collect();
let field_pats =
try!(fields.iter()
.map(|field| Ok(codemap::Spanned {
span: codemap::DUMMY_SP,
node: hir::FieldPat {
name: field.name.node,
pat: try!(const_expr_to_pat(tcx, &field.expr, span)),
is_shorthand: false,
},
}))
.collect());
PatKind::Struct(path.clone(), field_pats, false)
}
hir::ExprVec(ref exprs) => {
let pats = exprs.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect();
let pats = try!(exprs.iter()
.map(|expr| const_expr_to_pat(tcx, &expr, span))
.collect());
PatKind::Vec(pats, None, hir::HirVec::new())
}
@ -381,7 +391,7 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
_ => PatKind::Lit(P(expr.clone()))
};
P(hir::Pat { id: expr.id, node: pat, span: span })
Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
}
pub fn eval_const_expr(tcx: &TyCtxt, e: &Expr) -> ConstVal {

View File

@ -90,9 +90,15 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
let substs = Some(self.cx.tcx.node_id_item_substs(pat.id).substs);
match const_eval::lookup_const_by_id(self.cx.tcx, def_id, substs) {
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);
match const_eval::const_expr_to_pat(self.cx.tcx,
const_expr,
pat.span) {
Ok(pat) =>
return self.to_pattern(&pat),
Err(_) =>
self.cx.tcx.sess.span_bug(
pat.span, "illegal constant"),
}
}
None => {
self.cx.tcx.sess.span_bug(