<commit_before>use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ops::Deref;

use types;
use types::{AliasData, Type, Generic, TcType, TypeEnv, merge};
use symbol::Symbol;

pub struct AliasInstantiator<'a> {
    pub inst: &'a Instantiator,
    pub env: &'a TypeEnv,
}

impl<'a> AliasInstantiator<'a> {
    pub fn new(inst: &'a Instantiator, env: &'a TypeEnv) -> AliasInstantiator<'a> {
        AliasInstantiator {
            inst: inst,
            env: env,
        }
    }

    /// Removes type aliases from `typ` until it is an actual type
    pub fn remove_aliases(&self, mut typ: TcType) -> TcType {
        while let Ok(Some(new)) = self.maybe_remove_alias(&typ) {
            typ = new;
        }
        typ
    }

    pub fn remove_aliases_cow<'t>(&self, typ: &'t TcType) -> Cow<'t, TcType> {
        let mut typ = match self.maybe_remove_alias(typ) {
            Ok(Some(new)) => new,
            _ => return Cow::Borrowed(typ),
        };
        while let Ok(Some(new)) = self.maybe_remove_alias(&typ) {
            typ = new;
        }
        Cow::Owned(typ)
    }

    pub fn remove_alias(&self, typ: TcType) -> TcType {
        self.maybe_remove_alias(&typ).unwrap_or(None).unwrap_or(typ)
    }

    pub fn maybe_remove_alias(&self, typ: &TcType) -> Result<Option<TcType>, ()> {
        let maybe_alias = match **typ {
            Type::Alias(ref alias) if alias.args.is_empty() => Some(alias),
            Type::Data(ref alias, ref args) => {
                match **alias {
                    Type::Alias(ref alias) if alias.args.len() == args.len() => Some(alias),
                    _ => None,
                }
            }
            _ => None,
        };
        let (id, args) = match typ.as_alias() {
            Some(x) => x,
            None => return Ok(None),
        };
        let maybe_alias = maybe_alias.or_else(|| {
            self.env
                .find_type_info(&id)
                .map(|a| &**a)
        });
        let alias = match maybe_alias {
            Some(alias) => alias,
            None => return Ok(None),
        };
        self.type_of_alias(alias, args)
    }

    pub fn type_of_alias(&self,
                         alias: &AliasData<Symbol, TcType>,
                         arguments: &[TcType])
                         -> Result<Option<TcType>, ()> {
        let args = &alias.args;
        let mut typ = match alias.typ {
            Some(ref typ) => typ.clone(),
            None => return Ok(None),
        };
        // It is ok to take the aliased type only if the alias is fully applied or if it
        // the missing argument only appear in order at the end of the alias
        // i.e
        // type Test a b c = Type (a Int) b c
        //
        // Test a b == Type (a Int) b
        // Test a == Type (a Int)
        // Test == ??? (Impossible to do a sane substitution)

        let ok_substitution = match *typ.clone() {
            Type::Data(ref d, ref arg_types) => {
                let allowed_missing_args = arg_types.iter()
                    .rev()
                    .zip(args.iter().rev())
                    .take_while(|&(l, r)| {
                        match **l {
                            Type::Generic(ref g) => g == r,
                            _ => false,
                        }
                    })
                    .count();
                if args.len() - arguments.len() <= allowed_missing_args {
                    // Remove the args at the end of the aliased type
                    let arg_types: Vec<_> = arg_types.iter()
                        .take(arg_types.len() - (args.len() - arguments.len()))
                        .cloned()
                        .collect();
                    typ = Type::data(d.clone(), arg_types);
                    true
                } else {
                    false
                }
            }
            _ => arguments.len() == args.len(),
        };
        if !ok_substitution {
            return Ok(None);
        }
        let typ = self.inst.instantiate_with(typ, arguments, &args);
        Ok(Some(typ))
    }
}

#[derive(Debug, Default)]
pub struct Instantiator {
    pub named_variables: RefCell<HashMap<Symbol, TcType>>,
}

impl Instantiator {
    pub fn new() -> Instantiator {
        Instantiator { named_variables: RefCell::new(HashMap::new()) }
    }

    fn variable_for(&self,
                    generic: &Generic<Symbol>,
                    on_unbound: &mut FnMut(&Symbol) -> TcType)
                    -> TcType {
        let mut variables = self.named_variables.borrow_mut();
        let var = match variables.entry(generic.id.clone()) {
            Entry::Vacant(entry) => {
                let t = on_unbound(&generic.id);
                entry.insert(t).clone()
            }
            Entry::Occupied(entry) => entry.get().clone(),
        };
        let mut var = (*var).clone();
        if let Type::Variable(ref mut var) = var {
            var.kind = generic.kind.clone();
        }
        TcType::from(var)
    }

    /// Instantiates a type, replacing all generic variables with fresh type variables
    pub fn instantiate<F>(&mut self, typ: &TcType, on_unbound: F) -> TcType
        where F: FnMut(&Symbol) -> TcType
    {
        self.named_variables.borrow_mut().clear();
        self.instantiate_(typ, on_unbound)
    }

    pub fn instantiate_<F>(&mut self, typ: &TcType, mut on_unbound: F) -> TcType
        where F: FnMut(&Symbol) -> TcType
    {
        instantiate(typ.clone(),
                    |id| Some(self.variable_for(id, &mut on_unbound)))
    }

    fn instantiate_with(&self,
                        typ: TcType,
                        arguments: &[TcType],
                        args: &[Generic<Symbol>])
                        -> TcType {
        self.named_variables.borrow_mut().clear();
        instantiate(typ, |gen| {
            // Replace the generic variable with the type from the list
            // or if it is not found the make a fresh variable
            args.iter()
                .zip(arguments)
                .find(|&(arg, _)| arg.id == gen.id)
                .map(|(_, typ)| typ.clone())
        })
    }
}

pub fn instantiate<F>(typ: TcType, mut f: F) -> TcType
    where F: FnMut(&Generic<Symbol>) -> Option<TcType>
{
    walk_move_type_no_recurse(typ,
                              &mut |typ| {
                                  match *typ {
                                      Type::Generic(ref x) => f(x),
                                      _ => None,
                                  }
                              })
}

pub fn unroll_app(typ: &Type<Symbol>) -> Option<TcType> {
    let mut args = Vec::new();
    let mut current = typ;
    loop {
        match *current {
            Type::App(ref l, ref r) => {
                args.push(r.clone());
                current = &**l;
            }
            Type::Data(ref l, ref rest) => {
                args.extend(rest.iter().rev().cloned());
                args.reverse();
                return Some(Type::data(l.clone(), args));
            }
            _ => return None,
        }
    }
}

/// Walks through a type replacing some types
/// If a type is replaced the new type will not be traversed
fn walk_move_type_no_recurse<F, I, T>(typ: T, f: &mut F) -> T
    where F: FnMut(&Type<I, T>) -> Option<T>,
          T: Deref<Target = Type<I, T>> + From<Type<I, T>> + Clone,
          I: Clone
{
    walk_move_type2(&typ, f).unwrap_or(typ)
}

fn walk_move_type2<F, I, T>(typ: &Type<I, T>, f: &mut F) -> Option<T>
    where F: FnMut(&Type<I, T>) -> Option<T>,
          T: Deref<Target = Type<I, T>> + From<Type<I, T>> + Clone,
          I: Clone
{
    let new = f(typ);
    let result = match new {
        Some(new_type) => return Some(new_type),
        None => {
            let typ = new.as_ref().map_or(typ, |t| &**t);
            match *typ {
                Type::Data(ref id, ref args) => {
                    let new_args = walk_move_types(args.iter(), |t| walk_move_type2(t, f));
                    merge(id, walk_move_type2(id, f), args, new_args, Type::data)
                }
                Type::Array(ref inner) => walk_move_type2(&**inner, f).map(Type::array),
                Type::Function(ref args, ref ret) => {
                    let new_args = walk_move_types(args.iter(), |t| walk_move_type2(t, f));
                    merge(args, new_args, ret, walk_move_type2(ret, f), Type::function)
                }
                Type::Record { ref types, ref fields } => {
                    let new_types = None;
                    let new_fields = walk_move_types(fields.iter(), |field| {
                        walk_move_type2(&field.typ, f).map(|typ| {
                            types::Field {
                                name: field.name.clone(),
                                typ: typ,
                            }
                        })
                    });
                    merge(types, new_types, fields, new_fields, Type::record)
                }
                Type::App(ref l, ref r) => {
                    merge(l,
                          walk_move_type2(l, f),
                          r,
                          walk_move_type2(r, f),
                          Type::app)
                }
                Type::Variants(ref variants) => {
                    walk_move_types(variants.iter(),
                                    |v| walk_move_type2(&v.1, f).map(|t| (v.0.clone(), t)))
                        .map(Type::variants)
                }
                Type::Builtin(_) |
                Type::Variable(_) |
                Type::Generic(_) |
                Type::Id(_) |
                Type::Alias(_) => None,
            }
        }
    };
    result.or(new)
}
fn walk_move_types<'a, I, F, T>(types: I, mut f: F) -> Option<Vec<T>>
    where I: Iterator<Item = &'a T>,
          F: FnMut(&'a T) -> Option<T>,
          T: Clone + 'a
{
    let mut out = Vec::new();
    walk_move_types2(types, false, &mut out, &mut f);
    if out.is_empty() {
        None
    } else {
        out.reverse();
        Some(out)
    }
}
fn walk_move_types2<'a, I, F, T>(mut types: I, replaced: bool, output: &mut Vec<T>, f: &mut F)
    where I: Iterator<Item = &'a T>,
          F: FnMut(&'a T) -> Option<T>,
          T: Clone + 'a
{
    if let Some(typ) = types.next() {
        let new = f(typ);
        walk_move_types2(types, replaced || new.is_some(), output, f);
        match new {
            Some(typ) => {
                output.push(typ);
            }
            None if replaced || !output.is_empty() => {
                output.push(typ.clone());
            }
            None => (),
        }
    }
}
<commit_msg>feat(instantiate): Unroll Data((->), [a, b]) into Function(a, b)<commit_after>use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ops::Deref;

use types;
use types::{AliasData, BuiltinType, Type, Generic, TcType, TypeEnv, merge};
use symbol::Symbol;

pub struct AliasInstantiator<'a> {
    pub inst: &'a Instantiator,
    pub env: &'a TypeEnv,
}

impl<'a> AliasInstantiator<'a> {
    pub fn new(inst: &'a Instantiator, env: &'a TypeEnv) -> AliasInstantiator<'a> {
        AliasInstantiator {
            inst: inst,
            env: env,
        }
    }

    /// Removes type aliases from `typ` until it is an actual type
    pub fn remove_aliases(&self, mut typ: TcType) -> TcType {
        while let Ok(Some(new)) = self.maybe_remove_alias(&typ) {
            typ = new;
        }
        typ
    }

    pub fn remove_aliases_cow<'t>(&self, typ: &'t TcType) -> Cow<'t, TcType> {
        let mut typ = match self.maybe_remove_alias(typ) {
            Ok(Some(new)) => new,
            _ => return Cow::Borrowed(typ),
        };
        while let Ok(Some(new)) = self.maybe_remove_alias(&typ) {
            typ = new;
        }
        Cow::Owned(typ)
    }

    pub fn remove_alias(&self, typ: TcType) -> TcType {
        self.maybe_remove_alias(&typ).unwrap_or(None).unwrap_or(typ)
    }

    pub fn maybe_remove_alias(&self, typ: &TcType) -> Result<Option<TcType>, ()> {
        let maybe_alias = match **typ {
            Type::Alias(ref alias) if alias.args.is_empty() => Some(alias),
            Type::Data(ref alias, ref args) => {
                match **alias {
                    Type::Alias(ref alias) if alias.args.len() == args.len() => Some(alias),
                    _ => None,
                }
            }
            _ => None,
        };
        let (id, args) = match typ.as_alias() {
            Some(x) => x,
            None => return Ok(None),
        };
        let maybe_alias = maybe_alias.or_else(|| {
            self.env
                .find_type_info(&id)
                .map(|a| &**a)
        });
        let alias = match maybe_alias {
            Some(alias) => alias,
            None => return Ok(None),
        };
        self.type_of_alias(alias, args)
    }

    pub fn type_of_alias(&self,
                         alias: &AliasData<Symbol, TcType>,
                         arguments: &[TcType])
                         -> Result<Option<TcType>, ()> {
        let args = &alias.args;
        let mut typ = match alias.typ {
            Some(ref typ) => typ.clone(),
            None => return Ok(None),
        };
        // It is ok to take the aliased type only if the alias is fully applied or if it
        // the missing argument only appear in order at the end of the alias
        // i.e
        // type Test a b c = Type (a Int) b c
        //
        // Test a b == Type (a Int) b
        // Test a == Type (a Int)
        // Test == ??? (Impossible to do a sane substitution)

        let ok_substitution = match *typ.clone() {
            Type::Data(ref d, ref arg_types) => {
                let allowed_missing_args = arg_types.iter()
                    .rev()
                    .zip(args.iter().rev())
                    .take_while(|&(l, r)| {
                        match **l {
                            Type::Generic(ref g) => g == r,
                            _ => false,
                        }
                    })
                    .count();
                if args.len() - arguments.len() <= allowed_missing_args {
                    // Remove the args at the end of the aliased type
                    let arg_types: Vec<_> = arg_types.iter()
                        .take(arg_types.len() - (args.len() - arguments.len()))
                        .cloned()
                        .collect();
                    typ = Type::data(d.clone(), arg_types);
                    true
                } else {
                    false
                }
            }
            _ => arguments.len() == args.len(),
        };
        if !ok_substitution {
            return Ok(None);
        }
        let typ = self.inst.instantiate_with(typ, arguments, &args);
        Ok(Some(typ))
    }
}

