<commit_before>//! This modules implements a function to resolve a path `foo::bar::baz` to a
//! def, which is used within the name resolution.
//!
//! When name resolution is finished, the result of resolving a path is either
//! `Some(def)` or `None`. However, when we are in process of resolving imports
//! or macros, there's a third possibility:
//!
//!   I can't resolve this path right now, but I might be resolve this path
//!   later, when more macros are expanded.
//!
//! `ReachedFixedPoint` signals about this.

use base_db::Edition;
use hir_expand::name;
use hir_expand::name::Name;

use crate::{
    db::DefDatabase,
    item_scope::BUILTIN_SCOPE,
    nameres::{BuiltinShadowMode, DefMap},
    path::{ModPath, PathKind},
    per_ns::PerNs,
    visibility::{RawVisibility, Visibility},
    AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ResolveMode {
    Import,
    Other,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ReachedFixedPoint {
    Yes,
    No,
}

#[derive(Debug, Clone)]
pub(super) struct ResolvePathResult {
    pub(super) resolved_def: PerNs,
    pub(super) segment_index: Option<usize>,
    pub(super) reached_fixedpoint: ReachedFixedPoint,
    pub(super) krate: Option<CrateId>,
}

impl ResolvePathResult {
    fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
        ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None)
    }

    fn with(
        resolved_def: PerNs,
        reached_fixedpoint: ReachedFixedPoint,
        segment_index: Option<usize>,
        krate: Option<CrateId>,
    ) -> ResolvePathResult {
        ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, krate }
    }
}

impl DefMap {
    pub(super) fn resolve_name_in_extern_prelude(
        &self,
        db: &dyn DefDatabase,
        name: &Name,
    ) -> PerNs {
        if name == &name!(self) {
            cov_mark::hit!(extern_crate_self_as);
            return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
        }

        let arc;
        let root = match self.block {
            Some(_) => {
                arc = self.crate_root(db).def_map(db);
                &*arc
            }
            None => self,
        };

        root.extern_prelude
            .get(name)
            .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
    }

    pub(crate) fn resolve_visibility(
        &self,
        db: &dyn DefDatabase,
        original_module: LocalModuleId,
        visibility: &RawVisibility,
    ) -> Option<Visibility> {
        let mut vis = match visibility {
            RawVisibility::Module(path) => {
                let (result, remaining) =
                    self.resolve_path(db, original_module, path, BuiltinShadowMode::Module);
                if remaining.is_some() {
                    return None;
                }
                let types = result.take_types()?;
                match types {
                    ModuleDefId::ModuleId(m) => Visibility::Module(m),
                    _ => {
                        // error: visibility needs to refer to module
                        return None;
                    }
                }
            }
            RawVisibility::Public => Visibility::Public,
        };

        // In block expressions, `self` normally refers to the containing non-block module, and
        // `super` to its parent (etc.). However, visibilities must only refer to a module in the
        // DefMap they're written in, so we restrict them when that happens.
        if let Visibility::Module(m) = vis {
            if self.block_id() != m.block {
                cov_mark::hit!(adjust_vis_in_block_def_map);
                vis = Visibility::Module(self.module_id(self.root()));
                tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
            }
        }

        Some(vis)
    }

    // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
    // the result.
    pub(super) fn resolve_path_fp_with_macro(
        &self,
        db: &dyn DefDatabase,
        mode: ResolveMode,
        mut original_module: LocalModuleId,
        path: &ModPath,
        shadow: BuiltinShadowMode,
    ) -> ResolvePathResult {
        let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);

        let mut arc;
        let mut current_map = self;
        loop {
            let new = current_map.resolve_path_fp_with_macro_single(
                db,
                mode,
                original_module,
                path,
                shadow,
            );

            // Merge `new` into `result`.
            result.resolved_def = result.resolved_def.or(new.resolved_def);
            if result.reached_fixedpoint == ReachedFixedPoint::No {
                result.reached_fixedpoint = new.reached_fixedpoint;
            }
            // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates?
            result.krate = result.krate.or(new.krate);
            result.segment_index = match (result.segment_index, new.segment_index) {
                (Some(idx), None) => Some(idx),
                (Some(old), Some(new)) => Some(old.max(new)),
                (None, new) => new,
            };

            match &current_map.block {
                Some(block) => {
                    original_module = block.parent.local_id;
                    arc = block.parent.def_map(db);
                    current_map = &*arc;
                }
                None => return result,
            }
        }
    }

    pub(super) fn resolve_path_fp_with_macro_single(
        &self,
        db: &dyn DefDatabase,
        mode: ResolveMode,
        original_module: LocalModuleId,
        path: &ModPath,
        shadow: BuiltinShadowMode,
    ) -> ResolvePathResult {
        let mut segments = path.segments().iter().enumerate();
        let mut curr_per_ns: PerNs = match path.kind {
            PathKind::DollarCrate(krate) => {
                if krate == self.krate {
                    cov_mark::hit!(macro_dollar_crate_self);
                    PerNs::types(self.crate_root(db).into(), Visibility::Public)
                } else {
                    let def_map = db.crate_def_map(krate);
                    let module = def_map.module_id(def_map.root);
                    cov_mark::hit!(macro_dollar_crate_other);
                    PerNs::types(module.into(), Visibility::Public)
                }
            }
            PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public),
            // plain import or absolute path in 2015: crate-relative with
            // fallback to extern prelude (with the simplification in
            // rust-lang/rust#57745)
            // FIXME there must be a nicer way to write this condition
            PathKind::Plain | PathKind::Abs
                if self.edition == Edition::Edition2015
                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
            {
                let (_, segment) = match segments.next() {
                    Some((idx, segment)) => (idx, segment),
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
                self.resolve_name_in_crate_root_or_extern_prelude(db, segment)
            }
            PathKind::Plain => {
                let (_, segment) = match segments.next() {
                    Some((idx, segment)) => (idx, segment),
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                // The first segment may be a builtin type. If the path has more
                // than one segment, we first try resolving it as a module
                // anyway.
                // FIXME: If the next segment doesn't resolve in the module and
                // BuiltinShadowMode wasn't Module, then we need to try
                // resolving it as a builtin.
                let prefer_module =
                    if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };

                tracing::debug!("resolving {:?} in module", segment);
                self.resolve_name_in_module(db, original_module, segment, prefer_module)
            }
            PathKind::Super(lvl) => {
                let mut module = original_module;
                for i in 0..lvl {
                    match self.modules[module].parent {
                        Some(it) => module = it,
                        None => match &self.block {
                            Some(block) => {
                                // Look up remaining path in parent `DefMap`
                                let new_path = ModPath::from_segments(
                                    PathKind::Super(lvl - i),
                                    path.segments().to_vec(),
                                );
                                tracing::debug!(
                                    "`super` path: {} -> {} in parent map",
                                    path,
                                    new_path
                                );
                                return block.parent.def_map(db).resolve_path_fp_with_macro(
                                    db,
                                    mode,
                                    block.parent.local_id,
                                    &new_path,
                                    shadow,
                                );
                            }
                            None => {
                                tracing::debug!("super path in root module");
                                return ResolvePathResult::empty(ReachedFixedPoint::Yes);
                            }
                        },
                    }
                }

                // Resolve `self` to the containing crate-rooted module if we're a block
                self.with_ancestor_maps(db, module, &mut |def_map, module| {
                    if def_map.block.is_some() {
                        None // keep ascending
                    } else {
                        Some(PerNs::types(def_map.module_id(module).into(), Visibility::Public))
                    }
                })
                .expect("block DefMap not rooted in crate DefMap")
            }
            PathKind::Abs => {
                // 2018-style absolute path -- only extern prelude
                let segment = match segments.next() {
                    Some((_, segment)) => segment,
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                if let Some(def) = self.extern_prelude.get(segment) {
                    tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
                    PerNs::types(*def, Visibility::Public)
                } else {
                    return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
                }
            }
        };

        for (i, segment) in segments {
            let (curr, vis) = match curr_per_ns.take_types_vis() {
                Some(r) => r,
                None => {
                    // we still have path segments left, but the path so far
                    // didn't resolve in the types namespace => no resolution
                    // (don't break here because `curr_per_ns` might contain
                    // something in the value namespace, and it would be wrong
                    // to return that)
                    return ResolvePathResult::empty(ReachedFixedPoint::No);
                }
            };
            // resolve segment in curr

            curr_per_ns = match curr {
                ModuleDefId::ModuleId(module) => {
                    if module.krate != self.krate {
                        let path = ModPath::from_segments(
                            PathKind::Super(0),
                            path.segments()[i..].iter().cloned(),
                        );
                        tracing::debug!("resolving {:?} in other crate", path);
                        let defp_map = module.def_map(db);
                        let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
                        return ResolvePathResult::with(
                            def,
                            ReachedFixedPoint::Yes,
                            s.map(|s| s + i),
                            Some(module.krate),
                        );
                    }

                    let def_map;
                    let module_data = if module.block == self.block_id() {
                        &self[module.local_id]
                    } else {
                        def_map = module.def_map(db);
                        &def_map[module.local_id]
                    };

                    // Since it is a qualified path here, it should not contains legacy macros
                    module_data.scope.get(segment)
                }
                ModuleDefId::AdtId(AdtId::EnumId(e)) => {
                    // enum variant
                    cov_mark::hit!(can_import_enum_variant);
                    let enum_data = db.enum_data(e);
                    match enum_data.variant(segment) {
                        Some(local_id) => {
                            let variant = EnumVariantId { parent: e, local_id };
                            match &*enum_data.variants[local_id].variant_data {
                                crate::adt::VariantData::Record(_) => {
                                    PerNs::types(variant.into(), Visibility::Public)
                                }
                                crate::adt::VariantData::Tuple(_)
                                | crate::adt::VariantData::Unit => {
                                    PerNs::both(variant.into(), variant.into(), Visibility::Public)
                                }
                            }
                        }
                        None => {
                            return ResolvePathResult::with(
                                PerNs::types(e.into(), vis),
                                ReachedFixedPoint::Yes,
                                Some(i),
                                Some(self.krate),
                            );
                        }
                    }
                }
                s => {
                    // could be an inherent method call in UFCS form
                    // (`Struct::method`), or some other kind of associated item
                    tracing::debug!(
                        "path segment {:?} resolved to non-module {:?}, but is not last",
                        segment,
                        curr,
                    );

                    return ResolvePathResult::with(
                        PerNs::types(s, vis),
                        ReachedFixedPoint::Yes,
                        Some(i),
                        Some(self.krate),
                    );
                }
            };
        }

        ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate))
    }

    fn resolve_name_in_module(
        &self,
        db: &dyn DefDatabase,
        module: LocalModuleId,
        name: &Name,
        shadow: BuiltinShadowMode,
    ) -> PerNs {
        // Resolve in:
        //  - legacy scope of macro
        //  - current module / scope
        //  - extern prelude
        //  - std prelude
        let from_legacy_macro = self[module]
            .scope
            .get_legacy_macro(name)
            .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
        let from_scope = self[module].scope.get(name);
        let from_builtin = match self.block {
            Some(_) => {
                // Only resolve to builtins in the root `DefMap`.
                PerNs::none()
            }
            None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none),
        };
        let from_scope_or_builtin = match shadow {
            BuiltinShadowMode::Module => from_scope.or(from_builtin),
            BuiltinShadowMode::Other => {
                if let Some(ModuleDefId::ModuleId(_)) = from_scope.take_types() {
                    from_builtin.or(from_scope)
                } else {
                    from_scope.or(from_builtin)
                }
            }
        };
        let from_extern_prelude = self
            .extern_prelude
            .get(name)
            .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));

        let from_prelude = self.resolve_in_prelude(db, name);

        from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
    }

    fn resolve_name_in_crate_root_or_extern_prelude(
        &self,
        db: &dyn DefDatabase,
        name: &Name,
    ) -> PerNs {
        let arc;
        let crate_def_map = match self.block {
            Some(_) => {
                arc = self.crate_root(db).def_map(db);
                &arc
            }
            None => self,
        };
        let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name);
        let from_extern_prelude = self.resolve_name_in_extern_prelude(db, name);

        from_crate_root.or(from_extern_prelude)
    }

    fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
        if let Some(prelude) = self.prelude {
            let keep;
            let def_map = if prelude.krate == self.krate {
                self
            } else {
                // Extend lifetime
                keep = prelude.def_map(db);
                &keep
            };
            def_map[prelude.local_id].scope.get(name)
        } else {
            PerNs::none()
        }
    }
}
<commit_msg>Augment panic context when resolving path<commit_after>//! This modules implements a function to resolve a path `foo::bar::baz` to a
//! def, which is used within the name resolution.
//!
//! When name resolution is finished, the result of resolving a path is either
//! `Some(def)` or `None`. However, when we are in process of resolving imports
//! or macros, there's a third possibility:
//!
//!   I can't resolve this path right now, but I might be resolve this path
//!   later, when more macros are expanded.
//!
//! `ReachedFixedPoint` signals about this.

