From 2ed80c35e2c3a454a72ffb6eff60e451e4768dda Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 21 Mar 2013 00:27:26 -0700 Subject: [PATCH] librustc: Fix path-qualified and cross-crate constants in match patterns. --- src/librustc/middle/check_match.rs | 19 ++++++++++++++++ src/librustc/middle/const_eval.rs | 23 ++++++++++++++++++- src/librustc/middle/mem_categorization.rs | 5 +++++ src/librustc/middle/pat_util.rs | 2 +- src/librustc/middle/resolve.rs | 11 ++++----- src/librustc/middle/trans/_match.rs | 26 ++++++++++++++-------- src/librustc/middle/typeck/check/_match.rs | 1 + 7 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 245872c39c6..24e94c7ca6d 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -528,6 +528,25 @@ pub fn specialize(cx: @MatchCheckCtxt, } pat_enum(_, args) => { match cx.tcx.def_map.get(&pat_id) { + def_const(did) => { + let const_expr = + lookup_const_by_id(cx.tcx, did).get(); + let e_v = eval_const_expr(cx.tcx, const_expr); + let match_ = match ctor_id { + val(ref v) => compare_const_vals(e_v, (*v)) == 0, + range(ref c_lo, ref c_hi) => { + compare_const_vals((*c_lo), e_v) >= 0 && + compare_const_vals((*c_hi), e_v) <= 0 + } + single => true, + _ => fail!(~"type error") + }; + if match_ { + Some(vec::from_slice(r.tail())) + } else { + None + } + } def_variant(_, id) if variant(id) == ctor_id => { let args = match args { Some(args) => args, diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 4888a01c6b9..ba6348bb1de 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -10,6 +10,8 @@ use core::prelude::*; +use metadata::csearch; +use middle::astencode; use middle::resolve; use middle::ty; use middle; @@ -19,6 +21,8 @@ use syntax::{ast, ast_map, ast_util, visit}; use syntax::ast::*; +use std::oldmap::HashMap; + // // This pass classifies expressions by their constant-ness. // @@ -187,7 +191,24 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, Some(_) => None } } else { - None + let maps = astencode::Maps { + mutbl_map: HashMap(), + root_map: HashMap(), + last_use_map: HashMap(), + method_map: HashMap(), + vtable_map: HashMap(), + write_guard_map: HashMap(), + moves_map: HashMap(), + capture_map: HashMap() + }; + match csearch::maybe_get_item_ast(tcx, def_id, + |a, b, c, d| astencode::decode_inlined_item(a, b, maps, /*bar*/ copy c, d)) { + csearch::found(ast::ii_item(item)) => match item.node { + item_const(_, const_expr) => Some(const_expr), + _ => None + }, + _ => None + } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index fee3695002d..a471d91877a 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -916,6 +916,11 @@ fn cat_pattern(&self, self.cat_pattern(cmt_field, *subpat, op); } } + Some(ast::def_const(*)) => { + for subpats.each |subpat| { + self.cat_pattern(cmt, *subpat, op); + } + } _ => { self.tcx.sess.span_bug( pat.span, diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 4522977a4ab..a25fddcad88 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -43,7 +43,7 @@ pub fn pat_is_variant_or_struct(dm: resolve::DefMap, pat: @pat) -> bool { pub fn pat_is_const(dm: resolve::DefMap, pat: &pat) -> bool { match pat.node { - pat_ident(_, _, None) => { + pat_ident(_, _, None) | pat_enum(*) => { match dm.find(&pat.id) { Some(def_const(*)) => true, _ => false diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 6c2168548f1..8a6cc8de382 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4333,23 +4333,24 @@ struct in scope", } pat_enum(path, _) => { - // This must be an enum variant or struct. + // This must be an enum variant, struct or const. match self.resolve_path(path, ValueNS, false, visitor) { Some(def @ def_variant(*)) | - Some(def @ def_struct(*)) => { + Some(def @ def_struct(*)) | + Some(def @ def_const(*)) => { self.record_def(pattern.id, def); } Some(_) => { self.session.span_err( path.span, - fmt!("not an enum variant or struct: %s", + fmt!("not an enum variant, struct or const: %s", *self.session.str_of( *path.idents.last()))); } None => { self.session.span_err(path.span, - ~"unresolved enum variant \ - or struct"); + ~"unresolved enum variant, \ + struct or const"); } } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 45fe40ca1f7..09f0a4f547a 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -502,6 +502,16 @@ pub fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint, let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()}; do enter_match(bcx, tcx.def_map, m, col, val) |p| { match p.node { + ast::pat_enum(*) | + ast::pat_ident(_, _, None) if pat_is_const(tcx.def_map, p) => { + let const_def = tcx.def_map.get(&p.id); + let const_def_id = ast_util::def_id_of_def(const_def); + if opt_eq(tcx, &lit(ConstLit(const_def_id)), opt) { + Some(~[]) + } else { + None + } + } ast::pat_enum(_, ref subpats) => { if opt_eq(tcx, &variant_opt(bcx, p.id), opt) { match *subpats { @@ -520,15 +530,6 @@ pub fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint, None } } - ast::pat_ident(_, _, None) if pat_is_const(tcx.def_map, p) => { - let const_def = tcx.def_map.get(&p.id); - let const_def_id = ast_util::def_id_of_def(const_def); - if opt_eq(tcx, &lit(ConstLit(const_def_id)), opt) { - Some(~[]) - } else { - None - } - } ast::pat_lit(l) => { if opt_eq(tcx, &lit(ExprLit(l)), opt) {Some(~[])} else {None} } @@ -806,6 +807,10 @@ fn add_to_set(tcx: ty::ctxt, set: &mut ~[Opt], +val: Opt) { add_to_set(ccx.tcx, &mut found, variant_opt(bcx, cur.id)); } + Some(ast::def_const(const_did)) => { + add_to_set(ccx.tcx, &mut found, + lit(ConstLit(const_did))); + } _ => {} } } @@ -1782,6 +1787,9 @@ pub fn bind_irrefutable_pat(bcx: block, } } } + Some(ast::def_const(*)) => { + bcx = bind_irrefutable_pat(bcx, pat, val, make_copy, binding_mode); + } _ => { // Nothing to do here. } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 5e106668fc9..5dcbcbda35c 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -366,6 +366,7 @@ pub fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { } fcx.write_ty(pat.id, b_ty); } + ast::pat_enum(*) | ast::pat_ident(*) if pat_is_const(tcx.def_map, pat) => { let const_did = ast_util::def_id_of_def(tcx.def_map.get(&pat.id)); let const_tpt = ty::lookup_item_type(tcx, const_did); -- 2.44.0