Skip to content
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

Rewrite the pattern matching code in trans. #27050

Closed
wants to merge 3 commits into from
Closed
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
1 change: 0 additions & 1 deletion src/librustc_trans/lib.rs
Original file line number Diff line number Diff line change
@@ -29,7 +29,6 @@
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(iter_cmp)]
#![feature(iter_arith)]
#![feature(libc)]
#![feature(path_ext)]
#![feature(path_ext)]
1,372 changes: 350 additions & 1,022 deletions src/librustc_trans/trans/_match.rs

Large diffs are not rendered by default.

57 changes: 41 additions & 16 deletions src/librustc_trans/trans/adt.rs
Original file line number Diff line number Diff line change
@@ -56,7 +56,6 @@ use middle::ty::Disr;
use syntax::ast;
use syntax::attr;
use syntax::attr::IntType;
use trans::_match;
use trans::build::*;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
@@ -776,19 +775,17 @@ fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>,

/// Obtain a representation of the discriminant sufficient to translate
/// destructuring; this may or may not involve the actual discriminant.
///
/// This should ideally be less tightly tied to `_match`.
pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
r: &Repr<'tcx>, scrutinee: ValueRef)
-> (_match::BranchKind, Option<ValueRef>) {
-> Option<ValueRef> {
match *r {
CEnum(..) | General(..) |
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
(_match::Switch, Some(trans_get_discr(bcx, r, scrutinee, None)))
Some(trans_get_discr(bcx, r, scrutinee, None))
}
Univariant(..) => {
// N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
(_match::Single, None)
None
}
}
}
@@ -864,26 +861,24 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)

/// Yield information about how to dispatch a case of the
/// discriminant-like value returned by `trans_switch`.
///
/// This should ideally be less tightly tied to `_match`.
pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
-> _match::OptResult<'blk, 'tcx> {
pub fn trans_case<'bcx, 'tcx>(ccx: &CrateContext<'bcx, 'tcx>,
r: &Repr,
discr: Disr)
-> ValueRef {
match *r {
CEnum(ity, _, _) => {
_match::SingleResult(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
discr as u64, true)))
C_integral(ll_inttype(ccx, ity), discr as u64, true)
}
General(ity, _, _) => {
_match::SingleResult(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
discr as u64, true)))
C_integral(ll_inttype(ccx, ity), discr as u64, true)
}
Univariant(..) => {
bcx.ccx().sess().bug("no cases for univariants or structs")
ccx.sess().bug("no cases for univariants or structs")
}
RawNullablePointer { .. } |
StructWrappedNullablePointer { .. } => {
assert!(discr == 0 || discr == 1);
_match::SingleResult(Result::new(bcx, C_bool(bcx.ccx(), discr != 0)))
C_bool(ccx, discr != 0)
}
}
}
@@ -999,6 +994,36 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
}
}

/// Get a field's type.
pub fn trans_field_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
discr: Disr, ix: usize) -> Ty<'tcx> {
match *r {
CEnum(..) => {
bcx.ccx().sess().bug("element access in C-like enum")
}
Univariant(ref st, _) => {
assert_eq!(discr, 0);
st.fields[ix]
}
General(_, ref cases, _) => {
&cases[discr as usize].fields[ix + 1]
}
RawNullablePointer { nndiscr, ref nullfields, .. } |
StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => {
nullfields[ix]
}
RawNullablePointer { nndiscr, nnty, .. } => {
assert_eq!(ix, 0);
assert_eq!(discr, nndiscr);
nnty
}
StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
assert_eq!(discr, nndiscr);
nonnull.fields[ix]
}
}
}

