<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Finds items that are externally reachable, to determine which items
// need to have their metadata (and possibly their AST) serialized.
// All items that can be referred to through an exported name are
// reachable, and when a reachable thing is inline or generic, it
// makes all other generics or inline functions that it references
// reachable as well.

use middle::ty;
use middle::typeck;

use std::hashmap::HashSet;
use syntax::ast::*;
use syntax::ast_map;
use syntax::ast_util::def_id_of_def;
use syntax::attr;
use syntax::parse::token;
use syntax::oldvisit::Visitor;
use syntax::oldvisit;

// Returns true if the given set of attributes contains the `#[inline]`
// attribute.
fn attributes_specify_inlining(attrs: &[Attribute]) -> bool {
    attr::contains_name(attrs, "inline")
}

// Returns true if the given set of generics implies that the item it's
// associated with must be inlined.
fn generics_require_inlining(generics: &Generics) -> bool {
    !generics.ty_params.is_empty()
}

// Returns true if the given item must be inlined because it may be
// monomorphized or it was marked with `#[inline]`. This will only return
// true for functions.
fn item_might_be_inlined(item: @item) -> bool {
    if attributes_specify_inlining(item.attrs) {
        return true
    }

    match item.node {
        item_fn(_, _, _, ref generics, _) => {
            generics_require_inlining(generics)
        }
        _ => false,
    }
}

// Returns true if the given type method must be inlined because it may be
// monomorphized or it was marked with `#[inline]`.
fn ty_method_might_be_inlined(ty_method: &TypeMethod) -> bool {
    attributes_specify_inlining(ty_method.attrs) ||
        generics_require_inlining(&ty_method.generics)
}

// Returns true if the given trait method must be inlined because it may be
// monomorphized or it was marked with `#[inline]`.
fn trait_method_might_be_inlined(trait_method: &trait_method) -> bool {
    match *trait_method {
        required(ref ty_method) => ty_method_might_be_inlined(ty_method),
        provided(_) => true
    }
}

// The context we're in. If we're in a public context, then public symbols are
// marked reachable. If we're in a private context, then only trait
// implementations are marked reachable.
#[deriving(Clone, Eq)]
enum PrivacyContext {
    PublicContext,
    PrivateContext,
}

// Information needed while computing reachability.
struct ReachableContext {
    // The type context.
    tcx: ty::ctxt,
    // The method map, which links node IDs of method call expressions to the
    // methods they've been resolved to.
    method_map: typeck::method_map,
    // The set of items which must be exported in the linkage sense.
    reachable_symbols: @mut HashSet<NodeId>,
    // A worklist of item IDs. Each item ID in this worklist will be inlined
    // and will be scanned for further references.
    worklist: @mut ~[NodeId],
}

impl ReachableContext {
    // Creates a new reachability computation context.
    fn new(tcx: ty::ctxt, method_map: typeck::method_map)
           -> ReachableContext {
        ReachableContext {
            tcx: tcx,
            method_map: method_map,
            reachable_symbols: @mut HashSet::new(),
            worklist: @mut ~[],
        }
    }

    // Step 1: Mark all public symbols, and add all public symbols that might
    // be inlined to a worklist.
    fn mark_public_symbols(&self, crate: @Crate) {
        let reachable_symbols = self.reachable_symbols;
        let worklist = self.worklist;
        let visitor = oldvisit::mk_vt(@Visitor {
            visit_item: |item, (privacy_context, visitor):
                    (PrivacyContext, oldvisit::vt<PrivacyContext>)| {
                match item.node {
                    item_fn(*) => {
                        if privacy_context == PublicContext {
                            reachable_symbols.insert(item.id);
                        }
                        if item_might_be_inlined(item) {
                            worklist.push(item.id)
                        }
                    }
                    item_struct(ref struct_def, _) => {
                        match struct_def.ctor_id {
                            Some(ctor_id) if
                                    privacy_context == PublicContext => {
                                reachable_symbols.insert(ctor_id);
                            }
                            Some(_) | None => {}
                        }
                    }
                    item_enum(ref enum_def, _) => {
                        if privacy_context == PublicContext {
                            for variant in enum_def.variants.iter() {
                                reachable_symbols.insert(variant.node.id);
                            }
                        }
                    }
                    item_impl(ref generics, ref trait_ref, _, ref methods) => {
                        // XXX(pcwalton): We conservatively assume any methods
                        // on a trait implementation are reachable, when this
                        // is not the case. We could be more precise by only
                        // treating implementations of reachable or cross-
                        // crate traits as reachable.

                        let should_be_considered_public = |method: @method| {
                            (method.vis == public &&
                                    privacy_context == PublicContext) ||
                                    trait_ref.is_some()
                        };

                        // Mark all public methods as reachable.
                        for &method in methods.iter() {
                            if should_be_considered_public(method) {
                                reachable_symbols.insert(method.id);
                            }
                        }

                        if generics_require_inlining(generics) {
                            // If the impl itself has generics, add all public
                            // symbols to the worklist.
                            for &method in methods.iter() {
                                if should_be_considered_public(method) {
                                    worklist.push(method.id)
                                }
                            }
                        } else {
                            // Otherwise, add only public methods that have
                            // generics to the worklist.
                            for method in methods.iter() {
                                let generics = &method.generics;
                                let attrs = &method.attrs;
                                if generics_require_inlining(generics) ||
                                        attributes_specify_inlining(*attrs) ||
                                        should_be_considered_public(*method) {
                                    worklist.push(method.id)
                                }
                            }
                        }
                    }
                    item_trait(_, _, ref trait_methods) => {
                        // Mark all provided methods as reachable.
                        if privacy_context == PublicContext {
                            for trait_method in trait_methods.iter() {
                                match *trait_method {
                                    provided(method) => {
                                        reachable_symbols.insert(method.id);
                                        worklist.push(method.id)
                                    }
                                    required(_) => {}
                                }
                            }
                        }
                    }
                    _ => {}
                }

                if item.vis == public && privacy_context == PublicContext {
                    oldvisit::visit_item(item, (PublicContext, visitor))
                } else {
                    oldvisit::visit_item(item, (PrivateContext, visitor))
                }
            },
            .. *oldvisit::default_visitor()
        });

        oldvisit::visit_crate(crate, (PublicContext, visitor))
    }

    // Returns true if the given def ID represents a local item that is
    // eligible for inlining and false otherwise.
    fn def_id_represents_local_inlined_item(tcx: ty::ctxt, def_id: def_id)
                                            -> bool {
        if def_id.crate != LOCAL_CRATE {
            return false
        }

        let node_id = def_id.node;
        match tcx.items.find(&node_id) {
            Some(&ast_map::node_item(item, _)) => {
                match item.node {
                    item_fn(*) => item_might_be_inlined(item),
                    _ => false,
                }
            }
            Some(&ast_map::node_trait_method(trait_method, _, _)) => {
                match *trait_method {
                    required(_) => false,
                    provided(_) => true,
                }
            }
            Some(&ast_map::node_method(method, impl_did, _)) => {
                if generics_require_inlining(&method.generics) ||
                        attributes_specify_inlining(method.attrs) {
                    true
                } else {
                    // Check the impl. If the generics on the self type of the
                    // impl require inlining, this method does too.
                    assert!(impl_did.crate == LOCAL_CRATE);
                    match tcx.items.find(&impl_did.node) {
                        Some(&ast_map::node_item(item, _)) => {
                            match item.node {
                                item_impl(ref generics, _, _, _) => {
                                    generics_require_inlining(generics)
                                }
                                _ => false
                            }
                        }
                        Some(_) => {
                            tcx.sess.span_bug(method.span,
                                              "method is not inside an \
                                               impl?!")
                        }
                        None => {
                            tcx.sess.span_bug(method.span,
                                              "the impl that this method is \
                                               supposedly inside of doesn't \
                                               exist in the AST map?!")
                        }
                    }
                }
            }
            Some(_) => false,
            None => false   // This will happen for default methods.
        }
    }