#[derive(Debug, Default)]
pub struct Instantiator {
    pub named_variables: RefCell<HashMap<Symbol, TcType>>,
}

impl Instantiator {
    pub fn new() -> Instantiator {
        Instantiator { named_variables: RefCell::new(HashMap::new()) }
    }

    fn variable_for(&self,
                    generic: &Generic<Symbol>,
                    on_unbound: &mut FnMut(&Symbol) -> TcType)
                    -> TcType {
        let mut variables = self.named_variables.borrow_mut();
        let var = match variables.entry(generic.id.clone()) {
            Entry::Vacant(entry) => {
                let t = on_unbound(&generic.id);
                entry.insert(t).clone()
            }
            Entry::Occupied(entry) => entry.get().clone(),
        };
        let mut var = (*var).clone();
        if let Type::Variable(ref mut var) = var {
            var.kind = generic.kind.clone();
        }
        TcType::from(var)
    }

    /// Instantiates a type, replacing all generic variables with fresh type variables
    pub fn instantiate<F>(&mut self, typ: &TcType, on_unbound: F) -> TcType
        where F: FnMut(&Symbol) -> TcType
    {
        self.named_variables.borrow_mut().clear();
        self.instantiate_(typ, on_unbound)
    }

    pub fn instantiate_<F>(&mut self, typ: &TcType, mut on_unbound: F) -> TcType
        where F: FnMut(&Symbol) -> TcType
    {
        instantiate(typ.clone(),
                    |id| Some(self.variable_for(id, &mut on_unbound)))
    }

    fn instantiate_with(&self,
                        typ: TcType,
                        arguments: &[TcType],
                        args: &[Generic<Symbol>])
                        -> TcType {
        self.named_variables.borrow_mut().clear();
        instantiate(typ, |gen| {
            // Replace the generic variable with the type from the list
            // or if it is not found the make a fresh variable
            args.iter()
                .zip(arguments)
                .find(|&(arg, _)| arg.id == gen.id)
                .map(|(_, typ)| typ.clone())
        })
    }
}

pub fn instantiate<F>(typ: TcType, mut f: F) -> TcType
    where F: FnMut(&Generic<Symbol>) -> Option<TcType>
{
    walk_move_type_no_recurse(typ,
                              &mut |typ| {
                                  match *typ {
                                      Type::Generic(ref x) => f(x),
                                      _ => None,
                                  }
                              })
}

/// Removes layers of `Type::App` and `Type::Data`.
///
/// Example:
///
/// ```
/// use gluon_base::types::{Type, TcType, BuiltinType};
/// use gluon_base::instantiate::unroll_app;
/// let i: TcType = Type::int();
/// let s: TcType = Type::string();
/// assert_eq!(unroll_app(&*Type::app(Type::app(i.clone(), s.clone()), i.clone())),
///            Some(Type::data(i.clone(), vec![s.clone(), i.clone()])));
/// assert_eq!(unroll_app(&*Type::data(Type::app(i.clone(), i.clone()), vec![s.clone()])),
///            Some(Type::data(i.clone(), vec![i.clone(), s.clone()])));
/// let f: TcType = Type::builtin(BuiltinType::Function);
/// assert_eq!(unroll_app(&*Type::data(Type::app(f.clone(), i.clone()), vec![s.clone()])),
///            Some(Type::function(vec![i.clone()], s.clone())));
/// ```
pub fn unroll_app(typ: &Type<Symbol>) -> Option<TcType> {
    let mut args = Vec::new();
    let mut current = match *typ {
        Type::App(ref l, ref r) => {
            args.push(r.clone());
            l
        }
        Type::Data(ref l, ref rest) => {
            args.extend(rest.iter().rev().cloned());
            l
        }
        _ => return None,
    };
    loop {
        match **current {
            Type::App(ref l, ref r) => {
                args.push(r.clone());
                current = l;
            }
            Type::Data(ref l, ref rest) => {
                args.extend(rest.iter().rev().cloned());
                current = l;
            }
            _ => break,
        }
    }
    if args.is_empty() {
        None
    }
    else {
        args.reverse();
        Some(match **current {
            Type::Builtin(BuiltinType::Function) if args.len() == 2 => {
                let ret = args.pop().unwrap();
                Type::function(args, ret)
            }
            _ => Type::data(current.clone(), args),
        })
    }
}

/// Walks through a type replacing some types
/// If a type is replaced the new type will not be traversed
fn walk_move_type_no_recurse<F, I, T>(typ: T, f: &mut F) -> T
    where F: FnMut(&Type<I, T>) -> Option<T>,
          T: Deref<Target = Type<I, T>> + From<Type<I, T>> + Clone,
          I: Clone
{
    walk_move_type2(&typ, f).unwrap_or(typ)
}

fn walk_move_type2<F, I, T>(typ: &Type<I, T>, f: &mut F) -> Option<T>
    where F: FnMut(&Type<I, T>) -> Option<T>,
          T: Deref<Target = Type<I, T>> + From<Type<I, T>> + Clone,
          I: Clone
{
    let new = f(typ);
    let result = match new {
        Some(new_type) => return Some(new_type),
        None => {
            let typ = new.as_ref().map_or(typ, |t| &**t);
            match *typ {
                Type::Data(ref id, ref args) => {
                    let new_args = walk_move_types(args.iter(), |t| walk_move_type2(t, f));
                    merge(id, walk_move_type2(id, f), args, new_args, Type::data)
                }
                Type::Array(ref inner) => walk_move_type2(&**inner, f).map(Type::array),
                Type::Function(ref args, ref ret) => {
                    let new_args = walk_move_types(args.iter(), |t| walk_move_type2(t, f));
                    merge(args, new_args, ret, walk_move_type2(ret, f), Type::function)
                }
                Type::Record { ref types, ref fields } => {
                    let new_types = None;
                    let new_fields = walk_move_types(fields.iter(), |field| {
                        walk_move_type2(&field.typ, f).map(|typ| {
                            types::Field {
                                name: field.name.clone(),
                                typ: typ,
                            }
                        })
                    });
                    merge(types, new_types, fields, new_fields, Type::record)
                }
                Type::App(ref l, ref r) => {
                    merge(l,
                          walk_move_type2(l, f),
                          r,
                          walk_move_type2(r, f),
                          Type::app)
                }
                Type::Variants(ref variants) => {
                    walk_move_types(variants.iter(),
                                    |v| walk_move_type2(&v.1, f).map(|t| (v.0.clone(), t)))
                        .map(Type::variants)
                }
                Type::Builtin(_) |
                Type::Variable(_) |
                Type::Generic(_) |
                Type::Id(_) |
                Type::Alias(_) => None,
            }
        }
    };
    result.or(new)
}
fn walk_move_types<'a, I, F, T>(types: I, mut f: F) -> Option<Vec<T>>
    where I: Iterator<Item = &'a T>,
          F: FnMut(&'a T) -> Option<T>,
          T: Clone + 'a
{
    let mut out = Vec::new();
    walk_move_types2(types, false, &mut out, &mut f);
    if out.is_empty() {
        None
    } else {
        out.reverse();
        Some(out)
    }
}
fn walk_move_types2<'a, I, F, T>(mut types: I, replaced: bool, output: &mut Vec<T>, f: &mut F)
    where I: Iterator<Item = &'a T>,
          F: FnMut(&'a T) -> Option<T>,
          T: Clone + 'a
{
    if let Some(typ) = types.next() {
        let new = f(typ);
        walk_move_types2(types, replaced || new.is_some(), output, f);
        match new {
            Some(typ) => {
                output.push(typ);
            }
            None if replaced || !output.is_empty() => {
                output.push(typ.clone());
            }
            None => (),
        }
    }
}
<|endoftext|>


<commit_before>use super::{Hashes, Index, Mapper, Record, Records, Result, TransactionRecord};
use mysql;
use std::collections::HashMap;
use std::collections::btree_map::{BTreeMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockWriteGuard};

pub struct TransactionMapper {
  counter: Mutex<u64>,
  records: RwLock<Records<TransactionRecord>>,
  hashes: RwLock<Hashes>,
  indices: [RwLock<Records<Index>>; 2],
}

type FetchManyResult = Result<
  Vec<(u64, String, Arc<Mutex<TransactionRecord>>)>,
>;

type FetchIndexResult<'a> = Result<
  (
    MutexGuard<'a, Index>,
    Vec<(u64, Arc<Mutex<TransactionRecord>>)>,
  ),
>;

impl Mapper for TransactionMapper {
  type Record = TransactionRecord;

  fn new(conn: &mut mysql::Conn, retry_interval: u64) -> Result<Self> {
    let counter = Self::init_counter(
      conn,
      retry_interval,
      r"SELECT id_tx FROM tx ORDER BY id_tx DESC LIMIT 1",
    )?;
    let records = RwLock::new(BTreeMap::new());
    let hashes = RwLock::new(HashMap::new());
    let indices = [RwLock::new(BTreeMap::new()), RwLock::new(BTreeMap::new())];
    Ok(Self {
      counter,
      records,
      hashes,
      indices,
    })
  }

  fn counter(&self) -> &Mutex<u64> {
    &self.counter
  }

  fn records(&self) -> &RwLock<Records<TransactionRecord>> {
    &self.records
  }

  fn hashes(&self) -> &RwLock<Hashes> {
    &self.hashes
  }

  fn indices(&self) -> &[RwLock<Records<Index>>] {
    &self.indices
  }

  fn fill_indices(
    indices: &mut [RwLockWriteGuard<Records<Index>>],
    record: &TransactionRecord,
    skip_index: Option<(usize, u64)>,
  ) {
    let inner = if record.is_persisted() {
      None
    } else {
      Some(Vec::new())
    };
    indices[0].insert(record.id(), Arc::new(Mutex::new(inner.clone())));
    indices[1].insert(record.id(), Arc::new(Mutex::new(inner)));
    if let Some(id_trunk) = record.id_trunk() {
      match skip_index {
        Some((0, id)) if id == id_trunk => {}
        _ => if let Some(index) = indices[0].get(&id_trunk) {
          debug!("Mutex lock");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          record.fill_index(&mut index);
        },
      }
    }
    if let Some(id_branch) = record.id_branch() {
      match skip_index {
        Some((1, id)) if id == id_branch => {}
        _ => if let Some(index) = indices[1].get(&id_branch) {
          debug!("Mutex lock");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          record.fill_index(&mut index);
        },
      }
    }
  }
}

impl TransactionMapper {
  pub fn fetch_many(
    &self,
    conn: &mut mysql::Conn,
    mut input: Vec<&str>,
  ) -> FetchManyResult {
    input.dedup();
    let cached = {
      debug!("Mutex lock");
      let records = self.records.read().unwrap();
      debug!("Mutex lock/acquire");
      let hashes = self.hashes.read().unwrap();
      debug!("Mutex acquire");
      input
        .iter()
        .filter_map(|&hash| {
          hashes
            .get(hash)
            .and_then(|&id| records.get(&id).map(|x| (hash, (id, x.clone()))))
        })
        .collect::<HashMap<_, _>>()
    };
    let missing = input
      .iter()
      .filter(|&hash| !cached.contains_key(hash))
      .cloned()
      .collect::<Vec<_>>();
    let found = TransactionRecord::find_by_hashes(conn, missing)?;
    debug!("Mutex lock");
    let mut records = self.records.write().unwrap();
    debug!("Mutex lock/acquire");
    let mut hashes = self.hashes.write().unwrap();
    debug!("Mutex lock/acquire");
    let mut indices = self.lock_indices();
    debug!("Mutex acquire");
    let mut output = input
      .into_iter()
      .map(|hash| {
        cached
          .get(hash)
          .map(|&(id_tx, ref record)| {
            (id_tx, hash.to_owned(), record.clone())
          })
          .unwrap_or_else(|| {
            hashes
              .get(hash)
              .and_then(|&id_tx| {
                records
                  .get(&id_tx)
                  .map(|record| (id_tx, hash.to_owned(), record.clone()))
              })
              .unwrap_or_else(|| {
                let record = found
                  .iter()
                  .find(|record| record.hash() == hash)
                  .cloned()
                  .unwrap_or_else(|| {
                    TransactionRecord::placeholder(
                      hash.to_owned(),
                      self.next_id(),
                    )
                  });
                let id_tx = record.id();
                hashes.insert(hash.to_owned(), id_tx);
                Self::fill_indices(&mut indices, &record, None);
                let wrapper = Arc::new(Mutex::new(record));
                records.insert(id_tx, wrapper.clone());
                (id_tx, hash.to_owned(), wrapper)
              })
          })
      })
      .collect::<Vec<_>>();
    output.sort_unstable_by_key(|&(id_tx, _, _)| id_tx);
    Ok(output)
  }

  pub fn trunk_index(&self, id: u64) -> Option<Arc<Mutex<Index>>> {
    debug!("Mutex lock");
    let trunks = self.indices[0].read().unwrap();
    debug!("Mutex acquire");
    trunks.get(&id).cloned()
  }

  pub fn branch_index(&self, id: u64) -> Option<Arc<Mutex<Index>>> {
    debug!("Mutex lock");
    let branches = self.indices[1].read().unwrap();
    debug!("Mutex acquire");
    branches.get(&id).cloned()
  }

  pub fn fetch_trunk<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(
      conn,
      id,
      index,
      Some((0, id)),
      TransactionRecord::find_trunk,
    )
  }

  pub fn fetch_branch<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(
      conn,
      id,
      index,
      Some((1, id)),
      TransactionRecord::find_branch,
    )
  }

  pub fn fetch_bundle<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(conn, id, index, None, TransactionRecord::find_bundle)
  }

  fn fetch_index<'a, F>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
    skip_index: Option<(usize, u64)>,
    f: F,
  ) -> FetchIndexResult<'a>
  where
    F: Fn(&mut mysql::Conn, u64)
      -> Result<Vec<TransactionRecord>>,
  {
    'outer: loop {
      {
        let missing = {
          debug!("Mutex lock");
          let records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let index = index.lock().unwrap();
          debug!("Mutex acquire");
          index.as_ref().map(|index| {
            index
              .iter()
              .filter(|id_tx| !records.contains_key(id_tx))
              .cloned()
              .collect::<Vec<_>>()
          })
        };
        if let Some(missing) = missing {
          let found = TransactionRecord::find_by_ids(conn, &missing)?;
          debug!("Mutex lock");
          let mut records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut hashes = self.hashes.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut indices = self.lock_indices();
          debug!("Mutex lock/acquire");
          let index = index.lock().unwrap();
          debug!("Mutex acquire");
          if index.is_some() {
            let mut results = Vec::new();
            if let Some(ref index) = *index {
              for &id_tx in index {
                let record = match records.entry(id_tx) {
                  Entry::Occupied(entry) => (id_tx, entry.get().clone()),
                  Entry::Vacant(entry) => {
                    match found.iter().find(|record| record.id() == id_tx) {
                      Some(record) => {
                        let id_tx = record.id();
                        hashes.insert(record.hash().to_owned(), id_tx);
                        Self::fill_indices(&mut indices, record, skip_index);
                        let wrapper = Arc::new(Mutex::new(record.clone()));
                        entry.insert(wrapper.clone());
                        (id_tx, wrapper)
                      }
                      None => continue 'outer,
                    }
                  }
                };
                results.push(record);
              }
            }
            return Ok((index, results));
          }
        }
      }
      match f(conn, id) {
        Ok(found) => {
          debug!("Mutex lock");
          let mut records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut hashes = self.hashes.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut indices = self.lock_indices();
          debug!("Mutex lock/acquire");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          if index.is_none() {
            let mut records = found
              .into_iter()
              .map(|record| {
                let id_tx = record.id();
                let record = records.entry(id_tx).or_insert_with(|| {
                  hashes.insert(record.hash().to_owned(), id_tx);
                  Self::fill_indices(&mut indices, &record, skip_index);
                  Arc::new(Mutex::new(record))
                });
                (id_tx, record.clone())
              })
              .collect::<Vec<_>>();
            records.sort_unstable_by_key(|&(id_tx, _)| id_tx);
            let mut ids =
              records.iter().map(|&(id_tx, _)| id_tx).collect::<Vec<_>>();
            ids.dedup();
            *index = Some(ids);
            return Ok((index, records));
          }
        }
        Err(err) => return Err(err),
      }
    }
  }
}
<commit_msg>Small fix<commit_after>use super::{Error, Hashes, Index, Mapper, Record, Records, Result,
            TransactionRecord};