pub fn struct_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, st: &Struct<'tcx>, val: ValueRef,
ix: usize, needs_cast: bool) -> ValueRef {
let val = if needs_cast {
22 changes: 4 additions & 18 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
@@ -471,14 +471,14 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
// comparison know not to proceed when the discriminants differ.

match adt::trans_switch(cx, &*repr, av) {
(_match::Single, None) => {
None => {
if n_variants != 0 {
assert!(n_variants == 1);
cx = iter_variant(cx, &*repr, av, &*(*variants)[0],
substs, &mut f);
}
}
(_match::Switch, Some(lldiscrim_a)) => {
Some(lldiscrim_a) => {
cx = f(cx, lldiscrim_a, cx.tcx().types.isize);

// Create a fall-through basic block for the "else" case of
@@ -506,13 +506,8 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
&format!("enum-iter-variant-{}",
&variant.disr_val.to_string())
);
match adt::trans_case(cx, &*repr, variant.disr_val) {
_match::SingleResult(r) => {
AddCase(llswitch, r.val, variant_cx.llbb)
}
_ => ccx.sess().unimpl("value from adt::trans_case \
in iter_structural_ty")
}
let r = adt::trans_case(cx.ccx(), &repr, variant.disr_val);
AddCase(llswitch, r, variant_cx.llbb);
let variant_cx =
iter_variant(variant_cx,
&*repr,
@@ -524,8 +519,6 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
}
cx = next_cx;
}
_ => ccx.sess().unimpl("value from adt::trans_switch \
in iter_structural_ty")
}
}
_ => {
@@ -770,13 +763,6 @@ pub fn need_invoke(bcx: Block) -> bool {
bcx.fcx.needs_invoke()
}

pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
v: ValueRef, t: Ty<'tcx>) -> ValueRef {
let _icx = push_ctxt("load_if_immediate");
if type_is_immediate(cx.ccx(), t) { return load_ty(cx, v, t); }
return v;
}

/// Helper for loading values from memory. Does the necessary conversion if the in-memory type
/// differs from the type used for SSA values. Also handles various special cases where the type
/// gives us better information about what we are loading.
9 changes: 4 additions & 5 deletions src/librustc_trans/trans/callee.rs
Original file line number Diff line number Diff line change
@@ -902,12 +902,11 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
let repr = adt::represent_type(bcx.ccx(), tuple_type);
let repr_ptr = &*repr;
for (i, field_type) in field_types.iter().enumerate() {
let arg_datum = tuple_lvalue_datum.get_element(
let arg_datum = tuple_lvalue_datum.get_field(
bcx,
field_type,
|srcval| {
adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i)
}).to_expr_datum();
repr_ptr,
0,
i).to_expr_datum();
bcx = trans_arg_datum(bcx,
field_type,
arg_datum,
19 changes: 12 additions & 7 deletions src/librustc_trans/trans/datum.rs
Original file line number Diff line number Diff line change
@@ -93,6 +93,7 @@ pub use self::Expr::*;
pub use self::RvalueMode::*;

use llvm::ValueRef;
use trans::adt;
use trans::base::*;
use trans::build::Load;
use trans::common::*;
@@ -101,7 +102,7 @@ use trans::cleanup::CleanupMethods;
use trans::expr;
use trans::tvec;
use trans::type_of;
use middle::ty::Ty;
use middle::ty::{Disr, Ty};

use std::fmt;
use syntax::ast;
@@ -516,16 +517,20 @@ impl<'tcx> Datum<'tcx, Lvalue> {
// datum may also be unsized _without the size information_. It is the
// callers responsibility to package the result in some way to make a valid
// datum in that case (e.g., by making a fat pointer or opened pair).
pub fn get_element<'blk, F>(&self, bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>,
gep: F)
-> Datum<'tcx, Lvalue> where
F: FnOnce(ValueRef) -> ValueRef,
pub fn get_field<'blk>(&self,
bcx: Block<'blk, 'tcx>,
repr: &adt::Repr<'tcx>,
discr: Disr,
i: usize)
-> Datum<'tcx, Lvalue>
{
let val = if type_is_sized(bcx.tcx(), self.ty) {
gep(self.val)
self.val
} else {
gep(Load(bcx, expr::get_dataptr(bcx, self.val)))
Load(bcx, expr::get_dataptr(bcx, self.val))
};
let val = adt::trans_field_ptr(bcx, repr, val, discr, i);
let ty = adt::trans_field_ty(bcx, repr, discr, i);
Datum {
val: val,
kind: Lvalue,
10 changes: 3 additions & 7 deletions src/librustc_trans/trans/expr.rs
Original file line number Diff line number Diff line change
@@ -718,10 +718,7 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
let repr = adt::represent_type(bcx.ccx(), bare_ty);
with_field_tys(bcx.tcx(), bare_ty, None, move |discr, field_tys| {
let ix = get_idx(bcx.tcx(), field_tys);
let d = base_datum.get_element(
bcx,
field_tys[ix].mt.ty,
|srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
let d = base_datum.get_field(bcx, &*repr, discr, ix);

if type_is_sized(bcx.tcx(), d.ty) {
DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
@@ -1545,9 +1542,8 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
}
_ => {
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
for &(i, t) in &base.fields {
let datum = base_datum.get_element(
bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
for (i, _) in base.fields {
let datum = base_datum.get_field(bcx, &*repr, discr, i);
assert!(type_is_sized(bcx.tcx(), datum.ty));
let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
bcx = datum.store_to(bcx, dest);
14 changes: 14 additions & 0 deletions src/test/run-pass/issue-18060.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2015 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.

fn main() {
assert_eq!(2, match (1, 3) { (0, 2...5) => 1, (1, 3) => 2, (_, 3) => 3, (_, _) => 4 });
assert_eq!(2, match (1, 3) { (0, 2...5) => 1, (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4 });
}
25 changes: 25 additions & 0 deletions src/test/run-pass/issue-19064.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2015 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.


struct Foo(pub str);

impl Foo {
fn print(&self) -> &str {
match self {
&Foo(ref s) => s,
}
}
}

fn main() {
let f: &Foo = unsafe { std::mem::transmute("foo") };
assert_eq!(f.print(), "foo");
}
25 changes: 25 additions & 0 deletions src/test/run-pass/issue-20046.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2015 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.

#[derive(PartialEq)]
enum IoErrorKind { BrokenPipe, XXX }
struct IoError {
pub kind: IoErrorKind,
pub detail: Option<String>
}
fn main() {
let e: Result<u8, _> = Err(IoError{ kind: IoErrorKind::XXX, detail: None });
match e {
Ok(_) => panic!(),
Err(ref e) if e.kind == IoErrorKind::BrokenPipe => panic!(),
Err(IoError { kind: IoErrorKind::BrokenPipe, ..}) => panic!(),
Err(err) => return
};
}
19 changes: 19 additions & 0 deletions src/test/run-pass/issue-23311.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2015 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.

#![feature(slice_patterns)]

fn main() {
match "foo".as_bytes() {
b"food" => panic!(),
[b'f', ..] => (),
_ => panic!()
}
}
25 changes: 25 additions & 0 deletions src/test/run-pass/issue-24875.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2015 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.

#![feature(slice_patterns)]

fn main() {
let v = vec![1, 2];
assert_eq!(101, test(&v));
}

fn test(a: &[u64]) -> u64 {
match a {
[a, _b ..] if a == 3 => 100,
[a, _b] if a == 1 => 101,
[_a, _b ..] => 102,
_ => 103
}
}
20 changes: 20 additions & 0 deletions src/test/run-pass/issue-26251.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2015 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.

fn main() {
let x = 'a';

match x {
'a'...'b' if false => panic!(),
'a' => {},
'a'...'b' => panic!(),
_ => panic!("what?")
}
}
17 changes: 17 additions & 0 deletions src/test/run-pass/issue-26989.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2015 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.

fn main() {
match (0, 0) {
(0, ref _a) => {}
(_, 0) => {}
_ => {}
}
}