    // Helper function to set up a visitor for `propagate()` below.
    fn init_visitor(&self) -> oldvisit::vt<()> {
        let (worklist, method_map) = (self.worklist, self.method_map);
        let (tcx, reachable_symbols) = (self.tcx, self.reachable_symbols);
        oldvisit::mk_vt(@oldvisit::Visitor {
            visit_expr: |expr, (_, visitor)| {
                match expr.node {
                    expr_path(_) => {
                        let def = match tcx.def_map.find(&expr.id) {
                            Some(&def) => def,
                            None => {
                                tcx.sess.span_bug(expr.span,
                                                  "def ID not in def map?!")
                            }
                        };

                        let def_id = def_id_of_def(def);
                        if ReachableContext::
                                def_id_represents_local_inlined_item(tcx,
                                                                     def_id) {
                            worklist.push(def_id.node)
                        }
                        reachable_symbols.insert(def_id.node);
                    }
                    expr_method_call(*) => {
                        match method_map.find(&expr.id) {
                            Some(&typeck::method_map_entry {
                                origin: typeck::method_static(def_id),
                                _
                            }) => {
                                if ReachableContext::
                                    def_id_represents_local_inlined_item(
                                        tcx,
                                        def_id) {
                                    worklist.push(def_id.node)
                                }
                                reachable_symbols.insert(def_id.node);
                            }
                            Some(_) => {}
                            None => {
                                tcx.sess.span_bug(expr.span,
                                                  "method call expression \
                                                   not in method map?!")
                            }
                        }
                    }
                    _ => {}
                }

                oldvisit::visit_expr(expr, ((), visitor))
            },
            ..*oldvisit::default_visitor()
        })
    }

    // Step 2: Mark all symbols that the symbols on the worklist touch.
    fn propagate(&self) {
        let visitor = self.init_visitor();
        let mut scanned = HashSet::new();
        while self.worklist.len() > 0 {
            let search_item = self.worklist.pop();
            if scanned.contains(&search_item) {
                loop
            }
            scanned.insert(search_item);
            self.reachable_symbols.insert(search_item);

            // Find the AST block corresponding to the item and visit it,
            // marking all path expressions that resolve to something
            // interesting.
            match self.tcx.items.find(&search_item) {
                Some(&ast_map::node_item(item, _)) => {
                    match item.node {
                        item_fn(_, _, _, _, ref search_block) => {
                            oldvisit::visit_block(search_block, ((), visitor))
                        }
                        _ => {
                            self.tcx.sess.span_bug(item.span,
                                                   "found non-function item \
                                                    in worklist?!")
                        }
                    }
                }
                Some(&ast_map::node_trait_method(trait_method, _, _)) => {
                    match *trait_method {
                        required(ref ty_method) => {
                            self.tcx.sess.span_bug(ty_method.span,
                                                   "found required method in \
                                                    worklist?!")
                        }
                        provided(ref method) => {
                            oldvisit::visit_block(&method.body, ((), visitor))
                        }
                    }
                }
                Some(&ast_map::node_method(ref method, _, _)) => {
                    oldvisit::visit_block(&method.body, ((), visitor))
                }
                Some(_) => {
                    let ident_interner = token::get_ident_interner();
                    let desc = ast_map::node_id_to_str(self.tcx.items,
                                                       search_item,
                                                       ident_interner);
                    self.tcx.sess.bug(fmt!("found unexpected thingy in \
                                            worklist: %s",
                                            desc))
                }
                None => {
                    self.tcx.sess.bug(fmt!("found unmapped ID in worklist: \
                                            %d",
                                           search_item))
                }
            }
        }
    }

    // Step 3: Mark all destructors as reachable.
    //
    // XXX(pcwalton): This is a conservative overapproximation, but fixing
    // this properly would result in the necessity of computing *type*
    // reachability, which might result in a compile time loss.
    fn mark_destructors_reachable(&self) {
        for (_, destructor_def_id) in self.tcx.destructor_for_type.iter() {
            if destructor_def_id.crate == LOCAL_CRATE {
                self.reachable_symbols.insert(destructor_def_id.node);
            }
        }
    }
}

pub fn find_reachable(tcx: ty::ctxt,
                      method_map: typeck::method_map,
                      crate: @Crate)
                      -> @mut HashSet<NodeId> {
    // XXX(pcwalton): We only need to mark symbols that are exported. But this
    // is more complicated than just looking at whether the symbol is `pub`,
    // because it might be the target of a `pub use` somewhere. For now, I
    // think we are fine, because you can't `pub use` something that wasn't
    // exported due to the bug whereby `use` only looks through public
    // modules even if you're inside the module the `use` appears in. When
    // this bug is fixed, however, this code will need to be updated. Probably
    // the easiest way to fix this (although a conservative overapproximation)
    // is to have the name resolution pass mark all targets of a `pub use` as
    // "must be reachable".

    let reachable_context = ReachableContext::new(tcx, method_map);

    // Step 1: Mark all public symbols, and add all public symbols that might
    // be inlined to a worklist.
    reachable_context.mark_public_symbols(crate);

    // Step 2: Mark all symbols that the symbols on the worklist touch.
    reachable_context.propagate();

    // Step 3: Mark all destructors as reachable.
    reachable_context.mark_destructors_reachable();

    // Return the set of reachable symbols.
    reachable_context.reachable_symbols
}
<commit_msg>port reachable.rs from oldvisit to <V:Visitor> trait.<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Finds items that are externally reachable, to determine which items
// need to have their metadata (and possibly their AST) serialized.
// All items that can be referred to through an exported name are
// reachable, and when a reachable thing is inline or generic, it
// makes all other generics or inline functions that it references
// reachable as well.

use middle::ty;
use middle::typeck;

use std::hashmap::HashSet;
use syntax::ast::*;
use syntax::ast_map;
use syntax::ast_util::def_id_of_def;
use syntax::attr;
use syntax::parse::token;
use syntax::visit::Visitor;
use syntax::visit;

// Returns true if the given set of attributes contains the `#[inline]`
// attribute.
fn attributes_specify_inlining(attrs: &[Attribute]) -> bool {
    attr::contains_name(attrs, "inline")
}

// Returns true if the given set of generics implies that the item it's
// associated with must be inlined.
fn generics_require_inlining(generics: &Generics) -> bool {
    !generics.ty_params.is_empty()
}

// Returns true if the given item must be inlined because it may be
// monomorphized or it was marked with `#[inline]`. This will only return
// true for functions.
fn item_might_be_inlined(item: @item) -> bool {
    if attributes_specify_inlining(item.attrs) {
        return true
    }

    match item.node {
        item_fn(_, _, _, ref generics, _) => {
            generics_require_inlining(generics)
        }
        _ => false,
    }
}

// Returns true if the given type method must be inlined because it may be
// monomorphized or it was marked with `#[inline]`.
fn ty_method_might_be_inlined(ty_method: &TypeMethod) -> bool {
    attributes_specify_inlining(ty_method.attrs) ||
        generics_require_inlining(&ty_method.generics)
}

// Returns true if the given trait method must be inlined because it may be
// monomorphized or it was marked with `#[inline]`.
fn trait_method_might_be_inlined(trait_method: &trait_method) -> bool {
    match *trait_method {
        required(ref ty_method) => ty_method_might_be_inlined(ty_method),
        provided(_) => true
    }
}

// The context we're in. If we're in a public context, then public symbols are
// marked reachable. If we're in a private context, then only trait
// implementations are marked reachable.
#[deriving(Clone, Eq)]
enum PrivacyContext {
    PublicContext,
    PrivateContext,
}

// Information needed while computing reachability.
struct ReachableContext {
    // The type context.
    tcx: ty::ctxt,
    // The method map, which links node IDs of method call expressions to the
    // methods they've been resolved to.
    method_map: typeck::method_map,
    // The set of items which must be exported in the linkage sense.
    reachable_symbols: @mut HashSet<NodeId>,
    // A worklist of item IDs. Each item ID in this worklist will be inlined
    // and will be scanned for further references.
    worklist: @mut ~[NodeId],
}