use mysql;
use std::collections::HashMap;
use std::collections::btree_map::{BTreeMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockWriteGuard};

pub struct TransactionMapper {
  counter: Mutex<u64>,
  records: RwLock<Records<TransactionRecord>>,
  hashes: RwLock<Hashes>,
  indices: [RwLock<Records<Index>>; 2],
}

type FetchManyResult = Result<
  Vec<(u64, String, Arc<Mutex<TransactionRecord>>)>,
>;

type FetchIndexResult<'a> = Result<
  (
    MutexGuard<'a, Index>,
    Vec<(u64, Arc<Mutex<TransactionRecord>>)>,
  ),
>;

impl Mapper for TransactionMapper {
  type Record = TransactionRecord;

  fn new(conn: &mut mysql::Conn, retry_interval: u64) -> Result<Self> {
    let counter = Self::init_counter(
      conn,
      retry_interval,
      r"SELECT id_tx FROM tx ORDER BY id_tx DESC LIMIT 1",
    )?;
    let records = RwLock::new(BTreeMap::new());
    let hashes = RwLock::new(HashMap::new());
    let indices = [RwLock::new(BTreeMap::new()), RwLock::new(BTreeMap::new())];
    Ok(Self {
      counter,
      records,
      hashes,
      indices,
    })
  }

  fn counter(&self) -> &Mutex<u64> {
    &self.counter
  }

  fn records(&self) -> &RwLock<Records<TransactionRecord>> {
    &self.records
  }

  fn hashes(&self) -> &RwLock<Hashes> {
    &self.hashes
  }

  fn indices(&self) -> &[RwLock<Records<Index>>] {
    &self.indices
  }

  fn fill_indices(
    indices: &mut [RwLockWriteGuard<Records<Index>>],
    record: &TransactionRecord,
    skip_index: Option<(usize, u64)>,
  ) {
    let inner = if record.is_persisted() {
      None
    } else {
      Some(Vec::new())
    };
    indices[0].insert(record.id(), Arc::new(Mutex::new(inner.clone())));
    indices[1].insert(record.id(), Arc::new(Mutex::new(inner)));
    if let Some(id_trunk) = record.id_trunk() {
      match skip_index {
        Some((0, id)) if id == id_trunk => {}
        _ => if let Some(index) = indices[0].get(&id_trunk) {
          debug!("Mutex lock");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          record.fill_index(&mut index);
        },
      }
    }
    if let Some(id_branch) = record.id_branch() {
      match skip_index {
        Some((1, id)) if id == id_branch => {}
        _ => if let Some(index) = indices[1].get(&id_branch) {
          debug!("Mutex lock");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          record.fill_index(&mut index);
        },
      }
    }
  }
}

impl TransactionMapper {
  pub fn fetch_many(
    &self,
    conn: &mut mysql::Conn,
    mut input: Vec<&str>,
  ) -> FetchManyResult {
    input.dedup();
    let cached = {
      debug!("Mutex lock");
      let records = self.records.read().unwrap();
      debug!("Mutex lock/acquire");
      let hashes = self.hashes.read().unwrap();
      debug!("Mutex acquire");
      input
        .iter()
        .filter_map(|&hash| {
          hashes
            .get(hash)
            .and_then(|&id| records.get(&id).map(|x| (hash, (id, x.clone()))))
        })
        .collect::<HashMap<_, _>>()
    };
    let missing = input
      .iter()
      .filter(|&hash| !cached.contains_key(hash))
      .cloned()
      .collect::<Vec<_>>();
    let found = TransactionRecord::find_by_hashes(conn, missing)?;
    debug!("Mutex lock");
    let mut records = self.records.write().unwrap();
    debug!("Mutex lock/acquire");
    let mut hashes = self.hashes.write().unwrap();
    debug!("Mutex lock/acquire");
    let mut indices = self.lock_indices();
    debug!("Mutex acquire");
    let mut output = input
      .into_iter()
      .map(|hash| {
        cached
          .get(hash)
          .map(|&(id_tx, ref record)| {
            (id_tx, hash.to_owned(), record.clone())
          })
          .unwrap_or_else(|| {
            hashes
              .get(hash)
              .and_then(|&id_tx| {
                records
                  .get(&id_tx)
                  .map(|record| (id_tx, hash.to_owned(), record.clone()))
              })
              .unwrap_or_else(|| {
                let record = found
                  .iter()
                  .find(|record| record.hash() == hash)
                  .cloned()
                  .unwrap_or_else(|| {
                    TransactionRecord::placeholder(
                      hash.to_owned(),
                      self.next_id(),
                    )
                  });
                let id_tx = record.id();
                hashes.insert(hash.to_owned(), id_tx);
                Self::fill_indices(&mut indices, &record, None);
                let wrapper = Arc::new(Mutex::new(record));
                records.insert(id_tx, wrapper.clone());
                (id_tx, hash.to_owned(), wrapper)
              })
          })
      })
      .collect::<Vec<_>>();
    output.sort_unstable_by_key(|&(id_tx, _, _)| id_tx);
    Ok(output)
  }

  pub fn trunk_index(&self, id: u64) -> Option<Arc<Mutex<Index>>> {
    debug!("Mutex lock");
    let trunks = self.indices[0].read().unwrap();
    debug!("Mutex acquire");
    trunks.get(&id).cloned()
  }

  pub fn branch_index(&self, id: u64) -> Option<Arc<Mutex<Index>>> {
    debug!("Mutex lock");
    let branches = self.indices[1].read().unwrap();
    debug!("Mutex acquire");
    branches.get(&id).cloned()
  }

