Skip to content

Fix path-qualified and cross-crate constants in match patterns. #5464

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 21, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/librustc/middle/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
23 changes: 22 additions & 1 deletion src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

use core::prelude::*;

use metadata::csearch;
use middle::astencode;
use middle::resolve;
use middle::ty;
use middle;
Expand All @@ -19,6 +21,8 @@ use core::vec;
use syntax::{ast, ast_map, ast_util, visit};
use syntax::ast::*;

use std::oldmap::HashMap;

//
// This pass classifies expressions by their constant-ness.
//
Expand Down Expand Up @@ -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
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,11 @@ pub impl mem_categorization_ctxt {
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,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/pat_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4333,23 +4333,24 @@ pub impl Resolver {
}

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");
}
}

Expand Down
26 changes: 17 additions & 9 deletions src/librustc/middle/trans/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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}
}
Expand Down Expand Up @@ -806,6 +807,10 @@ pub fn get_options(bcx: block, m: &[@Match], col: uint) -> ~[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)));
}
_ => {}
}
}
Expand Down Expand Up @@ -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.
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
22 changes: 22 additions & 0 deletions src/test/run-pass/cross-crate-const-pat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2013 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.

// xfail-fast
// aux-build:cci_const.rs

extern mod cci_const;

fn main() {
let x = cci_const::uint_val;
match x {
cci_const::uint_val => {}
_ => {}
}
}