struct ReachableVisitor {
    reachable_symbols: @mut HashSet<NodeId>,
    worklist: @mut ~[NodeId],
}

impl Visitor<PrivacyContext> for ReachableVisitor {

    fn visit_item(&mut self, item:@item, privacy_context:PrivacyContext) {

                match item.node {
                    item_fn(*) => {
                        if privacy_context == PublicContext {
                            self.reachable_symbols.insert(item.id);
                        }
                        if item_might_be_inlined(item) {
                            self.worklist.push(item.id)
                        }
                    }
                    item_struct(ref struct_def, _) => {
                        match struct_def.ctor_id {
                            Some(ctor_id) if
                                    privacy_context == PublicContext => {
                                self.reachable_symbols.insert(ctor_id);
                            }
                            Some(_) | None => {}
                        }
                    }
                    item_enum(ref enum_def, _) => {
                        if privacy_context == PublicContext {
                            for variant in enum_def.variants.iter() {
                                self.reachable_symbols.insert(variant.node.id);
                            }
                        }
                    }
                    item_impl(ref generics, ref trait_ref, _, ref methods) => {
                        // XXX(pcwalton): We conservatively assume any methods
                        // on a trait implementation are reachable, when this
                        // is not the case. We could be more precise by only
                        // treating implementations of reachable or cross-
                        // crate traits as reachable.

                        let should_be_considered_public = |method: @method| {
                            (method.vis == public &&
                                    privacy_context == PublicContext) ||
                                    trait_ref.is_some()
                        };

                        // Mark all public methods as reachable.
                        for &method in methods.iter() {
                            if should_be_considered_public(method) {
                                self.reachable_symbols.insert(method.id);
                            }
                        }

                        if generics_require_inlining(generics) {
                            // If the impl itself has generics, add all public
                            // symbols to the worklist.
                            for &method in methods.iter() {
                                if should_be_considered_public(method) {
                                    self.worklist.push(method.id)
                                }
                            }
                        } else {
                            // Otherwise, add only public methods that have
                            // generics to the worklist.
                            for method in methods.iter() {
                                let generics = &method.generics;
                                let attrs = &method.attrs;
                                if generics_require_inlining(generics) ||
                                        attributes_specify_inlining(*attrs) ||
                                        should_be_considered_public(*method) {
                                    self.worklist.push(method.id)
                                }
                            }
                        }
                    }
                    item_trait(_, _, ref trait_methods) => {
                        // Mark all provided methods as reachable.
                        if privacy_context == PublicContext {
                            for trait_method in trait_methods.iter() {
                                match *trait_method {
                                    provided(method) => {
                                        self.reachable_symbols.insert(method.id);
                                        self.worklist.push(method.id)
                                    }
                                    required(_) => {}
                                }
                            }
                        }
                    }
                    _ => {}
                }

                if item.vis == public && privacy_context == PublicContext {
                    visit::walk_item(self, item, PublicContext)
                } else {
                    visit::walk_item(self, item, PrivateContext)
                }
    }

}

struct MarkSymbolVisitor {
    worklist: @mut ~[NodeId],
    method_map: typeck::method_map,
    tcx: ty::ctxt,
    reachable_symbols: @mut HashSet<NodeId>,
}

impl Visitor<()> for MarkSymbolVisitor {

    fn visit_expr(&mut self, expr:@expr, _:()) {

                match expr.node {
                    expr_path(_) => {
                        let def = match self.tcx.def_map.find(&expr.id) {
                            Some(&def) => def,
                            None => {
                                self.tcx.sess.span_bug(expr.span,
                                                  "def ID not in def map?!")
                            }
                        };

                        let def_id = def_id_of_def(def);
                        if ReachableContext::
                                def_id_represents_local_inlined_item(self.tcx,
                                                                     def_id) {
                            self.worklist.push(def_id.node)
                        }
                        self.reachable_symbols.insert(def_id.node);
                    }
                    expr_method_call(*) => {
                        match self.method_map.find(&expr.id) {
                            Some(&typeck::method_map_entry {
                                origin: typeck::method_static(def_id),
                                _
                            }) => {
                                if ReachableContext::
                                    def_id_represents_local_inlined_item(
                                        self.tcx,
                                        def_id) {
                                    self.worklist.push(def_id.node)
                                }
                                self.reachable_symbols.insert(def_id.node);
                            }
                            Some(_) => {}
                            None => {
                                self.tcx.sess.span_bug(expr.span,
                                                  "method call expression \
                                                   not in method map?!")
                            }
                        }
                    }
                    _ => {}
                }

                visit::walk_expr(self, expr, ())
    }
}

impl ReachableContext {
    // Creates a new reachability computation context.
    fn new(tcx: ty::ctxt, method_map: typeck::method_map)
           -> ReachableContext {
        ReachableContext {
            tcx: tcx,
            method_map: method_map,
            reachable_symbols: @mut HashSet::new(),
            worklist: @mut ~[],
        }
    }

    // Step 1: Mark all public symbols, and add all public symbols that might
    // be inlined to a worklist.
    fn mark_public_symbols(&self, crate: @Crate) {
        let reachable_symbols = self.reachable_symbols;
        let worklist = self.worklist;

        let mut visitor = ReachableVisitor {
            reachable_symbols: reachable_symbols,
            worklist: worklist,
        };

        visit::walk_crate(&mut visitor, crate, PublicContext);
    }

    // Returns true if the given def ID represents a local item that is
    // eligible for inlining and false otherwise.
    fn def_id_represents_local_inlined_item(tcx: ty::ctxt, def_id: def_id)
                                            -> bool {
        if def_id.crate != LOCAL_CRATE {
            return false
        }

        let node_id = def_id.node;
        match tcx.items.find(&node_id) {
            Some(&ast_map::node_item(item, _)) => {
                match item.node {
                    item_fn(*) => item_might_be_inlined(item),
                    _ => false,
                }
            }
            Some(&ast_map::node_trait_method(trait_method, _, _)) => {
                match *trait_method {
                    required(_) => false,
                    provided(_) => true,
                }
            }
            Some(&ast_map::node_method(method, impl_did, _)) => {
                if generics_require_inlining(&method.generics) ||
                        attributes_specify_inlining(method.attrs) {
                    true
                } else {
                    // Check the impl. If the generics on the self type of the
                    // impl require inlining, this method does too.
                    assert!(impl_did.crate == LOCAL_CRATE);
                    match tcx.items.find(&impl_did.node) {
                        Some(&ast_map::node_item(item, _)) => {
                            match item.node {
                                item_impl(ref generics, _, _, _) => {
                                    generics_require_inlining(generics)
                                }
                                _ => false
                            }
                        }
                        Some(_) => {
                            tcx.sess.span_bug(method.span,
                                              "method is not inside an \
                                               impl?!")
                        }
                        None => {
                            tcx.sess.span_bug(method.span,
                                              "the impl that this method is \
                                               supposedly inside of doesn't \
                                               exist in the AST map?!")
                        }
                    }
                }
            }
            Some(_) => false,
            None => false   // This will happen for default methods.
        }
    }

    // Helper function to set up a visitor for `propagate()` below.
    fn init_visitor(&self) -> MarkSymbolVisitor {
        let (worklist, method_map) = (self.worklist, self.method_map);
        let (tcx, reachable_symbols) = (self.tcx, self.reachable_symbols);

        MarkSymbolVisitor {
            worklist: worklist,
            method_map: method_map,
            tcx: tcx,
            reachable_symbols: reachable_symbols,
        }
    }