  pub fn fetch_trunk<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(
      conn,
      id,
      index,
      Some((0, id)),
      TransactionRecord::find_trunk,
    )
  }

  pub fn fetch_branch<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(
      conn,
      id,
      index,
      Some((1, id)),
      TransactionRecord::find_branch,
    )
  }

  pub fn fetch_bundle<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(conn, id, index, None, TransactionRecord::find_bundle)
  }

  fn fetch_index<'a, F>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
    skip_index: Option<(usize, u64)>,
    f: F,
  ) -> FetchIndexResult<'a>
  where
    F: Fn(&mut mysql::Conn, u64)
      -> Result<Vec<TransactionRecord>>,
  {
    'outer: loop {
      {
        let missing = {
          debug!("Mutex lock");
          let records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let index = index.lock().unwrap();
          debug!("Mutex acquire");
          index.as_ref().map(|index| {
            index
              .iter()
              .filter(|id_tx| !records.contains_key(id_tx))
              .cloned()
              .collect::<Vec<_>>()
          })
        };
        if let Some(missing) = missing {
          let found = TransactionRecord::find_by_ids(conn, &missing)?;
          debug!("Mutex lock");
          let mut records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut hashes = self.hashes.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut indices = self.lock_indices();
          debug!("Mutex lock/acquire");
          let index = index.lock().unwrap();
          debug!("Mutex acquire");
          if index.is_some() {
            let mut results = Vec::new();
            if let Some(ref index) = *index {
              for &id_tx in index {
                let record = match records.entry(id_tx) {
                  Entry::Occupied(entry) => (id_tx, entry.get().clone()),
                  Entry::Vacant(entry) => {
                    match found.iter().find(|record| record.id() == id_tx) {
                      Some(record) => {
                        let id_tx = record.id();
                        hashes.insert(record.hash().to_owned(), id_tx);
                        Self::fill_indices(&mut indices, record, skip_index);
                        let wrapper = Arc::new(Mutex::new(record.clone()));
                        entry.insert(wrapper.clone());
                        (id_tx, wrapper)
                      }
                      None => if missing.contains(&id_tx) {
                        return Err(Error::RecordNotFound(id_tx));
                      } else {
                        continue 'outer;
                      },
                    }
                  }
                };
                results.push(record);
              }
            }
            return Ok((index, results));
          }
        }
      }
      match f(conn, id) {
        Ok(found) => {
          debug!("Mutex lock");
          let mut records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut hashes = self.hashes.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut indices = self.lock_indices();
          debug!("Mutex lock/acquire");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          if index.is_none() {
            let mut records = found
              .into_iter()
              .map(|record| {
                let id_tx = record.id();
                let record = records.entry(id_tx).or_insert_with(|| {
                  hashes.insert(record.hash().to_owned(), id_tx);
                  Self::fill_indices(&mut indices, &record, skip_index);
                  Arc::new(Mutex::new(record))
                });
                (id_tx, record.clone())
              })
              .collect::<Vec<_>>();
            records.sort_unstable_by_key(|&(id_tx, _)| id_tx);
            let mut ids =
              records.iter().map(|&(id_tx, _)| id_tx).collect::<Vec<_>>();
            ids.dedup();
            *index = Some(ids);
            return Ok((index, records));
          }
        }
        Err(err) => return Err(err),
      }
    }
  }
}
<|endoftext|>


<commit_before>use ide_db::{base_db::FileId, defs::Definition, search::FileReference};
use syntax::{
    algo::find_node_at_range,
    ast::{self, HasArgList},
    AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, T,
};

use SyntaxKind::WHITESPACE;

use crate::{
    assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists,
};

// Assist: remove_unused_param
//
// Removes unused function parameter.
//
// ```
// fn frobnicate(x: i32$0) {}
//
// fn main() {
//     frobnicate(92);
// }
// ```
// ->
// ```
// fn frobnicate() {}
//
// fn main() {
//     frobnicate();
// }
// ```
pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let param: ast::Param = ctx.find_node_at_offset()?;
    let ident_pat = match param.pat()? {
        ast::Pat::IdentPat(it) => it,
        _ => return None,
    };
    let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
    let is_self_present =
        param.syntax().parent()?.children().find_map(ast::SelfParam::cast).is_some();

    // check if fn is in impl Trait for ..
    if func
        .syntax()
        .parent() // AssocItemList
        .and_then(|x| x.parent())
        .and_then(ast::Impl::cast)
        .map_or(false, |imp| imp.trait_().is_some())
    {
        cov_mark::hit!(trait_impl);
        return None;
    }

    let mut param_position = func.param_list()?.params().position(|it| it == param)?;
    // param_list() does not take the self param into consideration, hence this additional check
    // is required. For associated functions, param_position is incremented here. For inherent
    // calls we revet the increment below, in process_usage, as those calls will not have an
    // explicit self parameter.
    if is_self_present {
        param_position += 1;
    }
    let fn_def = {
        let func = ctx.sema.to_def(&func)?;
        Definition::Function(func)
    };

    let param_def = {
        let local = ctx.sema.to_def(&ident_pat)?;
        Definition::Local(local)
    };
    if param_def.usages(&ctx.sema).at_least_one() {
        cov_mark::hit!(keep_used);
        return None;
    }
    acc.add(
        AssistId("remove_unused_param", AssistKind::Refactor),
        "Remove unused parameter",
        param.syntax().text_range(),
        |builder| {
            builder.delete(range_to_remove(param.syntax()));
            for (file_id, references) in fn_def.usages(&ctx.sema).all() {
                process_usages(ctx, builder, file_id, references, param_position, is_self_present);
            }
        },
    )
}

fn process_usages(
    ctx: &AssistContext,
    builder: &mut AssistBuilder,
    file_id: FileId,
    references: Vec<FileReference>,
    arg_to_remove: usize,
    is_self_present: bool,
) {
    let source_file = ctx.sema.parse(file_id);
    builder.edit_file(file_id);
    for usage in references {
        if let Some(text_range) = process_usage(&source_file, usage, arg_to_remove, is_self_present)
        {
            builder.delete(text_range);
        }
    }
}

fn process_usage(
    source_file: &SourceFile,
    FileReference { range, .. }: FileReference,
    mut arg_to_remove: usize,
    is_self_present: bool,
) -> Option<TextRange> {
    let call_expr_opt: Option<ast::CallExpr> = find_node_at_range(source_file.syntax(), range);
    if let Some(call_expr) = call_expr_opt {
        let call_expr_range = call_expr.expr()?.syntax().text_range();
        if !call_expr_range.contains_range(range) {
            return None;
        }

        let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
        return Some(range_to_remove(arg.syntax()));
    }

    let method_call_expr_opt: Option<ast::MethodCallExpr> =
        find_node_at_range(source_file.syntax(), range);
    if let Some(method_call_expr) = method_call_expr_opt {
        let method_call_expr_range = method_call_expr.name_ref()?.syntax().text_range();
        if !method_call_expr_range.contains_range(range) {
            return None;
        }

        if is_self_present {
            arg_to_remove -= 1;
        }

        let arg = method_call_expr.arg_list()?.args().nth(arg_to_remove)?;
        return Some(range_to_remove(arg.syntax()));
    }

    None
}

pub(crate) fn range_to_remove(node: &SyntaxNode) -> TextRange {
    let up_to_comma = next_prev().find_map(|dir| {
        node.siblings_with_tokens(dir)
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == T![,])
            .map(|it| (dir, it))
    });
    if let Some((dir, token)) = up_to_comma {
        if node.next_sibling().is_some() {
            let up_to_space = token
                .siblings_with_tokens(dir)
                .skip(1)
                .take_while(|it| it.kind() == WHITESPACE)
                .last()
                .and_then(|it| it.into_token());
            return node
                .text_range()
                .cover(up_to_space.map_or(token.text_range(), |it| it.text_range()));
        }
        node.text_range().cover(token.text_range())
    } else {
        node.text_range()
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn remove_unused() {
        check_assist(
            remove_unused_param,
            r#"
fn a() { foo(9, 2) }
fn foo(x: i32, $0y: i32) { x; }
fn b() { foo(9, 2,) }
"#,
            r#"
fn a() { foo(9) }
fn foo(x: i32) { x; }
fn b() { foo(9, ) }
"#,
        );
    }

    #[test]
    fn remove_unused_first_param() {
        check_assist(
            remove_unused_param,
            r#"
fn foo($0x: i32, y: i32) { y; }
fn a() { foo(1, 2) }
fn b() { foo(1, 2,) }
"#,
            r#"
fn foo(y: i32) { y; }
fn a() { foo(2) }
fn b() { foo(2,) }
"#,
        );
    }

    #[test]
    fn remove_unused_single_param() {
        check_assist(
            remove_unused_param,
            r#"
fn foo($0x: i32) { 0; }
fn a() { foo(1) }
fn b() { foo(1, ) }
"#,
            r#"
fn foo() { 0; }
fn a() { foo() }
fn b() { foo( ) }
"#,
        );
    }

    #[test]
    fn remove_unused_surrounded_by_parms() {
        check_assist(
            remove_unused_param,
            r#"
fn foo(x: i32, $0y: i32, z: i32) { x; }
fn a() { foo(1, 2, 3) }
fn b() { foo(1, 2, 3,) }
"#,
            r#"
fn foo(x: i32, z: i32) { x; }
fn a() { foo(1, 3) }
fn b() { foo(1, 3,) }
"#,
        );
    }

    #[test]
    fn remove_unused_qualified_call() {
        check_assist(
            remove_unused_param,
            r#"
mod bar { pub fn foo(x: i32, $0y: i32) { x; } }
fn b() { bar::foo(9, 2) }
"#,
            r#"
mod bar { pub fn foo(x: i32) { x; } }
fn b() { bar::foo(9) }
"#,
        );
    }

    #[test]
    fn remove_unused_turbofished_func() {
        check_assist(
            remove_unused_param,
            r#"
pub fn foo<T>(x: T, $0y: i32) { x; }
fn b() { foo::<i32>(9, 2) }
"#,
            r#"
pub fn foo<T>(x: T) { x; }
fn b() { foo::<i32>(9) }
"#,
        );
    }

    #[test]
    fn remove_unused_generic_unused_param_func() {
        check_assist(
            remove_unused_param,
            r#"
pub fn foo<T>(x: i32, $0y: T) { x; }
fn b() { foo::<i32>(9, 2) }
fn b2() { foo(9, 2) }
"#,
            r#"
pub fn foo<T>(x: i32) { x; }
fn b() { foo::<i32>(9) }
fn b2() { foo(9) }
"#,
        );
    }

    #[test]
    fn keep_used() {
        cov_mark::check!(keep_used);
        check_assist_not_applicable(
            remove_unused_param,
            r#"
fn foo(x: i32, $0y: i32) { y; }
fn main() { foo(9, 2) }
"#,
        );
    }

    #[test]
    fn trait_impl() {
        cov_mark::check!(trait_impl);
        check_assist_not_applicable(
            remove_unused_param,
            r#"
trait Trait {
    fn foo(x: i32);
}
impl Trait for () {
    fn foo($0x: i32) {}
}
"#,
        );
    }

    #[test]
    fn remove_across_files() {
        check_assist(
            remove_unused_param,
            r#"
//- /main.rs
fn foo(x: i32, $0y: i32) { x; }

mod foo;

//- /foo.rs
use super::foo;

fn bar() {
    let _ = foo(1, 2);
}
"#,
            r#"
//- /main.rs
fn foo(x: i32) { x; }

mod foo;

//- /foo.rs
use super::foo;

fn bar() {
    let _ = foo(1);
}
"#,
        )
    }

    #[test]
    fn test_remove_method_param() {
        check_assist(
            remove_unused_param,
            r#"
struct S;
impl S { fn f(&self, $0_unused: i32) {} }
fn main() {
    S.f(92);
    S.f();
    S.f(93, 92);
    S::f(&S, 92);
}
"#,
            r#"
struct S;
impl S { fn f(&self) {} }
fn main() {
    S.f();
    S.f();
    S.f(92);
    S::f(&S);
}
"#,
        )
    }
}
<commit_msg>Auto merge of #12789 - DorianListens:dscheidt/unused-param-overlapping, r=DorianListens<commit_after>use ide_db::{base_db::FileId, defs::Definition, search::FileReference};
use syntax::{
    algo::find_node_at_range,
    ast::{self, HasArgList},
    AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, T,
};

use SyntaxKind::WHITESPACE;

use crate::{
    assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists,
};

// Assist: remove_unused_param
//
// Removes unused function parameter.
//
// ```
// fn frobnicate(x: i32$0) {}
//
// fn main() {
//     frobnicate(92);
// }
// ```
// ->
// ```
// fn frobnicate() {}
//
// fn main() {
//     frobnicate();
// }
// ```
pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let param: ast::Param = ctx.find_node_at_offset()?;
    let ident_pat = match param.pat()? {
        ast::Pat::IdentPat(it) => it,
        _ => return None,
    };
    let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
    let is_self_present =
        param.syntax().parent()?.children().find_map(ast::SelfParam::cast).is_some();

    // check if fn is in impl Trait for ..
    if func
        .syntax()
        .parent() // AssocItemList
        .and_then(|x| x.parent())
        .and_then(ast::Impl::cast)
        .map_or(false, |imp| imp.trait_().is_some())
    {
        cov_mark::hit!(trait_impl);
        return None;
    }

    let mut param_position = func.param_list()?.params().position(|it| it == param)?;
    // param_list() does not take the self param into consideration, hence this additional check
    // is required. For associated functions, param_position is incremented here. For inherent
    // calls we revet the increment below, in process_usage, as those calls will not have an
    // explicit self parameter.
    if is_self_present {
        param_position += 1;
    }
    let fn_def = {
        let func = ctx.sema.to_def(&func)?;
        Definition::Function(func)
    };

    let param_def = {
        let local = ctx.sema.to_def(&ident_pat)?;
        Definition::Local(local)
    };
    if param_def.usages(&ctx.sema).at_least_one() {
        cov_mark::hit!(keep_used);
        return None;
    }
    acc.add(
        AssistId("remove_unused_param", AssistKind::Refactor),
        "Remove unused parameter",
        param.syntax().text_range(),
        |builder| {
            builder.delete(range_to_remove(param.syntax()));
            for (file_id, references) in fn_def.usages(&ctx.sema).all() {
                process_usages(ctx, builder, file_id, references, param_position, is_self_present);
            }
        },
    )
}