use base_db::Edition;
use hir_expand::name;
use hir_expand::name::Name;

use crate::{
    db::DefDatabase,
    item_scope::BUILTIN_SCOPE,
    nameres::{BuiltinShadowMode, DefMap},
    path::{ModPath, PathKind},
    per_ns::PerNs,
    visibility::{RawVisibility, Visibility},
    AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ResolveMode {
    Import,
    Other,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ReachedFixedPoint {
    Yes,
    No,
}

#[derive(Debug, Clone)]
pub(super) struct ResolvePathResult {
    pub(super) resolved_def: PerNs,
    pub(super) segment_index: Option<usize>,
    pub(super) reached_fixedpoint: ReachedFixedPoint,
    pub(super) krate: Option<CrateId>,
}

impl ResolvePathResult {
    fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
        ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None)
    }

    fn with(
        resolved_def: PerNs,
        reached_fixedpoint: ReachedFixedPoint,
        segment_index: Option<usize>,
        krate: Option<CrateId>,
    ) -> ResolvePathResult {
        ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, krate }
    }
}

impl DefMap {
    pub(super) fn resolve_name_in_extern_prelude(
        &self,
        db: &dyn DefDatabase,
        name: &Name,
    ) -> PerNs {
        if name == &name!(self) {
            cov_mark::hit!(extern_crate_self_as);
            return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
        }

        let arc;
        let root = match self.block {
            Some(_) => {
                arc = self.crate_root(db).def_map(db);
                &*arc
            }
            None => self,
        };

        root.extern_prelude
            .get(name)
            .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
    }

    pub(crate) fn resolve_visibility(
        &self,
        db: &dyn DefDatabase,
        original_module: LocalModuleId,
        visibility: &RawVisibility,
    ) -> Option<Visibility> {
        let mut vis = match visibility {
            RawVisibility::Module(path) => {
                let (result, remaining) =
                    self.resolve_path(db, original_module, path, BuiltinShadowMode::Module);
                if remaining.is_some() {
                    return None;
                }
                let types = result.take_types()?;
                match types {
                    ModuleDefId::ModuleId(m) => Visibility::Module(m),
                    _ => {
                        // error: visibility needs to refer to module
                        return None;
                    }
                }
            }
            RawVisibility::Public => Visibility::Public,
        };

        // In block expressions, `self` normally refers to the containing non-block module, and
        // `super` to its parent (etc.). However, visibilities must only refer to a module in the
        // DefMap they're written in, so we restrict them when that happens.
        if let Visibility::Module(m) = vis {
            if self.block_id() != m.block {
                cov_mark::hit!(adjust_vis_in_block_def_map);
                vis = Visibility::Module(self.module_id(self.root()));
                tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
            }
        }

        Some(vis)
    }

    // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
    // the result.
    pub(super) fn resolve_path_fp_with_macro(
        &self,
        db: &dyn DefDatabase,
        mode: ResolveMode,
        mut original_module: LocalModuleId,
        path: &ModPath,
        shadow: BuiltinShadowMode,
    ) -> ResolvePathResult {
        let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);