    // Step 2: Mark all symbols that the symbols on the worklist touch.
    fn propagate(&self) {
        let mut visitor = self.init_visitor();
        let mut scanned = HashSet::new();
        while self.worklist.len() > 0 {
            let search_item = self.worklist.pop();
            if scanned.contains(&search_item) {
                loop
            }
            scanned.insert(search_item);
            self.reachable_symbols.insert(search_item);

            // Find the AST block corresponding to the item and visit it,
            // marking all path expressions that resolve to something
            // interesting.
            match self.tcx.items.find(&search_item) {
                Some(&ast_map::node_item(item, _)) => {
                    match item.node {
                        item_fn(_, _, _, _, ref search_block) => {
                            visit::walk_block(&mut visitor, search_block, ())
                        }
                        _ => {
                            self.tcx.sess.span_bug(item.span,
                                                   "found non-function item \
                                                    in worklist?!")
                        }
                    }
                }
                Some(&ast_map::node_trait_method(trait_method, _, _)) => {
                    match *trait_method {
                        required(ref ty_method) => {
                            self.tcx.sess.span_bug(ty_method.span,
                                                   "found required method in \
                                                    worklist?!")
                        }
                        provided(ref method) => {
                            visit::walk_block(&mut visitor, &method.body, ())
                        }
                    }
                }
                Some(&ast_map::node_method(ref method, _, _)) => {
                    visit::walk_block(&mut visitor, &method.body, ())
                }
                Some(_) => {
                    let ident_interner = token::get_ident_interner();
                    let desc = ast_map::node_id_to_str(self.tcx.items,
                                                       search_item,
                                                       ident_interner);
                    self.tcx.sess.bug(fmt!("found unexpected thingy in \
                                            worklist: %s",
                                            desc))
                }
                None => {
                    self.tcx.sess.bug(fmt!("found unmapped ID in worklist: \
                                            %d",
                                           search_item))
                }
            }
        }
    }

    // Step 3: Mark all destructors as reachable.
    //
    // XXX(pcwalton): This is a conservative overapproximation, but fixing
    // this properly would result in the necessity of computing *type*
    // reachability, which might result in a compile time loss.
    fn mark_destructors_reachable(&self) {
        for (_, destructor_def_id) in self.tcx.destructor_for_type.iter() {
            if destructor_def_id.crate == LOCAL_CRATE {
                self.reachable_symbols.insert(destructor_def_id.node);
            }
        }
    }
}

pub fn find_reachable(tcx: ty::ctxt,
                      method_map: typeck::method_map,
                      crate: @Crate)
                      -> @mut HashSet<NodeId> {
    // XXX(pcwalton): We only need to mark symbols that are exported. But this
    // is more complicated than just looking at whether the symbol is `pub`,
    // because it might be the target of a `pub use` somewhere. For now, I
    // think we are fine, because you can't `pub use` something that wasn't
    // exported due to the bug whereby `use` only looks through public
    // modules even if you're inside the module the `use` appears in. When
    // this bug is fixed, however, this code will need to be updated. Probably
    // the easiest way to fix this (although a conservative overapproximation)
    // is to have the name resolution pass mark all targets of a `pub use` as
    // "must be reachable".

    let reachable_context = ReachableContext::new(tcx, method_map);

    // Step 1: Mark all public symbols, and add all public symbols that might
    // be inlined to a worklist.
    reachable_context.mark_public_symbols(crate);

    // Step 2: Mark all symbols that the symbols on the worklist touch.
    reachable_context.propagate();

    // Step 3: Mark all destructors as reachable.
    reachable_context.mark_destructors_reachable();

    // Return the set of reachable symbols.
    reachable_context.reachable_symbols
}
<|endoftext|>


<commit_before>//! Def-use analysis.

use rustc::mir::{Body, Local, Location, Place, PlaceElem};
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
use rustc_index::vec::IndexVec;
use std::mem;

pub struct DefUseAnalysis {
    info: IndexVec<Local, Info>,
}

#[derive(Clone)]
pub struct Info {
    pub defs_and_uses: Vec<Use>,
}

#[derive(Clone)]
pub struct Use {
    pub context: PlaceContext,
    pub location: Location,
}

impl DefUseAnalysis {
    pub fn new(body: &Body<'_>) -> DefUseAnalysis {
        DefUseAnalysis {
            info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
        }
    }

    pub fn analyze(&mut self, body: &Body<'_>) {
        self.clear();

        let mut finder = DefUseFinder {
            info: mem::take(&mut self.info),
        };
        finder.visit_body(body);
        self.info = finder.info
    }

    fn clear(&mut self) {
        for info in &mut self.info {
            info.clear();
        }
    }

    pub fn local_info(&self, local: Local) -> &Info {
        &self.info[local]
    }

    fn mutate_defs_and_uses<F>(&self, local: Local, body: &mut Body<'_>, callback: F)
                               where F: for<'a> Fn(&'a Local,
                                                      PlaceContext,
                                                      Location) -> Local {
        for place_use in &self.info[local].defs_and_uses {
            MutateUseVisitor::new(local,
                                  &callback,
                                  body).visit_location(body, place_use.location)
        }
    }

    // FIXME(pcwalton): this should update the def-use chains.
    pub fn replace_all_defs_and_uses_with(&self,
                                          local: Local,
                                          body: &mut Body<'_>,
                                          new_local: Local) {
        self.mutate_defs_and_uses(local, body, |_, _, _| new_local)
    }
}

struct DefUseFinder {
    info: IndexVec<Local, Info>,
}

impl Visitor<'_> for DefUseFinder {
    fn visit_local(&mut self,
                   &local: &Local,
                   context: PlaceContext,
                   location: Location) {
        self.info[local].defs_and_uses.push(Use {
            context,
            location,
        });
    }
}

impl Info {
    fn new() -> Info {
        Info {
            defs_and_uses: vec![],
        }
    }

    fn clear(&mut self) {
        self.defs_and_uses.clear();
    }

    pub fn def_count(&self) -> usize {
        self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
    }

    pub fn def_count_not_including_drop(&self) -> usize {
        self.defs_not_including_drop().count()
    }

    pub fn defs_not_including_drop(
        &self,
    ) -> impl Iterator<Item=&Use> {
        self.defs_and_uses.iter().filter(|place_use| {
            place_use.context.is_mutating_use() && !place_use.context.is_drop()
        })
    }

    pub fn use_count(&self) -> usize {
        self.defs_and_uses.iter().filter(|place_use| {
            place_use.context.is_nonmutating_use()
        }).count()
    }
}

struct MutateUseVisitor<F> {
    query: Local,
    callback: F,
}

impl<F> MutateUseVisitor<F> {
    fn new(query: Local, callback: F, _: &Body<'_>)
           -> MutateUseVisitor<F>
           where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local {
        MutateUseVisitor {
            query,
            callback,
        }
    }
}

impl<F> MutVisitor<'_> for MutateUseVisitor<F>
              where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local {
    fn visit_local(&mut self,
                    local: &mut Local,
                    context: PlaceContext,
                    location: Location) {
        if *local == self.query {
            *local = (self.callback)(local, context, location)
        }
    }

    fn visit_place(&mut self,
                    place: &mut Place<'tcx>,
                    context: PlaceContext,
                    location: Location) {
        self.visit_place_base(&mut place.base, context, location);

        let new_projection: Vec<_> = place.projection.iter().map(|elem|
            match elem {
                PlaceElem::Index(local) if *local == self.query => {
                    PlaceElem::Index((self.callback)(&local, context, location))
                }
                _ => elem.clone(),
            }
        ).collect();

        place.projection = new_projection.into_boxed_slice();
    }
}
<commit_msg>Remove unneeded callback and just use the new_local value<commit_after>//! Def-use analysis.

use rustc::mir::{Body, Local, Location, Place, PlaceElem};
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
use rustc_index::vec::IndexVec;
use std::mem;

pub struct DefUseAnalysis {
    info: IndexVec<Local, Info>,
}

#[derive(Clone)]
pub struct Info {
    pub defs_and_uses: Vec<Use>,
}

#[derive(Clone)]
pub struct Use {
    pub context: PlaceContext,
    pub location: Location,
}

impl DefUseAnalysis {
    pub fn new(body: &Body<'_>) -> DefUseAnalysis {
        DefUseAnalysis {
            info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
        }
    }

    pub fn analyze(&mut self, body: &Body<'_>) {
        self.clear();

        let mut finder = DefUseFinder {
            info: mem::take(&mut self.info),
        };
        finder.visit_body(body);
        self.info = finder.info
    }

    fn clear(&mut self) {
        for info in &mut self.info {
            info.clear();
        }
    }