fn process_usages(
    ctx: &AssistContext,
    builder: &mut AssistBuilder,
    file_id: FileId,
    references: Vec<FileReference>,
    arg_to_remove: usize,
    is_self_present: bool,
) {
    let source_file = ctx.sema.parse(file_id);
    builder.edit_file(file_id);
    let possible_ranges = references
        .into_iter()
        .filter_map(|usage| process_usage(&source_file, usage, arg_to_remove, is_self_present));

    let mut ranges_to_delete: Vec<TextRange> = vec![];
    for range in possible_ranges {
        if !ranges_to_delete.iter().any(|it| it.contains_range(range)) {
            ranges_to_delete.push(range)
        }
    }

    for range in ranges_to_delete {
        builder.delete(range)
    }
}

fn process_usage(
    source_file: &SourceFile,
    FileReference { range, .. }: FileReference,
    mut arg_to_remove: usize,
    is_self_present: bool,
) -> Option<TextRange> {
    let call_expr_opt: Option<ast::CallExpr> = find_node_at_range(source_file.syntax(), range);
    if let Some(call_expr) = call_expr_opt {
        let call_expr_range = call_expr.expr()?.syntax().text_range();
        if !call_expr_range.contains_range(range) {
            return None;
        }

        let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
        return Some(range_to_remove(arg.syntax()));
    }

    let method_call_expr_opt: Option<ast::MethodCallExpr> =
        find_node_at_range(source_file.syntax(), range);
    if let Some(method_call_expr) = method_call_expr_opt {
        let method_call_expr_range = method_call_expr.name_ref()?.syntax().text_range();
        if !method_call_expr_range.contains_range(range) {
            return None;
        }

        if is_self_present {
            arg_to_remove -= 1;
        }

        let arg = method_call_expr.arg_list()?.args().nth(arg_to_remove)?;
        return Some(range_to_remove(arg.syntax()));
    }

    None
}

pub(crate) fn range_to_remove(node: &SyntaxNode) -> TextRange {
    let up_to_comma = next_prev().find_map(|dir| {
        node.siblings_with_tokens(dir)
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == T![,])
            .map(|it| (dir, it))
    });
    if let Some((dir, token)) = up_to_comma {
        if node.next_sibling().is_some() {
            let up_to_space = token
                .siblings_with_tokens(dir)
                .skip(1)
                .take_while(|it| it.kind() == WHITESPACE)
                .last()
                .and_then(|it| it.into_token());
            return node
                .text_range()
                .cover(up_to_space.map_or(token.text_range(), |it| it.text_range()));
        }
        node.text_range().cover(token.text_range())
    } else {
        node.text_range()
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn remove_unused() {
        check_assist(
            remove_unused_param,
            r#"
fn a() { foo(9, 2) }
fn foo(x: i32, $0y: i32) { x; }
fn b() { foo(9, 2,) }
"#,
            r#"
fn a() { foo(9) }
fn foo(x: i32) { x; }
fn b() { foo(9, ) }
"#,
        );
    }

    #[test]
    fn remove_unused_first_param() {
        check_assist(
            remove_unused_param,
            r#"
fn foo($0x: i32, y: i32) { y; }
fn a() { foo(1, 2) }
fn b() { foo(1, 2,) }
"#,
            r#"
fn foo(y: i32) { y; }
fn a() { foo(2) }
fn b() { foo(2,) }
"#,
        );
    }

    #[test]
    fn remove_unused_single_param() {
        check_assist(
            remove_unused_param,
            r#"
fn foo($0x: i32) { 0; }
fn a() { foo(1) }
fn b() { foo(1, ) }
"#,
            r#"
fn foo() { 0; }
fn a() { foo() }
fn b() { foo( ) }
"#,
        );
    }

    #[test]
    fn remove_unused_surrounded_by_parms() {
        check_assist(
            remove_unused_param,
            r#"
fn foo(x: i32, $0y: i32, z: i32) { x; }
fn a() { foo(1, 2, 3) }
fn b() { foo(1, 2, 3,) }
"#,
            r#"
fn foo(x: i32, z: i32) { x; }
fn a() { foo(1, 3) }
fn b() { foo(1, 3,) }
"#,
        );
    }

    #[test]
    fn remove_unused_qualified_call() {
        check_assist(
            remove_unused_param,
            r#"
mod bar { pub fn foo(x: i32, $0y: i32) { x; } }
fn b() { bar::foo(9, 2) }
"#,
            r#"
mod bar { pub fn foo(x: i32) { x; } }
fn b() { bar::foo(9) }
"#,
        );
    }

    #[test]
    fn remove_unused_turbofished_func() {
        check_assist(
            remove_unused_param,
            r#"
pub fn foo<T>(x: T, $0y: i32) { x; }
fn b() { foo::<i32>(9, 2) }
"#,
            r#"
pub fn foo<T>(x: T) { x; }
fn b() { foo::<i32>(9) }
"#,
        );
    }

    #[test]
    fn remove_unused_generic_unused_param_func() {
        check_assist(
            remove_unused_param,
            r#"
pub fn foo<T>(x: i32, $0y: T) { x; }
fn b() { foo::<i32>(9, 2) }
fn b2() { foo(9, 2) }
"#,
            r#"
pub fn foo<T>(x: i32) { x; }
fn b() { foo::<i32>(9) }
fn b2() { foo(9) }
"#,
        );
    }

    #[test]
    fn keep_used() {
        cov_mark::check!(keep_used);
        check_assist_not_applicable(
            remove_unused_param,
            r#"
fn foo(x: i32, $0y: i32) { y; }
fn main() { foo(9, 2) }
"#,
        );
    }

    #[test]
    fn trait_impl() {
        cov_mark::check!(trait_impl);
        check_assist_not_applicable(
            remove_unused_param,
            r#"
trait Trait {
    fn foo(x: i32);
}
impl Trait for () {
    fn foo($0x: i32) {}
}
"#,
        );
    }

    #[test]
    fn remove_across_files() {
        check_assist(
            remove_unused_param,
            r#"
//- /main.rs
fn foo(x: i32, $0y: i32) { x; }

mod foo;

//- /foo.rs
use super::foo;

fn bar() {
    let _ = foo(1, 2);
}
"#,
            r#"
//- /main.rs
fn foo(x: i32) { x; }

mod foo;

//- /foo.rs
use super::foo;

fn bar() {
    let _ = foo(1);
}
"#,
        )
    }

    #[test]
    fn test_remove_method_param() {
        check_assist(
            remove_unused_param,
            r#"
struct S;
impl S { fn f(&self, $0_unused: i32) {} }
fn main() {
    S.f(92);
    S.f();
    S.f(93, 92);
    S::f(&S, 92);
}
"#,
            r#"
struct S;
impl S { fn f(&self) {} }
fn main() {
    S.f();
    S.f();
    S.f(92);
    S::f(&S);
}
"#,
        )
    }

    #[test]
    fn nested_call() {
        check_assist(
            remove_unused_param,
            r#"
fn foo(x: i32, $0y: i32) -> i32 {
    x
}

fn bar() {
    foo(1, foo(2, 3));
}
"#,
            r#"
fn foo(x: i32) -> i32 {
    x
}

fn bar() {
    foo(1);
}
"#,
        )
    }
}
<|endoftext|>


<commit_before>//! Allows dynamic dispatch to object-unsafe traits, with some caveats.
//!
//! `list_of_types` works around Rust's lack of generic/associated statics by requiring the program to specify a single "list of types" at compile time, which must include everything that you want to call into dynamically. This must be globally unique within the program. That is, if a *library* wants to use these features, it must rely on being passed the global list as a generic parameter.
//!
//! Creating a list of types is simple: you wrap each type `T` into `ListedType<T>`, then put the `ListedType`s into tuples (possibly nested tuples). All the traits necessary to use a list for automatically implemented for all nested tuples of `ListedType`s. For instance, ((ListedType<i64>, ListedType<String>, ListedType<Vec<usize>>), ListedType<bool>) is a valid list with 4 types in it.

use std::marker::PhantomData;

#[macro_export]
macro_rules! time_steward_make_sublist {
  (mod $mod: ident visits $T: ident where $($where:tt)*) => {mod $mod {
    use std::marker::PhantomData;
    use std::any::Any;
    use $crate::dynamic::list_of_types::{List, SubListRepresentative, ListedType};
    pub trait Visitor {
      fn visit<$T>(&mut self) where $($where)*;
    }
    pub unsafe trait SubList: List {
      fn visit_all<V: Visitor>(visitor: &mut V);
      fn count()->usize;
      fn count_before<T>()->usize;
    }
    unsafe impl <T: Any> SubList for ListedType<T> {
      #[inline(always)]
      default fn visit_all<V: Visitor>(_: &mut V) {}
      #[inline(always)]
      default fn count()->usize {0}
      #[inline(always)]
      default fn count_before<U>()->usize {panic!("invoked count_before on a list that doesn't contain the type")}
    }
    unsafe impl <$T: Any> SubList for ListedType<$T> where $($where)* {
      #[inline(always)]
      fn visit_all<V: Visitor>(visitor: &mut V) {
        visitor.visit::<$T>();
      }
      #[inline(always)]
      fn count()->usize {1}
      #[inline(always)]
      fn count_before<U>()->usize {0}
    }
    __time_steward_internal_sublist_tuple_impls! (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31);

    pub struct Representative <GlobalList: SubList> (PhantomData <GlobalList>,!);
    unsafe impl <GlobalList: SubList> SubListRepresentative for Representative <GlobalList> {
      fn count()->usize {
        $crate::dynamic::list_of_types::assert_unique_global_list::<GlobalList>();
        GlobalList::count()
      }
      fn count_before<T>()->usize {
        $crate::dynamic::list_of_types::assert_unique_global_list::<GlobalList>();
        GlobalList::count_before::<T>()
      }
    }/*{
      fn visit_all<V: Visitor>(visitor: &mut V) {
        GlobalList::visit_all(visitor);
      }
    }*/
  }}
}
pub struct ListedType<T: Any>(PhantomData <T>, !);

#[macro_export]
#[doc(hidden)]
macro_rules! __time_steward_internal_sublist_tuple_impls {
  ($TL: ident $(, $T: ident)*) => {
    unsafe impl<$($T,)* $TL> SubList for ($($T,)* $TL,)
      where $($T: SubList,)* $TL: SubList
    {
      #[inline(always)]
      fn visit_all<V: Visitor>(visitor: &mut V) {
        $($T::visit_all(visitor);)*
        $TL::visit_all(visitor);
      }
      #[inline(always)]
      fn count()->usize {
        $($T::count() + )* $TL::count()
      }
      #[inline(always)]
      fn count_before<T>()->usize {
        let count = 0;
        $(if $T::includes::<T> () {return count + $T::count_before::<T>()}
        let count = count + $T::count();)*
        if $TL::includes::<T> () {return count + $TL::count_before::<T>()}
        panic!("invoked count_before on a list that doesn't contain the type")
      }
    }
    __time_steward_internal_sublist_tuple_impls! ($($T),*);
  };
  () => {};
}

pub unsafe trait List: Any {
  fn includes <T> ()->bool;
}
pub unsafe trait SubListRepresentative {
  fn count()->usize;
  fn count_before<T>()->usize;
}

pub unsafe trait AmI <T> {fn am_i()->bool;}
unsafe impl <T, U> AmI <T> for U {default fn am_i()->bool {false}}
unsafe impl <T> AmI <T> for T {fn am_i()->bool {true}}