        let mut arc;
        let mut current_map = self;
        loop {
            let new = current_map.resolve_path_fp_with_macro_single(
                db,
                mode,
                original_module,
                path,
                shadow,
            );

            // Merge `new` into `result`.
            result.resolved_def = result.resolved_def.or(new.resolved_def);
            if result.reached_fixedpoint == ReachedFixedPoint::No {
                result.reached_fixedpoint = new.reached_fixedpoint;
            }
            // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates?
            result.krate = result.krate.or(new.krate);
            result.segment_index = match (result.segment_index, new.segment_index) {
                (Some(idx), None) => Some(idx),
                (Some(old), Some(new)) => Some(old.max(new)),
                (None, new) => new,
            };

            match &current_map.block {
                Some(block) => {
                    original_module = block.parent.local_id;
                    arc = block.parent.def_map(db);
                    current_map = &*arc;
                }
                None => return result,
            }
        }
    }

    pub(super) fn resolve_path_fp_with_macro_single(
        &self,
        db: &dyn DefDatabase,
        mode: ResolveMode,
        original_module: LocalModuleId,
        path: &ModPath,
        shadow: BuiltinShadowMode,
    ) -> ResolvePathResult {
        let _cx = stdx::panic_context::enter(format!(
            "DefMap {:?} {:?} path {}",
            self.krate, self.block, path
        ));

        let mut segments = path.segments().iter().enumerate();
        let mut curr_per_ns: PerNs = match path.kind {
            PathKind::DollarCrate(krate) => {
                if krate == self.krate {
                    cov_mark::hit!(macro_dollar_crate_self);
                    PerNs::types(self.crate_root(db).into(), Visibility::Public)
                } else {
                    let def_map = db.crate_def_map(krate);
                    let module = def_map.module_id(def_map.root);
                    cov_mark::hit!(macro_dollar_crate_other);
                    PerNs::types(module.into(), Visibility::Public)
                }
            }
            PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public),
            // plain import or absolute path in 2015: crate-relative with
            // fallback to extern prelude (with the simplification in
            // rust-lang/rust#57745)
            // FIXME there must be a nicer way to write this condition
            PathKind::Plain | PathKind::Abs
                if self.edition == Edition::Edition2015
                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
            {
                let (_, segment) = match segments.next() {
                    Some((idx, segment)) => (idx, segment),
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
                self.resolve_name_in_crate_root_or_extern_prelude(db, segment)
            }
            PathKind::Plain => {
                let (_, segment) = match segments.next() {
                    Some((idx, segment)) => (idx, segment),
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                // The first segment may be a builtin type. If the path has more
                // than one segment, we first try resolving it as a module
                // anyway.
                // FIXME: If the next segment doesn't resolve in the module and
                // BuiltinShadowMode wasn't Module, then we need to try
                // resolving it as a builtin.
                let prefer_module =
                    if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };

                tracing::debug!("resolving {:?} in module", segment);
                self.resolve_name_in_module(db, original_module, segment, prefer_module)
            }
            PathKind::Super(lvl) => {
                let mut module = original_module;
                for i in 0..lvl {
                    match self.modules[module].parent {
                        Some(it) => module = it,
                        None => match &self.block {
                            Some(block) => {
                                // Look up remaining path in parent `DefMap`
                                let new_path = ModPath::from_segments(
                                    PathKind::Super(lvl - i),
                                    path.segments().to_vec(),
                                );
                                tracing::debug!(
                                    "`super` path: {} -> {} in parent map",
                                    path,
                                    new_path
                                );
                                return block.parent.def_map(db).resolve_path_fp_with_macro(
                                    db,
                                    mode,
                                    block.parent.local_id,
                                    &new_path,
                                    shadow,
                                );
                            }
                            None => {
                                tracing::debug!("super path in root module");
                                return ResolvePathResult::empty(ReachedFixedPoint::Yes);
                            }
                        },
                    }
                }

                // Resolve `self` to the containing crate-rooted module if we're a block
                self.with_ancestor_maps(db, module, &mut |def_map, module| {
                    if def_map.block.is_some() {
                        None // keep ascending
                    } else {
                        Some(PerNs::types(def_map.module_id(module).into(), Visibility::Public))
                    }
                })
                .expect("block DefMap not rooted in crate DefMap")
            }
            PathKind::Abs => {
                // 2018-style absolute path -- only extern prelude
                let segment = match segments.next() {
                    Some((_, segment)) => segment,
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                if let Some(def) = self.extern_prelude.get(segment) {
                    tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
                    PerNs::types(*def, Visibility::Public)
                } else {
                    return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
                }
            }
        };

        for (i, segment) in segments {
            let (curr, vis) = match curr_per_ns.take_types_vis() {
                Some(r) => r,
                None => {
                    // we still have path segments left, but the path so far
                    // didn't resolve in the types namespace => no resolution
                    // (don't break here because `curr_per_ns` might contain
                    // something in the value namespace, and it would be wrong
                    // to return that)
                    return ResolvePathResult::empty(ReachedFixedPoint::No);
                }
            };
            // resolve segment in curr

            curr_per_ns = match curr {
                ModuleDefId::ModuleId(module) => {
                    if module.krate != self.krate {
                        let path = ModPath::from_segments(
                            PathKind::Super(0),
                            path.segments()[i..].iter().cloned(),
                        );
                        tracing::debug!("resolving {:?} in other crate", path);
                        let defp_map = module.def_map(db);
                        let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
                        return ResolvePathResult::with(
                            def,
                            ReachedFixedPoint::Yes,
                            s.map(|s| s + i),
                            Some(module.krate),
                        );
                    }

                    let def_map;
                    let module_data = if module.block == self.block_id() {
                        &self[module.local_id]
                    } else {
                        def_map = module.def_map(db);
                        &def_map[module.local_id]
                    };

                    // Since it is a qualified path here, it should not contains legacy macros
                    module_data.scope.get(segment)
                }
                ModuleDefId::AdtId(AdtId::EnumId(e)) => {
                    // enum variant
                    cov_mark::hit!(can_import_enum_variant);
                    let enum_data = db.enum_data(e);
                    match enum_data.variant(segment) {
                        Some(local_id) => {
                            let variant = EnumVariantId { parent: e, local_id };
                            match &*enum_data.variants[local_id].variant_data {
                                crate::adt::VariantData::Record(_) => {
                                    PerNs::types(variant.into(), Visibility::Public)
                                }
                                crate::adt::VariantData::Tuple(_)
                                | crate::adt::VariantData::Unit => {
                                    PerNs::both(variant.into(), variant.into(), Visibility::Public)
                                }
                            }
                        }
                        None => {
                            return ResolvePathResult::with(
                                PerNs::types(e.into(), vis),
                                ReachedFixedPoint::Yes,
                                Some(i),
                                Some(self.krate),
                            );
                        }
                    }
                }
                s => {
                    // could be an inherent method call in UFCS form
                    // (`Struct::method`), or some other kind of associated item
                    tracing::debug!(
                        "path segment {:?} resolved to non-module {:?}, but is not last",
                        segment,
                        curr,
                    );

                    return ResolvePathResult::with(
                        PerNs::types(s, vis),
                        ReachedFixedPoint::Yes,
                        Some(i),
                        Some(self.krate),
                    );
                }
            };
        }

        ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate))
    }

    fn resolve_name_in_module(
        &self,
        db: &dyn DefDatabase,
        module: LocalModuleId,
        name: &Name,
        shadow: BuiltinShadowMode,
    ) -> PerNs {
        // Resolve in:
        //  - legacy scope of macro
        //  - current module / scope
        //  - extern prelude
        //  - std prelude
        let from_legacy_macro = self[module]
            .scope
            .get_legacy_macro(name)
            .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
        let from_scope = self[module].scope.get(name);
        let from_builtin = match self.block {
            Some(_) => {
                // Only resolve to builtins in the root `DefMap`.
                PerNs::none()
            }
            None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none),
        };
        let from_scope_or_builtin = match shadow {
            BuiltinShadowMode::Module => from_scope.or(from_builtin),
            BuiltinShadowMode::Other => {
                if let Some(ModuleDefId::ModuleId(_)) = from_scope.take_types() {
                    from_builtin.or(from_scope)
                } else {
                    from_scope.or(from_builtin)
                }
            }
        };
        let from_extern_prelude = self
            .extern_prelude
            .get(name)
            .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));

        let from_prelude = self.resolve_in_prelude(db, name);

        from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
    }

    fn resolve_name_in_crate_root_or_extern_prelude(
        &self,
        db: &dyn DefDatabase,
        name: &Name,
    ) -> PerNs {
        let arc;
        let crate_def_map = match self.block {
            Some(_) => {
                arc = self.crate_root(db).def_map(db);
                &arc
            }
            None => self,
        };
        let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name);
        let from_extern_prelude = self.resolve_name_in_extern_prelude(db, name);

        from_crate_root.or(from_extern_prelude)
    }

    fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
        if let Some(prelude) = self.prelude {
            let keep;
            let def_map = if prelude.krate == self.krate {
                self
            } else {
                // Extend lifetime
                keep = prelude.def_map(db);
                &keep
            };
            def_map[prelude.local_id].scope.get(name)
        } else {
            PerNs::none()
        }
    }
}
<|endoftext|>


<commit_before>use crate::{
    analysis::{
        bounds::{Bounds, PropertyBound},
        imports::Imports,
        ref_mode::RefMode,
        rust_type::*,
        signals,
        signatures::{Signature, Signatures},
        trampolines,
    },
    config::{self, GObject, PropertyGenerateFlags},
    env::Env,
    library, nameutil,
    traits::*,
    version::Version,
};
use log::warn;

#[derive(Debug)]
pub struct Property {
    pub name: String,
    pub var_name: String,
    pub typ: library::TypeId,
    pub is_get: bool,
    pub func_name: String,
    pub func_name_alias: Option<String>,
    pub nullable: library::Nullable,
    pub get_out_ref_mode: RefMode,
    pub set_in_ref_mode: RefMode,
    pub bounds: Bounds,
    pub set_bound: Option<PropertyBound>,
    pub version: Option<Version>,
    pub deprecated_version: Option<Version>,
}

pub fn analyze(
    env: &Env,
    props: &[library::Property],
    type_tid: library::TypeId,
    generate_trait: bool,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Vec<Property>, Vec<signals::Info>) {
    let mut properties = Vec::new();
    let mut notify_signals = Vec::new();

    for prop in props {
        let configured_properties = obj.properties.matched(&prop.name);
        if !configured_properties
            .iter()
            .all(|f| f.status.need_generate())
        {
            continue;
        }

        if env.is_totally_deprecated(prop.deprecated_version) {
            continue;
        }

        let (getter, setter, notify_signal) = analyze_property(
            env,
            prop,
            type_tid,
            &configured_properties,
            generate_trait,
            obj,
            imports,
            signatures,
            deps,
        );

        if let Some(notify_signal) = notify_signal {
            notify_signals.push(notify_signal);
        }

        if let Some(prop) = getter {
            properties.push(prop);
        }
        if let Some(prop) = setter {
            properties.push(prop);
        }
    }

    (properties, notify_signals)
}