    pub fn local_info(&self, local: Local) -> &Info {
        &self.info[local]
    }

    fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) {
        for place_use in &self.info[local].defs_and_uses {
            MutateUseVisitor::new(local,
                                  new_local,
                                  body).visit_location(body, place_use.location)
        }
    }

    // FIXME(pcwalton): this should update the def-use chains.
    pub fn replace_all_defs_and_uses_with(&self,
                                          local: Local,
                                          body: &mut Body<'_>,
                                          new_local: Local) {
        self.mutate_defs_and_uses(local, body, new_local)
    }
}

struct DefUseFinder {
    info: IndexVec<Local, Info>,
}

impl Visitor<'_> for DefUseFinder {
    fn visit_local(&mut self,
                   &local: &Local,
                   context: PlaceContext,
                   location: Location) {
        self.info[local].defs_and_uses.push(Use {
            context,
            location,
        });
    }
}

impl Info {
    fn new() -> Info {
        Info {
            defs_and_uses: vec![],
        }
    }

    fn clear(&mut self) {
        self.defs_and_uses.clear();
    }

    pub fn def_count(&self) -> usize {
        self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
    }

    pub fn def_count_not_including_drop(&self) -> usize {
        self.defs_not_including_drop().count()
    }

    pub fn defs_not_including_drop(
        &self,
    ) -> impl Iterator<Item=&Use> {
        self.defs_and_uses.iter().filter(|place_use| {
            place_use.context.is_mutating_use() && !place_use.context.is_drop()
        })
    }

    pub fn use_count(&self) -> usize {
        self.defs_and_uses.iter().filter(|place_use| {
            place_use.context.is_nonmutating_use()
        }).count()
    }
}

struct MutateUseVisitor {
    query: Local,
    new_local: Local,
}

impl MutateUseVisitor {
    fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor {
        MutateUseVisitor {
            query,
            new_local,
        }
    }
}

impl MutVisitor<'_> for MutateUseVisitor {
    fn visit_local(&mut self,
                    local: &mut Local,
                    _context: PlaceContext,
                    _location: Location) {
        if *local == self.query {
            *local = self.new_local;
        }
    }

    fn visit_place(&mut self,
                    place: &mut Place<'tcx>,
                    context: PlaceContext,
                    location: Location) {
        self.visit_place_base(&mut place.base, context, location);

        let new_projection: Vec<_> = place.projection.iter().map(|elem|
            match elem {
                PlaceElem::Index(local) if *local == self.query => {
                    PlaceElem::Index(self.new_local)
                }
                _ => elem.clone(),
            }
        ).collect();

        place.projection = new_projection.into_boxed_slice();
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
#[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write};
use std::ops::{Deref, DerefMut, Mul};

#[cfg(feature = "serde-serialize")]
use serde::de::{Error, SeqAccess, Visitor};
#[cfg(feature = "serde-serialize")]
use serde::ser::SerializeSeq;
#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "serde-serialize")]
use std::marker::PhantomData;
#[cfg(feature = "serde-serialize")]
use std::mem;

#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;

use generic_array::{ArrayLength, GenericArray};
use typenum::Prod;

use base::allocator::Allocator;
use base::default_allocator::DefaultAllocator;
use base::dimension::{DimName, U1};
use base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut};
use base::Scalar;

/*
 *
 * Static Storage.
 *
 */
/// A array-based statically sized matrix data storage.
#[repr(C)]
pub struct ArrayStorage<N, R, C>
where
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    data: GenericArray<N, Prod<R::Value, C::Value>>,
}

#[deprecated(note="renamed to `ArrayStorage`")]
/// Renamed to [ArrayStorage].
pub type MatrixArray<N, R, C> = ArrayStorage<N, R, C>;

impl<N, R, C> Hash for ArrayStorage<N, R, C>
where
    N: Hash,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.data[..].hash(state)
    }
}

impl<N, R, C> Deref for ArrayStorage<N, R, C>
where
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    type Target = GenericArray<N, Prod<R::Value, C::Value>>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<N, R, C> DerefMut for ArrayStorage<N, R, C>
where
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.data
    }
}

impl<N, R, C> Debug for ArrayStorage<N, R, C>
where
    N: Debug,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    #[inline]
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.data.fmt(fmt)
    }
}

impl<N, R, C> Copy for ArrayStorage<N, R, C>
where
    N: Copy,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    GenericArray<N, Prod<R::Value, C::Value>>: Copy,
{}

impl<N, R, C> Clone for ArrayStorage<N, R, C>
where
    N: Clone,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    #[inline]
    fn clone(&self) -> Self {
        ArrayStorage {
            data: self.data.clone(),
        }
    }
}

impl<N, R, C> Eq for ArrayStorage<N, R, C>
where
    N: Eq,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{}

impl<N, R, C> PartialEq for ArrayStorage<N, R, C>
where
    N: PartialEq,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    #[inline]
    fn eq(&self, right: &Self) -> bool {
        self.data == right.data
    }
}

unsafe impl<N, R, C> Storage<N, R, C> for ArrayStorage<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{
    type RStride = U1;
    type CStride = R;

    #[inline]
    fn ptr(&self) -> *const N {
        self[..].as_ptr()
    }

    #[inline]
    fn shape(&self) -> (R, C) {
        (R::name(), C::name())
    }

    #[inline]
    fn strides(&self) -> (Self::RStride, Self::CStride) {
        (Self::RStride::name(), Self::CStride::name())
    }

    #[inline]
    fn is_contiguous(&self) -> bool {
        true
    }

    #[inline]
    fn into_owned(self) -> Owned<N, R, C>
    where DefaultAllocator: Allocator<N, R, C> {
        self
    }

    #[inline]
    fn clone_owned(&self) -> Owned<N, R, C>
    where DefaultAllocator: Allocator<N, R, C> {
        let it = self.iter().cloned();

        DefaultAllocator::allocate_from_iterator(self.shape().0, self.shape().1, it)
    }

    #[inline]
    fn as_slice(&self) -> &[N] {
        &self[..]
    }
}

unsafe impl<N, R, C> StorageMut<N, R, C> for ArrayStorage<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{
    #[inline]
    fn ptr_mut(&mut self) -> *mut N {
        self[..].as_mut_ptr()
    }

    #[inline]
    fn as_mut_slice(&mut self) -> &mut [N] {
        &mut self[..]
    }
}

unsafe impl<N, R, C> ContiguousStorage<N, R, C> for ArrayStorage<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{}

unsafe impl<N, R, C> ContiguousStorageMut<N, R, C> for ArrayStorage<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{}

/*
 *
 * Allocation-less serde impls.
 *
 */
// XXX: open an issue for GenericArray so that it implements serde traits?
#[cfg(feature = "serde-serialize")]
impl<N, R, C> Serialize for ArrayStorage<N, R, C>
where
    N: Scalar + Serialize,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer {
        let mut serializer = serializer.serialize_seq(Some(R::dim() * C::dim()))?;

        for e in self.iter() {
            serializer.serialize_element(e)?;
        }

        serializer.end()
    }
}

#[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Deserialize<'a> for ArrayStorage<N, R, C>
where
    N: Scalar + Deserialize<'a>,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: Deserializer<'a> {
        deserializer.deserialize_seq(ArrayStorageVisitor::new())
    }
}

#[cfg(feature = "serde-serialize")]
/// A visitor that produces a matrix array.
struct ArrayStorageVisitor<N, R, C> {
    marker: PhantomData<(N, R, C)>,
}

#[cfg(feature = "serde-serialize")]
impl<N, R, C> ArrayStorageVisitor<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    /// Construct a new sequence visitor.
    pub fn new() -> Self {
        ArrayStorageVisitor {
            marker: PhantomData,
        }
    }
}