unsafe impl <T: Any> List for ListedType<T> {
  #[inline(always)]
  fn includes<U>()->bool {<T as AmI<U>>::am_i()}
}

macro_rules! tuple_impls {
  ($TL: ident $(, $T: ident)*) => {
    unsafe impl<$($T,)* $TL> List for ($($T,)* $TL,)
      where $($T: List,)* $TL: List
    {
      #[inline(always)]
      fn includes<T>()->bool {
        $($T::includes::<T>() || )* $TL::includes::<T>()
      }
    }
    tuple_impls! ($($T),*);
  };
  () => {};
}

tuple_impls! (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31);

#[derive (Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct DeterministicallyRandomlyIdentifiedTypeId(u64);
pub trait DeterministicallyRandomlyIdentifiedType {
  const ID: DeterministicallyRandomlyIdentifiedTypeId;
}

fn assert_unique_global_list <GlobalList: List>() {
  use std::any::TypeId;
  use std::cell::Cell;
  thread_local! {
    static LIST_ID: Cell<Option <TypeId>> = Cell::new (None);
  }
  LIST_ID.with (| id_cell | {
    let id = TypeId::of::<GlobalList>();
    if let Some (existing) = id_cell.get() {
      assert!(id == existing, "invoked dynamic function with two different global lists (see the list_of_types documentation for why this is wrong");
      return
    }
    id_cell.set (Some(id));
  });
}

time_steward_make_sublist! (
mod whatever visits T where T: super::DeterministicallyRandomlyIdentifiedType);
/*
#[macro_export]
macro_rules! time_steward_sublist_fn {
  (static $visitor_data: ident: $VisitorData: ty: $VisitorTrait: ident = $initial_value: expr followed by visit<$T> (&mut $self_hack) $visitation_effect: expr; fn $function_name: ident <$GlobalList: $SubList: ident> ($($argument_name: ident: $argument_type:ty),*)->$return_type:ty $($body:tt)*) => {

    fn $function_name <GlobalList: $List> $($argument_name: $argument_type),*)->$return_type:ty {
      struct Visitor ($VisitorData);
      impl VisitorTrait for Visitor {
        fn visit<$T>(&mut $self_hack) where  {$visitation_effect}
      }
      thread_local! {
        static DATA: $VisitorData = {
          let mut visitor = Visitor ($initial_value);
          <GlobalList as DeterministicallyRandomlyIdentifiedTypesList>::visit_all (&mut visitor);
          visitor.0
        };
      }
      DATA.with (| $visitor_data | {$($body)*})
  }
}
  */

#[macro_export]
macro_rules! time_steward_visit_sublist {
  (&mut $object: ident: $Object: ty, <$GlobalList: ident as $mod: ident::SubList>, $($method: tt)*) => {
    impl $mod::Visitor for $Object {
      $($method)*
    }
    <$GlobalList as $mod::SubList>::visit_all (&mut $object);
  }
}
#[macro_export]
macro_rules! time_steward_with_sublist_table {
  (Vec<$Entry: ty> [$T: ident => {$entry: expr} where $($where: tt)*], <$GlobalList: ident as $mod: ident::SubList>, {$($method: tt)*} | $table: ident | $($closure: tt)*) => {{
    assert_unique_global_list::<GlobalList>();
    use std::cell::RefCell;
    use std::mem;
    thread_local! {
      static TABLE: RefCell<Vec<DeterministicallyRandomlyIdentifiedTypeId>> = RefCell::new(Vec::new());
    }
    TABLE.with (| table | {
      let mut guard = table.borrow_mut();
      if guard.is_empty() {
        mem::replace (&mut*guard, {
          let mut result = Vec::with_capacity(whatever::Representative::<GlobalList>::count());
          time_steward_visit_sublist! (
            &mut result: Vec<$Entry>,
            <GlobalList as whatever::SubList>,
            fn visit<$T>(&mut self) where $($where)* {self.push ($entry);}
          );
          result
        });
      }
      let $table = &*guard;
      $($closure)*
    })
  }}
}

use std::any::Any ;

fn index_to_id <GlobalList: whatever::SubList> (index: usize)->Option <DeterministicallyRandomlyIdentifiedTypeId> {
  time_steward_with_sublist_table! (
    Vec<DeterministicallyRandomlyIdentifiedTypeId> [T => {T::ID} where T: DeterministicallyRandomlyIdentifiedType],
    <GlobalList as whatever::SubList>,
    { fn visit<T>(&mut self) where T: DeterministicallyRandomlyIdentifiedType {self.push (T::ID);}}
    | table | table.get (index).cloned()
  )
}

<commit_msg>More macro polishing<commit_after>//! Allows dynamic dispatch to object-unsafe traits, with some caveats.
//!
//! `list_of_types` works around Rust's lack of generic/associated statics by requiring the program to specify a single "list of types" at compile time, which must include everything that you want to call into dynamically. This must be globally unique within the program. That is, if a *library* wants to use these features, it must rely on being passed the global list as a generic parameter.
//!
//! Creating a list of types is simple: you wrap each type `T` into `ListedType<T>`, then put the `ListedType`s into tuples (possibly nested tuples). All the traits necessary to use a list for automatically implemented for all nested tuples of `ListedType`s. For instance, ((ListedType<i64>, ListedType<String>, ListedType<Vec<usize>>), ListedType<bool>) is a valid list with 4 types in it.

use std::marker::PhantomData;

#[macro_export]
macro_rules! time_steward_make_sublist {
  (mod $mod: ident visits $T: ident where $($where:tt)*) => {mod $mod {
    use std::marker::PhantomData;
    use std::any::Any;
    use $crate::dynamic::list_of_types::{List, SubListRepresentative, ListedType};
    pub trait Visitor {
      fn visit<$T>(&mut self) where $($where)*;
    }
    pub unsafe trait SubList: List {
      fn visit_all<V: Visitor>(visitor: &mut V);
      fn count()->usize;
      fn count_before<T>()->usize;
    }
    unsafe impl <T: Any> SubList for ListedType<T> {
      #[inline(always)]
      default fn visit_all<V: Visitor>(_: &mut V) {}
      #[inline(always)]
      default fn count()->usize {0}
      #[inline(always)]
      default fn count_before<U>()->usize {panic!("invoked count_before on a list that doesn't contain the type")}
    }
    unsafe impl <$T: Any> SubList for ListedType<$T> where $($where)* {
      #[inline(always)]
      fn visit_all<V: Visitor>(visitor: &mut V) {
        visitor.visit::<$T>();
      }
      #[inline(always)]
      fn count()->usize {1}
      #[inline(always)]
      fn count_before<U>()->usize {0}
    }
    __time_steward_internal_sublist_tuple_impls! (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31);

    pub struct Representative <GlobalList: SubList> (PhantomData <GlobalList>,!);
    unsafe impl <GlobalList: SubList> SubListRepresentative for Representative <GlobalList> {
      fn count()->usize {
        $crate::dynamic::list_of_types::assert_unique_global_list::<GlobalList>();
        GlobalList::count()
      }
      fn count_before<T>()->usize {
        $crate::dynamic::list_of_types::assert_unique_global_list::<GlobalList>();
        GlobalList::count_before::<T>()
      }
    }/*{
      fn visit_all<V: Visitor>(visitor: &mut V) {
        GlobalList::visit_all(visitor);
      }
    }*/
  }}
}
pub struct ListedType<T: Any>(PhantomData <T>, !);

#[macro_export]
#[doc(hidden)]
macro_rules! __time_steward_internal_sublist_tuple_impls {
  ($TL: ident $(, $T: ident)*) => {
    unsafe impl<$($T,)* $TL> SubList for ($($T,)* $TL,)
      where $($T: SubList,)* $TL: SubList
    {
      #[inline(always)]
      fn visit_all<V: Visitor>(visitor: &mut V) {
        $($T::visit_all(visitor);)*
        $TL::visit_all(visitor);
      }
      #[inline(always)]
      fn count()->usize {
        $($T::count() + )* $TL::count()
      }
      #[inline(always)]
      fn count_before<T>()->usize {
        let count = 0;
        $(if $T::includes::<T> () {return count + $T::count_before::<T>()}
        let count = count + $T::count();)*
        if $TL::includes::<T> () {return count + $TL::count_before::<T>()}
        panic!("invoked count_before on a list that doesn't contain the type")
      }
    }
    __time_steward_internal_sublist_tuple_impls! ($($T),*);
  };
  () => {};
}

pub unsafe trait List: Any {
  fn includes <T> ()->bool;
}
pub unsafe trait SubListRepresentative {
  fn count()->usize;
  fn count_before<T>()->usize;
}

pub unsafe trait AmI <T> {fn am_i()->bool;}
unsafe impl <T, U> AmI <T> for U {default fn am_i()->bool {false}}
unsafe impl <T> AmI <T> for T {fn am_i()->bool {true}}

unsafe impl <T: Any> List for ListedType<T> {
  #[inline(always)]
  fn includes<U>()->bool {<T as AmI<U>>::am_i()}
}

macro_rules! tuple_impls {
  ($TL: ident $(, $T: ident)*) => {
    unsafe impl<$($T,)* $TL> List for ($($T,)* $TL,)
      where $($T: List,)* $TL: List
    {
      #[inline(always)]
      fn includes<T>()->bool {
        $($T::includes::<T>() || )* $TL::includes::<T>()
      }
    }
    tuple_impls! ($($T),*);
  };
  () => {};
}

tuple_impls! (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31);

#[derive (Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct DeterministicallyRandomlyIdentifiedTypeId(u64);
pub trait DeterministicallyRandomlyIdentifiedType {
  const ID: DeterministicallyRandomlyIdentifiedTypeId;
}

fn assert_unique_global_list <GlobalList: List>() {
  use std::any::TypeId;
  use std::cell::Cell;
  thread_local! {
    static LIST_ID: Cell<Option <TypeId>> = Cell::new (None);
  }
  LIST_ID.with (| id_cell | {
    let id = TypeId::of::<GlobalList>();
    if let Some (existing) = id_cell.get() {
      assert!(id == existing, "invoked dynamic function with two different global lists (see the list_of_types documentation for why this is wrong");
      return
    }
    id_cell.set (Some(id));
  });
}

time_steward_make_sublist! (
mod whatever visits T where T: super::DeterministicallyRandomlyIdentifiedType);
/*
#[macro_export]
macro_rules! time_steward_sublist_fn {
  (static $visitor_data: ident: $VisitorData: ty: $VisitorTrait: ident = $initial_value: expr followed by visit<$T> (&mut $self_hack) $visitation_effect: expr; fn $function_name: ident <$GlobalList: $SubList: ident> ($($argument_name: ident: $argument_type:ty),*)->$return_type:ty $($body:tt)*) => {

    fn $function_name <GlobalList: $List> $($argument_name: $argument_type),*)->$return_type:ty {
      struct Visitor ($VisitorData);
      impl VisitorTrait for Visitor {
        fn visit<$T>(&mut $self_hack) where  {$visitation_effect}
      }
      thread_local! {
        static DATA: $VisitorData = {
          let mut visitor = Visitor ($initial_value);
          <GlobalList as DeterministicallyRandomlyIdentifiedTypesList>::visit_all (&mut visitor);
          visitor.0
        };
      }
      DATA.with (| $visitor_data | {$($body)*})
  }
}
  */

#[macro_export]
macro_rules! time_steward_visit_sublist {
  (&mut $object: ident: $Object: ty, <$GlobalList: ident as $mod: ident::SubList>, $($method: tt)*) => {
    impl $mod::Visitor for $Object {
      $($method)*
    }
    <$GlobalList as $mod::SubList>::visit_all (&mut $object);
  }
}
#[macro_export]
macro_rules! time_steward_with_sublist_table {
  (<$GlobalList: ident as $mod: ident::SubList>, Vec<$Entry: ty> [$T: ident => {$entry: expr} where $($where: tt)*], | $table: ident | $($closure: tt)*) => {{
    assert_unique_global_list::<GlobalList>();
    use std::cell::RefCell;
    use std::mem;
    thread_local! {
      static TABLE: RefCell<Vec<DeterministicallyRandomlyIdentifiedTypeId>> = RefCell::new(Vec::new());
    }
    TABLE.with (| table | {
      let mut guard = table.borrow_mut();
      if guard.is_empty() {
        mem::replace (&mut*guard, {
          let mut result = Vec::with_capacity(whatever::Representative::<GlobalList>::count());
          time_steward_visit_sublist! (
            &mut result: Vec<$Entry>,
            <GlobalList as whatever::SubList>,
            fn visit<$T>(&mut self) where $($where)* {self.push ($entry);}
          );
          result
        });
      }
      let $table = &*guard;
      $($closure)*
    })
  }}
}