fn analyze_property(
    env: &Env,
    prop: &library::Property,
    type_tid: library::TypeId,
    configured_properties: &[&config::properties::Property],
    generate_trait: bool,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Option<Property>, Option<Property>, Option<signals::Info>) {
    let type_name = type_tid.full_name(&env.library);
    let name = prop.name.clone();

    let prop_version = configured_properties
        .iter()
        .filter_map(|f| f.version)
        .min()
        .or(prop.version)
        .or(Some(env.config.min_cfg_version));
    let generate = configured_properties
        .iter()
        .filter_map(|f| f.generate)
        .next();
    let generate_set = generate.is_some();
    let generate = generate.unwrap_or_else(PropertyGenerateFlags::all);

    let imports = &mut imports.with_defaults(prop_version, &None);
    imports.add("glib::translate::*");

    let type_string = rust_type(env, prop.typ);
    let name_for_func = nameutil::signal_to_snake(&name);

    let mut get_prop_name = Some(format!("get_property_{}", name_for_func));

    let bypass_auto_rename = configured_properties.iter().any(|f| f.bypass_auto_rename);
    let (check_get_func_names, mut get_func_name) = if bypass_auto_rename {
        (
            vec![format!("get_{}", name_for_func)],
            get_prop_name.take().expect("defined 10 lines above"),
        )
    } else {
        get_func_name(&name_for_func, prop.typ == library::TypeId::tid_bool())
    };

    let mut set_func_name = format!("set_{}", name_for_func);
    let mut set_prop_name = Some(format!("set_property_{}", name_for_func));

    let mut readable = prop.readable;
    let mut writable = if prop.construct_only {
        false
    } else {
        prop.writable
    };
    let mut notifiable = !prop.construct_only;
    if generate_set && generate.contains(PropertyGenerateFlags::GET) && !readable {
        warn!(
            "Attempt to generate getter for notreadable property \"{}.{}\"",
            type_name, name
        );
    }
    if generate_set && generate.contains(PropertyGenerateFlags::SET) && !writable {
        warn!(
            "Attempt to generate setter for nonwritable property \"{}.{}\"",
            type_name, name
        );
    }
    readable &= generate.contains(PropertyGenerateFlags::GET);
    writable &= generate.contains(PropertyGenerateFlags::SET);
    if generate_set {
        notifiable = generate.contains(PropertyGenerateFlags::NOTIFY);
    }

    if readable {
        for check_get_func_name in check_get_func_names {
            let (has, version) = Signature::has_for_property(
                env,
                &check_get_func_name,
                true,
                prop.typ,
                signatures,
                deps,
            );
            if has {
                // There is a matching get func
                if env.is_totally_deprecated(version) || version <= prop_version {
                    // And its availability covers the property's availability
                    // => don't generate the get property.
                    readable = false;
                } else {
                    // The property is required in earlier versions than the getter
                    // => we need both, but there will be a name clash due to auto renaming
                    // => keep the get_property name.
                    if let Some(get_prop_name) = get_prop_name.take() {
                        get_func_name = get_prop_name;
                    }
                }
            }
        }
    }
    if writable {
        let (has, version) =
            Signature::has_for_property(env, &set_func_name, false, prop.typ, signatures, deps);
        if has {
            // There is a matching set func
            if env.is_totally_deprecated(version) || version <= prop_version {
                // And its availability covers the property's availability
                // => don't generate the set property.
                writable = false;
            } else {
                // The property is required in earlier versions than the setter
                // => we need both, but there will be a name clash due to auto renaming
                // => keep the set_property name.
                if let Some(set_prop_name) = set_prop_name.take() {
                    set_func_name = set_prop_name;
                }
            }
        }
    }

    let (get_out_ref_mode, set_in_ref_mode, nullable) = get_property_ref_modes(env, prop);

    let getter = if readable {
        if let Ok(ref s) = used_rust_type(env, prop.typ, false) {
            imports.add_used_type(s);
        }
        if type_string.is_ok() {
            imports.add("glib::StaticType");
            imports.add("glib::ToValue");
        }

        Some(Property {
            name: name.clone(),
            var_name: String::new(),
            typ: prop.typ,
            is_get: true,
            func_name: get_func_name,
            func_name_alias: get_prop_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            set_bound: None,
            bounds: Bounds::default(),
            version: prop_version,
            deprecated_version: prop.deprecated_version,
        })
    } else {
        None
    };

    let setter = if writable {
        if let Ok(ref s) = used_rust_type(env, prop.typ, true) {
            imports.add_used_type(s);
        }
        if type_string.is_ok() {
            imports.add("glib::ToValue");
        }
        let set_bound = PropertyBound::get(env, prop.typ);
        if type_string.is_ok() && set_bound.is_some() {
            imports.add("glib::object::IsA");
            if !*nullable {
                //TODO: support non-nullable setter if found any
                warn!(
                    "Non nullable setter for property generated as nullable \"{}.{}\"",
                    type_name, name
                );
            }
        }

        Some(Property {
            name: name.clone(),
            var_name: nameutil::mangle_keywords(&*name_for_func).into_owned(),
            typ: prop.typ,
            is_get: false,
            func_name: set_func_name,
            func_name_alias: set_prop_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            set_bound,
            bounds: Bounds::default(),
            version: prop_version,
            deprecated_version: prop.deprecated_version,
        })
    } else {
        None
    };

    if !generate_trait && (writable || readable || notifiable) {
        //To resolve a conflict with OSTree::ObjectType
        imports.add("glib::object::ObjectType as ObjectType_");
    }

    let notify_signal = if notifiable {
        let mut used_types: Vec<String> = Vec::with_capacity(4);
        let trampoline = trampolines::analyze(
            env,
            &library::Signal {
                name: format!("notify::{}", name),
                parameters: Vec::new(),
                ret: library::Parameter {
                    name: "".into(),
                    typ: env
                        .library
                        .find_type(library::INTERNAL_NAMESPACE, "none")
                        .unwrap(),
                    c_type: "none".into(),
                    instance_parameter: false,
                    direction: library::ParameterDirection::Return,
                    transfer: library::Transfer::None,
                    caller_allocates: false,
                    nullable: library::Nullable(false),
                    allow_none: false,
                    array_length: None,
                    is_error: false,
                    doc: None,
                    scope: library::ParameterScope::None,
                    closure: None,
                    destroy: None,
                },
                is_action: false,
                is_detailed: false, // well, technically this *is* an instance of a detailed signal, but we "pre-detailed" it
                version: prop_version,
                deprecated_version: prop.deprecated_version,
                doc: None,
                doc_deprecated: None,
            },
            type_tid,
            generate_trait,
            &[],
            obj,
            &mut used_types,
            prop_version,
        );

        if trampoline.is_ok() {
            imports.add_used_types(&used_types);
            if generate_trait {
                imports.add("glib::object::Cast");
            }
            imports.add("glib::signal::connect_raw");
            imports.add("glib::signal::SignalHandlerId");
            imports.add("std::mem::transmute");
            imports.add("std::boxed::Box as Box_");

            Some(signals::Info {
                connect_name: format!("connect_property_{}_notify", name_for_func),
                signal_name: format!("notify::{}", name),
                trampoline,
                action_emit_name: None,
                version: prop_version,
                deprecated_version: prop.deprecated_version,
                doc_hidden: false,
                is_detailed: false, // see above comment
            })
        } else {
            None
        }
    } else {
        None
    };

    (getter, setter, notify_signal)
}

/// Returns (the list of get functions to check, the desired get function name).
fn get_func_name(prop_name: &str, is_bool_getter: bool) -> (Vec<String>, String) {
    let get_rename_res = getter_rules::try_rename_getter_suffix(&prop_name, is_bool_getter);
    match get_rename_res {
        Ok(new_name) => {
            let new_name = new_name.unwrap();
            let mut check_get_func_names = vec![
                format!("get_{}", prop_name),
                prop_name.to_string(),
                format!("get_{}", new_name),
                new_name.clone(),
            ];

            if is_bool_getter {
                check_get_func_names.push(format!("is_{}", prop_name));
                check_get_func_names.push(format!("is_{}", new_name));
            }
            (check_get_func_names, new_name)
        }
        Err(_) => {
            let mut check_get_func_names =
                vec![format!("get_{}", prop_name), prop_name.to_string()];

            // Name is reserved
            let get_func_name = if is_bool_getter {
                let get_func_name = format!("is_{}", prop_name);
                check_get_func_names.push(get_func_name.clone());
                get_func_name
            } else {
                format!("get_{}", prop_name)
            };
            (check_get_func_names, get_func_name)
        }
    }
}

pub fn get_property_ref_modes(
    env: &Env,
    prop: &library::Property,
) -> (RefMode, RefMode, library::Nullable) {
    let get_out_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::Return);
    let mut set_in_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::In);
    if set_in_ref_mode == RefMode::ByRefMut {
        set_in_ref_mode = RefMode::ByRef;
    }
    let nullable = library::Nullable(set_in_ref_mode.is_ref());
    (get_out_ref_mode, set_in_ref_mode, nullable)
}
<commit_msg>analysis/properties: Remove unused ToValue import for property getters<commit_after>use crate::{
    analysis::{
        bounds::{Bounds, PropertyBound},
        imports::Imports,
        ref_mode::RefMode,
        rust_type::*,
        signals,
        signatures::{Signature, Signatures},
        trampolines,
    },
    config::{self, GObject, PropertyGenerateFlags},
    env::Env,
    library, nameutil,
    traits::*,
    version::Version,
};
use log::warn;