#[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Visitor<'a> for ArrayStorageVisitor<N, R, C>
where
    N: Scalar + Deserialize<'a>,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    type Value = ArrayStorage<N, R, C>;

    fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
        formatter.write_str("a matrix array")
    }

    #[inline]
    fn visit_seq<V>(self, mut visitor: V) -> Result<ArrayStorage<N, R, C>, V::Error>
    where V: SeqAccess<'a> {
        let mut out: Self::Value = unsafe { mem::uninitialized() };
        let mut curr = 0;

        while let Some(value) = try!(visitor.next_element()) {
            out[curr] = value;
            curr += 1;
        }

        if curr == R::dim() * C::dim() {
            Ok(out)
        } else {
            Err(V::Error::invalid_length(curr, &self))
        }
    }
}

#[cfg(feature = "abomonation-serialize")]
impl<N, R, C> Abomonation for ArrayStorage<N, R, C>
where
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    N: Abomonation,
{
    unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
        for element in self.data.as_slice() {
            element.entomb(writer)?;
        }

        Ok(())
    }

    unsafe fn exhume<'a, 'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
        for element in self.data.as_mut_slice() {
            let temp = bytes;
            bytes = if let Some(remainder) = element.exhume(temp) {
                remainder
            } else {
                return None;
            }
        }
        Some(bytes)
    }

    fn extent(&self) -> usize {
        self.data
            .as_slice()
            .iter()
            .fold(0, |acc, e| acc + e.extent())
    }
}
<commit_msg>Fix out-of-bounds panic during deserialization; produce error instead.<commit_after>use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
#[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write};
use std::ops::{Deref, DerefMut, Mul};

#[cfg(feature = "serde-serialize")]
use serde::de::{Error, SeqAccess, Visitor};
#[cfg(feature = "serde-serialize")]
use serde::ser::SerializeSeq;
#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "serde-serialize")]
use std::marker::PhantomData;
#[cfg(feature = "serde-serialize")]
use std::mem;

#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;

use generic_array::{ArrayLength, GenericArray};
use typenum::Prod;

use base::allocator::Allocator;
use base::default_allocator::DefaultAllocator;
use base::dimension::{DimName, U1};
use base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut};
use base::Scalar;

/*
 *
 * Static Storage.
 *
 */
/// A array-based statically sized matrix data storage.
#[repr(C)]
pub struct ArrayStorage<N, R, C>
where
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    data: GenericArray<N, Prod<R::Value, C::Value>>,
}

#[deprecated(note="renamed to `ArrayStorage`")]
/// Renamed to [ArrayStorage].
pub type MatrixArray<N, R, C> = ArrayStorage<N, R, C>;

impl<N, R, C> Hash for ArrayStorage<N, R, C>
where
    N: Hash,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.data[..].hash(state)
    }
}

impl<N, R, C> Deref for ArrayStorage<N, R, C>
where
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    type Target = GenericArray<N, Prod<R::Value, C::Value>>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<N, R, C> DerefMut for ArrayStorage<N, R, C>
where
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.data
    }
}

impl<N, R, C> Debug for ArrayStorage<N, R, C>
where
    N: Debug,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    #[inline]
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.data.fmt(fmt)
    }
}

impl<N, R, C> Copy for ArrayStorage<N, R, C>
where
    N: Copy,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    GenericArray<N, Prod<R::Value, C::Value>>: Copy,
{}

impl<N, R, C> Clone for ArrayStorage<N, R, C>
where
    N: Clone,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    #[inline]
    fn clone(&self) -> Self {
        ArrayStorage {
            data: self.data.clone(),
        }
    }
}

impl<N, R, C> Eq for ArrayStorage<N, R, C>
where
    N: Eq,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{}

impl<N, R, C> PartialEq for ArrayStorage<N, R, C>
where
    N: PartialEq,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    #[inline]
    fn eq(&self, right: &Self) -> bool {
        self.data == right.data
    }
}

unsafe impl<N, R, C> Storage<N, R, C> for ArrayStorage<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{
    type RStride = U1;
    type CStride = R;

    #[inline]
    fn ptr(&self) -> *const N {
        self[..].as_ptr()
    }

    #[inline]
    fn shape(&self) -> (R, C) {
        (R::name(), C::name())
    }

    #[inline]
    fn strides(&self) -> (Self::RStride, Self::CStride) {
        (Self::RStride::name(), Self::CStride::name())
    }

    #[inline]
    fn is_contiguous(&self) -> bool {
        true
    }

    #[inline]
    fn into_owned(self) -> Owned<N, R, C>
    where DefaultAllocator: Allocator<N, R, C> {
        self
    }

    #[inline]
    fn clone_owned(&self) -> Owned<N, R, C>
    where DefaultAllocator: Allocator<N, R, C> {
        let it = self.iter().cloned();

        DefaultAllocator::allocate_from_iterator(self.shape().0, self.shape().1, it)
    }

    #[inline]
    fn as_slice(&self) -> &[N] {
        &self[..]
    }
}

unsafe impl<N, R, C> StorageMut<N, R, C> for ArrayStorage<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{
    #[inline]
    fn ptr_mut(&mut self) -> *mut N {
        self[..].as_mut_ptr()
    }

    #[inline]
    fn as_mut_slice(&mut self) -> &mut [N] {
        &mut self[..]
    }
}

unsafe impl<N, R, C> ContiguousStorage<N, R, C> for ArrayStorage<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{}

unsafe impl<N, R, C> ContiguousStorageMut<N, R, C> for ArrayStorage<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{}

/*
 *
 * Allocation-less serde impls.
 *
 */
// XXX: open an issue for GenericArray so that it implements serde traits?
#[cfg(feature = "serde-serialize")]
impl<N, R, C> Serialize for ArrayStorage<N, R, C>
where
    N: Scalar + Serialize,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer {
        let mut serializer = serializer.serialize_seq(Some(R::dim() * C::dim()))?;

        for e in self.iter() {
            serializer.serialize_element(e)?;
        }

        serializer.end()
    }
}

#[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Deserialize<'a> for ArrayStorage<N, R, C>
where
    N: Scalar + Deserialize<'a>,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: Deserializer<'a> {
        deserializer.deserialize_seq(ArrayStorageVisitor::new())
    }
}

#[cfg(feature = "serde-serialize")]
/// A visitor that produces a matrix array.
struct ArrayStorageVisitor<N, R, C> {
    marker: PhantomData<(N, R, C)>,
}

#[cfg(feature = "serde-serialize")]
impl<N, R, C> ArrayStorageVisitor<N, R, C>
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    /// Construct a new sequence visitor.
    pub fn new() -> Self {
        ArrayStorageVisitor {
            marker: PhantomData,
        }
    }
}

#[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Visitor<'a> for ArrayStorageVisitor<N, R, C>
where
    N: Scalar + Deserialize<'a>,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    type Value = ArrayStorage<N, R, C>;

    fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
        formatter.write_str("a matrix array")
    }

    #[inline]
    fn visit_seq<V>(self, mut visitor: V) -> Result<ArrayStorage<N, R, C>, V::Error>
    where V: SeqAccess<'a> {
        let mut out: Self::Value = unsafe { mem::uninitialized() };
        let mut curr = 0;

        while let Some(value) = try!(visitor.next_element()) {
            *out.get_mut(curr).ok_or_else(|| V::Error::invalid_length(curr, &self))? = value;
            curr += 1;
        }

        if curr == R::dim() * C::dim() {
            Ok(out)
        } else {
            Err(V::Error::invalid_length(curr, &self))
        }
    }
}

#[cfg(feature = "abomonation-serialize")]
impl<N, R, C> Abomonation for ArrayStorage<N, R, C>
where
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
    N: Abomonation,
{
    unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
        for element in self.data.as_slice() {
            element.entomb(writer)?;
        }

        Ok(())
    }

    unsafe fn exhume<'a, 'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
        for element in self.data.as_mut_slice() {
            let temp = bytes;
            bytes = if let Some(remainder) = element.exhume(temp) {
                remainder
            } else {
                return None;
            }
        }
        Some(bytes)
    }

    fn extent(&self) -> usize {
        self.data
            .as_slice()
            .iter()
            .fold(0, |acc, e| acc + e.extent())
    }
}
<|endoftext|>


<commit_before><commit_msg>changes<commit_after><|endoftext|>


<commit_before>//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
mod lower;