use std::any::Any ;

fn index_to_id <GlobalList: whatever::SubList> (index: usize)->Option <DeterministicallyRandomlyIdentifiedTypeId> {
  time_steward_with_sublist_table! (
    <GlobalList as whatever::SubList>,
    Vec<DeterministicallyRandomlyIdentifiedTypeId> [T => {T::ID} where T: DeterministicallyRandomlyIdentifiedType],
    | table | table.get (index).cloned()
  )
}

<|endoftext|>


<commit_before>use super::types::{OrigFileName, Details};
use parser::{Parser, ParseError};

// Parses a wuala file conflict encoded in the file name in the form:
//
//    '<base_name> (conflicting version <version> from <host>).<extension>'
//
// e.g:
//
//    'x_original (conflicting version 5 from blub).txt'
//
// would return:
//
//    Some("x_original.txt", "Version 5 from blub")
//
pub fn parse(file_name: &str) -> Option<(OrigFileName, Details)>
{
   None
}

fn parse_internal(file_name: &str) -> Result<(OrigFileName, Details), ParseError>
{
   Err("eee".to_string())
}

#[test]
fn tests()
{
}

#[cfg(test)]
fn test_str(file_name: &str, orig_name: &str, details: &str)
{
   println!("test: {}", file_name);
   match parse(file_name) {
      Ok((name, det)) => {
         assert_eq!(orig_name.to_string(), name);
         assert_eq!(details.to_string()  , det);
      }

      Err(err) => assert!(false, err)
   }
}
<commit_msg>Use parse_internal instead of parse<commit_after>use super::types::{OrigFileName, Details};
use parser::{Parser, ParseError};

// Parses a wuala file conflict encoded in the file name in the form:
//
//    '<base_name> (conflicting version <version> from <host>).<extension>'
//
// e.g:
//
//    'x_original (conflicting version 5 from blub).txt'
//
// would return:
//
//    Some("x_original.txt", "Version 5 from blub")
//
pub fn parse(file_name: &str) -> Option<(OrigFileName, Details)>
{
   None
}

fn parse_internal(file_name: &str) -> Result<(OrigFileName, Details), ParseError>
{
   Err("eee".to_string())
}

#[test]
fn tests()
{
}

#[cfg(test)]
fn test_str(file_name: &str, orig_name: &str, details: &str)
{
   println!("test: {}", file_name);
   match parse_internal(file_name) {
      Ok((name, det)) => {
         assert_eq!(orig_name.to_string(), name);
         assert_eq!(details.to_string()  , det);
      }

      Err(err) => assert!(false, err)
   }
}
<|endoftext|>


<commit_before>import util::interner;
import util::interner::interner;
import std::map::{hashmap, str_hash};
import std::serialization::{serializer,
                            deserializer,
                            serialize_uint,
                            deserialize_uint,
                            serialize_i64,
                            deserialize_i64,
                            serialize_u64,
                            deserialize_u64,
                            serialize_bool,
                            deserialize_bool};

#[auto_serialize]
type str_num = uint;

#[auto_serialize]
enum binop {
    PLUS,
    MINUS,
    STAR,
    SLASH,
    PERCENT,
    CARET,
    AND,
    OR,
    SHL,
    SHR,
}

#[auto_serialize]
enum token {
    /* Expression-operator symbols. */
    EQ,
    LT,
    LE,
    EQEQ,
    NE,
    GE,
    GT,
    ANDAND,
    OROR,
    NOT,
    TILDE,
    BINOP(binop),
    BINOPEQ(binop),

    /* Structural symbols */
    AT,
    DOT,
    ELLIPSIS,
    COMMA,
    SEMI,
    COLON,
    MOD_SEP,
    RARROW,
    LARROW,
    DARROW,
    FAT_ARROW,
    LPAREN,
    RPAREN,
    LBRACKET,
    RBRACKET,
    LBRACE,
    RBRACE,
    POUND,
    DOLLAR,

    /* Literals */
    LIT_INT(i64, ast::int_ty),
    LIT_UINT(u64, ast::uint_ty),
    LIT_INT_UNSUFFIXED(i64),
    LIT_FLOAT(str_num, ast::float_ty),
    LIT_STR(str_num),

    /* Name components */
    IDENT(str_num, bool),
    UNDERSCORE,

    /* For interpolation */
    INTERPOLATED(nonterminal),

    DOC_COMMENT(str_num),
    EOF,
}

#[auto_serialize]
/// For interpolation during macro expansion.
enum nonterminal {
    nt_item(@ast::item),
    nt_block(ast::blk),
    nt_stmt(@ast::stmt),
    nt_pat( @ast::pat),
    nt_expr(@ast::expr),
    nt_ty(  @ast::ty),
    nt_ident(str_num, bool),
    nt_path(@ast::path),
    nt_tt(  @ast::token_tree), //needs @ed to break a circularity
    nt_matchers(~[ast::matcher])
}

fn binop_to_str(o: binop) -> ~str {
    alt o {
      PLUS { ~"+" }
      MINUS { ~"-" }
      STAR { ~"*" }
      SLASH { ~"/" }
      PERCENT { ~"%" }
      CARET { ~"^" }
      AND { ~"&" }
      OR { ~"|" }
      SHL { ~"<<" }
      SHR { ~">>" }
    }
}

fn to_str(in: interner<@~str>, t: token) -> ~str {
    alt t {
      EQ { ~"=" }
      LT { ~"<" }
      LE { ~"<=" }
      EQEQ { ~"==" }
      NE { ~"!=" }
      GE { ~">=" }
      GT { ~">" }
      NOT { ~"!" }
      TILDE { ~"~" }
      OROR { ~"||" }
      ANDAND { ~"&&" }
      BINOP(op) { binop_to_str(op) }
      BINOPEQ(op) { binop_to_str(op) + ~"=" }

      /* Structural symbols */
      AT { ~"@" }
      DOT { ~"." }
      ELLIPSIS { ~"..." }
      COMMA { ~"," }
      SEMI { ~";" }
      COLON { ~":" }
      MOD_SEP { ~"::" }
      RARROW { ~"->" }
      LARROW { ~"<-" }
      DARROW { ~"<->" }
      FAT_ARROW { ~"=>" }
      LPAREN { ~"(" }
      RPAREN { ~")" }
      LBRACKET { ~"[" }
      RBRACKET { ~"]" }
      LBRACE { ~"{" }
      RBRACE { ~"}" }
      POUND { ~"#" }
      DOLLAR { ~"$" }

      /* Literals */
      LIT_INT(c, ast::ty_char) {
        ~"'" + char::escape_default(c as char) + ~"'"
      }
      LIT_INT(i, t) {
        int::to_str(i as int, 10u) + ast_util::int_ty_to_str(t)
      }
      LIT_UINT(u, t) {
        uint::to_str(u as uint, 10u) + ast_util::uint_ty_to_str(t)
      }
      LIT_INT_UNSUFFIXED(i) {
        int::to_str(i as int, 10u)
      }
      LIT_FLOAT(s, t) {
        let mut body = *in.get(s);
        if body.ends_with(".") {
            body = body + "0";  // `10.f` is not a float literal
        }
        body + ast_util::float_ty_to_str(t)
      }
      LIT_STR(s) { ~"\"" + str::escape_default( *in.get(s)) + ~"\"" }

      /* Name components */
      IDENT(s, _) { *in.get(s) }

      UNDERSCORE { ~"_" }

      /* Other */
      DOC_COMMENT(s) { *in.get(s) }
      EOF { ~"<eof>" }
      INTERPOLATED(nt) {
        ~"an interpolated " +
            alt nt {
              nt_item(*) { ~"item" } nt_block(*) { ~"block" }
              nt_stmt(*) { ~"statement" } nt_pat(*) { ~"pattern" }
              nt_expr(*) { ~"expression" } nt_ty(*) { ~"type" }
              nt_ident(*) { ~"identifier" } nt_path(*) { ~"path" }
              nt_tt(*) { ~"tt" } nt_matchers(*) { ~"matcher sequence" }
            }
      }
    }
}

pure fn can_begin_expr(t: token) -> bool {
    alt t {
      LPAREN { true }
      LBRACE { true }
      LBRACKET { true }
      IDENT(_, _) { true }
      UNDERSCORE { true }
      TILDE { true }
      LIT_INT(_, _) { true }
      LIT_UINT(_, _) { true }
      LIT_INT_UNSUFFIXED(_) { true }
      LIT_FLOAT(_, _) { true }
      LIT_STR(_) { true }
      POUND { true }
      AT { true }
      NOT { true }
      BINOP(MINUS) { true }
      BINOP(STAR) { true }
      BINOP(AND) { true }
      BINOP(OR) { true } // in lambda syntax
      OROR { true } // in lambda syntax
      MOD_SEP { true }
      INTERPOLATED(nt_expr(*))
      | INTERPOLATED(nt_ident(*))
      | INTERPOLATED(nt_block(*))
      | INTERPOLATED(nt_path(*)) { true }
      _ { false }
    }
}

/// what's the opposite delimiter?
fn flip_delimiter(&t: token::token) -> token::token {
    alt t {
      token::LPAREN { token::RPAREN }
      token::LBRACE { token::RBRACE }
      token::LBRACKET { token::RBRACKET }
      token::RPAREN { token::LPAREN }
      token::RBRACE { token::LBRACE }
      token::RBRACKET { token::LBRACKET }
      _ { fail }
    }
}

fn is_lit(t: token) -> bool {
    alt t {
      LIT_INT(_, _) { true }
      LIT_UINT(_, _) { true }
      LIT_INT_UNSUFFIXED(_) { true }
      LIT_FLOAT(_, _) { true }
      LIT_STR(_) { true }
      _ { false }
    }
}

pure fn is_ident(t: token) -> bool {
    alt t { IDENT(_, _) { true } _ { false } }
}

pure fn is_plain_ident(t: token) -> bool {
    alt t { IDENT(_, false) { true } _ { false } }
}

pure fn is_bar(t: token) -> bool {
    alt t { BINOP(OR) | OROR { true } _ { false } }
}

/**
 * All the valid words that have meaning in the Rust language.
 *
 * Rust keywords are either 'contextual' or 'restricted'. Contextual
 * keywords may be used as identifiers because their appearance in
 * the grammar is unambiguous. Restricted keywords may not appear
 * in positions that might otherwise contain _value identifiers_.
 */
fn keyword_table() -> hashmap<~str, ()> {
    let keywords = str_hash();
    for contextual_keyword_table().each_key |word| {
        keywords.insert(word, ());
    }
    for restricted_keyword_table().each_key |word| {
        keywords.insert(word, ());
    }
    keywords
}

/// Keywords that may be used as identifiers
fn contextual_keyword_table() -> hashmap<~str, ()> {
    let words = str_hash();
    let keys = ~[
        ~"as",
        ~"else",
        ~"move",
        ~"of",
        ~"priv", ~"pub",
        ~"self", ~"send", ~"static",
        ~"to",
        ~"use",
        ~"with"
    ];
    for keys.each |word| {
        words.insert(word, ());
    }
    words
}

/**
 * Keywords that may not appear in any position that might otherwise contain a
 * _value identifier_. Restricted keywords may still be used as other types of
 * identifiers.
 *
 * Reasons:
 *
 * * For some (most?), if used at the start of a line, they will cause the
 *   line to be interpreted as a specific kind of statement, which would be
 *   confusing.
 *
 * * `true` or `false` as identifiers would always be shadowed by
 *   the boolean constants
 */