#[derive(Debug)]
pub struct Property {
    pub name: String,
    pub var_name: String,
    pub typ: library::TypeId,
    pub is_get: bool,
    pub func_name: String,
    pub func_name_alias: Option<String>,
    pub nullable: library::Nullable,
    pub get_out_ref_mode: RefMode,
    pub set_in_ref_mode: RefMode,
    pub bounds: Bounds,
    pub set_bound: Option<PropertyBound>,
    pub version: Option<Version>,
    pub deprecated_version: Option<Version>,
}

pub fn analyze(
    env: &Env,
    props: &[library::Property],
    type_tid: library::TypeId,
    generate_trait: bool,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Vec<Property>, Vec<signals::Info>) {
    let mut properties = Vec::new();
    let mut notify_signals = Vec::new();

    for prop in props {
        let configured_properties = obj.properties.matched(&prop.name);
        if !configured_properties
            .iter()
            .all(|f| f.status.need_generate())
        {
            continue;
        }

        if env.is_totally_deprecated(prop.deprecated_version) {
            continue;
        }

        let (getter, setter, notify_signal) = analyze_property(
            env,
            prop,
            type_tid,
            &configured_properties,
            generate_trait,
            obj,
            imports,
            signatures,
            deps,
        );

        if let Some(notify_signal) = notify_signal {
            notify_signals.push(notify_signal);
        }

        if let Some(prop) = getter {
            properties.push(prop);
        }
        if let Some(prop) = setter {
            properties.push(prop);
        }
    }

    (properties, notify_signals)
}

fn analyze_property(
    env: &Env,
    prop: &library::Property,
    type_tid: library::TypeId,
    configured_properties: &[&config::properties::Property],
    generate_trait: bool,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Option<Property>, Option<Property>, Option<signals::Info>) {
    let type_name = type_tid.full_name(&env.library);
    let name = prop.name.clone();

    let prop_version = configured_properties
        .iter()
        .filter_map(|f| f.version)
        .min()
        .or(prop.version)
        .or(Some(env.config.min_cfg_version));
    let generate = configured_properties
        .iter()
        .filter_map(|f| f.generate)
        .next();
    let generate_set = generate.is_some();
    let generate = generate.unwrap_or_else(PropertyGenerateFlags::all);

    let imports = &mut imports.with_defaults(prop_version, &None);
    imports.add("glib::translate::*");

    let type_string = rust_type(env, prop.typ);
    let name_for_func = nameutil::signal_to_snake(&name);

    let mut get_prop_name = Some(format!("get_property_{}", name_for_func));

    let bypass_auto_rename = configured_properties.iter().any(|f| f.bypass_auto_rename);
    let (check_get_func_names, mut get_func_name) = if bypass_auto_rename {
        (
            vec![format!("get_{}", name_for_func)],
            get_prop_name.take().expect("defined 10 lines above"),
        )
    } else {
        get_func_name(&name_for_func, prop.typ == library::TypeId::tid_bool())
    };

    let mut set_func_name = format!("set_{}", name_for_func);
    let mut set_prop_name = Some(format!("set_property_{}", name_for_func));

    let mut readable = prop.readable;
    let mut writable = if prop.construct_only {
        false
    } else {
        prop.writable
    };
    let mut notifiable = !prop.construct_only;
    if generate_set && generate.contains(PropertyGenerateFlags::GET) && !readable {
        warn!(
            "Attempt to generate getter for notreadable property \"{}.{}\"",
            type_name, name
        );
    }
    if generate_set && generate.contains(PropertyGenerateFlags::SET) && !writable {
        warn!(
            "Attempt to generate setter for nonwritable property \"{}.{}\"",
            type_name, name
        );
    }
    readable &= generate.contains(PropertyGenerateFlags::GET);
    writable &= generate.contains(PropertyGenerateFlags::SET);
    if generate_set {
        notifiable = generate.contains(PropertyGenerateFlags::NOTIFY);
    }

    if readable {
        for check_get_func_name in check_get_func_names {
            let (has, version) = Signature::has_for_property(
                env,
                &check_get_func_name,
                true,
                prop.typ,
                signatures,
                deps,
            );
            if has {
                // There is a matching get func
                if env.is_totally_deprecated(version) || version <= prop_version {
                    // And its availability covers the property's availability
                    // => don't generate the get property.
                    readable = false;
                } else {
                    // The property is required in earlier versions than the getter
                    // => we need both, but there will be a name clash due to auto renaming
                    // => keep the get_property name.
                    if let Some(get_prop_name) = get_prop_name.take() {
                        get_func_name = get_prop_name;
                    }
                }
            }
        }
    }
    if writable {
        let (has, version) =
            Signature::has_for_property(env, &set_func_name, false, prop.typ, signatures, deps);
        if has {
            // There is a matching set func
            if env.is_totally_deprecated(version) || version <= prop_version {
                // And its availability covers the property's availability
                // => don't generate the set property.
                writable = false;
            } else {
                // The property is required in earlier versions than the setter
                // => we need both, but there will be a name clash due to auto renaming
                // => keep the set_property name.
                if let Some(set_prop_name) = set_prop_name.take() {
                    set_func_name = set_prop_name;
                }
            }
        }
    }

    let (get_out_ref_mode, set_in_ref_mode, nullable) = get_property_ref_modes(env, prop);

    let getter = if readable {
        if let Ok(ref s) = used_rust_type(env, prop.typ, false) {
            imports.add_used_type(s);
        }
        if type_string.is_ok() {
            imports.add("glib::StaticType");
        }

        Some(Property {
            name: name.clone(),
            var_name: String::new(),
            typ: prop.typ,
            is_get: true,
            func_name: get_func_name,
            func_name_alias: get_prop_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            set_bound: None,
            bounds: Bounds::default(),
            version: prop_version,
            deprecated_version: prop.deprecated_version,
        })
    } else {
        None
    };

    let setter = if writable {
        if let Ok(ref s) = used_rust_type(env, prop.typ, true) {
            imports.add_used_type(s);
        }
        if type_string.is_ok() {
            imports.add("glib::ToValue");
        }
        let set_bound = PropertyBound::get(env, prop.typ);
        if type_string.is_ok() && set_bound.is_some() {
            imports.add("glib::object::IsA");
            if !*nullable {
                //TODO: support non-nullable setter if found any
                warn!(
                    "Non nullable setter for property generated as nullable \"{}.{}\"",
                    type_name, name
                );
            }
        }

        Some(Property {
            name: name.clone(),
            var_name: nameutil::mangle_keywords(&*name_for_func).into_owned(),
            typ: prop.typ,
            is_get: false,
            func_name: set_func_name,
            func_name_alias: set_prop_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            set_bound,
            bounds: Bounds::default(),
            version: prop_version,
            deprecated_version: prop.deprecated_version,
        })
    } else {
        None
    };

    if !generate_trait && (writable || readable || notifiable) {
        //To resolve a conflict with OSTree::ObjectType
        imports.add("glib::object::ObjectType as ObjectType_");
    }

    let notify_signal = if notifiable {
        let mut used_types: Vec<String> = Vec::with_capacity(4);
        let trampoline = trampolines::analyze(
            env,
            &library::Signal {
                name: format!("notify::{}", name),
                parameters: Vec::new(),
                ret: library::Parameter {
                    name: "".into(),
                    typ: env
                        .library
                        .find_type(library::INTERNAL_NAMESPACE, "none")
                        .unwrap(),
                    c_type: "none".into(),
                    instance_parameter: false,
                    direction: library::ParameterDirection::Return,
                    transfer: library::Transfer::None,
                    caller_allocates: false,
                    nullable: library::Nullable(false),
                    allow_none: false,
                    array_length: None,
                    is_error: false,
                    doc: None,
                    scope: library::ParameterScope::None,
                    closure: None,
                    destroy: None,
                },
                is_action: false,
                is_detailed: false, // well, technically this *is* an instance of a detailed signal, but we "pre-detailed" it
                version: prop_version,
                deprecated_version: prop.deprecated_version,
                doc: None,
                doc_deprecated: None,
            },
            type_tid,
            generate_trait,
            &[],
            obj,
            &mut used_types,
            prop_version,
        );

        if trampoline.is_ok() {
            imports.add_used_types(&used_types);
            if generate_trait {
                imports.add("glib::object::Cast");
            }
            imports.add("glib::signal::connect_raw");
            imports.add("glib::signal::SignalHandlerId");
            imports.add("std::mem::transmute");
            imports.add("std::boxed::Box as Box_");

            Some(signals::Info {
                connect_name: format!("connect_property_{}_notify", name_for_func),
                signal_name: format!("notify::{}", name),
                trampoline,
                action_emit_name: None,
                version: prop_version,
                deprecated_version: prop.deprecated_version,
                doc_hidden: false,
                is_detailed: false, // see above comment
            })
        } else {
            None
        }
    } else {
        None
    };

    (getter, setter, notify_signal)
}