use std::{
    fmt::{self, Display},
    iter,
    sync::Arc,
};

use crate::{body::LowerCtx, type_ref::LifetimeRef};
use base_db::CrateId;
use hir_expand::{hygiene::Hygiene, name::Name};
use syntax::ast;

use crate::{
    type_ref::{TypeBound, TypeRef},
    InFile,
};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModPath {
    pub kind: PathKind,
    pub segments: Vec<Name>,
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PathKind {
    Plain,
    /// `self::` is `Super(0)`
    Super(u8),
    Crate,
    /// Absolute path (::foo)
    Abs,
    /// `$crate` from macro expansion
    DollarCrate(CrateId),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ImportAlias {
    /// Unnamed alias, as in `use Foo as _;`
    Underscore,
    /// Named alias
    Alias(Name),
}

impl ModPath {
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
        lower::lower_path(path, hygiene).map(|it| it.mod_path)
    }

    pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
        let segments = segments.into_iter().collect::<Vec<_>>();
        ModPath { kind, segments }
    }

    /// Calls `cb` with all paths, represented by this use item.
    pub(crate) fn expand_use_item(
        item_src: InFile<ast::Use>,
        hygiene: &Hygiene,
        mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
    ) {
        if let Some(tree) = item_src.value.use_tree() {
            lower::lower_use_tree(None, tree, hygiene, &mut cb);
        }
    }

    /// Returns the number of segments in the path (counting special segments like `$crate` and
    /// `super`).
    pub fn len(&self) -> usize {
        self.segments.len()
            + match self.kind {
                PathKind::Plain => 0,
                PathKind::Super(i) => i as usize,
                PathKind::Crate => 1,
                PathKind::Abs => 0,
                PathKind::DollarCrate(_) => 1,
            }
    }

    pub fn is_ident(&self) -> bool {
        self.kind == PathKind::Plain && self.segments.len() == 1
    }

    pub fn is_self(&self) -> bool {
        self.kind == PathKind::Super(0) && self.segments.is_empty()
    }

    /// If this path is a single identifier, like `foo`, return its name.
    pub fn as_ident(&self) -> Option<&Name> {
        if !self.is_ident() {
            return None
        }
        self.segments.first()
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path {
    /// Type based path like `<T>::foo`.
    /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
    type_anchor: Option<Box<TypeRef>>,
    mod_path: ModPath,
    /// Invariant: the same len as `self.mod_path.segments`
    generic_args: Vec<Option<Arc<GenericArgs>>>,
}

/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericArgs {
    pub args: Vec<GenericArg>,
    /// This specifies whether the args contain a Self type as the first
    /// element. This is the case for path segments like `<T as Trait>`, where
    /// `T` is actually a type parameter for the path `Trait` specifying the
    /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
    /// is left out.
    pub has_self_type: bool,
    /// Associated type bindings like in `Iterator<Item = T>`.
    pub bindings: Vec<AssociatedTypeBinding>,
}

/// An associated type binding like in `Iterator<Item = T>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AssociatedTypeBinding {
    /// The name of the associated type.
    pub name: Name,
    /// The type bound to this associated type (in `Item = T`, this would be the
    /// `T`). This can be `None` if there are bounds instead.
    pub type_ref: Option<TypeRef>,
    /// Bounds for the associated type, like in `Iterator<Item:
    /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
    /// feature.)
    pub bounds: Vec<TypeBound>,
}

/// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg {
    Type(TypeRef),
    Lifetime(LifetimeRef),
}

impl Path {
    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// It correctly handles `$crate` based path from macro call.
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
        lower::lower_path(path, hygiene)
    }

    /// Converts a known mod path to `Path`.
    pub(crate) fn from_known_path(
        path: ModPath,
        generic_args: Vec<Option<Arc<GenericArgs>>>,
    ) -> Path {
        Path { type_anchor: None, mod_path: path, generic_args }
    }

    pub fn kind(&self) -> &PathKind {
        &self.mod_path.kind
    }

    pub fn type_anchor(&self) -> Option<&TypeRef> {
        self.type_anchor.as_deref()
    }

    pub fn segments(&self) -> PathSegments<'_> {
        PathSegments {
            segments: self.mod_path.segments.as_slice(),
            generic_args: self.generic_args.as_slice(),
        }
    }

    pub fn mod_path(&self) -> &ModPath {
        &self.mod_path
    }

    pub fn qualifier(&self) -> Option<Path> {
        if self.mod_path.is_ident() {
            return None;
        }
        let res = Path {
            type_anchor: self.type_anchor.clone(),
            mod_path: ModPath {
                kind: self.mod_path.kind.clone(),
                segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
            },
            generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
        };
        Some(res)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PathSegment<'a> {
    pub name: &'a Name,
    pub args_and_bindings: Option<&'a GenericArgs>,
}

pub struct PathSegments<'a> {
    segments: &'a [Name],
    generic_args: &'a [Option<Arc<GenericArgs>>],
}

impl<'a> PathSegments<'a> {
    pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub fn len(&self) -> usize {
        self.segments.len()
    }
    pub fn first(&self) -> Option<PathSegment<'a>> {
        self.get(0)
    }
    pub fn last(&self) -> Option<PathSegment<'a>> {
        self.get(self.len().checked_sub(1)?)
    }
    pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        let res = PathSegment {
            name: self.segments.get(idx)?,
            args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
        };
        Some(res)
    }
    pub fn skip(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
    }
    pub fn take(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
    }
    pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
        self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
            name,
            args_and_bindings: args.as_ref().map(|it| &**it),
        })
    }
}

impl GenericArgs {
    pub(crate) fn from_ast(lower_ctx: &LowerCtx, node: ast::GenericArgList) -> Option<GenericArgs> {
        lower::lower_generic_args(lower_ctx, node)
    }

    pub(crate) fn empty() -> GenericArgs {
        GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
    }
}

impl From<Name> for Path {
    fn from(name: Name) -> Path {
        Path {
            type_anchor: None,
            mod_path: ModPath::from_segments(PathKind::Plain, iter::once(name)),
            generic_args: vec![None],
        }
    }
}

impl From<Name> for ModPath {
    fn from(name: Name) -> ModPath {
        ModPath::from_segments(PathKind::Plain, iter::once(name))
    }
}

impl Display for ModPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut first_segment = true;
        let mut add_segment = |s| -> fmt::Result {
            if !first_segment {
                f.write_str("::")?;
            }
            first_segment = false;
            f.write_str(s)?;
            Ok(())
        };
        match self.kind {
            PathKind::Plain => {}
            PathKind::Super(0) => add_segment("self")?,
            PathKind::Super(n) => {
                for _ in 0..n {
                    add_segment("super")?;
                }
            }
            PathKind::Crate => add_segment("crate")?,
            PathKind::Abs => add_segment("")?,
            PathKind::DollarCrate(_) => add_segment("$crate")?,
        }
        for segment in &self.segments {
            if !first_segment {
                f.write_str("::")?;
            }
            first_segment = false;
            write!(f, "{}", segment)?;
        }
        Ok(())
    }
}

pub use hir_expand::name as __name;

#[macro_export]
macro_rules! __known_path {
    (core::iter::IntoIterator) => {};
    (core::result::Result) => {};
    (core::ops::Range) => {};
    (core::ops::RangeFrom) => {};
    (core::ops::RangeFull) => {};
    (core::ops::RangeTo) => {};
    (core::ops::RangeToInclusive) => {};
    (core::ops::RangeInclusive) => {};
    (core::future::Future) => {};
    (core::ops::Try) => {};
    ($path:path) => {
        compile_error!("Please register your known path in the path module")
    };
}

#[macro_export]
macro_rules! __path {
    ($start:ident $(:: $seg:ident)*) => ({
        $crate::__known_path!($start $(:: $seg)*);
        $crate::path::ModPath::from_segments($crate::path::PathKind::Abs, vec![
            $crate::path::__name![$start], $($crate::path::__name![$seg],)*
        ])
    });
}

pub use crate::__path as path;
<commit_msg>cargo fmt<commit_after>//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
mod lower;

