<commit_before>//! Completion tests for pattern position.
use expect_test::{expect, Expect};

use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};

fn check_empty(ra_fixture: &str, expect: Expect) {
    let actual = completion_list(ra_fixture);
    expect.assert_eq(&actual)
}

fn check(ra_fixture: &str, expect: Expect) {
    let actual = completion_list(&format!("{}\n{}", BASE_ITEMS_FIXTURE, ra_fixture));
    expect.assert_eq(&actual)
}

#[test]
fn ident_rebind_pat() {
    check_empty(
        r#"
fn quux() {
    let en$0 @ x
}
"#,
        expect![[r#"
            kw ref
            kw mut
        "#]],
    );
}

#[test]
fn ident_ref_pat() {
    check_empty(
        r#"
fn quux() {
    let ref en$0
}
"#,
        expect![[r#"
            kw mut
        "#]],
    );
    check_empty(
        r#"
fn quux() {
    let ref en$0 @ x
}
"#,
        expect![[r#"
            kw mut
        "#]],
    );
}

#[test]
fn ident_ref_mut_pat() {
    check_empty(
        r#"
fn quux() {
    let ref mut en$0
}
"#,
        expect![[r#""#]],
    );
    check_empty(
        r#"
fn quux() {
    let ref mut en$0 @ x
}
"#,
        expect![[r#""#]],
    );
}

#[test]
fn ref_pat() {
    check_empty(
        r#"
fn quux() {
    let &en$0
}
"#,
        expect![[r#"
            kw mut
        "#]],
    );
    check_empty(
        r#"
fn quux() {
    let &mut en$0
}
"#,
        expect![[r#""#]],
    );
    check_empty(
        r#"
fn foo() {
    for &$0 in () {}
}
"#,
        expect![[r#"
            kw mut
        "#]],
    );
}

#[test]
fn refutable() {
    check(
        r#"
fn foo() {
    if let a$0
}
"#,
        expect![[r#"
            kw ref
            kw mut
            en Enum
            bn Record    Record { field$1 }$0
            st Record
            bn Tuple     Tuple($1)$0
            st Tuple
            md module
            st Unit
            ma makro!(…) macro_rules! makro
            bn TupleV    TupleV($1)$0
            ev TupleV
            ct CONST
        "#]],
    );
}

#[test]
fn irrefutable() {
    check(
        r#"
enum SingleVariantEnum {
    Variant
}
use SingleVariantEnum::Variant;
fn foo() {
   let a$0
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Record            Record { field$1 }$0
            st Record
            bn Tuple             Tuple($1)$0
            st Tuple
            ev Variant
            md module
            en SingleVariantEnum
            st Unit
            ma makro!(…)         macro_rules! makro
        "#]],
    );
}

#[test]
fn in_param() {
    check(
        r#"
fn foo(a$0) {
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Record    Record { field$1 }: Record$0
            st Record
            bn Tuple     Tuple($1): Tuple$0
            st Tuple
            md module
            st Unit
            ma makro!(…) macro_rules! makro
        "#]],
    );
    check(
        r#"
fn foo(a$0: Tuple) {
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Record    Record { field$1 }$0
            st Record
            bn Tuple     Tuple($1)$0
            st Tuple
            md module
            st Unit
            ma makro!(…) macro_rules! makro
        "#]],
    );
}

#[test]
fn only_fn_like_macros() {
    check_empty(
        r#"
macro_rules! m { ($e:expr) => { $e } }

#[rustc_builtin_macro]
macro Clone {}

fn foo() {
    let x$0
}
"#,
        expect![[r#"
            kw ref
            kw mut
            ma m!(…) macro_rules! m
        "#]],
    );
}

#[test]
fn in_simple_macro_call() {
    check_empty(
        r#"
macro_rules! m { ($e:expr) => { $e } }
enum E { X }

fn foo() {
   m!(match E::X { a$0 })
}
"#,
        expect![[r#"
            kw ref
            kw mut
            en E
            ma m!(…) macro_rules! m
        "#]],
    );
}

#[test]
fn omits_private_fields_pat() {
    check_empty(
        r#"
mod foo {
    pub struct Record { pub field: i32, _field: i32 }
    pub struct Tuple(pub u32, u32);
    pub struct Invisible(u32, u32);
}
use foo::*;

fn outer() {
    if let a$0
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Record    Record { field$1, .. }$0
            st Record
            bn Tuple     Tuple($1, ..)$0
            st Tuple
            st Invisible
            md foo
        "#]],
    )
}

#[test]
fn completes_self_pats() {
    check_empty(
        r#"
struct Foo(i32);
impl Foo {
    fn foo() {
        match Foo(0) {
            a$0
        }
    }
}
    "#,
        expect![[r#"
            kw ref
            kw mut
            bn Self Self($1)$0
            sp Self
            bn Foo  Foo($1)$0
            st Foo
        "#]],
    )
}

#[test]
fn enum_qualified() {
    check(
        r#"
impl Enum {
    type AssocType = ();
    const ASSOC_CONST: () = ();
    fn assoc_fn() {}
}
fn func() {
    if let Enum::$0 = unknown {}
}
"#,
        expect![[r#"
            ev TupleV(…)   TupleV(u32)
            ev RecordV {…} RecordV { field: u32 }
            ev UnitV       UnitV
            ct ASSOC_CONST const ASSOC_CONST: ()
        "#]],
    );
}

#[test]
fn completes_in_record_field_pat() {
    check_empty(
        r#"
struct Foo { bar: Bar }
struct Bar(u32);
fn outer(Foo { bar: $0 }: Foo) {}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Foo Foo { bar$1 }$0
            st Foo
            bn Bar Bar($1)$0
            st Bar
        "#]],
    )
}

#[test]
fn skips_in_record_field_pat_name() {
    check_empty(
        r#"
struct Foo { bar: Bar }
struct Bar(u32);
fn outer(Foo { bar$0 }: Foo) {}
"#,
        expect![[r#""#]],
    )
}

#[test]
fn completes_in_fn_param() {
    check_empty(
        r#"
struct Foo { bar: Bar }
struct Bar(u32);
fn foo($0) {}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Foo Foo { bar$1 }: Foo$0
            st Foo
            bn Bar Bar($1): Bar$0
            st Bar
        "#]],
    )
}

#[test]
fn completes_in_closure_param() {
    check_empty(
        r#"
struct Foo { bar: Bar }
struct Bar(u32);
fn foo() {
    |$0| {};
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Foo Foo { bar$1 }$0
            st Foo
            bn Bar Bar($1)$0
            st Bar
        "#]],
    )
}

#[test]
fn completes_no_delims_if_existing() {
    check_empty(
        r#"
struct Bar(u32);
fn foo() {
    match Bar(0) {
        B$0(b) => {}
    }
}
"#,
        expect![[r#"
            kw self::
            kw super::
            kw crate::
        "#]],
    );
    check_empty(
        r#"
struct Foo { bar: u32 }
fn foo() {
    match Foo { bar: 0 } {
        F$0 { bar } => {}
    }
}
"#,
        expect![[r#"
            kw return
            kw self
            kw super
            kw crate
            st Foo
            fn foo()  fn()
            bt u32
        "#]],
    );
    check_empty(
        r#"
enum Enum {
    TupleVariant(u32)
}
fn foo() {
    match Enum::TupleVariant(0) {
        Enum::T$0(b) => {}
    }
}
"#,
        expect![[r#""#]],
    );
    check_empty(
        r#"
enum Enum {
    RecordVariant { field: u32 }
}
fn foo() {
    match (Enum::RecordVariant { field: 0 }) {
        Enum::RecordV$0 { field } => {}
    }
}
"#,
        expect![[r#""#]],
    );
}

#[test]
fn completes_associated_const() {
    check_empty(
        r#"
#[derive(PartialEq, Eq)]
struct Ty(u8);

impl Ty {
    const ABC: Self = Self(0);
}

fn f(t: Ty) {
    match t {
        Ty::$0 => {}
        _ => {}
    }
}
"#,
        expect![[r#"
            ct ABC const ABC: Self
        "#]],
    );

    check_empty(
        r#"
struct MyEnum;

impl MyEnum {
    pub const A: i32 = 123;
    pub const B: i32 = 456;
}

fn f(e: MyEnum) {
    match e {
        MyEnum::$0 => {}
        _ => {}
    }
}
"#,
        expect![[r#"
            ct A pub const A: i32
            ct B pub const B: i32
        "#]],
    );

    check_empty(
        r#"
#[repr(C)]
union U {
    i: i32,
    f: f32,
}

impl U {
    pub const C: i32 = 123;
    pub const D: i32 = 456;
}

fn f(u: U) {
    match u {
        U::$0 => {}
        _ => {}
    }
}
"#,
        expect![[r#"
            ct C pub const C: i32
            ct D pub const D: i32
        "#]],
    )
}
<commit_msg>Fix typo<commit_after>//! Completion tests for pattern position.
use expect_test::{expect, Expect};

use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};

fn check_empty(ra_fixture: &str, expect: Expect) {
    let actual = completion_list(ra_fixture);
    expect.assert_eq(&actual)
}

fn check(ra_fixture: &str, expect: Expect) {
    let actual = completion_list(&format!("{}\n{}", BASE_ITEMS_FIXTURE, ra_fixture));
    expect.assert_eq(&actual)
}

#[test]
fn ident_rebind_pat() {
    check_empty(
        r#"
fn quux() {
    let en$0 @ x
}
"#,
        expect![[r#"
            kw ref
            kw mut
        "#]],
    );
}

#[test]
fn ident_ref_pat() {
    check_empty(
        r#"
fn quux() {
    let ref en$0
}
"#,
        expect![[r#"
            kw mut
        "#]],
    );
    check_empty(
        r#"
fn quux() {
    let ref en$0 @ x
}
"#,
        expect![[r#"
            kw mut
        "#]],
    );
}

#[test]
fn ident_ref_mut_pat() {
    check_empty(
        r#"
fn quux() {
    let ref mut en$0
}
"#,
        expect![[r#""#]],
    );
    check_empty(
        r#"
fn quux() {
    let ref mut en$0 @ x
}
"#,
        expect![[r#""#]],
    );
}

#[test]
fn ref_pat() {
    check_empty(
        r#"
fn quux() {
    let &en$0
}
"#,
        expect![[r#"
            kw mut
        "#]],
    );
    check_empty(
        r#"
fn quux() {
    let &mut en$0
}
"#,
        expect![[r#""#]],
    );
    check_empty(
        r#"
fn foo() {
    for &$0 in () {}
}
"#,
        expect![[r#"
            kw mut
        "#]],
    );
}

#[test]
fn refutable() {
    check(
        r#"
fn foo() {
    if let a$0
}
"#,
        expect![[r#"
            kw ref
            kw mut
            en Enum
            bn Record    Record { field$1 }$0
            st Record
            bn Tuple     Tuple($1)$0
            st Tuple
            md module
            st Unit
            ma makro!(…) macro_rules! makro
            bn TupleV    TupleV($1)$0
            ev TupleV
            ct CONST
        "#]],
    );
}

#[test]
fn irrefutable() {
    check(
        r#"
enum SingleVariantEnum {
    Variant
}
use SingleVariantEnum::Variant;
fn foo() {
   let a$0
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Record            Record { field$1 }$0
            st Record
            bn Tuple             Tuple($1)$0
            st Tuple
            ev Variant
            md module
            en SingleVariantEnum
            st Unit
            ma makro!(…)         macro_rules! makro
        "#]],
    );
}

#[test]
fn in_param() {
    check(
        r#"
fn foo(a$0) {
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Record    Record { field$1 }: Record$0
            st Record
            bn Tuple     Tuple($1): Tuple$0
            st Tuple
            md module
            st Unit
            ma makro!(…) macro_rules! makro
        "#]],
    );
    check(
        r#"
fn foo(a$0: Tuple) {
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Record    Record { field$1 }$0
            st Record
            bn Tuple     Tuple($1)$0
            st Tuple
            md module
            st Unit
            ma makro!(…) macro_rules! makro
        "#]],
    );
}

#[test]
fn only_fn_like_macros() {
    check_empty(
        r#"
macro_rules! m { ($e:expr) => { $e } }

#[rustc_builtin_macro]
macro Clone {}

fn foo() {
    let x$0
}
"#,
        expect![[r#"
            kw ref
            kw mut
            ma m!(…) macro_rules! m
        "#]],
    );
}

#[test]
fn in_simple_macro_call() {
    check_empty(
        r#"
macro_rules! m { ($e:expr) => { $e } }
enum E { X }

fn foo() {
   m!(match E::X { a$0 })
}
"#,
        expect![[r#"
            kw ref
            kw mut
            en E
            ma m!(…) macro_rules! m
        "#]],
    );
}

#[test]
fn omits_private_fields_pat() {
    check_empty(
        r#"
mod foo {
    pub struct Record { pub field: i32, _field: i32 }
    pub struct Tuple(pub u32, u32);
    pub struct Invisible(u32, u32);
}
use foo::*;

fn outer() {
    if let a$0
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Record    Record { field$1, .. }$0
            st Record
            bn Tuple     Tuple($1, ..)$0
            st Tuple
            st Invisible
            md foo
        "#]],
    )
}

#[test]
fn completes_self_pats() {
    check_empty(
        r#"
struct Foo(i32);
impl Foo {
    fn foo() {
        match Foo(0) {
            a$0
        }
    }
}
    "#,
        expect![[r#"
            kw ref
            kw mut
            bn Self Self($1)$0
            sp Self
            bn Foo  Foo($1)$0
            st Foo
        "#]],
    )
}

#[test]
fn enum_qualified() {
    check(
        r#"
impl Enum {
    type AssocType = ();
    const ASSOC_CONST: () = ();
    fn assoc_fn() {}
}
fn func() {
    if let Enum::$0 = unknown {}
}
"#,
        expect![[r#"
            ev TupleV(…)   TupleV(u32)
            ev RecordV {…} RecordV { field: u32 }
            ev UnitV       UnitV
            ct ASSOC_CONST const ASSOC_CONST: ()
        "#]],
    );
}

#[test]
fn completes_in_record_field_pat() {
    check_empty(
        r#"
struct Foo { bar: Bar }
struct Bar(u32);
fn outer(Foo { bar: $0 }: Foo) {}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Foo Foo { bar$1 }$0
            st Foo
            bn Bar Bar($1)$0
            st Bar
        "#]],
    )
}

#[test]
fn skips_in_record_field_pat_name() {
    check_empty(
        r#"
struct Foo { bar: Bar }
struct Bar(u32);
fn outer(Foo { bar$0 }: Foo) {}
"#,
        expect![[r#""#]],
    )
}

#[test]
fn completes_in_fn_param() {
    check_empty(
        r#"
struct Foo { bar: Bar }
struct Bar(u32);
fn foo($0) {}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Foo Foo { bar$1 }: Foo$0
            st Foo
            bn Bar Bar($1): Bar$0
            st Bar
        "#]],
    )
}

#[test]
fn completes_in_closure_param() {
    check_empty(
        r#"
struct Foo { bar: Bar }
struct Bar(u32);
fn foo() {
    |$0| {};
}
"#,
        expect![[r#"
            kw ref
            kw mut
            bn Foo Foo { bar$1 }$0
            st Foo
            bn Bar Bar($1)$0
            st Bar
        "#]],
    )
}

#[test]
fn completes_no_delims_if_existing() {
    check_empty(
        r#"
struct Bar(u32);
fn foo() {
    match Bar(0) {
        B$0(b) => {}
    }
}
"#,
        expect![[r#"
            kw self::
            kw super::
            kw crate::
        "#]],
    );
    check_empty(
        r#"
struct Foo { bar: u32 }
fn foo() {
    match Foo { bar: 0 } {
        F$0 { bar } => {}
    }
}
"#,
        expect![[r#"
            kw return
            kw self
            kw super
            kw crate
            st Foo
            fn foo()  fn()
            bt u32
        "#]],
    );
    check_empty(
        r#"
enum Enum {
    TupleVariant(u32)
}
fn foo() {
    match Enum::TupleVariant(0) {
        Enum::T$0(b) => {}
    }
}
"#,
        expect![[r#""#]],
    );
    check_empty(
        r#"
enum Enum {
    RecordVariant { field: u32 }
}
fn foo() {
    match (Enum::RecordVariant { field: 0 }) {
        Enum::RecordV$0 { field } => {}
    }
}
"#,
        expect![[r#""#]],
    );
}

#[test]
fn completes_associated_const() {
    check_empty(
        r#"
#[derive(PartialEq, Eq)]
struct Ty(u8);

impl Ty {
    const ABC: Self = Self(0);
}

fn f(t: Ty) {
    match t {
        Ty::$0 => {}
        _ => {}
    }
}
"#,
        expect![[r#"
            ct ABC const ABC: Self
        "#]],
    );

    check_empty(
        r#"
enum MyEnum;

impl MyEnum {
    pub const A: i32 = 123;
    pub const B: i32 = 456;
}

fn f(e: MyEnum) {
    match e {
        MyEnum::$0 => {}
        _ => {}
    }
}
"#,
        expect![[r#"
            ct A pub const A: i32
            ct B pub const B: i32
        "#]],
    );

    check_empty(
        r#"
#[repr(C)]
union U {
    i: i32,
    f: f32,
}

impl U {
    pub const C: i32 = 123;
    pub const D: i32 = 456;
}

fn f(u: U) {
    match u {
        U::$0 => {}
        _ => {}
    }
}
"#,
        expect![[r#"
            ct C pub const C: i32
            ct D pub const D: i32
        "#]],
    )
}
<|endoftext|>


<commit_before>use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::LayoutOf;
use syntax::codemap::Span;
use rustc_target::spec::abi::Abi;

use rustc::mir::interpret::EvalResult;
use super::{EvalContext, Place, Machine, ValTy};

use rustc_data_structures::indexed_vec::Idx;
use interpret::memory::HasMemory;

mod drop;

impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
    pub fn goto_block(&mut self, target: mir::BasicBlock) {
        self.frame_mut().block = target;
        self.frame_mut().stmt = 0;
    }

    pub(super) fn eval_terminator(
        &mut self,
        terminator: &mir::Terminator<'tcx>,
    ) -> EvalResult<'tcx> {
        use rustc::mir::TerminatorKind::*;
        match terminator.kind {
            Return => {
                self.dump_local(self.frame().return_place);
                self.pop_stack_frame()?
            }

            Goto { target } => self.goto_block(target),

            SwitchInt {
                ref discr,
                ref values,
                ref targets,
                ..
            } => {
                let discr_val = self.eval_operand(discr)?;
                let discr_prim = self.value_to_scalar(discr_val)?;
                let discr_layout = self.layout_of(discr_val.ty).unwrap();
                trace!("SwitchInt({:?}, {:#?})", discr_prim, discr_layout);
                let discr_prim = discr_prim.to_bits(discr_layout.size)?;

                // Branch to the `otherwise` case by default, if no match is found.
                let mut target_block = targets[targets.len() - 1];

                for (index, &const_int) in values.iter().enumerate() {
                    if discr_prim == const_int {
                        target_block = targets[index];
                        break;
                    }
                }

                self.goto_block(target_block);
            }

            Call {
                ref func,
                ref args,
                ref destination,
                ..
            } => {
                let destination = match *destination {
                    Some((ref lv, target)) => Some((self.eval_place(lv)?, target)),
                    None => None,
                };

                let func = self.eval_operand(func)?;
                let (fn_def, sig) = match func.ty.sty {
                    ty::TyFnPtr(sig) => {
                        let fn_ptr = self.value_to_scalar(func)?.to_ptr()?;
                        let instance = self.memory.get_fn(fn_ptr)?;
                        let instance_ty = instance.ty(*self.tcx);
                        match instance_ty.sty {
                            ty::TyFnDef(..) => {
                                let real_sig = instance_ty.fn_sig(*self.tcx);
                                let sig = self.tcx.normalize_erasing_late_bound_regions(
                                    ty::ParamEnv::reveal_all(),
                                    &sig,
                                );
                                let real_sig = self.tcx.normalize_erasing_late_bound_regions(
                                    ty::ParamEnv::reveal_all(),
                                    &real_sig,
                                );
                                if !self.check_sig_compat(sig, real_sig)? {
                                    return err!(FunctionPointerTyMismatch(real_sig, sig));
                                }
                            }
                            ref other => bug!("instance def ty: {:?}", other),
                        }
                        (instance, sig)
                    }
                    ty::TyFnDef(def_id, substs) => (
                        self.resolve(def_id, substs)?,
                        func.ty.fn_sig(*self.tcx),
                    ),
                    _ => {
                        let msg = format!("can't handle callee of type {:?}", func.ty);
                        return err!(Unimplemented(msg));
                    }
                };
                let args = self.operands_to_args(args)?;
                let sig = self.tcx.normalize_erasing_late_bound_regions(
                    ty::ParamEnv::reveal_all(),
                    &sig,
                );
                self.eval_fn_call(
                    fn_def,
                    destination,
                    &args,
                    terminator.source_info.span,
                    sig,
                )?;
            }

            Drop {
                ref location,
                target,
                ..
            } => {
                // FIXME(CTFE): forbid drop in const eval
                let place = self.eval_place(location)?;
                let ty = self.place_ty(location);
                let ty = self.tcx.subst_and_normalize_erasing_regions(
                    self.substs(),
                    ty::ParamEnv::reveal_all(),
                    &ty,
                );
                trace!("TerminatorKind::drop: {:?}, type {}", location, ty);

                let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
                self.drop_place(
                    place,
                    instance,
                    ty,
                    terminator.source_info.span,
                    target,
                )?;
            }

            Assert {
                ref cond,
                expected,
                ref msg,
                target,
                ..
            } => {
                let cond_val = self.eval_operand_to_scalar(cond)?.to_bool()?;
                if expected == cond_val {
                    self.goto_block(target);
                } else {
                    use rustc::mir::interpret::EvalErrorKind::*;
                    return match *msg {
                        BoundsCheck { ref len, ref index } => {
                            let len = self.eval_operand_to_scalar(len)
                                .expect("can't eval len")
                                .to_bits(self.memory().pointer_size())? as u64;
                            let index = self.eval_operand_to_scalar(index)
                                .expect("can't eval index")
                                .to_bits(self.memory().pointer_size())? as u64;
                            err!(BoundsCheck { len, index })
                        }
                        Overflow(op) => Err(Overflow(op).into()),
                        OverflowNeg => Err(OverflowNeg.into()),
                        DivisionByZero => Err(DivisionByZero.into()),
                        RemainderByZero => Err(RemainderByZero.into()),
                        GeneratorResumedAfterReturn |
                        GeneratorResumedAfterPanic => unimplemented!(),
                        _ => bug!(),
                    };
                }
            }

            Yield { .. } => unimplemented!("{:#?}", terminator.kind),
            GeneratorDrop => unimplemented!(),
            DropAndReplace { .. } => unimplemented!(),
            Resume => unimplemented!(),
            Abort => unimplemented!(),
            FalseEdges { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
            FalseUnwind { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
            Unreachable => return err!(Unreachable),
        }

        Ok(())
    }

    /// Decides whether it is okay to call the method with signature `real_sig` using signature `sig`.
    /// FIXME: This should take into account the platform-dependent ABI description.
    fn check_sig_compat(
        &mut self,
        sig: ty::FnSig<'tcx>,
        real_sig: ty::FnSig<'tcx>,
    ) -> EvalResult<'tcx, bool> {
        fn check_ty_compat<'tcx>(ty: Ty<'tcx>, real_ty: Ty<'tcx>) -> bool {
            if ty == real_ty {
                return true;
            } // This is actually a fast pointer comparison
            return match (&ty.sty, &real_ty.sty) {
                // Permit changing the pointer type of raw pointers and references as well as
                // mutability of raw pointers.
                // TODO: Should not be allowed when fat pointers are involved.
                (&ty::TyRawPtr(_), &ty::TyRawPtr(_)) => true,
                (&ty::TyRef(_, _, _), &ty::TyRef(_, _, _)) => {
                    ty.is_mutable_pointer() == real_ty.is_mutable_pointer()
                }
                // rule out everything else
                _ => false,
            };
        }

        if sig.abi == real_sig.abi && sig.variadic == real_sig.variadic &&
            sig.inputs_and_output.len() == real_sig.inputs_and_output.len() &&
            sig.inputs_and_output
                .iter()
                .zip(real_sig.inputs_and_output)
                .all(|(ty, real_ty)| check_ty_compat(ty, real_ty))
        {
            // Definitely good.
            return Ok(true);
        }

        if sig.variadic || real_sig.variadic {
            // We're not touching this
            return Ok(false);
        }

        // We need to allow what comes up when a non-capturing closure is cast to a fn().
        match (sig.abi, real_sig.abi) {
            (Abi::Rust, Abi::RustCall) // check the ABIs.  This makes the test here non-symmetric.
                if check_ty_compat(sig.output(), real_sig.output()) && real_sig.inputs_and_output.len() == 3 => {
                // First argument of real_sig must be a ZST
                let fst_ty = real_sig.inputs_and_output[0];
                if self.layout_of(fst_ty)?.is_zst() {
                    // Second argument must be a tuple matching the argument list of sig
                    let snd_ty = real_sig.inputs_and_output[1];
                    match snd_ty.sty {
                        ty::TyTuple(tys) if sig.inputs().len() == tys.len() =>
                            if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
                                return Ok(true)
                            },
                        _ => {}
                    }
                }
            }
            _ => {}
        };

        // Nope, this doesn't work.
        return Ok(false);
    }

    fn eval_fn_call(
        &mut self,
        instance: ty::Instance<'tcx>,
        destination: Option<(Place, mir::BasicBlock)>,
        args: &[ValTy<'tcx>],
        span: Span,
        sig: ty::FnSig<'tcx>,
    ) -> EvalResult<'tcx> {
        trace!("eval_fn_call: {:#?}", instance);
        match instance.def {
            ty::InstanceDef::Intrinsic(..) => {
                let (ret, target) = match destination {
                    Some(dest) => dest,
                    _ => return err!(Unreachable),
                };
                let ty = sig.output();
                let layout = self.layout_of(ty)?;
                M::call_intrinsic(self, instance, args, ret, layout, target)?;
                self.dump_local(ret);
                Ok(())
            }
            // FIXME: figure out why we can't just go through the shim
            ty::InstanceDef::ClosureOnceShim { .. } => {
                if M::eval_fn_call(self, instance, destination, args, span, sig)? {
                    return Ok(());
                }
                let mut arg_locals = self.frame().mir.args_iter();
                match sig.abi {
                    // closure as closure once
                    Abi::RustCall => {
                        for (arg_local, &valty) in arg_locals.zip(args) {
                            let dest = self.eval_place(&mir::Place::Local(arg_local))?;
                            self.write_value(valty, dest)?;
                        }
                    }
                    // non capture closure as fn ptr
                    // need to inject zst ptr for closure object (aka do nothing)
                    // and need to pack arguments
                    Abi::Rust => {
                        trace!(
                            "arg_locals: {:#?}",
                            self.frame().mir.args_iter().collect::<Vec<_>>()
                        );
                        trace!("args: {:#?}", args);
                        let local = arg_locals.nth(1).unwrap();
                        for (i, &valty) in args.into_iter().enumerate() {
                            let dest = self.eval_place(&mir::Place::Local(local).field(
                                mir::Field::new(i),
                                valty.ty,
                            ))?;
                            self.write_value(valty, dest)?;
                        }
                    }
                    _ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi),
                }
                Ok(())
            }
            ty::InstanceDef::FnPtrShim(..) |
            ty::InstanceDef::DropGlue(..) |
            ty::InstanceDef::CloneShim(..) |
            ty::InstanceDef::Item(_) => {
                // Push the stack frame, and potentially be entirely done if the call got hooked
                if M::eval_fn_call(self, instance, destination, args, span, sig)? {
                    return Ok(());
                }

                // Pass the arguments
                let mut arg_locals = self.frame().mir.args_iter();
                trace!("ABI: {:?}", sig.abi);
                trace!(
                    "arg_locals: {:#?}",
                    self.frame().mir.args_iter().collect::<Vec<_>>()
                );
                trace!("args: {:#?}", args);
                match sig.abi {
                    Abi::RustCall => {
                        assert_eq!(args.len(), 2);

                        {
                            // write first argument
                            let first_local = arg_locals.next().unwrap();
                            let dest = self.eval_place(&mir::Place::Local(first_local))?;
                            self.write_value(args[0], dest)?;
                        }

                        // unpack and write all other args
                        let layout = self.layout_of(args[1].ty)?;
                        if let ty::TyTuple(_) = args[1].ty.sty {
                            if layout.is_zst() {
                                // Nothing to do, no need to unpack zsts
                                return Ok(());
                            }
                            if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
                                for (i, arg_local) in arg_locals.enumerate() {
                                    let field = mir::Field::new(i);
                                    let valty = self.read_field(args[1].value, None, field, args[1].ty)?;
                                    let dest = self.eval_place(&mir::Place::Local(arg_local))?;
                                    self.write_value(valty, dest)?;
                                }
                            } else {
                                trace!("manual impl of rust-call ABI");
                                // called a manual impl of a rust-call function
                                let dest = self.eval_place(
                                    &mir::Place::Local(arg_locals.next().unwrap()),
                                )?;
                                self.write_value(args[1], dest)?;
                            }
                        } else {
                            bug!(
                                "rust-call ABI tuple argument was {:#?}, {:#?}",
                                args[1].ty,
                                layout
                            );
                        }
                    }
                    _ => {
                        for (arg_local, &valty) in arg_locals.zip(args) {
                            let dest = self.eval_place(&mir::Place::Local(arg_local))?;
                            self.write_value(valty, dest)?;
                        }
                    }
                }
                Ok(())
            }
            // cannot use the shim here, because that will only result in infinite recursion
            ty::InstanceDef::Virtual(_, idx) => {
                let ptr_size = self.memory.pointer_size();
                let ptr_align = self.tcx.data_layout.pointer_align;
                let (ptr, vtable) = self.into_ptr_vtable_pair(args[0].value)?;
                let fn_ptr = self.memory.read_ptr_sized(
                    vtable.offset(ptr_size * (idx as u64 + 3), &self)?,
                    ptr_align
                )?.to_ptr()?;
                let instance = self.memory.get_fn(fn_ptr)?;
                let mut args = args.to_vec();
                let ty = self.layout_of(args[0].ty)?.field(&self, 0)?.ty;
                args[0].ty = ty;
                args[0].value = ptr.to_value();
                // recurse with concrete function
                self.eval_fn_call(instance, destination, &args, span, sig)
            }
        }
    }
}
<commit_msg>CTFE: use binary_op to compare integer with match disriminant<commit_after>use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{LayoutOf, Size};
use syntax::codemap::Span;
use rustc_target::spec::abi::Abi;

use rustc::mir::interpret::{EvalResult, Scalar};
use super::{EvalContext, Place, Machine, ValTy};

use rustc_data_structures::indexed_vec::Idx;
use interpret::memory::HasMemory;

mod drop;

impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
    pub fn goto_block(&mut self, target: mir::BasicBlock) {
        self.frame_mut().block = target;
        self.frame_mut().stmt = 0;
    }

    pub(super) fn eval_terminator(
        &mut self,
        terminator: &mir::Terminator<'tcx>,
    ) -> EvalResult<'tcx> {
        use rustc::mir::TerminatorKind::*;
        match terminator.kind {
            Return => {
                self.dump_local(self.frame().return_place);
                self.pop_stack_frame()?
            }

            Goto { target } => self.goto_block(target),

            SwitchInt {
                ref discr,
                ref values,
                ref targets,
                ..
            } => {
                let discr_val = self.eval_operand(discr)?;
                let discr_prim = self.value_to_scalar(discr_val)?;
                let discr_layout = self.layout_of(discr_val.ty).unwrap();
                trace!("SwitchInt({:?}, {:#?})", discr_prim, discr_layout);

                // Branch to the `otherwise` case by default, if no match is found.
                let mut target_block = targets[targets.len() - 1];

                for (index, &const_int) in values.iter().enumerate() {
                    // Compare using binary_op
                    let const_int = Scalar::Bits { bits: const_int, defined: 128 };
                    let res = self.binary_op(mir::BinOp::Eq,
                        discr_prim, discr_val.ty,
                        const_int, discr_val.ty
                    )?;
                    if res.0.to_bits(Size::from_bytes(1))? != 0 {
                        target_block = targets[index];
                        break;
                    }
                }

                self.goto_block(target_block);
            }

            Call {
                ref func,
                ref args,
                ref destination,
                ..
            } => {
                let destination = match *destination {
                    Some((ref lv, target)) => Some((self.eval_place(lv)?, target)),
                    None => None,
                };

                let func = self.eval_operand(func)?;
                let (fn_def, sig) = match func.ty.sty {
                    ty::TyFnPtr(sig) => {
                        let fn_ptr = self.value_to_scalar(func)?.to_ptr()?;
                        let instance = self.memory.get_fn(fn_ptr)?;
                        let instance_ty = instance.ty(*self.tcx);
                        match instance_ty.sty {
                            ty::TyFnDef(..) => {
                                let real_sig = instance_ty.fn_sig(*self.tcx);
                                let sig = self.tcx.normalize_erasing_late_bound_regions(
                                    ty::ParamEnv::reveal_all(),
                                    &sig,
                                );
                                let real_sig = self.tcx.normalize_erasing_late_bound_regions(
                                    ty::ParamEnv::reveal_all(),
                                    &real_sig,
                                );
                                if !self.check_sig_compat(sig, real_sig)? {
                                    return err!(FunctionPointerTyMismatch(real_sig, sig));
                                }
                            }
                            ref other => bug!("instance def ty: {:?}", other),
                        }
                        (instance, sig)
                    }
                    ty::TyFnDef(def_id, substs) => (
                        self.resolve(def_id, substs)?,
                        func.ty.fn_sig(*self.tcx),
                    ),
                    _ => {
                        let msg = format!("can't handle callee of type {:?}", func.ty);
                        return err!(Unimplemented(msg));
                    }
                };
                let args = self.operands_to_args(args)?;
                let sig = self.tcx.normalize_erasing_late_bound_regions(
                    ty::ParamEnv::reveal_all(),
                    &sig,
                );
                self.eval_fn_call(
                    fn_def,
                    destination,
                    &args,
                    terminator.source_info.span,
                    sig,
                )?;
            }

            Drop {
                ref location,
                target,
                ..
            } => {
                // FIXME(CTFE): forbid drop in const eval
                let place = self.eval_place(location)?;
                let ty = self.place_ty(location);
                let ty = self.tcx.subst_and_normalize_erasing_regions(
                    self.substs(),
                    ty::ParamEnv::reveal_all(),
                    &ty,
                );
                trace!("TerminatorKind::drop: {:?}, type {}", location, ty);

                let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
                self.drop_place(
                    place,
                    instance,
                    ty,
                    terminator.source_info.span,
                    target,
                )?;
            }

            Assert {
                ref cond,
                expected,
                ref msg,
                target,
                ..
            } => {
                let cond_val = self.eval_operand_to_scalar(cond)?.to_bool()?;
                if expected == cond_val {
                    self.goto_block(target);
                } else {
                    use rustc::mir::interpret::EvalErrorKind::*;
                    return match *msg {
                        BoundsCheck { ref len, ref index } => {
                            let len = self.eval_operand_to_scalar(len)
                                .expect("can't eval len")
                                .to_bits(self.memory().pointer_size())? as u64;
                            let index = self.eval_operand_to_scalar(index)
                                .expect("can't eval index")
                                .to_bits(self.memory().pointer_size())? as u64;
                            err!(BoundsCheck { len, index })
                        }
                        Overflow(op) => Err(Overflow(op).into()),
                        OverflowNeg => Err(OverflowNeg.into()),
                        DivisionByZero => Err(DivisionByZero.into()),
                        RemainderByZero => Err(RemainderByZero.into()),
                        GeneratorResumedAfterReturn |
                        GeneratorResumedAfterPanic => unimplemented!(),
                        _ => bug!(),
                    };
                }
            }

            Yield { .. } => unimplemented!("{:#?}", terminator.kind),
            GeneratorDrop => unimplemented!(),
            DropAndReplace { .. } => unimplemented!(),
            Resume => unimplemented!(),
            Abort => unimplemented!(),
            FalseEdges { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
            FalseUnwind { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
            Unreachable => return err!(Unreachable),
        }

        Ok(())
    }

    /// Decides whether it is okay to call the method with signature `real_sig` using signature `sig`.
    /// FIXME: This should take into account the platform-dependent ABI description.
    fn check_sig_compat(
        &mut self,
        sig: ty::FnSig<'tcx>,
        real_sig: ty::FnSig<'tcx>,
    ) -> EvalResult<'tcx, bool> {
        fn check_ty_compat<'tcx>(ty: Ty<'tcx>, real_ty: Ty<'tcx>) -> bool {
            if ty == real_ty {
                return true;
            } // This is actually a fast pointer comparison
            return match (&ty.sty, &real_ty.sty) {
                // Permit changing the pointer type of raw pointers and references as well as
                // mutability of raw pointers.
                // TODO: Should not be allowed when fat pointers are involved.
                (&ty::TyRawPtr(_), &ty::TyRawPtr(_)) => true,
                (&ty::TyRef(_, _, _), &ty::TyRef(_, _, _)) => {
                    ty.is_mutable_pointer() == real_ty.is_mutable_pointer()
                }
                // rule out everything else
                _ => false,
            };
        }

        if sig.abi == real_sig.abi && sig.variadic == real_sig.variadic &&
            sig.inputs_and_output.len() == real_sig.inputs_and_output.len() &&
            sig.inputs_and_output
                .iter()
                .zip(real_sig.inputs_and_output)
                .all(|(ty, real_ty)| check_ty_compat(ty, real_ty))
        {
            // Definitely good.
            return Ok(true);
        }

        if sig.variadic || real_sig.variadic {
            // We're not touching this
            return Ok(false);
        }

        // We need to allow what comes up when a non-capturing closure is cast to a fn().
        match (sig.abi, real_sig.abi) {
            (Abi::Rust, Abi::RustCall) // check the ABIs.  This makes the test here non-symmetric.
                if check_ty_compat(sig.output(), real_sig.output()) && real_sig.inputs_and_output.len() == 3 => {
                // First argument of real_sig must be a ZST
                let fst_ty = real_sig.inputs_and_output[0];
                if self.layout_of(fst_ty)?.is_zst() {
                    // Second argument must be a tuple matching the argument list of sig
                    let snd_ty = real_sig.inputs_and_output[1];
                    match snd_ty.sty {
                        ty::TyTuple(tys) if sig.inputs().len() == tys.len() =>
                            if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
                                return Ok(true)
                            },
                        _ => {}
                    }
                }
            }
            _ => {}
        };

        // Nope, this doesn't work.
        return Ok(false);
    }

    fn eval_fn_call(
        &mut self,
        instance: ty::Instance<'tcx>,
        destination: Option<(Place, mir::BasicBlock)>,
        args: &[ValTy<'tcx>],
        span: Span,
        sig: ty::FnSig<'tcx>,
    ) -> EvalResult<'tcx> {
        trace!("eval_fn_call: {:#?}", instance);
        match instance.def {
            ty::InstanceDef::Intrinsic(..) => {
                let (ret, target) = match destination {
                    Some(dest) => dest,
                    _ => return err!(Unreachable),
                };
                let ty = sig.output();
                let layout = self.layout_of(ty)?;
                M::call_intrinsic(self, instance, args, ret, layout, target)?;
                self.dump_local(ret);
                Ok(())
            }
            // FIXME: figure out why we can't just go through the shim
            ty::InstanceDef::ClosureOnceShim { .. } => {
                if M::eval_fn_call(self, instance, destination, args, span, sig)? {
                    return Ok(());
                }
                let mut arg_locals = self.frame().mir.args_iter();
                match sig.abi {
                    // closure as closure once
                    Abi::RustCall => {
                        for (arg_local, &valty) in arg_locals.zip(args) {
                            let dest = self.eval_place(&mir::Place::Local(arg_local))?;
                            self.write_value(valty, dest)?;
                        }
                    }
                    // non capture closure as fn ptr
                    // need to inject zst ptr for closure object (aka do nothing)
                    // and need to pack arguments
                    Abi::Rust => {
                        trace!(
                            "arg_locals: {:#?}",
                            self.frame().mir.args_iter().collect::<Vec<_>>()
                        );
                        trace!("args: {:#?}", args);
                        let local = arg_locals.nth(1).unwrap();
                        for (i, &valty) in args.into_iter().enumerate() {
                            let dest = self.eval_place(&mir::Place::Local(local).field(
                                mir::Field::new(i),
                                valty.ty,
                            ))?;
                            self.write_value(valty, dest)?;
                        }
                    }
                    _ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi),
                }
                Ok(())
            }
            ty::InstanceDef::FnPtrShim(..) |
            ty::InstanceDef::DropGlue(..) |
            ty::InstanceDef::CloneShim(..) |
            ty::InstanceDef::Item(_) => {
                // Push the stack frame, and potentially be entirely done if the call got hooked
                if M::eval_fn_call(self, instance, destination, args, span, sig)? {
                    return Ok(());
                }

                // Pass the arguments
                let mut arg_locals = self.frame().mir.args_iter();
                trace!("ABI: {:?}", sig.abi);
                trace!(
                    "arg_locals: {:#?}",
                    self.frame().mir.args_iter().collect::<Vec<_>>()
                );
                trace!("args: {:#?}", args);
                match sig.abi {
                    Abi::RustCall => {
                        assert_eq!(args.len(), 2);

                        {
                            // write first argument
                            let first_local = arg_locals.next().unwrap();
                            let dest = self.eval_place(&mir::Place::Local(first_local))?;
                            self.write_value(args[0], dest)?;
                        }

                        // unpack and write all other args
                        let layout = self.layout_of(args[1].ty)?;
                        if let ty::TyTuple(_) = args[1].ty.sty {
                            if layout.is_zst() {
                                // Nothing to do, no need to unpack zsts
                                return Ok(());
                            }
                            if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
                                for (i, arg_local) in arg_locals.enumerate() {
                                    let field = mir::Field::new(i);
                                    let valty = self.read_field(args[1].value, None, field, args[1].ty)?;
                                    let dest = self.eval_place(&mir::Place::Local(arg_local))?;
                                    self.write_value(valty, dest)?;
                                }
                            } else {
                                trace!("manual impl of rust-call ABI");
                                // called a manual impl of a rust-call function
                                let dest = self.eval_place(
                                    &mir::Place::Local(arg_locals.next().unwrap()),
                                )?;
                                self.write_value(args[1], dest)?;
                            }
                        } else {
                            bug!(
                                "rust-call ABI tuple argument was {:#?}, {:#?}",
                                args[1].ty,
                                layout
                            );
                        }
                    }
                    _ => {
                        for (arg_local, &valty) in arg_locals.zip(args) {
                            let dest = self.eval_place(&mir::Place::Local(arg_local))?;
                            self.write_value(valty, dest)?;
                        }
                    }
                }
                Ok(())
            }
            // cannot use the shim here, because that will only result in infinite recursion
            ty::InstanceDef::Virtual(_, idx) => {
                let ptr_size = self.memory.pointer_size();
                let ptr_align = self.tcx.data_layout.pointer_align;
                let (ptr, vtable) = self.into_ptr_vtable_pair(args[0].value)?;
                let fn_ptr = self.memory.read_ptr_sized(
                    vtable.offset(ptr_size * (idx as u64 + 3), &self)?,
                    ptr_align
                )?.to_ptr()?;
                let instance = self.memory.get_fn(fn_ptr)?;
                let mut args = args.to_vec();
                let ty = self.layout_of(args[0].ty)?.field(&self, 0)?.ty;
                args[0].ty = ty;
                args[0].value = ptr.to_value();
                // recurse with concrete function
                self.eval_fn_call(instance, destination, &args, span, sig)
            }
        }
    }
}
<|endoftext|>


<commit_before>use libc::c_char;

use runtime::{Class, Object, Sel};

/// Types that have an Objective-C type encoding. For more information, see
/// Apple's documentation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
pub trait Encode {
    /// Return the Encoding for Self.
    fn code() -> &'static str;
}

impl Encode for i8 {
    fn code() -> &'static str { "c" }
}

impl Encode for i16 {
    fn code() -> &'static str { "s" }
}

impl Encode for i32 {
    fn code() -> &'static str { "i" }
}

impl Encode for i64 {
    fn code() -> &'static str { "q" }
}

impl Encode for isize {
    #[cfg(target_pointer_width = "32")]
    fn code() -> &'static str { "i" }

    #[cfg(target_pointer_width = "64")]
    fn code() -> &'static str { "q" }
}

impl Encode for u8 {
    fn code() -> &'static str { "C" }
}

impl Encode for u16 {
    fn code() -> &'static str { "S" }
}

impl Encode for u32 {
    fn code() -> &'static str { "I" }
}

impl Encode for u64 {
    fn code() -> &'static str { "Q" }
}

impl Encode for usize {
    #[cfg(target_pointer_width = "32")]
    fn code() -> &'static str { "I" }

    #[cfg(target_pointer_width = "64")]
    fn code() -> &'static str { "Q" }
}

impl Encode for f32 {
    fn code() -> &'static str { "f" }
}

impl Encode for f64 {
    fn code() -> &'static str { "d" }
}

impl Encode for bool {
    fn code() -> &'static str { "B" }
}

impl Encode for () {
    fn code() -> &'static str { "v" }
}

impl Encode for *mut c_char {
    fn code() -> &'static str { "*" }
}

impl Encode for *const c_char {
    fn code() -> &'static str { "r*" }
}

impl Encode for Sel {
    fn code() -> &'static str { ":" }
}

pub trait EncodePtr {
    fn ptr_code() -> &'static str;
}

impl<'a, T> Encode for &'a T where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<'a, T> Encode for &'a mut T where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<'a, T> Encode for Option<&'a T> where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<'a, T> Encode for Option<&'a mut T> where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<T> Encode for *const T where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<T> Encode for *mut T where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl EncodePtr for Object {
    fn ptr_code() -> &'static str { "@" }
}

impl EncodePtr for Class {
    fn ptr_code() -> &'static str { "#" }
}

/// Returns the Objective-C type encoding for a type.
pub fn encode<T>() -> &'static str where T: Encode {
    <T as Encode>::code()
}

#[cfg(test)]
mod tests {
    use runtime::{Class, Object, Sel};
    use super::encode;

    #[test]
    fn test_encode() {
        assert!(encode::<u32>() == "I");
        assert!(encode::<()>() == "v");
        assert!(encode::<&Object>() == "@");
        assert!(encode::<*mut Object>() == "@");
        assert!(encode::<&Class>() == "#");
        assert!(encode::<Sel>() == ":");
    }
}
<commit_msg>Implemented encode for void pointers.<commit_after>use libc::{c_char, c_void};

use runtime::{Class, Object, Sel};

/// Types that have an Objective-C type encoding. For more information, see
/// Apple's documentation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
pub trait Encode {
    /// Return the Encoding for Self.
    fn code() -> &'static str;
}

impl Encode for i8 {
    fn code() -> &'static str { "c" }
}

impl Encode for i16 {
    fn code() -> &'static str { "s" }
}

impl Encode for i32 {
    fn code() -> &'static str { "i" }
}

impl Encode for i64 {
    fn code() -> &'static str { "q" }
}

impl Encode for isize {
    #[cfg(target_pointer_width = "32")]
    fn code() -> &'static str { "i" }

    #[cfg(target_pointer_width = "64")]
    fn code() -> &'static str { "q" }
}

impl Encode for u8 {
    fn code() -> &'static str { "C" }
}

impl Encode for u16 {
    fn code() -> &'static str { "S" }
}

impl Encode for u32 {
    fn code() -> &'static str { "I" }
}

impl Encode for u64 {
    fn code() -> &'static str { "Q" }
}

impl Encode for usize {
    #[cfg(target_pointer_width = "32")]
    fn code() -> &'static str { "I" }

    #[cfg(target_pointer_width = "64")]
    fn code() -> &'static str { "Q" }
}

impl Encode for f32 {
    fn code() -> &'static str { "f" }
}

impl Encode for f64 {
    fn code() -> &'static str { "d" }
}

impl Encode for bool {
    fn code() -> &'static str { "B" }
}

impl Encode for () {
    fn code() -> &'static str { "v" }
}

impl Encode for *mut c_char {
    fn code() -> &'static str { "*" }
}

impl Encode for *const c_char {
    fn code() -> &'static str { "r*" }
}

impl Encode for *mut c_void {
    fn code() -> &'static str { "^v" }
}

impl Encode for *const c_void {
    fn code() -> &'static str { "r^v" }
}

impl Encode for Sel {
    fn code() -> &'static str { ":" }
}

pub trait EncodePtr {
    fn ptr_code() -> &'static str;
}

impl<'a, T> Encode for &'a T where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<'a, T> Encode for &'a mut T where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<'a, T> Encode for Option<&'a T> where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<'a, T> Encode for Option<&'a mut T> where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<T> Encode for *const T where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl<T> Encode for *mut T where T: EncodePtr {
    fn code() -> &'static str { <T as EncodePtr>::ptr_code() }
}

impl EncodePtr for Object {
    fn ptr_code() -> &'static str { "@" }
}

impl EncodePtr for Class {
    fn ptr_code() -> &'static str { "#" }
}

/// Returns the Objective-C type encoding for a type.
pub fn encode<T>() -> &'static str where T: Encode {
    <T as Encode>::code()
}

#[cfg(test)]
mod tests {
    use runtime::{Class, Object, Sel};
    use super::encode;

    #[test]
    fn test_encode() {
        assert!(encode::<u32>() == "I");
        assert!(encode::<()>() == "v");
        assert!(encode::<&Object>() == "@");
        assert!(encode::<*mut Object>() == "@");
        assert!(encode::<&Class>() == "#");
        assert!(encode::<Sel>() == ":");
    }
}
<|endoftext|>


<commit_before>use std::io::{Error, ErrorKind};
use std::ops::Add;
use std::result::Result;

fn range_vec<T>(nl: &Vec<T>, i: usize, j: usize) -> Result<Vec<T>, Error>
where
    T: Copy + Clone,
{
    if i >= nl.len() {
        return Result::Err(Error::new(
            ErrorKind::Other,
            "first index larger than length",
        ));
    }

    let mut jj;

    if j > nl.len() {
        jj = nl.len();
    } else {
        jj = j;
    }

    let mut ind = 0;
    let mut result: Vec<T> = vec![];

    for this in nl {
        if ind >= i && ind <= jj {
            result.push(*this);
        }
        ind += 1;
    }

    Result::Ok(result)
}

fn sum_vec<T>(nl: &Vec<T>) -> T
where
    T: Add<Output = T> + Copy + Clone,
{
    let mut result: T = *nl.first().unwrap();
    if let Some((_, last)) = nl.split_first() {
        for this in last {
            result = result + (*this);
        }
    }
    result
}

fn sum_range<T>(nl: &Vec<T>, i: usize, j: usize) -> Result<T, Error>
where
    T: Add<Output = T> + Copy + Clone,
{
    match range_vec(nl, i, j) {
        Result::Ok(temp_l) => return Result::Ok(sum_vec(&temp_l)),
        Result::Err(e) => return Result::Err(e),
    }
}

fn main() {
    let a = vec![-2, 0, 3, -5, 2, -1];
    println!("{:?}", range_vec(&a, 0, 1));
    println!("{:?}", range_vec(&a, 2, 6));
    println!("{:?}", range_vec(&a, 6, 6));
    println!("{:?}", range_vec(&a, 5, 6));
    //main thread cannot use `?`
    //println!("{:?}", range_vec(&a, 2, 6)?);

    println!("{:?}", sum_vec(&a));

    println!("{:?}", sum_range(&a, 0, 2));
    println!("{:?}", sum_range(&a, 2, 5));
    println!("{:?}", sum_range(&a, 0, 5));
}
<commit_msg>test result in main()<commit_after>use std::io::{Error, ErrorKind};
use std::ops::Add;
use std::result::Result;

fn range_vec<T>(nl: &Vec<T>, i: usize, j: usize) -> Result<Vec<T>, Error>
where
    T: Copy + Clone,
{
    if i >= nl.len() {
        return Result::Err(Error::new(
            ErrorKind::Other,
            "first index larger than length",
        ));
    }

    let mut jj;

    if j > nl.len() {
        jj = nl.len();
    } else {
        jj = j;
    }

    let mut ind = 0;
    let mut result: Vec<T> = vec![];

    for this in nl {
        if ind >= i && ind <= jj {
            result.push(*this);
        }
        ind += 1;
    }

    Result::Ok(result)
}

fn sum_vec<T>(nl: &Vec<T>) -> T
where
    T: Add<Output = T> + Copy + Clone,
{
    let mut result: T = *nl.first().unwrap();
    if let Some((_, last)) = nl.split_first() {
        for this in last {
            result = result + (*this);
        }
    }
    result
}

fn sum_range<T>(nl: &Vec<T>, i: usize, j: usize) -> Result<T, Error>
where
    T: Add<Output = T> + Copy + Clone,
{
    match range_vec(nl, i, j) {
        Result::Ok(temp_l) => return Result::Ok(sum_vec(&temp_l)),
        Result::Err(e) => return Result::Err(e),
    }
}

fn main() -> Result<(), std::io::Error> {
    let a = vec![-2, 0, 3, -5, 2, -1];
    println!("{:?}", range_vec(&a, 0, 1));
    println!("{:?}", range_vec(&a, 2, 6));
    println!("{:?}", range_vec(&a, 6, 6));
    println!("{:?}", range_vec(&a, 5, 6));

    //main thread cannot use `?`
    //1.26 can use `?`
    //https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
    let b = range_vec(&a, 2, 6)?;
    println!("{:?}", b);

    println!("{:?}", sum_vec(&a));

    println!("{:?}", sum_range(&a, 0, 2));
    println!("{:?}", sum_range(&a, 2, 5));
    println!("{:?}", sum_range(&a, 0, 5));

    Result::Ok(())
}
<|endoftext|>


<commit_before>// 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.

//! Simplification of where clauses and parameter bounds into a prettier and
//! more canonical form.
//!
//! Currently all cross-crate-inlined function use `rustc::ty` to reconstruct
//! the AST (e.g. see all of `clean::inline`), but this is not always a
//! non-lossy transformation. The current format of storage for where clauses
//! for functions and such is simply a list of predicates. One example of this
//! is that the AST predicate of:
//!
//!     where T: Trait<Foo=Bar>
//!
//! is encoded as:
//!
//!     where T: Trait, <T as Trait>::Foo = Bar
//!
//! This module attempts to reconstruct the original where and/or parameter
//! bounds by special casing scenarios such as these. Fun!

use std::mem;
use std::collections::HashMap;

use rustc::hir::def_id::DefId;
use rustc::ty::subst;

use clean::PathParameters as PP;
use clean::WherePredicate as WP;
use clean::{self, Clean};
use core::DocContext;

pub fn where_clauses(cx: &DocContext, clauses: Vec<WP>) -> Vec<WP> {
    // First, partition the where clause into its separate components
    let mut params = HashMap::new();
    let mut lifetimes = Vec::new();
    let mut equalities = Vec::new();
    let mut tybounds = Vec::new();
    for clause in clauses {
        match clause {
            WP::BoundPredicate { ty, bounds } => {
                match ty {
                    clean::Generic(s) => params.entry(s).or_insert(Vec::new())
                                               .extend(bounds),
                    t => tybounds.push((t, ty_bounds(bounds))),
                }
            }
            WP::RegionPredicate { lifetime, bounds } => {
                lifetimes.push((lifetime, bounds));
            }
            WP::EqPredicate { lhs, rhs } => equalities.push((lhs, rhs)),
        }
    }

    // Simplify the type parameter bounds on all the generics
    let mut params = params.into_iter().map(|(k, v)| {
        (k, ty_bounds(v))
    }).collect::<HashMap<_, _>>();

    // Look for equality predicates on associated types that can be merged into
    // general bound predicates
    equalities.retain(|&(ref lhs, ref rhs)| {
        let (self_, trait_, name) = match *lhs {
            clean::QPath { ref self_type, ref trait_, ref name } => {
                (self_type, trait_, name)
            }
            _ => return true,
        };
        let generic = match **self_ {
            clean::Generic(ref s) => s,
            _ => return true,
        };
        let trait_did = match **trait_ {
            clean::ResolvedPath { did, .. } => did,
            _ => return true,
        };
        let bounds = match params.get_mut(generic) {
            Some(bound) => bound,
            None => return true,
        };
        !bounds.iter_mut().any(|b| {
            let trait_ref = match *b {
                clean::TraitBound(ref mut tr, _) => tr,
                clean::RegionBound(..) => return false,
            };
            let (did, path) = match trait_ref.trait_ {
                clean::ResolvedPath { did, ref mut path, ..} => (did, path),
                _ => return false,
            };
            // If this QPath's trait `trait_did` is the same as, or a supertrait
            // of, the bound's trait `did` then we can keep going, otherwise
            // this is just a plain old equality bound.
            if !trait_is_same_or_supertrait(cx, did, trait_did) {
                return false
            }
            let last = path.segments.last_mut().unwrap();
            match last.params {
                PP::AngleBracketed { ref mut bindings, .. } => {
                    bindings.push(clean::TypeBinding {
                        name: name.clone(),
                        ty: rhs.clone(),
                    });
                }
                PP::Parenthesized { ref mut output, .. } => {
                    assert!(output.is_none());
                    *output = Some(rhs.clone());
                }
            };
            true
        })
    });

    // And finally, let's reassemble everything
    let mut clauses = Vec::new();
    clauses.extend(lifetimes.into_iter().map(|(lt, bounds)| {
        WP::RegionPredicate { lifetime: lt, bounds: bounds }
    }));
    clauses.extend(params.into_iter().map(|(k, v)| {
        WP::BoundPredicate {
            ty: clean::Generic(k),
            bounds: v,
        }
    }));
    clauses.extend(tybounds.into_iter().map(|(ty, bounds)| {
        WP::BoundPredicate { ty: ty, bounds: bounds }
    }));
    clauses.extend(equalities.into_iter().map(|(lhs, rhs)| {
        WP::EqPredicate { lhs: lhs, rhs: rhs }
    }));
    clauses
}

pub fn ty_params(mut params: Vec<clean::TyParam>) -> Vec<clean::TyParam> {
    for param in &mut params {
        param.bounds = ty_bounds(mem::replace(&mut param.bounds, Vec::new()));
    }
    return params;
}

fn ty_bounds(bounds: Vec<clean::TyParamBound>) -> Vec<clean::TyParamBound> {
    bounds
}

fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId,
                               trait_: DefId) -> bool {
    if child == trait_ {
        return true
    }
    let def = cx.tcx().lookup_trait_def(child);
    let predicates = cx.tcx().lookup_predicates(child);
    let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
    generics.where_predicates.iter().filter_map(|pred| {
        match *pred {
            clean::WherePredicate::BoundPredicate {
                ty: clean::Generic(ref s),
                ref bounds
            } if *s == "Self" => Some(bounds),
            _ => None,
        }
    }).flat_map(|bounds| bounds).any(|bound| {
        let poly_trait = match *bound {
            clean::TraitBound(ref t, _) => t,
            _ => return false,
        };
        match poly_trait.trait_ {
            clean::ResolvedPath { did, .. } => {
                trait_is_same_or_supertrait(cx, did, trait_)
            }
            _ => false,
        }
    })
}
<commit_msg>Rollup merge of #33373 - birkenfeld:issue-32555, r=bluss<commit_after>// 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.

//! Simplification of where clauses and parameter bounds into a prettier and
//! more canonical form.
//!
//! Currently all cross-crate-inlined function use `rustc::ty` to reconstruct
//! the AST (e.g. see all of `clean::inline`), but this is not always a
//! non-lossy transformation. The current format of storage for where clauses
//! for functions and such is simply a list of predicates. One example of this
//! is that the AST predicate of:
//!
//!     where T: Trait<Foo=Bar>
//!
//! is encoded as:
//!
//!     where T: Trait, <T as Trait>::Foo = Bar
//!
//! This module attempts to reconstruct the original where and/or parameter
//! bounds by special casing scenarios such as these. Fun!

use std::mem;
use std::collections::BTreeMap;

use rustc::hir::def_id::DefId;
use rustc::ty::subst;

use clean::PathParameters as PP;
use clean::WherePredicate as WP;
use clean::{self, Clean};
use core::DocContext;

pub fn where_clauses(cx: &DocContext, clauses: Vec<WP>) -> Vec<WP> {
    // First, partition the where clause into its separate components
    let mut params = BTreeMap::new();
    let mut lifetimes = Vec::new();
    let mut equalities = Vec::new();
    let mut tybounds = Vec::new();
    for clause in clauses {
        match clause {
            WP::BoundPredicate { ty, bounds } => {
                match ty {
                    clean::Generic(s) => params.entry(s).or_insert(Vec::new())
                                               .extend(bounds),
                    t => tybounds.push((t, ty_bounds(bounds))),
                }
            }
            WP::RegionPredicate { lifetime, bounds } => {
                lifetimes.push((lifetime, bounds));
            }
            WP::EqPredicate { lhs, rhs } => equalities.push((lhs, rhs)),
        }
    }

    // Simplify the type parameter bounds on all the generics
    let mut params = params.into_iter().map(|(k, v)| {
        (k, ty_bounds(v))
    }).collect::<BTreeMap<_, _>>();

    // Look for equality predicates on associated types that can be merged into
    // general bound predicates
    equalities.retain(|&(ref lhs, ref rhs)| {
        let (self_, trait_, name) = match *lhs {
            clean::QPath { ref self_type, ref trait_, ref name } => {
                (self_type, trait_, name)
            }
            _ => return true,
        };
        let generic = match **self_ {
            clean::Generic(ref s) => s,
            _ => return true,
        };
        let trait_did = match **trait_ {
            clean::ResolvedPath { did, .. } => did,
            _ => return true,
        };
        let bounds = match params.get_mut(generic) {
            Some(bound) => bound,
            None => return true,
        };
        !bounds.iter_mut().any(|b| {
            let trait_ref = match *b {
                clean::TraitBound(ref mut tr, _) => tr,
                clean::RegionBound(..) => return false,
            };
            let (did, path) = match trait_ref.trait_ {
                clean::ResolvedPath { did, ref mut path, ..} => (did, path),
                _ => return false,
            };
            // If this QPath's trait `trait_did` is the same as, or a supertrait
            // of, the bound's trait `did` then we can keep going, otherwise
            // this is just a plain old equality bound.
            if !trait_is_same_or_supertrait(cx, did, trait_did) {
                return false
            }
            let last = path.segments.last_mut().unwrap();
            match last.params {
                PP::AngleBracketed { ref mut bindings, .. } => {
                    bindings.push(clean::TypeBinding {
                        name: name.clone(),
                        ty: rhs.clone(),
                    });
                }
                PP::Parenthesized { ref mut output, .. } => {
                    assert!(output.is_none());
                    *output = Some(rhs.clone());
                }
            };
            true
        })
    });

    // And finally, let's reassemble everything
    let mut clauses = Vec::new();
    clauses.extend(lifetimes.into_iter().map(|(lt, bounds)| {
        WP::RegionPredicate { lifetime: lt, bounds: bounds }
    }));
    clauses.extend(params.into_iter().map(|(k, v)| {
        WP::BoundPredicate {
            ty: clean::Generic(k),
            bounds: v,
        }
    }));
    clauses.extend(tybounds.into_iter().map(|(ty, bounds)| {
        WP::BoundPredicate { ty: ty, bounds: bounds }
    }));
    clauses.extend(equalities.into_iter().map(|(lhs, rhs)| {
        WP::EqPredicate { lhs: lhs, rhs: rhs }
    }));
    clauses
}

pub fn ty_params(mut params: Vec<clean::TyParam>) -> Vec<clean::TyParam> {
    for param in &mut params {
        param.bounds = ty_bounds(mem::replace(&mut param.bounds, Vec::new()));
    }
    return params;
}

fn ty_bounds(bounds: Vec<clean::TyParamBound>) -> Vec<clean::TyParamBound> {
    bounds
}

fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId,
                               trait_: DefId) -> bool {
    if child == trait_ {
        return true
    }
    let def = cx.tcx().lookup_trait_def(child);
    let predicates = cx.tcx().lookup_predicates(child);
    let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
    generics.where_predicates.iter().filter_map(|pred| {
        match *pred {
            clean::WherePredicate::BoundPredicate {
                ty: clean::Generic(ref s),
                ref bounds
            } if *s == "Self" => Some(bounds),
            _ => None,
        }
    }).flat_map(|bounds| bounds).any(|bound| {
        let poly_trait = match *bound {
            clean::TraitBound(ref t, _) => t,
            _ => return false,
        };
        match poly_trait.trait_ {
            clean::ResolvedPath { did, .. } => {
                trait_is_same_or_supertrait(cx, did, trait_)
            }
            _ => false,
        }
    })
}
<|endoftext|>


<commit_before>//! Basic syntax highlighting functionality.
//!
//! This module uses librustc_ast's lexer to provide token-based highlighting for
//! the HTML documentation generated by rustdoc.
//!
//! Use the `render_with_highlighting` to highlight some rust code.

use crate::html::escape::Escape;

use std::fmt::Display;
use std::iter::Peekable;

use rustc_lexer::{LiteralKind, TokenKind};
use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol;
use rustc_span::with_default_session_globals;

use super::format::Buffer;

/// Highlights `src`, returning the HTML output.
crate fn render_with_highlighting(
    src: &str,
    out: &mut Buffer,
    class: Option<&str>,
    playground_button: Option<&str>,
    tooltip: Option<(Option<Edition>, &str)>,
    edition: Edition,
) {
    debug!("highlighting: ================\n{}\n==============", src);
    if let Some((edition_info, class)) = tooltip {
        write!(
            out,
            "

ⓘ

",
            class,
            if let Some(edition_info) = edition_info {
                format!(" data-edition=\"{}\"", edition_info)
            } else {
                String::new()
            },
        );
    }

    write_header(out, class);
    write_code(out, &src, edition);
    write_footer(out, playground_button);
}

fn write_header(out: &mut Buffer, class: Option<&str>) {
    write!(out, "

\n", class.unwrap_or_default());
}

fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
    // This replace allows to fix how the code source with DOS backline characters is displayed.
    let src = src.replace("\r\n", "\n");
    Classifier::new(&src, edition).highlight(&mut |highlight| {
        match highlight {
            Highlight::Token { text, class } => string(out, Escape(text), class),
            Highlight::EnterSpan { class } => enter_span(out, class),
            Highlight::ExitSpan => exit_span(out),
        };
    });
}

fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
    write!(out, "
{}
\n", playground_button.unwrap_or_default());
}

/// How a span of text is classified. Mostly corresponds to token kinds.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Class {
    Comment,
    DocComment,
    Attribute,
    KeyWord,
    // Keywords that do pointer/reference stuff.
    RefKeyWord,
    Self_,
    Op,
    Macro,
    MacroNonTerminal,
    String,
    Number,
    Bool,
    Ident,
    Lifetime,
    PreludeTy,
    PreludeVal,
    QuestionMark,
}

impl Class {
    /// Returns the css class expected by rustdoc for each `Class`.
    fn as_html(self) -> &'static str {
        match self {
            Class::Comment => "comment",
            Class::DocComment => "doccomment",
            Class::Attribute => "attribute",
            Class::KeyWord => "kw",
            Class::RefKeyWord => "kw-2",
            Class::Self_ => "self",
            Class::Op => "op",
            Class::Macro => "macro",
            Class::MacroNonTerminal => "macro-nonterminal",
            Class::String => "string",
            Class::Number => "number",
            Class::Bool => "bool-val",
            Class::Ident => "ident",
            Class::Lifetime => "lifetime",
            Class::PreludeTy => "prelude-ty",
            Class::PreludeVal => "prelude-val",
            Class::QuestionMark => "question-mark",
        }
    }
}

enum Highlight<'a> {
    Token { text: &'a str, class: Option<Class> },
    EnterSpan { class: Class },
    ExitSpan,
}

struct TokenIter<'a> {
    src: &'a str,
}

impl Iterator for TokenIter<'a> {
    type Item = (TokenKind, &'a str);
    fn next(&mut self) -> Option<(TokenKind, &'a str)> {
        if self.src.is_empty() {
            return None;
        }
        let token = rustc_lexer::first_token(self.src);
        let (text, rest) = self.src.split_at(token.len);
        self.src = rest;
        Some((token.kind, text))
    }
}

/// Processes program tokens, classifying strings of text by highlighting
/// category (`Class`).
struct Classifier<'a> {
    tokens: Peekable<TokenIter<'a>>,
    in_attribute: bool,
    in_macro: bool,
    in_macro_nonterminal: bool,
    edition: Edition,
}

impl<'a> Classifier<'a> {
    fn new(src: &str, edition: Edition) -> Classifier<'_> {
        let tokens = TokenIter { src }.peekable();
        Classifier {
            tokens,
            in_attribute: false,
            in_macro: false,
            in_macro_nonterminal: false,
            edition,
        }
    }

    /// Exhausts the `Classifier` writing the output into `sink`.
    ///
    /// The general structure for this method is to iterate over each token,
    /// possibly giving it an HTML span with a class specifying what flavor of
    /// token is used.
    fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
        with_default_session_globals(|| {
            while let Some((token, text)) = self.tokens.next() {
                self.advance(token, text, sink);
            }
        })
    }

    /// Single step of highlighting. This will classify `token`, but maybe also
    /// a couple of following ones as well.
    fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) {
        let lookahead = self.peek();
        let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None });
        let class = match token {
            TokenKind::Whitespace => return no_highlight(sink),
            TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => {
                if doc_style.is_some() {
                    Class::DocComment
                } else {
                    Class::Comment
                }
            }
            // Consider this as part of a macro invocation if there was a
            // leading identifier.
            TokenKind::Bang if self.in_macro => {
                self.in_macro = false;
                Class::Macro
            }

            // Assume that '&' or '*' is the reference or dereference operator
            // or a reference or pointer type. Unless, of course, it looks like
            // a logical and or a multiplication operator: `&&` or `* `.
            TokenKind::Star => match lookahead {
                Some(TokenKind::Whitespace) => Class::Op,
                _ => Class::RefKeyWord,
            },
            TokenKind::And => match lookahead {
                Some(TokenKind::And) => {
                    let _and = self.tokens.next();
                    sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
                    return;
                }
                Some(TokenKind::Eq) => {
                    let _eq = self.tokens.next();
                    sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
                    return;
                }
                Some(TokenKind::Whitespace) => Class::Op,
                _ => Class::RefKeyWord,
            },

            // Operators.
            TokenKind::Minus
            | TokenKind::Plus
            | TokenKind::Or
            | TokenKind::Slash
            | TokenKind::Caret
            | TokenKind::Percent
            | TokenKind::Bang
            | TokenKind::Eq
            | TokenKind::Lt
            | TokenKind::Gt => Class::Op,

            // Miscellaneous, no highlighting.
            TokenKind::Dot
            | TokenKind::Semi
            | TokenKind::Comma
            | TokenKind::OpenParen
            | TokenKind::CloseParen
            | TokenKind::OpenBrace
            | TokenKind::CloseBrace
            | TokenKind::OpenBracket
            | TokenKind::At
            | TokenKind::Tilde
            | TokenKind::Colon
            | TokenKind::Unknown => return no_highlight(sink),

            TokenKind::Question => Class::QuestionMark,

            TokenKind::Dollar => match lookahead {
                Some(TokenKind::Ident) => {
                    self.in_macro_nonterminal = true;
                    Class::MacroNonTerminal
                }
                _ => return no_highlight(sink),
            },

            // This might be the start of an attribute. We're going to want to
            // continue highlighting it as an attribute until the ending ']' is
            // seen, so skip out early. Down below we terminate the attribute
            // span when we see the ']'.
            TokenKind::Pound => {
                match lookahead {
                    // Case 1: #![inner_attribute]
                    Some(TokenKind::Bang) => {
                        let _not = self.tokens.next().unwrap();
                        if let Some(TokenKind::OpenBracket) = self.peek() {
                            self.in_attribute = true;
                            sink(Highlight::EnterSpan { class: Class::Attribute });
                        }
                        sink(Highlight::Token { text: "#", class: None });
                        sink(Highlight::Token { text: "!", class: None });
                        return;
                    }
                    // Case 2: #[outer_attribute]
                    Some(TokenKind::OpenBracket) => {
                        self.in_attribute = true;
                        sink(Highlight::EnterSpan { class: Class::Attribute });
                    }
                    _ => (),
                }
                return no_highlight(sink);
            }
            TokenKind::CloseBracket => {
                if self.in_attribute {
                    self.in_attribute = false;
                    sink(Highlight::Token { text: "]", class: None });
                    sink(Highlight::ExitSpan);
                    return;
                }
                return no_highlight(sink);
            }
            TokenKind::Literal { kind, .. } => match kind {
                // Text literals.
                LiteralKind::Byte { .. }
                | LiteralKind::Char { .. }
                | LiteralKind::Str { .. }
                | LiteralKind::ByteStr { .. }
                | LiteralKind::RawStr { .. }
                | LiteralKind::RawByteStr { .. } => Class::String,
                // Number literals.
                LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
            },
            TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => {
                self.in_macro = true;
                Class::Macro
            }
            TokenKind::Ident => match text {
                "ref" | "mut" => Class::RefKeyWord,
                "self" | "Self" => Class::Self_,
                "false" | "true" => Class::Bool,
                "Option" | "Result" => Class::PreludeTy,
                "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
                // Keywords are also included in the identifier set.
                _ if Symbol::intern(text).is_reserved(|| self.edition) => Class::KeyWord,
                _ if self.in_macro_nonterminal => {
                    self.in_macro_nonterminal = false;
                    Class::MacroNonTerminal
                }
                _ => Class::Ident,
            },
            TokenKind::RawIdent => Class::Ident,
            TokenKind::Lifetime { .. } => Class::Lifetime,
        };
        // Anything that didn't return above is the simple case where we the
        // class just spans a single token, so we can use the `string` method.
        sink(Highlight::Token { text, class: Some(class) });
    }

    fn peek(&mut self) -> Option<TokenKind> {
        self.tokens.peek().map(|(toke_kind, _text)| *toke_kind)
    }
}

/// Called when we start processing a span of text that should be highlighted.
/// The `Class` argument specifies how it should be highlighted.
fn enter_span(out: &mut Buffer, klass: Class) {
    write!(out, "", klass.as_html());
}

/// Called at the end of a span of highlighted text.
fn exit_span(out: &mut Buffer) {
    out.write_str("");
}

/// Called for a span of text. If the text should be highlighted differently
/// from the surrounding text, then the `Class` argument will be a value other
/// than `None`.
///
/// The following sequences of callbacks are equivalent:
/// ```plain
///     enter_span(Foo), string("text", None), exit_span()
///     string("text", Foo)
/// ```
/// The latter can be thought of as a shorthand for the former, which is more
/// flexible.
fn string<T: Display>(out: &mut Buffer, text: T, klass: Option<Class>) {
    match klass {
        None => write!(out, "{}", text),
        Some(klass) => write!(out, "{}", klass.as_html(), text),
    }
}

#[cfg(test)]
mod tests;
<commit_msg>rustdoc: highlight macros more efficiently<commit_after>//! Basic syntax highlighting functionality.
//!
//! This module uses librustc_ast's lexer to provide token-based highlighting for
//! the HTML documentation generated by rustdoc.
//!
//! Use the `render_with_highlighting` to highlight some rust code.

use crate::html::escape::Escape;

use std::fmt::Display;
use std::iter::Peekable;

use rustc_lexer::{LiteralKind, TokenKind};
use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol;
use rustc_span::with_default_session_globals;

use super::format::Buffer;

/// Highlights `src`, returning the HTML output.
crate fn render_with_highlighting(
    src: &str,
    out: &mut Buffer,
    class: Option<&str>,
    playground_button: Option<&str>,
    tooltip: Option<(Option<Edition>, &str)>,
    edition: Edition,
) {
    debug!("highlighting: ================\n{}\n==============", src);
    if let Some((edition_info, class)) = tooltip {
        write!(
            out,
            "

ⓘ

",
            class,
            if let Some(edition_info) = edition_info {
                format!(" data-edition=\"{}\"", edition_info)
            } else {
                String::new()
            },
        );
    }

    write_header(out, class);
    write_code(out, &src, edition);
    write_footer(out, playground_button);
}

fn write_header(out: &mut Buffer, class: Option<&str>) {
    write!(out, "

\n", class.unwrap_or_default());
}

fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
    // This replace allows to fix how the code source with DOS backline characters is displayed.
    let src = src.replace("\r\n", "\n");
    Classifier::new(&src, edition).highlight(&mut |highlight| {
        match highlight {
            Highlight::Token { text, class } => string(out, Escape(text), class),
            Highlight::EnterSpan { class } => enter_span(out, class),
            Highlight::ExitSpan => exit_span(out),
        };
    });
}

fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
    write!(out, "
{}
\n", playground_button.unwrap_or_default());
}

/// How a span of text is classified. Mostly corresponds to token kinds.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Class {
    Comment,
    DocComment,
    Attribute,
    KeyWord,
    // Keywords that do pointer/reference stuff.
    RefKeyWord,
    Self_,
    Op,
    Macro,
    MacroNonTerminal,
    String,
    Number,
    Bool,
    Ident,
    Lifetime,
    PreludeTy,
    PreludeVal,
    QuestionMark,
}

impl Class {
    /// Returns the css class expected by rustdoc for each `Class`.
    fn as_html(self) -> &'static str {
        match self {
            Class::Comment => "comment",
            Class::DocComment => "doccomment",
            Class::Attribute => "attribute",
            Class::KeyWord => "kw",
            Class::RefKeyWord => "kw-2",
            Class::Self_ => "self",
            Class::Op => "op",
            Class::Macro => "macro",
            Class::MacroNonTerminal => "macro-nonterminal",
            Class::String => "string",
            Class::Number => "number",
            Class::Bool => "bool-val",
            Class::Ident => "ident",
            Class::Lifetime => "lifetime",
            Class::PreludeTy => "prelude-ty",
            Class::PreludeVal => "prelude-val",
            Class::QuestionMark => "question-mark",
        }
    }
}

enum Highlight<'a> {
    Token { text: &'a str, class: Option<Class> },
    EnterSpan { class: Class },
    ExitSpan,
}

struct TokenIter<'a> {
    src: &'a str,
}

impl Iterator for TokenIter<'a> {
    type Item = (TokenKind, &'a str);
    fn next(&mut self) -> Option<(TokenKind, &'a str)> {
        if self.src.is_empty() {
            return None;
        }
        let token = rustc_lexer::first_token(self.src);
        let (text, rest) = self.src.split_at(token.len);
        self.src = rest;
        Some((token.kind, text))
    }
}

/// Processes program tokens, classifying strings of text by highlighting
/// category (`Class`).
struct Classifier<'a> {
    tokens: Peekable<TokenIter<'a>>,
    in_attribute: bool,
    in_macro: bool,
    in_macro_nonterminal: bool,
    edition: Edition,
}

impl<'a> Classifier<'a> {
    fn new(src: &str, edition: Edition) -> Classifier<'_> {
        let tokens = TokenIter { src }.peekable();
        Classifier {
            tokens,
            in_attribute: false,
            in_macro: false,
            in_macro_nonterminal: false,
            edition,
        }
    }

    /// Exhausts the `Classifier` writing the output into `sink`.
    ///
    /// The general structure for this method is to iterate over each token,
    /// possibly giving it an HTML span with a class specifying what flavor of
    /// token is used.
    fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
        with_default_session_globals(|| {
            while let Some((token, text)) = self.tokens.next() {
                self.advance(token, text, sink);
            }
        })
    }

    /// Single step of highlighting. This will classify `token`, but maybe also
    /// a couple of following ones as well.
    fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) {
        let lookahead = self.peek();
        let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None });
        let class = match token {
            TokenKind::Whitespace => return no_highlight(sink),
            TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => {
                if doc_style.is_some() {
                    Class::DocComment
                } else {
                    Class::Comment
                }
            }
            // Consider this as part of a macro invocation if there was a
            // leading identifier.
            TokenKind::Bang if self.in_macro => {
                self.in_macro = false;
                sink(Highlight::Token { text, class: None });
                sink(Highlight::ExitSpan);
                return;
            }

            // Assume that '&' or '*' is the reference or dereference operator
            // or a reference or pointer type. Unless, of course, it looks like
            // a logical and or a multiplication operator: `&&` or `* `.
            TokenKind::Star => match lookahead {
                Some(TokenKind::Whitespace) => Class::Op,
                _ => Class::RefKeyWord,
            },
            TokenKind::And => match lookahead {
                Some(TokenKind::And) => {
                    let _and = self.tokens.next();
                    sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
                    return;
                }
                Some(TokenKind::Eq) => {
                    let _eq = self.tokens.next();
                    sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
                    return;
                }
                Some(TokenKind::Whitespace) => Class::Op,
                _ => Class::RefKeyWord,
            },

            // Operators.
            TokenKind::Minus
            | TokenKind::Plus
            | TokenKind::Or
            | TokenKind::Slash
            | TokenKind::Caret
            | TokenKind::Percent
            | TokenKind::Bang
            | TokenKind::Eq
            | TokenKind::Lt
            | TokenKind::Gt => Class::Op,

            // Miscellaneous, no highlighting.
            TokenKind::Dot
            | TokenKind::Semi
            | TokenKind::Comma
            | TokenKind::OpenParen
            | TokenKind::CloseParen
            | TokenKind::OpenBrace
            | TokenKind::CloseBrace
            | TokenKind::OpenBracket
            | TokenKind::At
            | TokenKind::Tilde
            | TokenKind::Colon
            | TokenKind::Unknown => return no_highlight(sink),

            TokenKind::Question => Class::QuestionMark,

            TokenKind::Dollar => match lookahead {
                Some(TokenKind::Ident) => {
                    self.in_macro_nonterminal = true;
                    Class::MacroNonTerminal
                }
                _ => return no_highlight(sink),
            },

            // This might be the start of an attribute. We're going to want to
            // continue highlighting it as an attribute until the ending ']' is
            // seen, so skip out early. Down below we terminate the attribute
            // span when we see the ']'.
            TokenKind::Pound => {
                match lookahead {
                    // Case 1: #![inner_attribute]
                    Some(TokenKind::Bang) => {
                        let _not = self.tokens.next().unwrap();
                        if let Some(TokenKind::OpenBracket) = self.peek() {
                            self.in_attribute = true;
                            sink(Highlight::EnterSpan { class: Class::Attribute });
                        }
                        sink(Highlight::Token { text: "#", class: None });
                        sink(Highlight::Token { text: "!", class: None });
                        return;
                    }
                    // Case 2: #[outer_attribute]
                    Some(TokenKind::OpenBracket) => {
                        self.in_attribute = true;
                        sink(Highlight::EnterSpan { class: Class::Attribute });
                    }
                    _ => (),
                }
                return no_highlight(sink);
            }
            TokenKind::CloseBracket => {
                if self.in_attribute {
                    self.in_attribute = false;
                    sink(Highlight::Token { text: "]", class: None });
                    sink(Highlight::ExitSpan);
                    return;
                }
                return no_highlight(sink);
            }
            TokenKind::Literal { kind, .. } => match kind {
                // Text literals.
                LiteralKind::Byte { .. }
                | LiteralKind::Char { .. }
                | LiteralKind::Str { .. }
                | LiteralKind::ByteStr { .. }
                | LiteralKind::RawStr { .. }
                | LiteralKind::RawByteStr { .. } => Class::String,
                // Number literals.
                LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
            },
            TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => {
                self.in_macro = true;
                sink(Highlight::EnterSpan { class: Class::Macro });
                sink(Highlight::Token { text, class: None });
                return;
            }
            TokenKind::Ident => match text {
                "ref" | "mut" => Class::RefKeyWord,
                "self" | "Self" => Class::Self_,
                "false" | "true" => Class::Bool,
                "Option" | "Result" => Class::PreludeTy,
                "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
                // Keywords are also included in the identifier set.
                _ if Symbol::intern(text).is_reserved(|| self.edition) => Class::KeyWord,
                _ if self.in_macro_nonterminal => {
                    self.in_macro_nonterminal = false;
                    Class::MacroNonTerminal
                }
                _ => Class::Ident,
            },
            TokenKind::RawIdent => Class::Ident,
            TokenKind::Lifetime { .. } => Class::Lifetime,
        };
        // Anything that didn't return above is the simple case where we the
        // class just spans a single token, so we can use the `string` method.
        sink(Highlight::Token { text, class: Some(class) });
    }

    fn peek(&mut self) -> Option<TokenKind> {
        self.tokens.peek().map(|(toke_kind, _text)| *toke_kind)
    }
}

/// Called when we start processing a span of text that should be highlighted.
/// The `Class` argument specifies how it should be highlighted.
fn enter_span(out: &mut Buffer, klass: Class) {
    write!(out, "", klass.as_html());
}

/// Called at the end of a span of highlighted text.
fn exit_span(out: &mut Buffer) {
    out.write_str("");
}

/// Called for a span of text. If the text should be highlighted differently
/// from the surrounding text, then the `Class` argument will be a value other
/// than `None`.
///
/// The following sequences of callbacks are equivalent:
/// ```plain
///     enter_span(Foo), string("text", None), exit_span()
///     string("text", Foo)
/// ```
/// The latter can be thought of as a shorthand for the former, which is more
/// flexible.
fn string<T: Display>(out: &mut Buffer, text: T, klass: Option<Class>) {
    match klass {
        None => write!(out, "{}", text),
        Some(klass) => write!(out, "{}", klass.as_html(), text),
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>