/// Returns (the list of get functions to check, the desired get function name).
fn get_func_name(prop_name: &str, is_bool_getter: bool) -> (Vec<String>, String) {
    let get_rename_res = getter_rules::try_rename_getter_suffix(&prop_name, is_bool_getter);
    match get_rename_res {
        Ok(new_name) => {
            let new_name = new_name.unwrap();
            let mut check_get_func_names = vec![
                format!("get_{}", prop_name),
                prop_name.to_string(),
                format!("get_{}", new_name),
                new_name.clone(),
            ];

            if is_bool_getter {
                check_get_func_names.push(format!("is_{}", prop_name));
                check_get_func_names.push(format!("is_{}", new_name));
            }
            (check_get_func_names, new_name)
        }
        Err(_) => {
            let mut check_get_func_names =
                vec![format!("get_{}", prop_name), prop_name.to_string()];

            // Name is reserved
            let get_func_name = if is_bool_getter {
                let get_func_name = format!("is_{}", prop_name);
                check_get_func_names.push(get_func_name.clone());
                get_func_name
            } else {
                format!("get_{}", prop_name)
            };
            (check_get_func_names, get_func_name)
        }
    }
}

pub fn get_property_ref_modes(
    env: &Env,
    prop: &library::Property,
) -> (RefMode, RefMode, library::Nullable) {
    let get_out_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::Return);
    let mut set_in_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::In);
    if set_in_ref_mode == RefMode::ByRefMut {
        set_in_ref_mode = RefMode::ByRef;
    }
    let nullable = library::Nullable(set_in_ref_mode.is_ref());
    (get_out_ref_mode, set_in_ref_mode, nullable)
}
<|endoftext|>


<commit_before>fn main() {
    // Pull in jemalloc when enabled.
    //
    // Note that we're pulling in a static copy of jemalloc which means that to
    // pull it in we need to actually reference its symbols for it to get
    // linked. The two crates we link to here, std and rustc_driver, are both
    // dynamic libraries. That means to pull in jemalloc we need to actually
    // reference allocation symbols one way or another (as this file is the only
    // object code in the rustc executable).
    #[cfg(feature = "jemalloc-sys")]
    {
        use std::os::raw::{c_int, c_void};

        #[used]
        static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
        #[used]
        static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int =
            jemalloc_sys::posix_memalign;
        #[used]
        static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
        #[used]
        static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
        #[used]
        static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
        #[used]
        static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;
    }

    rustc_driver::set_sigpipe_handler();
    rustc_driver::main()
}
<commit_msg>Rollup merge of #82822 - henryboisdequin:fix-typo-rustc, r=oli-obk<commit_after>fn main() {
    // Pull in jemalloc when enabled.
    //
    // Note that we're pulling in a static copy of jemalloc which means that to
    // pull it in we need to actually reference its symbols for it to get
    // linked. The two crates we link to here, std and rustc_driver, are both
    // dynamic libraries. That means to pull in jemalloc we actually need to
    // reference allocation symbols one way or another (as this file is the only
    // object code in the rustc executable).
    #[cfg(feature = "jemalloc-sys")]
    {
        use std::os::raw::{c_int, c_void};

        #[used]
        static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
        #[used]
        static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int =
            jemalloc_sys::posix_memalign;
        #[used]
        static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
        #[used]
        static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
        #[used]
        static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
        #[used]
        static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;
    }

    rustc_driver::set_sigpipe_handler();
    rustc_driver::main()
}
<|endoftext|>


<commit_before>use std::fmt;
use std::convert::From;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
use std::io::{self, Read};

use rustc_serialize::json::{self, DecoderError};
use url::Url;
use hyper;
use hyper::client::request::Request;
use hyper::method::Method::Get;
use time::{Timespec, get_time, Duration, SteadyTime};

use irc::parse::IrcMsg;

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator,
    Format,
    Token,
};

static UPCOMING_URL: &'static str = "http://anime.yshi.org/api/calendar/upcoming/100";

const CMD_UPCOMING: Token = Token(0);

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct Upcoming {
    title_name: String,
    syoboi_pid: i32,
    start_time: i64,
    end_time: i64,
    count: String,
    start_offset: i64,
    episode_name: String,
    channel_name: String,
    special_name: String,
    comment: String,
}

impl Upcoming {
    pub fn start_time(&self) -> Timespec {
        Timespec::new(self.start_time, 0)
    }

    pub fn start_offset(&self) -> Duration {
        Duration::seconds(self.start_offset)
    }
}

impl fmt::Display for Upcoming {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let now = get_time();
        write!(f, "{} episode {} airs in {} on {}",
            self.title_name, self.count,
            self.start_time() - now,
            self.channel_name)
    }
}

#[derive(Debug)]
enum ApiFailure {
    RequestError(hyper::Error),
    ResponseReadError(io::Error),
    ResponseDeserializeError(DecoderError)
}

impl From<hyper::Error> for ApiFailure {
    fn from(err: hyper::Error) -> ApiFailure {
        ApiFailure::RequestError(err)
    }
}

impl From<io::Error> for ApiFailure {
    fn from(err: io::Error) -> ApiFailure {
        ApiFailure::ResponseReadError(err)
    }
}

impl From<DecoderError> for ApiFailure {
    fn from(err: DecoderError) -> ApiFailure {
        ApiFailure::ResponseDeserializeError(err)
    }
}

fn get_upcoming() -> Result<Vec<Upcoming>, ApiFailure> {
    let url = Url::parse(UPCOMING_URL).ok().expect("Invalid UPCOMING_URL");
    let mut resp = try!(try!(try!(Request::new(Get, url)).start()).send());

    let mut body = String::new();
    try!(resp.read_to_string(&mut body));
    Ok(try!(json::decode::<Vec<Upcoming>>(&body)))
}

pub struct AnimeCalendarPlugin {
    sender: Option<SyncSender<(CommandMapperDispatch, IrcMsg)>>
}

impl AnimeCalendarPlugin {
    pub fn new() -> AnimeCalendarPlugin {
        AnimeCalendarPlugin { sender: None }
    }

    pub fn get_plugin_name() -> &'static str {
        "animecalendar"
    }
}

struct CacheItem<T, E> {
    retrieval_time: SteadyTime,
    value: Result<T, E>
}

struct Cache<T, E> {
    negative_expiry: Duration,
    positive_expiry: Duration,
    item: Option<CacheItem<T, E>>,
}

impl<T, E> Cache<T, E> {
    fn new() -> Cache<T, E> {
        Cache {
            negative_expiry: Duration::seconds(30),
            positive_expiry: Duration::minutes(5),
            item: None,
        }
    }

    fn is_valid(&self) -> bool {
        self.get().is_some()
    }

    fn set<'a>(&'a mut self, result: Result<T, E>) -> &'a Result<T, E> {
        self.item = Some(CacheItem {
            retrieval_time: SteadyTime::now(),
            value: result,
        });
        &self.item.as_ref().unwrap().value
    }

    fn get<'a>(&'a self) -> Option<&'a Result<T, E>> {
        let now = SteadyTime::now();
        match self.item {
            Some(ref item) => match item.value.is_ok() {
                true if now < item.retrieval_time + self.positive_expiry => {
                    Some(&item.value)
                },
                false if now < item.retrieval_time + self.negative_expiry => {
                    Some(&item.value)
                },
                _ => None
            },
            None => None,
        }
    }

    fn get_or_else<'a, F>(&'a mut self, func: F) -> &'a Result<T, E> where F: FnOnce() -> Result<T, E> {
        if self.is_valid() {
            self.get().unwrap()
        } else {
            let value = func();
            self.set(value)
        }
    }
}

struct AniCalInternal {
    cache: Cache<Vec<Upcoming>, ApiFailure>,
}

// This could be made allocation-free
fn lower_contains(haystack: &str, needle: &str) -> bool {
    let haystack = haystack.to_lowercase();
    let needle = needle.to_lowercase();

    haystack.contains(&needle)
}

impl AniCalInternal {
    fn new() -> AniCalInternal {
        AniCalInternal {
            cache: Cache::new(),
        }
    }

    fn handle_upcoming(&mut self, m: &CommandMapperDispatch, search: &str) {
        match *self.cache.get_or_else(get_upcoming) {
            Ok(ref records) => {
                let now = get_time();
                let found_records = records.iter()
                    .filter(|r| lower_contains(&r.title_name, search))
                    .filter(|r| r.start_time() > now)
                    .take(5);
                for record in found_records {
                    m.reply(&format!("{}", record));
                }

            }
            Err(ref err) => m.reply(&format!("err: {:?}", err)),
        }
    }

    fn start(&mut self, rx: Receiver<(CommandMapperDispatch, IrcMsg)>) {
        for (m, _) in rx.iter() {
            let command_phrase = m.command();
            match command_phrase.token {
                CMD_UPCOMING => match command_phrase.get::<String>(&"search") {
                    Some(ref search) => self.handle_upcoming(&m, search),
                    None => (),
                },
                _ => ()
            }
        }
    }
}