fn restricted_keyword_table() -> hashmap<~str, ()> {
    let words = str_hash();
    let keys = ~[
        ~"alt", ~"again", ~"assert",
        ~"break",
        ~"check", ~"class", ~"const", ~"copy",
        ~"do", ~"drop",
        ~"else", ~"enum", ~"export", ~"extern",
        ~"fail", ~"false", ~"fn", ~"for",
        ~"if", ~"impl", ~"import",
        ~"let", ~"log", ~"loop",
        ~"match", ~"mod", ~"module", ~"move", ~"mut",
        ~"new",
        ~"owned",
        ~"pure",
        ~"ref", ~"return",
        ~"struct",
        ~"true", ~"trait", ~"type",
        ~"unchecked", ~"unsafe",
        ~"while"
    ];
    for keys.each |word| {
        words.insert(word, ());
    }
    words
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Revert "Remove "iface" from keyword table."<commit_after>import util::interner;
import util::interner::interner;
import std::map::{hashmap, str_hash};
import std::serialization::{serializer,
                            deserializer,
                            serialize_uint,
                            deserialize_uint,
                            serialize_i64,
                            deserialize_i64,
                            serialize_u64,
                            deserialize_u64,
                            serialize_bool,
                            deserialize_bool};

#[auto_serialize]
type str_num = uint;

#[auto_serialize]
enum binop {
    PLUS,
    MINUS,
    STAR,
    SLASH,
    PERCENT,
    CARET,
    AND,
    OR,
    SHL,
    SHR,
}

#[auto_serialize]
enum token {
    /* Expression-operator symbols. */
    EQ,
    LT,
    LE,
    EQEQ,
    NE,
    GE,
    GT,
    ANDAND,
    OROR,
    NOT,
    TILDE,
    BINOP(binop),
    BINOPEQ(binop),

    /* Structural symbols */
    AT,
    DOT,
    ELLIPSIS,
    COMMA,
    SEMI,
    COLON,
    MOD_SEP,
    RARROW,
    LARROW,
    DARROW,
    FAT_ARROW,
    LPAREN,
    RPAREN,
    LBRACKET,
    RBRACKET,
    LBRACE,
    RBRACE,
    POUND,
    DOLLAR,

    /* Literals */
    LIT_INT(i64, ast::int_ty),
    LIT_UINT(u64, ast::uint_ty),
    LIT_INT_UNSUFFIXED(i64),
    LIT_FLOAT(str_num, ast::float_ty),
    LIT_STR(str_num),

    /* Name components */
    IDENT(str_num, bool),
    UNDERSCORE,

    /* For interpolation */
    INTERPOLATED(nonterminal),

    DOC_COMMENT(str_num),
    EOF,
}

#[auto_serialize]
/// For interpolation during macro expansion.
enum nonterminal {
    nt_item(@ast::item),
    nt_block(ast::blk),
    nt_stmt(@ast::stmt),
    nt_pat( @ast::pat),
    nt_expr(@ast::expr),
    nt_ty(  @ast::ty),
    nt_ident(str_num, bool),
    nt_path(@ast::path),
    nt_tt(  @ast::token_tree), //needs @ed to break a circularity
    nt_matchers(~[ast::matcher])
}

fn binop_to_str(o: binop) -> ~str {
    alt o {
      PLUS { ~"+" }
      MINUS { ~"-" }
      STAR { ~"*" }
      SLASH { ~"/" }
      PERCENT { ~"%" }
      CARET { ~"^" }
      AND { ~"&" }
      OR { ~"|" }
      SHL { ~"<<" }
      SHR { ~">>" }
    }
}

fn to_str(in: interner<@~str>, t: token) -> ~str {
    alt t {
      EQ { ~"=" }
      LT { ~"<" }
      LE { ~"<=" }
      EQEQ { ~"==" }
      NE { ~"!=" }
      GE { ~">=" }
      GT { ~">" }
      NOT { ~"!" }
      TILDE { ~"~" }
      OROR { ~"||" }
      ANDAND { ~"&&" }
      BINOP(op) { binop_to_str(op) }
      BINOPEQ(op) { binop_to_str(op) + ~"=" }

      /* Structural symbols */
      AT { ~"@" }
      DOT { ~"." }
      ELLIPSIS { ~"..." }
      COMMA { ~"," }
      SEMI { ~";" }
      COLON { ~":" }
      MOD_SEP { ~"::" }
      RARROW { ~"->" }
      LARROW { ~"<-" }
      DARROW { ~"<->" }
      FAT_ARROW { ~"=>" }
      LPAREN { ~"(" }
      RPAREN { ~")" }
      LBRACKET { ~"[" }
      RBRACKET { ~"]" }
      LBRACE { ~"{" }
      RBRACE { ~"}" }
      POUND { ~"#" }
      DOLLAR { ~"$" }

      /* Literals */
      LIT_INT(c, ast::ty_char) {
        ~"'" + char::escape_default(c as char) + ~"'"
      }
      LIT_INT(i, t) {
        int::to_str(i as int, 10u) + ast_util::int_ty_to_str(t)
      }
      LIT_UINT(u, t) {
        uint::to_str(u as uint, 10u) + ast_util::uint_ty_to_str(t)
      }
      LIT_INT_UNSUFFIXED(i) {
        int::to_str(i as int, 10u)
      }
      LIT_FLOAT(s, t) {
        let mut body = *in.get(s);
        if body.ends_with(".") {
            body = body + "0";  // `10.f` is not a float literal
        }
        body + ast_util::float_ty_to_str(t)
      }
      LIT_STR(s) { ~"\"" + str::escape_default( *in.get(s)) + ~"\"" }

      /* Name components */
      IDENT(s, _) { *in.get(s) }

      UNDERSCORE { ~"_" }

      /* Other */
      DOC_COMMENT(s) { *in.get(s) }
      EOF { ~"<eof>" }
      INTERPOLATED(nt) {
        ~"an interpolated " +
            alt nt {
              nt_item(*) { ~"item" } nt_block(*) { ~"block" }
              nt_stmt(*) { ~"statement" } nt_pat(*) { ~"pattern" }
              nt_expr(*) { ~"expression" } nt_ty(*) { ~"type" }
              nt_ident(*) { ~"identifier" } nt_path(*) { ~"path" }
              nt_tt(*) { ~"tt" } nt_matchers(*) { ~"matcher sequence" }
            }
      }
    }
}

pure fn can_begin_expr(t: token) -> bool {
    alt t {
      LPAREN { true }
      LBRACE { true }
      LBRACKET { true }
      IDENT(_, _) { true }
      UNDERSCORE { true }
      TILDE { true }
      LIT_INT(_, _) { true }
      LIT_UINT(_, _) { true }
      LIT_INT_UNSUFFIXED(_) { true }
      LIT_FLOAT(_, _) { true }
      LIT_STR(_) { true }
      POUND { true }
      AT { true }
      NOT { true }
      BINOP(MINUS) { true }
      BINOP(STAR) { true }
      BINOP(AND) { true }
      BINOP(OR) { true } // in lambda syntax
      OROR { true } // in lambda syntax
      MOD_SEP { true }
      INTERPOLATED(nt_expr(*))
      | INTERPOLATED(nt_ident(*))
      | INTERPOLATED(nt_block(*))
      | INTERPOLATED(nt_path(*)) { true }
      _ { false }
    }
}

/// what's the opposite delimiter?
fn flip_delimiter(&t: token::token) -> token::token {
    alt t {
      token::LPAREN { token::RPAREN }
      token::LBRACE { token::RBRACE }
      token::LBRACKET { token::RBRACKET }
      token::RPAREN { token::LPAREN }
      token::RBRACE { token::LBRACE }
      token::RBRACKET { token::LBRACKET }
      _ { fail }
    }
}

fn is_lit(t: token) -> bool {
    alt t {
      LIT_INT(_, _) { true }
      LIT_UINT(_, _) { true }
      LIT_INT_UNSUFFIXED(_) { true }
      LIT_FLOAT(_, _) { true }
      LIT_STR(_) { true }
      _ { false }
    }
}

pure fn is_ident(t: token) -> bool {
    alt t { IDENT(_, _) { true } _ { false } }
}

pure fn is_plain_ident(t: token) -> bool {
    alt t { IDENT(_, false) { true } _ { false } }
}

pure fn is_bar(t: token) -> bool {
    alt t { BINOP(OR) | OROR { true } _ { false } }
}

/**
 * All the valid words that have meaning in the Rust language.
 *
 * Rust keywords are either 'contextual' or 'restricted'. Contextual
 * keywords may be used as identifiers because their appearance in
 * the grammar is unambiguous. Restricted keywords may not appear
 * in positions that might otherwise contain _value identifiers_.
 */
fn keyword_table() -> hashmap<~str, ()> {
    let keywords = str_hash();
    for contextual_keyword_table().each_key |word| {
        keywords.insert(word, ());
    }
    for restricted_keyword_table().each_key |word| {
        keywords.insert(word, ());
    }
    keywords
}

/// Keywords that may be used as identifiers
fn contextual_keyword_table() -> hashmap<~str, ()> {
    let words = str_hash();
    let keys = ~[
        ~"as",
        ~"else",
        ~"move",
        ~"of",
        ~"priv", ~"pub",
        ~"self", ~"send", ~"static",
        ~"to",
        ~"use",
        ~"with"
    ];
    for keys.each |word| {
        words.insert(word, ());
    }
    words
}

/**
 * Keywords that may not appear in any position that might otherwise contain a
 * _value identifier_. Restricted keywords may still be used as other types of
 * identifiers.
 *
 * Reasons:
 *
 * * For some (most?), if used at the start of a line, they will cause the
 *   line to be interpreted as a specific kind of statement, which would be
 *   confusing.
 *
 * * `true` or `false` as identifiers would always be shadowed by
 *   the boolean constants
 */
fn restricted_keyword_table() -> hashmap<~str, ()> {
    let words = str_hash();
    let keys = ~[
        ~"alt", ~"again", ~"assert",
        ~"break",
        ~"check", ~"class", ~"const", ~"copy",
        ~"do", ~"drop",
        ~"else", ~"enum", ~"export", ~"extern",
        ~"fail", ~"false", ~"fn", ~"for",
        ~"if", ~"iface", ~"impl", ~"import",
        ~"let", ~"log", ~"loop",
        ~"match", ~"mod", ~"module", ~"move", ~"mut",
        ~"new",
        ~"owned",
        ~"pure",
        ~"ref", ~"return",
        ~"struct",
        ~"true", ~"trait", ~"type",
        ~"unchecked", ~"unsafe",
        ~"while"
    ];
    for keys.each |word| {
        words.insert(word, ());
    }
    words
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use self::x86::*;

mod x86 {
    pub fn wmb() {
        unsafe {
            asm!("sfence" ::: "memory" : "volatile");
        }
    }
}
<commit_msg>libxen: Add atomic_set_bit and atomic_clear_bit<commit_after>#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use self::x86::*;

mod x86 {
    pub unsafe fn atomic_set_bit<T>(nr: usize, addr: *mut T) {
        asm!("lock bts $1, $0"
             :: "=*m" (addr as *mut u32), "Ir" (nr)
             : "memory"
             : "volatile");
    }

    pub unsafe fn atomic_clear_bit<T>(nr: usize, addr: *mut T) {
        asm!("lock btr $1, $0"
             :: "=*m" (addr as *mut u32), "Ir" (nr)
             : "memory"
             : "volatile");
    }

    pub fn wmb() {
        unsafe {
            asm!("sfence" ::: "memory" : "volatile");
        }
    }

    #[test]
    pub fn test_set_and_clear() {
        let mut array = [0u32; 4];

        unsafe  {
            atomic_set_bit(1, &mut array[0] as *mut u32);
            atomic_set_bit(2, &mut array[0] as *mut u32);
            atomic_set_bit(3, &mut array[0] as *mut u32);
            atomic_set_bit(32, &mut array[0] as *mut u32);
            atomic_set_bit(33, &mut array[0] as *mut u32);
            atomic_set_bit(34, &mut array[0] as *mut u32);
            atomic_set_bit(127, &mut array[0] as *mut u32);

            assert_eq!(array[0], 0xE);
            assert_eq!(array[1], 0x7);
            assert_eq!(array[2], 0x0);
            assert_eq!(array[3], 0x80000000);

            atomic_clear_bit(1, &mut array[0] as *mut u32);
            atomic_clear_bit(2, &mut array[0] as *mut u32);
            atomic_clear_bit(3, &mut array[0] as *mut u32);
            atomic_clear_bit(32, &mut array[0] as *mut u32);
            atomic_clear_bit(33, &mut array[0] as *mut u32);
            atomic_clear_bit(34, &mut array[0] as *mut u32);
            atomic_clear_bit(127, &mut array[0] as *mut u32);

            assert_eq!(array[0], 0x0);
            assert_eq!(array[1], 0x0);
            assert_eq!(array[2], 0x0);
            assert_eq!(array[3], 0x0);
        }
    }
}
<|endoftext|>