use std::{
    fmt::{self, Display},
    iter,
    sync::Arc,
};

use crate::{body::LowerCtx, type_ref::LifetimeRef};
use base_db::CrateId;
use hir_expand::{hygiene::Hygiene, name::Name};
use syntax::ast;

use crate::{
    type_ref::{TypeBound, TypeRef},
    InFile,
};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModPath {
    pub kind: PathKind,
    pub segments: Vec<Name>,
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PathKind {
    Plain,
    /// `self::` is `Super(0)`
    Super(u8),
    Crate,
    /// Absolute path (::foo)
    Abs,
    /// `$crate` from macro expansion
    DollarCrate(CrateId),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ImportAlias {
    /// Unnamed alias, as in `use Foo as _;`
    Underscore,
    /// Named alias
    Alias(Name),
}

impl ModPath {
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
        lower::lower_path(path, hygiene).map(|it| it.mod_path)
    }

    pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
        let segments = segments.into_iter().collect::<Vec<_>>();
        ModPath { kind, segments }
    }

    /// Calls `cb` with all paths, represented by this use item.
    pub(crate) fn expand_use_item(
        item_src: InFile<ast::Use>,
        hygiene: &Hygiene,
        mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
    ) {
        if let Some(tree) = item_src.value.use_tree() {
            lower::lower_use_tree(None, tree, hygiene, &mut cb);
        }
    }

    /// Returns the number of segments in the path (counting special segments like `$crate` and
    /// `super`).
    pub fn len(&self) -> usize {
        self.segments.len()
            + match self.kind {
                PathKind::Plain => 0,
                PathKind::Super(i) => i as usize,
                PathKind::Crate => 1,
                PathKind::Abs => 0,
                PathKind::DollarCrate(_) => 1,
            }
    }

    pub fn is_ident(&self) -> bool {
        self.kind == PathKind::Plain && self.segments.len() == 1
    }

    pub fn is_self(&self) -> bool {
        self.kind == PathKind::Super(0) && self.segments.is_empty()
    }

    /// If this path is a single identifier, like `foo`, return its name.
    pub fn as_ident(&self) -> Option<&Name> {
        if !self.is_ident() {
            return None;
        }
        self.segments.first()
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path {
    /// Type based path like `<T>::foo`.
    /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
    type_anchor: Option<Box<TypeRef>>,
    mod_path: ModPath,
    /// Invariant: the same len as `self.mod_path.segments`
    generic_args: Vec<Option<Arc<GenericArgs>>>,
}

/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericArgs {
    pub args: Vec<GenericArg>,
    /// This specifies whether the args contain a Self type as the first
    /// element. This is the case for path segments like `<T as Trait>`, where
    /// `T` is actually a type parameter for the path `Trait` specifying the
    /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
    /// is left out.
    pub has_self_type: bool,
    /// Associated type bindings like in `Iterator<Item = T>`.
    pub bindings: Vec<AssociatedTypeBinding>,
}

/// An associated type binding like in `Iterator<Item = T>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AssociatedTypeBinding {
    /// The name of the associated type.
    pub name: Name,
    /// The type bound to this associated type (in `Item = T`, this would be the
    /// `T`). This can be `None` if there are bounds instead.
    pub type_ref: Option<TypeRef>,
    /// Bounds for the associated type, like in `Iterator<Item:
    /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
    /// feature.)
    pub bounds: Vec<TypeBound>,
}

/// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg {
    Type(TypeRef),
    Lifetime(LifetimeRef),
}

impl Path {
    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// It correctly handles `$crate` based path from macro call.
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
        lower::lower_path(path, hygiene)
    }

    /// Converts a known mod path to `Path`.
    pub(crate) fn from_known_path(
        path: ModPath,
        generic_args: Vec<Option<Arc<GenericArgs>>>,
    ) -> Path {
        Path { type_anchor: None, mod_path: path, generic_args }
    }

    pub fn kind(&self) -> &PathKind {
        &self.mod_path.kind
    }

    pub fn type_anchor(&self) -> Option<&TypeRef> {
        self.type_anchor.as_deref()
    }

    pub fn segments(&self) -> PathSegments<'_> {
        PathSegments {
            segments: self.mod_path.segments.as_slice(),
            generic_args: self.generic_args.as_slice(),
        }
    }

    pub fn mod_path(&self) -> &ModPath {
        &self.mod_path
    }

    pub fn qualifier(&self) -> Option<Path> {
        if self.mod_path.is_ident() {
            return None;
        }
        let res = Path {
            type_anchor: self.type_anchor.clone(),
            mod_path: ModPath {
                kind: self.mod_path.kind.clone(),
                segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
            },
            generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
        };
        Some(res)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PathSegment<'a> {
    pub name: &'a Name,
    pub args_and_bindings: Option<&'a GenericArgs>,
}

pub struct PathSegments<'a> {
    segments: &'a [Name],
    generic_args: &'a [Option<Arc<GenericArgs>>],
}

impl<'a> PathSegments<'a> {
    pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub fn len(&self) -> usize {
        self.segments.len()
    }
    pub fn first(&self) -> Option<PathSegment<'a>> {
        self.get(0)
    }
    pub fn last(&self) -> Option<PathSegment<'a>> {
        self.get(self.len().checked_sub(1)?)
    }
    pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        let res = PathSegment {
            name: self.segments.get(idx)?,
            args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
        };
        Some(res)
    }
    pub fn skip(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
    }
    pub fn take(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
    }
    pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
        self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
            name,
            args_and_bindings: args.as_ref().map(|it| &**it),
        })
    }
}

impl GenericArgs {
    pub(crate) fn from_ast(lower_ctx: &LowerCtx, node: ast::GenericArgList) -> Option<GenericArgs> {
        lower::lower_generic_args(lower_ctx, node)
    }

    pub(crate) fn empty() -> GenericArgs {
        GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
    }
}

impl From<Name> for Path {
    fn from(name: Name) -> Path {
        Path {
            type_anchor: None,
            mod_path: ModPath::from_segments(PathKind::Plain, iter::once(name)),
            generic_args: vec![None],
        }
    }
}

impl From<Name> for ModPath {
    fn from(name: Name) -> ModPath {
        ModPath::from_segments(PathKind::Plain, iter::once(name))
    }
}

impl Display for ModPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut first_segment = true;
        let mut add_segment = |s| -> fmt::Result {
            if !first_segment {
                f.write_str("::")?;
            }
            first_segment = false;
            f.write_str(s)?;
            Ok(())
        };
        match self.kind {
            PathKind::Plain => {}
            PathKind::Super(0) => add_segment("self")?,
            PathKind::Super(n) => {
                for _ in 0..n {
                    add_segment("super")?;
                }
            }
            PathKind::Crate => add_segment("crate")?,
            PathKind::Abs => add_segment("")?,
            PathKind::DollarCrate(_) => add_segment("$crate")?,
        }
        for segment in &self.segments {
            if !first_segment {
                f.write_str("::")?;
            }
            first_segment = false;
            write!(f, "{}", segment)?;
        }
        Ok(())
    }
}

pub use hir_expand::name as __name;

#[macro_export]
macro_rules! __known_path {
    (core::iter::IntoIterator) => {};
    (core::result::Result) => {};
    (core::ops::Range) => {};
    (core::ops::RangeFrom) => {};
    (core::ops::RangeFull) => {};
    (core::ops::RangeTo) => {};
    (core::ops::RangeToInclusive) => {};
    (core::ops::RangeInclusive) => {};
    (core::future::Future) => {};
    (core::ops::Try) => {};
    ($path:path) => {
        compile_error!("Please register your known path in the path module")
    };
}

#[macro_export]
macro_rules! __path {
    ($start:ident $(:: $seg:ident)*) => ({
        $crate::__known_path!($start $(:: $seg)*);
        $crate::path::ModPath::from_segments($crate::path::PathKind::Abs, vec![
            $crate::path::__name![$start], $($crate::path::__name![$seg],)*
        ])
    });
}

pub use crate::__path as path;
<|endoftext|>