impl RustBotPlugin for AnimeCalendarPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map_format(CMD_UPCOMING, Format::from_str("upcoming {*search}").unwrap());
    }

    fn start(&mut self) {
        info!("started AnimeCalendarPlugin");
        let (tx, rx) = sync_channel(10);
        self.sender = Some(tx);

        let _ = ::std::thread::Builder::new().name("plugin-animecalendar".to_string()).spawn(move || {
            info!("AniCalInternal started.");
            AniCalInternal::new().start(rx);
        });
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMsg) {
        info!("dispatching AnimeCalendarPlugin command");
        match self.sender {
            Some(ref sender) => {
                if let Err(err) = sender.send((m.clone(), message.clone())) {
                    m.reply(&format!("Service ``animecalendar'' unavailable: {:?}", err));
                }
            }
            None => ()
        };
    }
}

<commit_msg>fixes to animecal<commit_after>use std::fmt;
use std::convert::From;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
use std::io::{self, Read};

use rustc_serialize::json::{self, DecoderError};
use url::Url;
use hyper;
use hyper::client::request::Request;
use hyper::method::Method::Get;
use time::{Timespec, get_time, Duration, SteadyTime};

use irc::parse::IrcMsg;

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator,
    Format,
    Token,
};

static UPCOMING_URL: &'static str = "http://anime.yshi.org/api/calendar/upcoming/100";

const CMD_UPCOMING: Token = Token(0);

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct Upcoming {
    title_name: String,
    syoboi_pid: i32,
    start_time: i64,
    end_time: i64,
    count: String,
    start_offset: i64,
    episode_name: String,
    channel_name: String,
    special_name: String,
    comment: String,
}

impl Upcoming {
    pub fn start_time(&self) -> Timespec {
        Timespec::new(self.start_time, 0)
    }

    pub fn end_time(&self) -> Timespec {
        Timespec::new(self.end_time, 0)
    }

    pub fn start_offset(&self) -> Duration {
        Duration::seconds(self.start_offset)
    }
}

impl fmt::Display for Upcoming {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let now = get_time();
        write!(f, "{} episode {} airs in {} on {}",
            self.title_name, self.count,
            self.start_time() - now,
            self.channel_name)
    }
}

#[derive(Debug)]
enum ApiFailure {
    RequestError(hyper::Error),
    ResponseReadError(io::Error),
    ResponseDeserializeError(DecoderError)
}

impl From<hyper::Error> for ApiFailure {
    fn from(err: hyper::Error) -> ApiFailure {
        ApiFailure::RequestError(err)
    }
}

impl From<io::Error> for ApiFailure {
    fn from(err: io::Error) -> ApiFailure {
        ApiFailure::ResponseReadError(err)
    }
}

impl From<DecoderError> for ApiFailure {
    fn from(err: DecoderError) -> ApiFailure {
        ApiFailure::ResponseDeserializeError(err)
    }
}

fn get_upcoming() -> Result<Vec<Upcoming>, ApiFailure> {
    let url = Url::parse(UPCOMING_URL).ok().expect("Invalid UPCOMING_URL");
    let mut resp = try!(try!(try!(Request::new(Get, url)).start()).send());

    let mut body = String::new();
    try!(resp.read_to_string(&mut body));
    Ok(try!(json::decode::<Vec<Upcoming>>(&body)))
}

pub struct AnimeCalendarPlugin {
    sender: Option<SyncSender<(CommandMapperDispatch, IrcMsg)>>
}

impl AnimeCalendarPlugin {
    pub fn new() -> AnimeCalendarPlugin {
        AnimeCalendarPlugin { sender: None }
    }

    pub fn get_plugin_name() -> &'static str {
        "animecalendar"
    }
}

struct CacheItem<T, E> {
    retrieval_time: SteadyTime,
    value: Result<T, E>
}

struct Cache<T, E> {
    negative_expiry: Duration,
    positive_expiry: Duration,
    item: Option<CacheItem<T, E>>,
}

impl<T, E> Cache<T, E> {
    fn new() -> Cache<T, E> {
        Cache {
            negative_expiry: Duration::seconds(30),
            positive_expiry: Duration::minutes(5),
            item: None,
        }
    }

    fn is_valid(&self) -> bool {
        self.get().is_some()
    }

    fn set<'a>(&'a mut self, result: Result<T, E>) -> &'a Result<T, E> {
        self.item = Some(CacheItem {
            retrieval_time: SteadyTime::now(),
            value: result,
        });
        &self.item.as_ref().unwrap().value
    }

    fn get<'a>(&'a self) -> Option<&'a Result<T, E>> {
        let now = SteadyTime::now();
        match self.item {
            Some(ref item) => match item.value.is_ok() {
                true if now < item.retrieval_time + self.positive_expiry => {
                    Some(&item.value)
                },
                false if now < item.retrieval_time + self.negative_expiry => {
                    Some(&item.value)
                },
                _ => None
            },
            None => None,
        }
    }

    fn get_or_else<'a, F>(&'a mut self, func: F) -> &'a Result<T, E> where F: FnOnce() -> Result<T, E> {
        if self.is_valid() {
            self.get().unwrap()
        } else {
            let value = func();
            self.set(value)
        }
    }
}

struct AniCalInternal {
    cache: Cache<Vec<Upcoming>, ApiFailure>,
}

// This could be made allocation-free
fn lower_contains(haystack: &str, needle: &str) -> bool {
    let haystack = haystack.to_lowercase();
    let needle = needle.to_lowercase();

    haystack.contains(&needle)
}

fn maybe_lower_contains(haystack: &str, needle: Option<&str>) -> Option<bool> {
    needle.map(|n| lower_contains(haystack, n))
}

// THere must be a better way to do this.
fn maybe_str_ref<'a>(opt: &'a Option<String>) -> Option<&'a str> {
    match opt.as_ref() {
        Some(val) => Some(val.as_ref()),
        None => None
    }
}

impl AniCalInternal {
    fn new() -> AniCalInternal {
        AniCalInternal {
            cache: Cache::new(),
        }
    }

    fn handle_upcoming(&mut self, m: &CommandMapperDispatch, search: Option<&str>) {
        match *self.cache.get_or_else(get_upcoming) {
            Ok(ref records) => {
                let now = get_time();
                let found_records = records.iter()
                    .filter(|r| maybe_lower_contains(&r.title_name, search).unwrap_or(true))
                    .filter(|r| r.end_time() > now)
                    .take(5);

                let mut found = false;
                for record in found_records {
                    found = true;
                    m.reply(&format!("{}", record));
                }
                if !found {
                    m.reply("No results found");
                }
            }
            Err(ref err) => m.reply(&format!("err: {:?}", err)),
        }
    }

    fn start(&mut self, rx: Receiver<(CommandMapperDispatch, IrcMsg)>) {
        for (m, _) in rx.iter() {
            let command_phrase = m.command();
            match command_phrase.token {
                CMD_UPCOMING => {
                    let search = command_phrase.get::<String>(&"search");
                    self.handle_upcoming(&m, maybe_str_ref(&search))
                }
                _ => ()
            }
        }
    }
}

impl RustBotPlugin for AnimeCalendarPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map_format(CMD_UPCOMING, Format::from_str("upcoming").unwrap());
        conf.map_format(CMD_UPCOMING, Format::from_str("upcoming {*search}").unwrap());
    }

    fn start(&mut self) {
        info!("started AnimeCalendarPlugin");
        let (tx, rx) = sync_channel(10);
        self.sender = Some(tx);

        let _ = ::std::thread::Builder::new().name("plugin-animecalendar".to_string()).spawn(move || {
            info!("AniCalInternal started.");
            AniCalInternal::new().start(rx);
        });
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMsg) {
        info!("dispatching AnimeCalendarPlugin command");
        match self.sender {
            Some(ref sender) => {
                if let Err(err) = sender.send((m.clone(), message.clone())) {
                    m.reply(&format!("Service ``animecalendar'' unavailable: {:?}", err));
                }
            }
            None => ()
        };
    }
}
<|endoftext|>


<commit_before>//! Eigenvalue decomposition for non-symmetric square matrices

use crate::error::*;
use crate::layout::*;
use crate::types::*;
use ndarray::*;

/// Eigenvalue decomposition of general matrix reference
pub trait Eig {
    /// EigVec is the right eivenvector
    type EigVal;
    type EigVec;
    /// Calculate eigenvalues with the right eigenvector
    ///
    /// $$ A u_i = \lambda_i u_i $$
    ///
    /// ```
    /// use ndarray::*;
    /// use ndarray_linalg::*;
    ///
    /// let a: Array2<f64> = array![
    ///     [-1.01,  0.86, -4.60,  3.31, -4.81],
    ///     [ 3.98,  0.53, -7.04,  5.29,  3.55],
    ///     [ 3.30,  8.26, -3.89,  8.20, -1.51],
    ///     [ 4.43,  4.96, -7.66, -7.33,  6.18],
    ///     [ 7.31, -6.43, -6.16,  2.47,  5.58],
    /// ];
    /// let (eigs, vecs) = a.eig().unwrap();
    ///
    /// let a = a.map(|v| v.as_c());
    /// for (&e, vec) in eigs.iter().zip(vecs.axis_iter(Axis(1))) {
    ///     let ev = vec.map(|v| v * e);
    ///     let av = a.dot(&vec);
    ///     assert_close_l2!(&av, &ev, 1e-5);
    /// }
    /// ```
    fn eig(&self) -> Result<(Self::EigVal, Self::EigVec)>;
}

impl<A, S> Eig for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    type EigVal = Array1<A::Complex>;
    type EigVec = Array2<A::Complex>;

    fn eig(&self) -> Result<(Self::EigVal, Self::EigVec)> {
        let mut a = self.to_owned();
        let layout = a.square_layout()?;
        let (s, t) = A::eig(true, layout, a.as_allocated_mut()?)?;
        let n = layout.len() as usize;
        Ok((
            ArrayBase::from(s),
            Array2::from_shape_vec((n, n).f(), t).unwrap(),
        ))
    }
}

/// Calculate eigenvalues without eigenvectors
pub trait EigVals {
    type EigVal;
    fn eigvals(&self) -> Result<Self::EigVal>;
}

impl<A, S> EigVals for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Complex>;

    fn eigvals(&self) -> Result<Self::EigVal> {
        let mut a = self.to_owned();
        let (s, _) = A::eig(true, a.square_layout()?, a.as_allocated_mut()?)?;
        Ok(ArrayBase::from(s))
    }
}
<commit_msg>Avoid calculating eigenvectors unless requested<commit_after>//! Eigenvalue decomposition for non-symmetric square matrices

use crate::error::*;
use crate::layout::*;
use crate::types::*;
use ndarray::*;

/// Eigenvalue decomposition of general matrix reference
pub trait Eig {
    /// EigVec is the right eivenvector
    type EigVal;
    type EigVec;
    /// Calculate eigenvalues with the right eigenvector
    ///
    /// $$ A u_i = \lambda_i u_i $$
    ///
    /// ```
    /// use ndarray::*;
    /// use ndarray_linalg::*;
    ///
    /// let a: Array2<f64> = array![
    ///     [-1.01,  0.86, -4.60,  3.31, -4.81],
    ///     [ 3.98,  0.53, -7.04,  5.29,  3.55],
    ///     [ 3.30,  8.26, -3.89,  8.20, -1.51],
    ///     [ 4.43,  4.96, -7.66, -7.33,  6.18],
    ///     [ 7.31, -6.43, -6.16,  2.47,  5.58],
    /// ];
    /// let (eigs, vecs) = a.eig().unwrap();
    ///
    /// let a = a.map(|v| v.as_c());
    /// for (&e, vec) in eigs.iter().zip(vecs.axis_iter(Axis(1))) {
    ///     let ev = vec.map(|v| v * e);
    ///     let av = a.dot(&vec);
    ///     assert_close_l2!(&av, &ev, 1e-5);
    /// }
    /// ```
    fn eig(&self) -> Result<(Self::EigVal, Self::EigVec)>;
}

impl<A, S> Eig for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    type EigVal = Array1<A::Complex>;
    type EigVec = Array2<A::Complex>;

    fn eig(&self) -> Result<(Self::EigVal, Self::EigVec)> {
        let mut a = self.to_owned();
        let layout = a.square_layout()?;
        let (s, t) = A::eig(true, layout, a.as_allocated_mut()?)?;
        let n = layout.len() as usize;
        Ok((
            ArrayBase::from(s),
            Array2::from_shape_vec((n, n).f(), t).unwrap(),
        ))
    }
}

/// Calculate eigenvalues without eigenvectors
pub trait EigVals {
    type EigVal;
    fn eigvals(&self) -> Result<Self::EigVal>;
}

impl<A, S> EigVals for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Complex>;

    fn eigvals(&self) -> Result<Self::EigVal> {
        let mut a = self.to_owned();
        let (s, _) = A::eig(false, a.square_layout()?, a.as_allocated_mut()?)?;
        Ok(ArrayBase::from(s))
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{HashSet, VecDeque};
use std::fmt::Debug;

use itertools::Itertools;

use crate::types::QualifiedName;

use super::deps::HasDependencies;

/// Return APIs in a depth-first order, i.e. those with no dependencies first.
pub(super) fn depth_first<'a, T: HasDependencies + Debug + 'a>(
    inputs: impl Iterator<Item = &'a mut T> + 'a,
) -> impl Iterator<Item = &'a mut T> {
    let queue: VecDeque<_> = inputs.collect();
    let yet_to_do = queue.iter().map(|api| api.name()).cloned().collect();
    DepthFirstIter { queue, yet_to_do }
}

struct DepthFirstIter<'a, T: HasDependencies + Debug> {
    queue: VecDeque<&'a mut T>,
    yet_to_do: HashSet<QualifiedName>,
}

impl<'a, T: HasDependencies + Debug> Iterator for DepthFirstIter<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        let first_candidate = self.queue.get(0).map(|api| api.name()).cloned();
        while let Some(candidate) = self.queue.pop_front() {
            if !candidate.deps().any(|d| self.yet_to_do.contains(d)) {
                self.yet_to_do.remove(candidate.name());
                return Some(candidate);
            }
            self.queue.push_back(candidate);
            if self.queue.get(0).map(|api| api.name()) == first_candidate.as_ref() {
                panic!(
                    "Failed to find a candidate; there must be a circular dependency. Queue is {}",
                    self.queue
                        .iter()
                        .map(|item| format!("{}: {}", item.name(), item.deps().join(",")))
                        .join("\n")
                );
            }
        }
        None
    }
}

#[cfg(test)]
mod test {
    use crate::types::QualifiedName;

    use super::{depth_first, HasDependencies};

    #[derive(Debug)]
    struct Thing(QualifiedName, Vec<QualifiedName>);

    impl HasDependencies for Thing {
        fn name(&self) -> &QualifiedName {
            &self.0
        }

        fn deps(&self) -> Box<dyn Iterator<Item = &QualifiedName> + '_> {
            Box::new(self.1.iter())
        }
    }

    #[test]
    fn test() {
        let a = Thing(QualifiedName::new_from_cpp_name("a"), vec![]);
        let b = Thing(
            QualifiedName::new_from_cpp_name("b"),
            vec![
                QualifiedName::new_from_cpp_name("a"),
                QualifiedName::new_from_cpp_name("c"),
            ],
        );
        let c = Thing(
            QualifiedName::new_from_cpp_name("c"),
            vec![QualifiedName::new_from_cpp_name("a")],
        );
        let api_list = vec![a, b, c];
        let mut it = depth_first(api_list.iter());
        assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("a"));
        assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("c"));
        assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("b"));
        assert!(it.next().is_none());
    }
}
<commit_msg>Fix test<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{HashSet, VecDeque};
use std::fmt::Debug;

use itertools::Itertools;

use crate::types::QualifiedName;

use super::deps::HasDependencies;

/// Return APIs in a depth-first order, i.e. those with no dependencies first.
pub(super) fn depth_first<'a, T: HasDependencies + Debug + 'a>(
    inputs: impl Iterator<Item = &'a mut T> + 'a,
) -> impl Iterator<Item = &'a mut T> {
    let queue: VecDeque<_> = inputs.collect();
    let yet_to_do = queue.iter().map(|api| api.name()).cloned().collect();
    DepthFirstIter { queue, yet_to_do }
}

struct DepthFirstIter<'a, T: HasDependencies + Debug> {
    queue: VecDeque<&'a mut T>,
    yet_to_do: HashSet<QualifiedName>,
}

impl<'a, T: HasDependencies + Debug> Iterator for DepthFirstIter<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        let first_candidate = self.queue.get(0).map(|api| api.name()).cloned();
        while let Some(candidate) = self.queue.pop_front() {
            if !candidate.deps().any(|d| self.yet_to_do.contains(d)) {
                self.yet_to_do.remove(candidate.name());
                return Some(candidate);
            }
            self.queue.push_back(candidate);
            if self.queue.get(0).map(|api| api.name()) == first_candidate.as_ref() {
                panic!(
                    "Failed to find a candidate; there must be a circular dependency. Queue is {}",
                    self.queue
                        .iter()
                        .map(|item| format!("{}: {}", item.name(), item.deps().join(",")))
                        .join("\n")
                );
            }
        }
        None
    }
}

#[cfg(test)]
mod test {
    use crate::types::QualifiedName;

    use super::{depth_first, HasDependencies};

    #[derive(Debug)]
    struct Thing(QualifiedName, Vec<QualifiedName>);

    impl HasDependencies for Thing {
        fn name(&self) -> &QualifiedName {
            &self.0
        }

        fn deps(&self) -> Box<dyn Iterator<Item = &QualifiedName> + '_> {
            Box::new(self.1.iter())
        }
    }

    #[test]
    fn test() {
        let a = Thing(QualifiedName::new_from_cpp_name("a"), vec![]);
        let b = Thing(
            QualifiedName::new_from_cpp_name("b"),
            vec![
                QualifiedName::new_from_cpp_name("a"),
                QualifiedName::new_from_cpp_name("c"),
            ],
        );
        let c = Thing(
            QualifiedName::new_from_cpp_name("c"),
            vec![QualifiedName::new_from_cpp_name("a")],
        );
        let mut api_list = vec![a, b, c];
        let mut it = depth_first(api_list.iter_mut());
        assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("a"));
        assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("c"));
        assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("b"));
        assert!(it.next().is_none());
    }
}
<|endoftext|>