<commit_before>//! Abstract-ish representation of paths for VFS.
use std::fmt;

use paths::{AbsPath, AbsPathBuf};

/// Long-term, we want to support files which do not reside in the file-system,
/// so we treat VfsPaths as opaque identifiers.
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct VfsPath(VfsPathRepr);

impl VfsPath {
    /// Creates an "in-memory" path from `/`-separates string.
    /// This is most useful for testing, to avoid windows/linux differences
    pub fn new_virtual_path(path: String) -> VfsPath {
        assert!(path.starts_with('/'));
        VfsPath(VfsPathRepr::VirtualPath(VirtualPath(path)))
    }

    pub fn as_path(&self) -> Option<&AbsPath> {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => Some(it.as_path()),
            VfsPathRepr::VirtualPath(_) => None,
        }
    }
    pub fn join(&self, path: &str) -> Option<VfsPath> {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => {
                let res = it.join(path).normalize();
                Some(VfsPath(VfsPathRepr::PathBuf(res)))
            }
            VfsPathRepr::VirtualPath(it) => {
                let res = it.join(path)?;
                Some(VfsPath(VfsPathRepr::VirtualPath(res)))
            }
        }
    }
    pub fn pop(&mut self) -> bool {
        match &mut self.0 {
            VfsPathRepr::PathBuf(it) => it.pop(),
            VfsPathRepr::VirtualPath(it) => it.pop(),
        }
    }
    pub fn starts_with(&self, other: &VfsPath) -> bool {
        match (&self.0, &other.0) {
            (VfsPathRepr::PathBuf(lhs), VfsPathRepr::PathBuf(rhs)) => lhs.starts_with(rhs),
            (VfsPathRepr::PathBuf(_), _) => false,
            (VfsPathRepr::VirtualPath(lhs), VfsPathRepr::VirtualPath(rhs)) => lhs.starts_with(rhs),
            (VfsPathRepr::VirtualPath(_), _) => false,
        }
    }
    pub fn parent(&self) -> Option<VfsPath> {
        let mut parent = self.clone();
        if parent.pop() {
            Some(parent)
        } else {
            None
        }
    }

    pub fn file_name_and_extension(&self) -> Option<(&str, Option<&str>)> {
        match &self.0 {
            VfsPathRepr::PathBuf(p) => Some((
                p.file_stem()?.to_str()?,
                p.extension().and_then(|extension| extension.to_str()),
            )),
            VfsPathRepr::VirtualPath(p) => p.file_name_and_extension(),
        }
    }

    // Don't make this `pub`
    pub(crate) fn encode(&self, buf: &mut Vec<u8>) {
        let tag = match &self.0 {
            VfsPathRepr::PathBuf(_) => 0,
            VfsPathRepr::VirtualPath(_) => 1,
        };
        buf.push(tag);
        match &self.0 {
            VfsPathRepr::PathBuf(path) => {
                #[cfg(windows)]
                {
                    use windows_paths::Encode;
                    let components = path.components();
                    let mut add_sep = false;
                    for component in components {
                        if add_sep {
                            windows_paths::SEP.encode(buf);
                        }
                        let len_before = buf.len();
                        match component {
                            std::path::Component::Prefix(prefix) => {
                                // kind() returns a normalized and comparable path prefix.
                                prefix.kind().encode(buf);
                            }
                            std::path::Component::RootDir => {
                                if !add_sep {
                                    component.as_os_str().encode(buf);
                                }
                            }
                            _ => component.as_os_str().encode(buf),
                        }

                        // some components may be encoded empty
                        add_sep = len_before != buf.len();
                    }
                }
                #[cfg(unix)]
                {
                    use std::os::unix::ffi::OsStrExt;
                    buf.extend(path.as_os_str().as_bytes());
                }
                #[cfg(not(any(windows, unix)))]
                {
                    buf.extend(path.as_os_str().to_string_lossy().as_bytes());
                }
            }
            VfsPathRepr::VirtualPath(VirtualPath(s)) => buf.extend(s.as_bytes()),
        }
    }
}

#[cfg(windows)]
mod windows_paths {
    pub trait Encode {
        fn encode(&self, buf: &mut Vec<u8>);
    }

    impl Encode for std::ffi::OsStr {
        fn encode(&self, buf: &mut Vec<u8>) {
            use std::os::windows::ffi::OsStrExt;
            for wchar in self.encode_wide() {
                buf.extend(wchar.to_le_bytes().iter().copied());
            }
        }
    }

    impl Encode for u8 {
        fn encode(&self, buf: &mut Vec<u8>) {
            let wide = *self as u16;
            buf.extend(wide.to_le_bytes().iter().copied())
        }
    }

    impl Encode for &str {
        fn encode(&self, buf: &mut Vec<u8>) {
            debug_assert!(self.is_ascii());
            for b in self.as_bytes() {
                b.encode(buf)
            }
        }
    }

    pub const SEP: &str = "\\";
    const VERBATIM: &str = "\\\\?\\";
    const UNC: &str = "UNC";
    const DEVICE: &str = "\\\\.\\";
    const COLON: &str = ":";

    impl Encode for std::path::Prefix<'_> {
        fn encode(&self, buf: &mut Vec<u8>) {
            match self {
                std::path::Prefix::Verbatim(c) => {
                    VERBATIM.encode(buf);
                    c.encode(buf);
                }
                std::path::Prefix::VerbatimUNC(server, share) => {
                    VERBATIM.encode(buf);
                    UNC.encode(buf);
                    SEP.encode(buf);
                    server.encode(buf);
                    SEP.encode(buf);
                    share.encode(buf);
                }
                std::path::Prefix::VerbatimDisk(d) => {
                    VERBATIM.encode(buf);
                    d.encode(buf);
                    COLON.encode(buf);
                }
                std::path::Prefix::DeviceNS(device) => {
                    DEVICE.encode(buf);
                    device.encode(buf);
                }
                std::path::Prefix::UNC(server, share) => {
                    SEP.encode(buf);
                    SEP.encode(buf);
                    server.encode(buf);
                    SEP.encode(buf);
                    share.encode(buf);
                }
                std::path::Prefix::Disk(d) => {
                    d.encode(buf);
                    COLON.encode(buf);
                }
            }
        }
    }
    #[test]
    fn paths_encoding() {
        // drive letter casing agnostic
        test_eq("C:/x.rs", "c:/x.rs");
        // separator agnostic
        test_eq("C:/x/y.rs", "C:\\x\\y.rs");

        fn test_eq(a: &str, b: &str) {
            let mut b1 = Vec::new();
            let mut b2 = Vec::new();
            vfs(a).encode(&mut b1);
            vfs(b).encode(&mut b2);
            assert_eq!(b1, b2);
        }
    }

    #[test]
    fn test_sep_root_dir_encoding() {
        let mut buf = Vec::new();
        vfs("C:/x/y").encode(&mut buf);
        assert_eq!(&buf, &[0, 67, 0, 58, 0, 92, 0, 120, 0, 92, 0, 121, 0])
    }

    #[cfg(test)]
    fn vfs(str: &str) -> super::VfsPath {
        use super::{AbsPathBuf, VfsPath};
        use std::convert::TryFrom;
        VfsPath::from(AbsPathBuf::try_from(str).unwrap())
    }
}

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
enum VfsPathRepr {
    PathBuf(AbsPathBuf),
    VirtualPath(VirtualPath),
}

impl From<AbsPathBuf> for VfsPath {
    fn from(v: AbsPathBuf) -> Self {
        VfsPath(VfsPathRepr::PathBuf(v.normalize()))
    }
}

impl fmt::Display for VfsPath {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => fmt::Display::fmt(&it.display(), f),
            VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Display::fmt(it, f),
        }
    }
}

impl fmt::Debug for VfsPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl fmt::Debug for VfsPathRepr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self {
            VfsPathRepr::PathBuf(it) => fmt::Debug::fmt(&it.display(), f),
            VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Debug::fmt(&it, f),
        }
    }
}

#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
struct VirtualPath(String);

impl VirtualPath {
    fn starts_with(&self, other: &VirtualPath) -> bool {
        self.0.starts_with(&other.0)
    }
    fn pop(&mut self) -> bool {
        let pos = match self.0.rfind('/') {
            Some(pos) => pos,
            None => return false,
        };
        self.0 = self.0[..pos].to_string();
        true
    }
    fn join(&self, mut path: &str) -> Option<VirtualPath> {
        let mut res = self.clone();
        while path.starts_with("../") {
            if !res.pop() {
                return None;
            }
            path = &path["../".len()..]
        }
        res.0 = format!("{}/{}", res.0, path);
        Some(res)
    }

    // FIXME: Currently VirtualPath does is unable to distinguish a directory from a file
    // hence this method will return `Some("directory_name", None)` for a directory
    pub fn file_name_and_extension(&self) -> Option<(&str, Option<&str>)> {
        let file_name = match self.0.rfind('/') {
            Some(position) => &self.0[position + 1..],
            None => &self.0,
        };

        if file_name.is_empty() {
            None
        } else {
            let mut file_stem_and_extension = file_name.rsplitn(2, '.');
            let extension = file_stem_and_extension.next();
            let file_stem = file_stem_and_extension.next();

            match (file_stem, extension) {
                (None, None) => None,
                (None, Some(_)) | (Some(""), Some(_)) => Some((file_name, None)),
                (Some(file_stem), extension) => Some((file_stem, extension)),
            }
        }
    }
}
<commit_msg>Add VirtualPath tests<commit_after>//! Abstract-ish representation of paths for VFS.
use std::fmt;

use paths::{AbsPath, AbsPathBuf};

/// Long-term, we want to support files which do not reside in the file-system,
/// so we treat VfsPaths as opaque identifiers.
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct VfsPath(VfsPathRepr);

impl VfsPath {
    /// Creates an "in-memory" path from `/`-separates string.
    /// This is most useful for testing, to avoid windows/linux differences
    pub fn new_virtual_path(path: String) -> VfsPath {
        assert!(path.starts_with('/'));
        VfsPath(VfsPathRepr::VirtualPath(VirtualPath(path)))
    }

    pub fn as_path(&self) -> Option<&AbsPath> {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => Some(it.as_path()),
            VfsPathRepr::VirtualPath(_) => None,
        }
    }
    pub fn join(&self, path: &str) -> Option<VfsPath> {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => {
                let res = it.join(path).normalize();
                Some(VfsPath(VfsPathRepr::PathBuf(res)))
            }
            VfsPathRepr::VirtualPath(it) => {
                let res = it.join(path)?;
                Some(VfsPath(VfsPathRepr::VirtualPath(res)))
            }
        }
    }
    pub fn pop(&mut self) -> bool {
        match &mut self.0 {
            VfsPathRepr::PathBuf(it) => it.pop(),
            VfsPathRepr::VirtualPath(it) => it.pop(),
        }
    }
    pub fn starts_with(&self, other: &VfsPath) -> bool {
        match (&self.0, &other.0) {
            (VfsPathRepr::PathBuf(lhs), VfsPathRepr::PathBuf(rhs)) => lhs.starts_with(rhs),
            (VfsPathRepr::PathBuf(_), _) => false,
            (VfsPathRepr::VirtualPath(lhs), VfsPathRepr::VirtualPath(rhs)) => lhs.starts_with(rhs),
            (VfsPathRepr::VirtualPath(_), _) => false,
        }
    }
    pub fn parent(&self) -> Option<VfsPath> {
        let mut parent = self.clone();
        if parent.pop() {
            Some(parent)
        } else {
            None
        }
    }

    pub fn file_name_and_extension(&self) -> Option<(&str, Option<&str>)> {
        match &self.0 {
            VfsPathRepr::PathBuf(p) => Some((
                p.file_stem()?.to_str()?,
                p.extension().and_then(|extension| extension.to_str()),
            )),
            VfsPathRepr::VirtualPath(p) => p.file_name_and_extension(),
        }
    }

    // Don't make this `pub`
    pub(crate) fn encode(&self, buf: &mut Vec<u8>) {
        let tag = match &self.0 {
            VfsPathRepr::PathBuf(_) => 0,
            VfsPathRepr::VirtualPath(_) => 1,
        };
        buf.push(tag);
        match &self.0 {
            VfsPathRepr::PathBuf(path) => {
                #[cfg(windows)]
                {
                    use windows_paths::Encode;
                    let components = path.components();
                    let mut add_sep = false;
                    for component in components {
                        if add_sep {
                            windows_paths::SEP.encode(buf);
                        }
                        let len_before = buf.len();
                        match component {
                            std::path::Component::Prefix(prefix) => {
                                // kind() returns a normalized and comparable path prefix.
                                prefix.kind().encode(buf);
                            }
                            std::path::Component::RootDir => {
                                if !add_sep {
                                    component.as_os_str().encode(buf);
                                }
                            }
                            _ => component.as_os_str().encode(buf),
                        }

                        // some components may be encoded empty
                        add_sep = len_before != buf.len();
                    }
                }
                #[cfg(unix)]
                {
                    use std::os::unix::ffi::OsStrExt;
                    buf.extend(path.as_os_str().as_bytes());
                }
                #[cfg(not(any(windows, unix)))]
                {
                    buf.extend(path.as_os_str().to_string_lossy().as_bytes());
                }
            }
            VfsPathRepr::VirtualPath(VirtualPath(s)) => buf.extend(s.as_bytes()),
        }
    }
}

#[cfg(windows)]
mod windows_paths {
    pub trait Encode {
        fn encode(&self, buf: &mut Vec<u8>);
    }

    impl Encode for std::ffi::OsStr {
        fn encode(&self, buf: &mut Vec<u8>) {
            use std::os::windows::ffi::OsStrExt;
            for wchar in self.encode_wide() {
                buf.extend(wchar.to_le_bytes().iter().copied());
            }
        }
    }

    impl Encode for u8 {
        fn encode(&self, buf: &mut Vec<u8>) {
            let wide = *self as u16;
            buf.extend(wide.to_le_bytes().iter().copied())
        }
    }

    impl Encode for &str {
        fn encode(&self, buf: &mut Vec<u8>) {
            debug_assert!(self.is_ascii());
            for b in self.as_bytes() {
                b.encode(buf)
            }
        }
    }

    pub const SEP: &str = "\\";
    const VERBATIM: &str = "\\\\?\\";
    const UNC: &str = "UNC";
    const DEVICE: &str = "\\\\.\\";
    const COLON: &str = ":";

    impl Encode for std::path::Prefix<'_> {
        fn encode(&self, buf: &mut Vec<u8>) {
            match self {
                std::path::Prefix::Verbatim(c) => {
                    VERBATIM.encode(buf);
                    c.encode(buf);
                }
                std::path::Prefix::VerbatimUNC(server, share) => {
                    VERBATIM.encode(buf);
                    UNC.encode(buf);
                    SEP.encode(buf);
                    server.encode(buf);
                    SEP.encode(buf);
                    share.encode(buf);
                }
                std::path::Prefix::VerbatimDisk(d) => {
                    VERBATIM.encode(buf);
                    d.encode(buf);
                    COLON.encode(buf);
                }
                std::path::Prefix::DeviceNS(device) => {
                    DEVICE.encode(buf);
                    device.encode(buf);
                }
                std::path::Prefix::UNC(server, share) => {
                    SEP.encode(buf);
                    SEP.encode(buf);
                    server.encode(buf);
                    SEP.encode(buf);
                    share.encode(buf);
                }
                std::path::Prefix::Disk(d) => {
                    d.encode(buf);
                    COLON.encode(buf);
                }
            }
        }
    }
    #[test]
    fn paths_encoding() {
        // drive letter casing agnostic
        test_eq("C:/x.rs", "c:/x.rs");
        // separator agnostic
        test_eq("C:/x/y.rs", "C:\\x\\y.rs");

        fn test_eq(a: &str, b: &str) {
            let mut b1 = Vec::new();
            let mut b2 = Vec::new();
            vfs(a).encode(&mut b1);
            vfs(b).encode(&mut b2);
            assert_eq!(b1, b2);
        }
    }

    #[test]
    fn test_sep_root_dir_encoding() {
        let mut buf = Vec::new();
        vfs("C:/x/y").encode(&mut buf);
        assert_eq!(&buf, &[0, 67, 0, 58, 0, 92, 0, 120, 0, 92, 0, 121, 0])
    }

    #[cfg(test)]
    fn vfs(str: &str) -> super::VfsPath {
        use super::{AbsPathBuf, VfsPath};
        use std::convert::TryFrom;
        VfsPath::from(AbsPathBuf::try_from(str).unwrap())
    }
}

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
enum VfsPathRepr {
    PathBuf(AbsPathBuf),
    VirtualPath(VirtualPath),
}

impl From<AbsPathBuf> for VfsPath {
    fn from(v: AbsPathBuf) -> Self {
        VfsPath(VfsPathRepr::PathBuf(v.normalize()))
    }
}

impl fmt::Display for VfsPath {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.0 {
            VfsPathRepr::PathBuf(it) => fmt::Display::fmt(&it.display(), f),
            VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Display::fmt(it, f),
        }
    }
}

impl fmt::Debug for VfsPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl fmt::Debug for VfsPathRepr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self {
            VfsPathRepr::PathBuf(it) => fmt::Debug::fmt(&it.display(), f),
            VfsPathRepr::VirtualPath(VirtualPath(it)) => fmt::Debug::fmt(&it, f),
        }
    }
}

#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
struct VirtualPath(String);

impl VirtualPath {
    fn starts_with(&self, other: &VirtualPath) -> bool {
        self.0.starts_with(&other.0)
    }
    fn pop(&mut self) -> bool {
        let pos = match self.0.rfind('/') {
            Some(pos) => pos,
            None => return false,
        };
        self.0 = self.0[..pos].to_string();
        true
    }
    fn join(&self, mut path: &str) -> Option<VirtualPath> {
        let mut res = self.clone();
        while path.starts_with("../") {
            if !res.pop() {
                return None;
            }
            path = &path["../".len()..]
        }
        res.0 = format!("{}/{}", res.0, path);
        Some(res)
    }

    // FIXME: Currently VirtualPath does is unable to distinguish a directory from a file
    // hence this method will return `Some("directory_name", None)` for a directory
    pub fn file_name_and_extension(&self) -> Option<(&str, Option<&str>)> {
        let file_path = if self.0.ends_with('/') { &self.0[..&self.0.len() - 1] } else { &self.0 };
        let file_name = match file_path.rfind('/') {
            Some(position) => &file_path[position + 1..],
            None => file_path,
        };

        if file_name.is_empty() {
            None
        } else {
            let mut file_stem_and_extension = file_name.rsplitn(2, '.');
            let extension = file_stem_and_extension.next();
            let file_stem = file_stem_and_extension.next();

            match (file_stem, extension) {
                (None, None) => None,
                (None, Some(_)) | (Some(""), Some(_)) => Some((file_name, None)),
                (Some(file_stem), extension) => Some((file_stem, extension)),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn virtual_path_extensions() {
        assert_eq!(VirtualPath("/".to_string()).file_name_and_extension(), None);
        assert_eq!(
            VirtualPath("/directory".to_string()).file_name_and_extension(),
            Some(("directory", None))
        );
        assert_eq!(
            VirtualPath("/directory/".to_string()).file_name_and_extension(),
            Some(("directory", None))
        );
        assert_eq!(
            VirtualPath("/directory/file".to_string()).file_name_and_extension(),
            Some(("file", None))
        );
        assert_eq!(
            VirtualPath("/directory/.file".to_string()).file_name_and_extension(),
            Some((".file", None))
        );
        assert_eq!(
            VirtualPath("/directory/.file.rs".to_string()).file_name_and_extension(),
            Some((".file", Some("rs")))
        );
        assert_eq!(
            VirtualPath("/directory/file.rs".to_string()).file_name_and_extension(),
            Some(("file", Some("rs")))
        );
    }
}
<|endoftext|>


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

trait Tr<T> {
    fn op(T) -> Self;
}

// these compile as if Self: Tr<U>, even tho only Self: Tr<Self or T>
trait A:    Tr<Self> {
    fn test<U>(u: U) -> Self {
        Tr::op(u)   //~ ERROR not implemented
    }
}
trait B<T>: Tr<T> {
    fn test<U>(u: U) -> Self {
        Tr::op(u)   //~ ERROR not implemented
    }
}

impl<T> Tr<T> for T {
    fn op(t: T) -> T { t }
}
impl<T> A for T {}

fn main() {
    std::io::println(A::test((&7306634593706211700, 8)));
}

<commit_msg>Correct a test. The error message changed because, with this fix, we detected (correctly) that there was only one impl and hence ignored the `Self` bound completely. I (semi-arbitrarily) elected to delect the impl, forcing the trait matcher to be more conservative and lean on the where clauses in scope, yielding the original error message.<commit_after>// Copyright 2014 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.

// Test static calls to make sure that we align the Self and input
// type parameters on a trait correctly.

trait Tr<T> {
    fn op(T) -> Self;
}

trait A:    Tr<Self> {
    fn test<U>(u: U) -> Self {
        Tr::op(u)   //~ ERROR not implemented
    }
}

trait B<T>: Tr<T> {
    fn test<U>(u: U) -> Self {
        Tr::op(u)   //~ ERROR not implemented
    }
}

fn main() {
}

<|endoftext|>


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

use infer::InferCtxt;
use ty::{self, Ty, TyCtxt};
use hir::def_id::DefId;

use super::{FulfillmentContext, FulfillmentError};
use super::{ObligationCause, PendingPredicateObligation, PredicateObligation};

pub trait TraitEngine<'tcx> {
    fn normalize_projection_type<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        projection_ty: ty::ProjectionTy<'tcx>,
        cause: ObligationCause<'tcx>,
    ) -> Ty<'tcx>;

    fn register_bound<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        ty: Ty<'tcx>,
        def_id: DefId,
        cause: ObligationCause<'tcx>,
    );

    fn register_predicate_obligation<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        obligation: PredicateObligation<'tcx>,
    );

    fn select_all_or_error<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn select_where_possible<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>;
}

impl<'a, 'gcx, 'tcx> TraitEngine<'tcx> + 'tcx {
    pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
        Box::new(FulfillmentContext::new())
    }

    pub fn register_predicate_obligations<I>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        obligations: I,
    ) where
        I: IntoIterator<Item = PredicateObligation<'tcx>>,
    {
        for obligation in obligations {
            self.register_predicate_obligation(infcx, obligation);
        }
    }
}
<commit_msg>move the defaut object lifetime bound into the trait<commit_after>// Copyright 2018 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.

use infer::InferCtxt;
use ty::{self, Ty, TyCtxt};
use hir::def_id::DefId;

use super::{FulfillmentContext, FulfillmentError};
use super::{ObligationCause, PendingPredicateObligation, PredicateObligation};

pub trait TraitEngine<'tcx>: 'tcx {
    fn normalize_projection_type<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        projection_ty: ty::ProjectionTy<'tcx>,
        cause: ObligationCause<'tcx>,
    ) -> Ty<'tcx>;

    fn register_bound<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        ty: Ty<'tcx>,
        def_id: DefId,
        cause: ObligationCause<'tcx>,
    );

    fn register_predicate_obligation<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        obligation: PredicateObligation<'tcx>,
    );

    fn select_all_or_error<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn select_where_possible<'a, 'gcx>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
    ) -> Result<(), Vec<FulfillmentError<'tcx>>>;

    fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>;
}

impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> {
    pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
        Box::new(FulfillmentContext::new())
    }

    pub fn register_predicate_obligations<I>(
        &mut self,
        infcx: &InferCtxt<'a, 'gcx, 'tcx>,
        obligations: I,
    ) where
        I: IntoIterator<Item = PredicateObligation<'tcx>>,
    {
        for obligation in obligations {
            self.register_predicate_obligation(infcx, obligation);
        }
    }
}
<|endoftext|>


<commit_before>use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use rustc::hir::*;
use syntax::ast::RangeLimits;
use syntax::source_map::Spanned;
use crate::utils::{is_integer_literal, paths, snippet, span_lint, span_lint_and_then, snippet_opt};
use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq};
use crate::utils::sugg::Sugg;

/// **What it does:** Checks for calling `.step_by(0)` on iterators,
/// which never terminates.
///
/// **Why is this bad?** This very much looks like an oversight, since with
/// `loop { .. }` there is an obvious better way to endlessly loop.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// for x in (5..5).step_by(0) { .. }
/// ```
declare_clippy_lint! {
    pub ITERATOR_STEP_BY_ZERO,
    correctness,
    "using `Iterator::step_by(0)`, which produces an infinite iterator"
}

/// **What it does:** Checks for zipping a collection with the range of
/// `0.._.len()`.
///
/// **Why is this bad?** The code is better expressed with `.enumerate()`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x.iter().zip(0..x.len())
/// ```
declare_clippy_lint! {
    pub RANGE_ZIP_WITH_LEN,
    complexity,
    "zipping iterator with a range when `enumerate()` would do"
}

/// **What it does:** Checks for exclusive ranges where 1 is added to the
/// upper bound, e.g. `x..(y+1)`.
///
/// **Why is this bad?** The code is more readable with an inclusive range
/// like `x..=y`.
///
/// **Known problems:** Will add unnecessary pair of parentheses when the
/// expression is not wrapped in a pair but starts with a opening parenthesis
/// and ends with a closing one.
/// I.e: `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..(f()+1))`.
///
/// **Example:**
/// ```rust
/// for x..(y+1) { .. }
/// ```
declare_clippy_lint! {
    pub RANGE_PLUS_ONE,
    complexity,
    "`x..(y+1)` reads better as `x..=y`"
}

/// **What it does:** Checks for inclusive ranges where 1 is subtracted from
/// the upper bound, e.g. `x..=(y-1)`.
///
/// **Why is this bad?** The code is more readable with an exclusive range
/// like `x..y`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// for x..=(y-1) { .. }
/// ```
declare_clippy_lint! {
    pub RANGE_MINUS_ONE,
    complexity,
    "`x..=(y-1)` reads better as `x..y`"
}

#[derive(Copy, Clone)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(ITERATOR_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if let ExprKind::MethodCall(ref path, _, ref args) = expr.node {
            let name = path.ident.as_str();

            // Range with step_by(0).
            if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) {
                use crate::consts::{constant, Constant};
                if let Some((Constant::Int(0), _)) = constant(cx, cx.tables, &args[1]) {
                    span_lint(
                        cx,
                        ITERATOR_STEP_BY_ZERO,
                        expr.span,
                        "Iterator::step_by(0) will panic at runtime",
                    );
                }
            } else if name == "zip" && args.len() == 2 {
                let iter = &args[0].node;
                let zip_arg = &args[1];
                if_chain! {
                    // .iter() call
                    if let ExprKind::MethodCall(ref iter_path, _, ref iter_args ) = *iter;
                    if iter_path.ident.name == "iter";
                    // range expression in .zip() call: 0..x.len()
                    if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg);
                    if is_integer_literal(start, 0);
                    // .len() call
                    if let ExprKind::MethodCall(ref len_path, _, ref len_args) = end.node;
                    if len_path.ident.name == "len" && len_args.len() == 1;
                    // .iter() and .len() called on same Path
                    if let ExprKind::Path(QPath::Resolved(_, ref iter_path)) = iter_args[0].node;
                    if let ExprKind::Path(QPath::Resolved(_, ref len_path)) = len_args[0].node;
                    if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
                     then {
                         span_lint(cx,
                                   RANGE_ZIP_WITH_LEN,
                                   expr.span,
                                   &format!("It is more idiomatic to use {}.iter().enumerate()",
                                            snippet(cx, iter_args[0].span, "_")));
                    }
                }
            }
        }

        // exclusive range plus one: x..(y+1)
        if_chain! {
            if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::HalfOpen }) = higher::range(cx, expr);
            if let Some(y) = y_plus_one(end);
            then {
                span_lint_and_then(
                    cx,
                    RANGE_PLUS_ONE,
                    expr.span,
                    "an inclusive range would be more readable",
                    |db| {
                        let start = start.map_or("".to_owned(), |x| Sugg::hir(cx, x, "x").to_string());
                        let end = Sugg::hir(cx, y, "y");
                        if let Some(is_wrapped) = &snippet_opt(cx, expr.span) {
                            if is_wrapped.starts_with("(") && is_wrapped.ends_with(")") {
                                db.span_suggestion(expr.span,
                                           "use",
                                           format!("({}..={})", start, end));
                            } else {
                                db.span_suggestion(expr.span,
                                           "use",
                                           format!("{}..={}", start, end));
                            }
                        }
                    },
                );
            }
        }

        // inclusive range minus one: x..=(y-1)
        if_chain! {
            if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(cx, expr);
            if let Some(y) = y_minus_one(end);
            then {
                span_lint_and_then(
                    cx,
                    RANGE_MINUS_ONE,
                    expr.span,
                    "an exclusive range would be more readable",
                    |db| {
                        let start = start.map_or("".to_owned(), |x| Sugg::hir(cx, x, "x").to_string());
                        let end = Sugg::hir(cx, y, "y");
                        db.span_suggestion(expr.span,
                                           "use",
                                           format!("{}..{}", start, end));
                    },
                );
            }
        }
    }
}

fn has_step_by(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    // No need for walk_ptrs_ty here because step_by moves self, so it
    // can't be called on a borrowed range.
    let ty = cx.tables.expr_ty_adjusted(expr);

    get_trait_def_id(cx, &paths::ITERATOR).map_or(false, |iterator_trait| implements_trait(cx, ty, iterator_trait, &[]))
}

fn y_plus_one(expr: &Expr) -> Option<&Expr> {
    match expr.node {
        ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref lhs, ref rhs) => if is_integer_literal(lhs, 1) {
            Some(rhs)
        } else if is_integer_literal(rhs, 1) {
            Some(lhs)
        } else {
            None
        },
        _ => None,
    }
}

fn y_minus_one(expr: &Expr) -> Option<&Expr> {
    match expr.node {
        ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) if is_integer_literal(rhs, 1) => Some(lhs),
        _ => None,
    }
}
<commit_msg>fixed known problems expression<commit_after>use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use rustc::hir::*;
use syntax::ast::RangeLimits;
use syntax::source_map::Spanned;
use crate::utils::{is_integer_literal, paths, snippet, span_lint, span_lint_and_then, snippet_opt};
use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq};
use crate::utils::sugg::Sugg;

/// **What it does:** Checks for calling `.step_by(0)` on iterators,
/// which never terminates.
///
/// **Why is this bad?** This very much looks like an oversight, since with
/// `loop { .. }` there is an obvious better way to endlessly loop.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// for x in (5..5).step_by(0) { .. }
/// ```
declare_clippy_lint! {
    pub ITERATOR_STEP_BY_ZERO,
    correctness,
    "using `Iterator::step_by(0)`, which produces an infinite iterator"
}

/// **What it does:** Checks for zipping a collection with the range of
/// `0.._.len()`.
///
/// **Why is this bad?** The code is better expressed with `.enumerate()`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x.iter().zip(0..x.len())
/// ```
declare_clippy_lint! {
    pub RANGE_ZIP_WITH_LEN,
    complexity,
    "zipping iterator with a range when `enumerate()` would do"
}

/// **What it does:** Checks for exclusive ranges where 1 is added to the
/// upper bound, e.g. `x..(y+1)`.
///
/// **Why is this bad?** The code is more readable with an inclusive range
/// like `x..=y`.
///
/// **Known problems:** Will add unnecessary pair of parentheses when the
/// expression is not wrapped in a pair but starts with a opening parenthesis
/// and ends with a closing one.
/// I.e: `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`.
///
/// **Example:**
/// ```rust
/// for x..(y+1) { .. }
/// ```
declare_clippy_lint! {
    pub RANGE_PLUS_ONE,
    complexity,
    "`x..(y+1)` reads better as `x..=y`"
}

/// **What it does:** Checks for inclusive ranges where 1 is subtracted from
/// the upper bound, e.g. `x..=(y-1)`.
///
/// **Why is this bad?** The code is more readable with an exclusive range
/// like `x..y`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// for x..=(y-1) { .. }
/// ```
declare_clippy_lint! {
    pub RANGE_MINUS_ONE,
    complexity,
    "`x..=(y-1)` reads better as `x..y`"
}

#[derive(Copy, Clone)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(ITERATOR_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if let ExprKind::MethodCall(ref path, _, ref args) = expr.node {
            let name = path.ident.as_str();

            // Range with step_by(0).
            if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) {
                use crate::consts::{constant, Constant};
                if let Some((Constant::Int(0), _)) = constant(cx, cx.tables, &args[1]) {
                    span_lint(
                        cx,
                        ITERATOR_STEP_BY_ZERO,
                        expr.span,
                        "Iterator::step_by(0) will panic at runtime",
                    );
                }
            } else if name == "zip" && args.len() == 2 {
                let iter = &args[0].node;
                let zip_arg = &args[1];
                if_chain! {
                    // .iter() call
                    if let ExprKind::MethodCall(ref iter_path, _, ref iter_args ) = *iter;
                    if iter_path.ident.name == "iter";
                    // range expression in .zip() call: 0..x.len()
                    if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg);
                    if is_integer_literal(start, 0);
                    // .len() call
                    if let ExprKind::MethodCall(ref len_path, _, ref len_args) = end.node;
                    if len_path.ident.name == "len" && len_args.len() == 1;
                    // .iter() and .len() called on same Path
                    if let ExprKind::Path(QPath::Resolved(_, ref iter_path)) = iter_args[0].node;
                    if let ExprKind::Path(QPath::Resolved(_, ref len_path)) = len_args[0].node;
                    if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
                     then {
                         span_lint(cx,
                                   RANGE_ZIP_WITH_LEN,
                                   expr.span,
                                   &format!("It is more idiomatic to use {}.iter().enumerate()",
                                            snippet(cx, iter_args[0].span, "_")));
                    }
                }
            }
        }

        // exclusive range plus one: x..(y+1)
        if_chain! {
            if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::HalfOpen }) = higher::range(cx, expr);
            if let Some(y) = y_plus_one(end);
            then {
                span_lint_and_then(
                    cx,
                    RANGE_PLUS_ONE,
                    expr.span,
                    "an inclusive range would be more readable",
                    |db| {
                        let start = start.map_or("".to_owned(), |x| Sugg::hir(cx, x, "x").to_string());
                        let end = Sugg::hir(cx, y, "y");
                        if let Some(is_wrapped) = &snippet_opt(cx, expr.span) {
                            if is_wrapped.starts_with("(") && is_wrapped.ends_with(")") {
                                db.span_suggestion(expr.span,
                                           "use",
                                           format!("({}..={})", start, end));
                            } else {
                                db.span_suggestion(expr.span,
                                           "use",
                                           format!("{}..={}", start, end));
                            }
                        }
                    },
                );
            }
        }

        // inclusive range minus one: x..=(y-1)
        if_chain! {
            if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(cx, expr);
            if let Some(y) = y_minus_one(end);
            then {
                span_lint_and_then(
                    cx,
                    RANGE_MINUS_ONE,
                    expr.span,
                    "an exclusive range would be more readable",
                    |db| {
                        let start = start.map_or("".to_owned(), |x| Sugg::hir(cx, x, "x").to_string());
                        let end = Sugg::hir(cx, y, "y");
                        db.span_suggestion(expr.span,
                                           "use",
                                           format!("{}..{}", start, end));
                    },
                );
            }
        }
    }
}

fn has_step_by(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    // No need for walk_ptrs_ty here because step_by moves self, so it
    // can't be called on a borrowed range.
    let ty = cx.tables.expr_ty_adjusted(expr);

    get_trait_def_id(cx, &paths::ITERATOR).map_or(false, |iterator_trait| implements_trait(cx, ty, iterator_trait, &[]))
}

fn y_plus_one(expr: &Expr) -> Option<&Expr> {
    match expr.node {
        ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref lhs, ref rhs) => if is_integer_literal(lhs, 1) {
            Some(rhs)
        } else if is_integer_literal(rhs, 1) {
            Some(lhs)
        } else {
            None
        },
        _ => None,
    }
}

fn y_minus_one(expr: &Expr) -> Option<&Expr> {
    match expr.node {
        ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) if is_integer_literal(rhs, 1) => Some(lhs),
        _ => None,
    }
}
<|endoftext|>


<commit_before>use if_chain::if_chain;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};

use crate::utils::{
    higher::if_block, in_macro_or_desugar, match_type, paths, span_lint_and_then, usage::is_potentially_mutated,
};
use rustc::hir::intravisit::*;
use rustc::hir::*;
use syntax::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for calls of `unwrap[_err]()` that cannot fail.
    ///
    /// **Why is this bad?** Using `if let` or `match` is more idiomatic.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust
    /// if option.is_some() {
    ///     do_something_with(option.unwrap())
    /// }
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// if let Some(value) = option {
    ///     do_something_with(value)
    /// }
    /// ```
    pub UNNECESSARY_UNWRAP,
    complexity,
    "checks for calls of unwrap[_err]() that cannot fail"
}

declare_clippy_lint! {
    /// **What it does:** Checks for calls of `unwrap[_err]()` that will always fail.
    ///
    /// **Why is this bad?** If panicking is desired, an explicit `panic!()` should be used.
    ///
    /// **Known problems:** This lint only checks `if` conditions not assignments.
    /// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized.
    ///
    /// **Example:**
    /// ```rust
    /// if option.is_none() {
    ///     do_something_with(option.unwrap())
    /// }
    /// ```
    ///
    /// This code will always panic. The if condition should probably be inverted.
    pub PANICKING_UNWRAP,
    correctness,
    "checks for calls of unwrap[_err]() that will always fail"
}

/// Visitor that keeps track of which variables are unwrappable.
struct UnwrappableVariablesVisitor<'a, 'tcx> {
    unwrappables: Vec<UnwrapInfo<'tcx>>,
    cx: &'a LateContext<'a, 'tcx>,
}
/// Contains information about whether a variable can be unwrapped.
#[derive(Copy, Clone, Debug)]
struct UnwrapInfo<'tcx> {
    /// The variable that is checked
    ident: &'tcx Path,
    /// The check, like `x.is_ok()`
    check: &'tcx Expr,
    /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`).
    safe_to_unwrap: bool,
}

/// Collects the information about unwrappable variables from an if condition
/// The `invert` argument tells us whether the condition is negated.
fn collect_unwrap_info<'a, 'tcx>(
    cx: &'a LateContext<'a, 'tcx>,
    expr: &'tcx Expr,
    invert: bool,
) -> Vec<UnwrapInfo<'tcx>> {
    if let ExprKind::Binary(op, left, right) = &expr.node {
        match (invert, op.node) {
            (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => {
                let mut unwrap_info = collect_unwrap_info(cx, left, invert);
                unwrap_info.append(&mut collect_unwrap_info(cx, right, invert));
                return unwrap_info;
            },
            _ => (),
        }
    } else if let ExprKind::Unary(UnNot, expr) = &expr.node {
        return collect_unwrap_info(cx, expr, !invert);
    } else {
        if_chain! {
            if let ExprKind::MethodCall(method_name, _, args) = &expr.node;
            if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].node;
            let ty = cx.tables.expr_ty(&args[0]);
            if match_type(cx, ty, &paths::OPTION) || match_type(cx, ty, &paths::RESULT);
            let name = method_name.ident.as_str();
            if ["is_some", "is_none", "is_ok", "is_err"].contains(&&*name);
            then {
                assert!(args.len() == 1);
                let unwrappable = match name.as_ref() {
                    "is_some" | "is_ok" => true,
                    "is_err" | "is_none" => false,
                    _ => unreachable!(),
                };
                let safe_to_unwrap = unwrappable != invert;
                return vec![UnwrapInfo { ident: path, check: expr, safe_to_unwrap }];
            }
        }
    }
    Vec::new()
}

impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
    fn visit_branch(&mut self, cond: &'tcx Expr, branch: &'tcx Expr, else_branch: bool) {
        let prev_len = self.unwrappables.len();
        for unwrap_info in collect_unwrap_info(self.cx, cond, else_branch) {
            if is_potentially_mutated(unwrap_info.ident, cond, self.cx)
                || is_potentially_mutated(unwrap_info.ident, branch, self.cx)
            {
                // if the variable is mutated, we don't know whether it can be unwrapped:
                continue;
            }
            self.unwrappables.push(unwrap_info);
        }
        walk_expr(self, branch);
        self.unwrappables.truncate(prev_len);
    }
}

impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx Expr) {
        if let Some((cond, then, els)) = if_block(&expr) {
            walk_expr(self, cond);
            self.visit_branch(cond, then, false);
            if let Some(els) = els {
                self.visit_branch(cond, els, true);
            }
        } else {
            // find `unwrap[_err]()` calls:
            if_chain! {
                if let ExprKind::MethodCall(ref method_name, _, ref args) = expr.node;
                if let ExprKind::Path(QPath::Resolved(None, ref path)) = args[0].node;
                if [sym!(unwrap), sym!(unwrap_err)].contains(&method_name.ident.name);
                let call_to_unwrap = method_name.ident.name == sym!(unwrap);
                if let Some(unwrappable) = self.unwrappables.iter()
                    .find(|u| u.ident.res == path.res);
                then {
                    if call_to_unwrap == unwrappable.safe_to_unwrap {
                        span_lint_and_then(
                            self.cx,
                            UNNECESSARY_UNWRAP,
                            expr.span,
                            &format!("You checked before that `{}()` cannot fail. \
                            Instead of checking and unwrapping, it's better to use `if let` or `match`.",
                            method_name.ident.name),
                            |db| { db.span_label(unwrappable.check.span, "the check is happening here"); },
                        );
                    } else {
                        span_lint_and_then(
                            self.cx,
                            PANICKING_UNWRAP,
                            expr.span,
                            &format!("This call to `{}()` will always panic.",
                            method_name.ident.name),
                            |db| { db.span_label(unwrappable.check.span, "because of this check"); },
                        );
                    }
                }
            }
            walk_expr(self, expr);
        }
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
    }
}

declare_lint_pass!(Unwrap => [PANICKING_UNWRAP, UNNECESSARY_UNWRAP]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Unwrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        fn_id: HirId,
    ) {
        if in_macro_or_desugar(span) {
            return;
        }

        let mut v = UnwrappableVariablesVisitor {
            cx,
            unwrappables: Vec::new(),
        };

        walk_fn(&mut v, kind, decl, body.id(), span, fn_id);
    }
}
<commit_msg>Fix doc tests<commit_after>use if_chain::if_chain;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};

use crate::utils::{
    higher::if_block, in_macro_or_desugar, match_type, paths, span_lint_and_then, usage::is_potentially_mutated,
};
use rustc::hir::intravisit::*;
use rustc::hir::*;
use syntax::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for calls of `unwrap[_err]()` that cannot fail.
    ///
    /// **Why is this bad?** Using `if let` or `match` is more idiomatic.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust
    /// # let option = Some(0);
    /// # fn do_something_with(_x: usize) {}
    /// if option.is_some() {
    ///     do_something_with(option.unwrap())
    /// }
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # let option = Some(0);
    /// # fn do_something_with(_x: usize) {}
    /// if let Some(value) = option {
    ///     do_something_with(value)
    /// }
    /// ```
    pub UNNECESSARY_UNWRAP,
    complexity,
    "checks for calls of unwrap[_err]() that cannot fail"
}

declare_clippy_lint! {
    /// **What it does:** Checks for calls of `unwrap[_err]()` that will always fail.
    ///
    /// **Why is this bad?** If panicking is desired, an explicit `panic!()` should be used.
    ///
    /// **Known problems:** This lint only checks `if` conditions not assignments.
    /// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized.
    ///
    /// **Example:**
    /// ```rust
    /// # let option = Some(0);
    /// # fn do_something_with(_x: usize) {}
    /// if option.is_none() {
    ///     do_something_with(option.unwrap())
    /// }
    /// ```
    ///
    /// This code will always panic. The if condition should probably be inverted.
    pub PANICKING_UNWRAP,
    correctness,
    "checks for calls of unwrap[_err]() that will always fail"
}

/// Visitor that keeps track of which variables are unwrappable.
struct UnwrappableVariablesVisitor<'a, 'tcx> {
    unwrappables: Vec<UnwrapInfo<'tcx>>,
    cx: &'a LateContext<'a, 'tcx>,
}
/// Contains information about whether a variable can be unwrapped.
#[derive(Copy, Clone, Debug)]
struct UnwrapInfo<'tcx> {
    /// The variable that is checked
    ident: &'tcx Path,
    /// The check, like `x.is_ok()`
    check: &'tcx Expr,
    /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`).
    safe_to_unwrap: bool,
}

/// Collects the information about unwrappable variables from an if condition
/// The `invert` argument tells us whether the condition is negated.
fn collect_unwrap_info<'a, 'tcx>(
    cx: &'a LateContext<'a, 'tcx>,
    expr: &'tcx Expr,
    invert: bool,
) -> Vec<UnwrapInfo<'tcx>> {
    if let ExprKind::Binary(op, left, right) = &expr.node {
        match (invert, op.node) {
            (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => {
                let mut unwrap_info = collect_unwrap_info(cx, left, invert);
                unwrap_info.append(&mut collect_unwrap_info(cx, right, invert));
                return unwrap_info;
            },
            _ => (),
        }
    } else if let ExprKind::Unary(UnNot, expr) = &expr.node {
        return collect_unwrap_info(cx, expr, !invert);
    } else {
        if_chain! {
            if let ExprKind::MethodCall(method_name, _, args) = &expr.node;
            if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].node;
            let ty = cx.tables.expr_ty(&args[0]);
            if match_type(cx, ty, &paths::OPTION) || match_type(cx, ty, &paths::RESULT);
            let name = method_name.ident.as_str();
            if ["is_some", "is_none", "is_ok", "is_err"].contains(&&*name);
            then {
                assert!(args.len() == 1);
                let unwrappable = match name.as_ref() {
                    "is_some" | "is_ok" => true,
                    "is_err" | "is_none" => false,
                    _ => unreachable!(),
                };
                let safe_to_unwrap = unwrappable != invert;
                return vec![UnwrapInfo { ident: path, check: expr, safe_to_unwrap }];
            }
        }
    }
    Vec::new()
}

impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
    fn visit_branch(&mut self, cond: &'tcx Expr, branch: &'tcx Expr, else_branch: bool) {
        let prev_len = self.unwrappables.len();
        for unwrap_info in collect_unwrap_info(self.cx, cond, else_branch) {
            if is_potentially_mutated(unwrap_info.ident, cond, self.cx)
                || is_potentially_mutated(unwrap_info.ident, branch, self.cx)
            {
                // if the variable is mutated, we don't know whether it can be unwrapped:
                continue;
            }
            self.unwrappables.push(unwrap_info);
        }
        walk_expr(self, branch);
        self.unwrappables.truncate(prev_len);
    }
}

impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx Expr) {
        if let Some((cond, then, els)) = if_block(&expr) {
            walk_expr(self, cond);
            self.visit_branch(cond, then, false);
            if let Some(els) = els {
                self.visit_branch(cond, els, true);
            }
        } else {
            // find `unwrap[_err]()` calls:
            if_chain! {
                if let ExprKind::MethodCall(ref method_name, _, ref args) = expr.node;
                if let ExprKind::Path(QPath::Resolved(None, ref path)) = args[0].node;
                if [sym!(unwrap), sym!(unwrap_err)].contains(&method_name.ident.name);
                let call_to_unwrap = method_name.ident.name == sym!(unwrap);
                if let Some(unwrappable) = self.unwrappables.iter()
                    .find(|u| u.ident.res == path.res);
                then {
                    if call_to_unwrap == unwrappable.safe_to_unwrap {
                        span_lint_and_then(
                            self.cx,
                            UNNECESSARY_UNWRAP,
                            expr.span,
                            &format!("You checked before that `{}()` cannot fail. \
                            Instead of checking and unwrapping, it's better to use `if let` or `match`.",
                            method_name.ident.name),
                            |db| { db.span_label(unwrappable.check.span, "the check is happening here"); },
                        );
                    } else {
                        span_lint_and_then(
                            self.cx,
                            PANICKING_UNWRAP,
                            expr.span,
                            &format!("This call to `{}()` will always panic.",
                            method_name.ident.name),
                            |db| { db.span_label(unwrappable.check.span, "because of this check"); },
                        );
                    }
                }
            }
            walk_expr(self, expr);
        }
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
    }
}

declare_lint_pass!(Unwrap => [PANICKING_UNWRAP, UNNECESSARY_UNWRAP]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Unwrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        fn_id: HirId,
    ) {
        if in_macro_or_desugar(span) {
            return;
        }

        let mut v = UnwrappableVariablesVisitor {
            cx,
            unwrappables: Vec::new(),
        };

        walk_fn(&mut v, kind, decl, body.id(), span, fn_id);
    }
}
<|endoftext|>


<commit_before>use bytes::Bytes;
use common::conn_write::CommonToWriteMessage;
use common::window_size::StreamOutWindowReceiver;
use data_or_headers::DataOrHeaders;
use data_or_headers_with_flag::DataOrHeadersWithFlag;
use error;
use futures::future;
use futures::future::Future;
use futures::sync::mpsc;
use futures::sync::mpsc::UnboundedSender;
use futures::Async;
use futures::Poll;
use futures::Stream;
use solicit::end_stream::EndStream;
use solicit::StreamId;
use DataOrTrailers;
use ErrorCode;
use Headers;
use HttpStreamAfterHeaders;
use StreamDead;

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum SenderState {
    ExpectingHeaders,
    ExpectingBodyOrTrailers,
    Done,
}

#[derive(Debug)]
pub enum SendError {
    ConnectionDied, // TODO: reason
    IncorrectState(SenderState),
}

struct CanSendData<M: From<CommonToWriteMessage>> {
    write_tx: UnboundedSender<M>,
    out_window: StreamOutWindowReceiver,
    seen_headers: bool,
}

/// Shared implementation of sender for client and server
pub(crate) struct CommonSender<M: From<CommonToWriteMessage>> {
    state: Option<CanSendData<M>>,
    stream_id: StreamId,
}

impl<M: From<CommonToWriteMessage>> CommonSender<M> {
    pub fn new(
        stream_id: StreamId,
        write_tx: UnboundedSender<M>,
        out_window: StreamOutWindowReceiver,
        seen_headers: bool,
    ) -> Self {
        CommonSender {
            state: Some(CanSendData {
                write_tx,
                out_window,
                seen_headers,
            }),
            stream_id,
        }
    }

    pub fn poll(&mut self) -> Poll<(), StreamDead> {
        match self.state {
            Some(ref mut state) => state.out_window.poll(),
            // TODO: different error
            None => Ok(Async::Ready(())),
        }
    }

    pub fn wait(&mut self) -> Result<(), StreamDead> {
        future::poll_fn(|| self.poll()).wait()
    }

    fn get_can_send(&mut self) -> Result<&mut CanSendData<M>, SendError> {
        match self.state {
            Some(ref mut state) => Ok(state),
            None => Err(SendError::IncorrectState(SenderState::Done)),
        }
    }

    fn state(&self) -> SenderState {
        match self.state {
            Some(CanSendData {
                seen_headers: true, ..
            }) => SenderState::ExpectingBodyOrTrailers,
            Some(CanSendData {
                seen_headers: false,
                ..
            }) => SenderState::ExpectingHeaders,
            None => SenderState::Done,
        }
    }

    pub fn send_common(&mut self, message: CommonToWriteMessage) -> Result<(), SendError> {
        // TODO: why client died?
        self.get_can_send()?
            .write_tx
            .unbounded_send(message.into())
            .map_err(|_: mpsc::SendError<_>| SendError::ConnectionDied)
    }

    fn send_data_impl(&mut self, data: Bytes, last: bool) -> Result<(), SendError> {
        if self.state() != SenderState::ExpectingBodyOrTrailers {
            return Err(SendError::IncorrectState(self.state()));
        }
        let stream_id = self.stream_id;
        self.get_can_send()?.out_window.decrease(data.len());
        self.send_common(CommonToWriteMessage::StreamEnqueue(
            stream_id,
            DataOrHeadersWithFlag {
                content: DataOrHeaders::Data(data),
                last,
            },
        ))
    }

    pub fn send_data(&mut self, data: Bytes) -> Result<(), SendError> {
        self.send_data_impl(data, false)
    }

    pub fn send_data_end_of_stream(&mut self, data: Bytes) -> Result<(), SendError> {
        self.send_data_impl(data, true)
    }

    pub fn send_headers(&mut self, headers: Headers) -> Result<(), SendError> {
        if self.state() != SenderState::ExpectingHeaders {
            return Err(SendError::IncorrectState(self.state()));
        }
        let stream_id = self.stream_id;
        self.send_common(CommonToWriteMessage::StreamEnqueue(
            stream_id,
            DataOrHeadersWithFlag {
                content: DataOrHeaders::Headers(headers),
                last: false,
            },
        ))?;
        self.state.as_mut().unwrap().seen_headers = true;
        Ok(())
    }

    pub fn send_trailers(&mut self, trailers: Headers) -> Result<(), SendError> {
        if self.state() != SenderState::ExpectingBodyOrTrailers {
            return Err(SendError::IncorrectState(self.state()));
        }
        let stream_id = self.stream_id;
        self.send_common(CommonToWriteMessage::StreamEnqueue(
            stream_id,
            DataOrHeadersWithFlag {
                content: DataOrHeaders::Headers(trailers),
                last: true,
            },
        ))?;
        self.state = None;
        Ok(())
    }

    pub fn send_data_or_trailers(
        &mut self,
        data_or_trailers: DataOrTrailers,
    ) -> Result<(), SendError> {
        match data_or_trailers {
            DataOrTrailers::Data(data, end_stream) => {
                self.send_data_impl(data, end_stream == EndStream::Yes)
            }
            DataOrTrailers::Trailers(trailers) => self.send_trailers(trailers),
        }
    }

    pub fn pull_from_stream(&mut self, stream: HttpStreamAfterHeaders) -> Result<(), SendError> {
        if self.state() != SenderState::ExpectingBodyOrTrailers {
            return Err(SendError::IncorrectState(self.state()));
        }

        match self.state.take() {
            Some(CanSendData {
                write_tx,
                out_window,
                ..
            }) => {
                // TODO: why client died
                write_tx
                    .unbounded_send(
                        CommonToWriteMessage::Pull(self.stream_id, stream, out_window).into(),
                    ).map_err(|_: mpsc::SendError<_>| SendError::ConnectionDied)
            }
            None => Err(SendError::IncorrectState(SenderState::Done)),
        }
    }

    pub fn pull_bytes_from_stream<S>(&mut self, stream: S) -> Result<(), SendError>
    where
        S: Stream<Item = Bytes, Error = error::Error> + Send + 'static,
    {
        self.pull_from_stream(HttpStreamAfterHeaders::bytes(stream))
    }

    pub fn reset(&mut self, error_code: ErrorCode) -> Result<(), SendError> {
        // TODO: do nothing if stream is explicitly closed
        let stream_id = self.stream_id;
        self.send_common(CommonToWriteMessage::StreamEnd(stream_id, error_code))?;
        self.state.take();
        Ok(())
    }

    pub fn close(&mut self) -> Result<(), SendError> {
        self.reset(ErrorCode::NoError)
    }
}

impl<M: From<CommonToWriteMessage>> Drop for CommonSender<M> {
    fn drop(&mut self) {
        // TODO: not sure correct code
        // TODO: warn if not called close or reset explicitly
        // TODO: different message if panicked
        drop(self.reset(ErrorCode::InternalError))
    }
}
<commit_msg>Warning if Sender was not properly finished<commit_after>use bytes::Bytes;
use common::conn_write::CommonToWriteMessage;
use common::window_size::StreamOutWindowReceiver;
use data_or_headers::DataOrHeaders;
use data_or_headers_with_flag::DataOrHeadersWithFlag;
use error;
use futures::future;
use futures::future::Future;
use futures::sync::mpsc;
use futures::sync::mpsc::UnboundedSender;
use futures::Async;
use futures::Poll;
use futures::Stream;
use solicit::end_stream::EndStream;
use solicit::StreamId;
use DataOrTrailers;
use ErrorCode;
use Headers;
use HttpStreamAfterHeaders;
use StreamDead;

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum SenderState {
    ExpectingHeaders,
    ExpectingBodyOrTrailers,
    Done,
}

#[derive(Debug)]
pub enum SendError {
    ConnectionDied, // TODO: reason
    IncorrectState(SenderState),
}

struct CanSendData<M: From<CommonToWriteMessage>> {
    write_tx: UnboundedSender<M>,
    out_window: StreamOutWindowReceiver,
    seen_headers: bool,
}

/// Shared implementation of sender for client and server
pub(crate) struct CommonSender<M: From<CommonToWriteMessage>> {
    state: Option<CanSendData<M>>,
    stream_id: StreamId,
}

impl<M: From<CommonToWriteMessage>> CommonSender<M> {
    pub fn new(
        stream_id: StreamId,
        write_tx: UnboundedSender<M>,
        out_window: StreamOutWindowReceiver,
        seen_headers: bool,
    ) -> Self {
        CommonSender {
            state: Some(CanSendData {
                write_tx,
                out_window,
                seen_headers,
            }),
            stream_id,
        }
    }

    pub fn poll(&mut self) -> Poll<(), StreamDead> {
        match self.state {
            Some(ref mut state) => state.out_window.poll(),
            // TODO: different error
            None => Ok(Async::Ready(())),
        }
    }

    pub fn wait(&mut self) -> Result<(), StreamDead> {
        future::poll_fn(|| self.poll()).wait()
    }

    fn get_can_send(&mut self) -> Result<&mut CanSendData<M>, SendError> {
        match self.state {
            Some(ref mut state) => Ok(state),
            None => Err(SendError::IncorrectState(SenderState::Done)),
        }
    }

    fn state(&self) -> SenderState {
        match self.state {
            Some(CanSendData {
                seen_headers: true, ..
            }) => SenderState::ExpectingBodyOrTrailers,
            Some(CanSendData {
                seen_headers: false,
                ..
            }) => SenderState::ExpectingHeaders,
            None => SenderState::Done,
        }
    }

    pub fn send_common(&mut self, message: CommonToWriteMessage) -> Result<(), SendError> {
        // TODO: why client died?
        self.get_can_send()?
            .write_tx
            .unbounded_send(message.into())
            .map_err(|_: mpsc::SendError<_>| SendError::ConnectionDied)
    }

    fn send_data_impl(&mut self, data: Bytes, last: bool) -> Result<(), SendError> {
        if self.state() != SenderState::ExpectingBodyOrTrailers {
            return Err(SendError::IncorrectState(self.state()));
        }
        let stream_id = self.stream_id;
        self.get_can_send()?.out_window.decrease(data.len());
        self.send_common(CommonToWriteMessage::StreamEnqueue(
            stream_id,
            DataOrHeadersWithFlag {
                content: DataOrHeaders::Data(data),
                last,
            },
        ))?;
        if last {
            self.state.take();
        }
        Ok(())
    }

    pub fn send_data(&mut self, data: Bytes) -> Result<(), SendError> {
        self.send_data_impl(data, false)
    }

    pub fn send_data_end_of_stream(&mut self, data: Bytes) -> Result<(), SendError> {
        self.send_data_impl(data, true)
    }

    pub fn send_headers(&mut self, headers: Headers) -> Result<(), SendError> {
        if self.state() != SenderState::ExpectingHeaders {
            return Err(SendError::IncorrectState(self.state()));
        }
        let stream_id = self.stream_id;
        self.send_common(CommonToWriteMessage::StreamEnqueue(
            stream_id,
            DataOrHeadersWithFlag {
                content: DataOrHeaders::Headers(headers),
                last: false,
            },
        ))?;
        self.state.as_mut().unwrap().seen_headers = true;
        Ok(())
    }

    pub fn send_trailers(&mut self, trailers: Headers) -> Result<(), SendError> {
        if self.state() != SenderState::ExpectingBodyOrTrailers {
            return Err(SendError::IncorrectState(self.state()));
        }
        let stream_id = self.stream_id;
        self.send_common(CommonToWriteMessage::StreamEnqueue(
            stream_id,
            DataOrHeadersWithFlag {
                content: DataOrHeaders::Headers(trailers),
                last: true,
            },
        ))?;
        self.state = None;
        Ok(())
    }

    pub fn send_data_or_trailers(
        &mut self,
        data_or_trailers: DataOrTrailers,
    ) -> Result<(), SendError> {
        match data_or_trailers {
            DataOrTrailers::Data(data, end_stream) => {
                self.send_data_impl(data, end_stream == EndStream::Yes)
            }
            DataOrTrailers::Trailers(trailers) => self.send_trailers(trailers),
        }
    }

    pub fn pull_from_stream(&mut self, stream: HttpStreamAfterHeaders) -> Result<(), SendError> {
        if self.state() != SenderState::ExpectingBodyOrTrailers {
            return Err(SendError::IncorrectState(self.state()));
        }

        match self.state.take() {
            Some(CanSendData {
                write_tx,
                out_window,
                ..
            }) => {
                // TODO: why client died
                write_tx
                    .unbounded_send(
                        CommonToWriteMessage::Pull(self.stream_id, stream, out_window).into(),
                    ).map_err(|_: mpsc::SendError<_>| SendError::ConnectionDied)
            }
            None => Err(SendError::IncorrectState(SenderState::Done)),
        }
    }

    pub fn pull_bytes_from_stream<S>(&mut self, stream: S) -> Result<(), SendError>
    where
        S: Stream<Item = Bytes, Error = error::Error> + Send + 'static,
    {
        self.pull_from_stream(HttpStreamAfterHeaders::bytes(stream))
    }

    pub fn reset(&mut self, error_code: ErrorCode) -> Result<(), SendError> {
        // TODO: do nothing if stream is explicitly closed
        let stream_id = self.stream_id;
        self.send_common(CommonToWriteMessage::StreamEnd(stream_id, error_code))?;
        self.state.take();
        Ok(())
    }

    pub fn close(&mut self) -> Result<(), SendError> {
        self.reset(ErrorCode::NoError)
    }
}

impl<M: From<CommonToWriteMessage>> Drop for CommonSender<M> {
    fn drop(&mut self) {
        // TODO: different message if panicked
        if self.state() != SenderState::Done {
            warn!("Sender was not properly finished, sending RST_STREAM InternalError");
        }
        drop(self.reset(ErrorCode::InternalError))
    }
}
<|endoftext|>


<commit_before>use cgmath::{InnerSpace, Matrix4, Rad, SquareMatrix, Vector3, Vector4};

use inverse_kinematics::{Chain};

pub fn cyclic_coordinate_descent(chain: &Chain, target: Vector3<f32>) -> Vec<f32> {
	const DISTANCE_THRESHOLD: f32 = 0.01; // ADD DYNOMISM
	const PERP_LENGTH_THRESHOLD: f32 = 0.0001;
	const MAX_ITERATIONS: usize = 30;

	if chain.joints.is_empty() { return Vec::new() }

	let len = chain.joints.len();

	let mut cumulative_transforms = chain.cumulative_transforms();

	let mut angles: Vec<f32> = chain.angles.to_vec();

	let mut end = (cumulative_transforms.last().unwrap() * Vector4::unit_w()).truncate();

	for _ in 0..MAX_ITERATIONS {
		if (end - target).magnitude() < DISTANCE_THRESHOLD { break }

		let mut reverse_accumulator: Matrix4<f32> = Matrix4::identity();

		for i in (0..len).rev() {
			let (joint, prev_transform, mut current_transform, mut angle) = unsafe {
				(
					chain.joints.get_unchecked(i),
					if i > 0 { cumulative_transforms.get_unchecked(i - 1).clone() }
					else     { Matrix4::identity() },
					cumulative_transforms.get_unchecked_mut(i),
					angles.get_unchecked_mut(i),
				)
			};
			let root = (prev_transform * Vector4::unit_w()).truncate();
			let axis = (prev_transform * joint.axis.to_vector3().extend(0.0)).truncate();

			let target_dir = target - root;
			let target_perp = target_dir - (axis * axis.dot(target_dir));
			let target_perp_len = target_perp.magnitude();

			if target_perp_len < PERP_LENGTH_THRESHOLD { continue }

			let target_perp_norm = target_perp / target_perp_len;

			let end_dir = end - root;
			let end_perp = end_dir - (axis * axis.dot(end_dir));
			let end_perp_len = end_perp.magnitude();

			if end_perp_len < PERP_LENGTH_THRESHOLD { continue }

			let end_perp_norm = end_perp / end_perp_len;

			let cross = end_perp_norm.cross(target_perp_norm);
			let magnitude = cross.magnitude();
			let sign = if cross.dot(axis) > 0.0 { 1.0 } else { -1.0 };
			*angle += sign * magnitude.asin();

			// TODO: this assumption about Y being our offset direction needs to be put in a single place
			//
			let translation = Matrix4::from_translation(Vector3::new(0.0, joint.length, 0.0));
			let rotation    = Matrix4::from_axis_angle(joint.axis.to_vector3(), Rad(*angle));
			let transform   = rotation * translation;

			*current_transform = prev_transform * transform;
			reverse_accumulator = transform * reverse_accumulator;

			let total = prev_transform * reverse_accumulator;
			end = (total * Vector4::unit_w()).truncate();
		}
	}

	angles
}
<commit_msg>Bump up CCD max iteration count<commit_after>use cgmath::{InnerSpace, Matrix4, Rad, SquareMatrix, Vector3, Vector4};

use inverse_kinematics::{Chain};

pub fn cyclic_coordinate_descent(chain: &Chain, target: Vector3<f32>) -> Vec<f32> {
	const DISTANCE_THRESHOLD: f32 = 0.01; // ADD DYNOMISM
	const PERP_LENGTH_THRESHOLD: f32 = 0.0001;
	const MAX_ITERATIONS: usize = 60;

	if chain.joints.is_empty() { return Vec::new() }

	let len = chain.joints.len();

	let mut cumulative_transforms = chain.cumulative_transforms();

	let mut angles: Vec<f32> = chain.angles.to_vec();

	let mut end = (cumulative_transforms.last().unwrap() * Vector4::unit_w()).truncate();

	for _ in 0..MAX_ITERATIONS {
		if (end - target).magnitude() < DISTANCE_THRESHOLD { break }

		let mut reverse_accumulator: Matrix4<f32> = Matrix4::identity();

		for i in (0..len).rev() {
			let (joint, prev_transform, mut current_transform, mut angle) = unsafe {
				(
					chain.joints.get_unchecked(i),
					if i > 0 { cumulative_transforms.get_unchecked(i - 1).clone() }
					else     { Matrix4::identity() },
					cumulative_transforms.get_unchecked_mut(i),
					angles.get_unchecked_mut(i),
				)
			};
			let root = (prev_transform * Vector4::unit_w()).truncate();
			let axis = (prev_transform * joint.axis.to_vector3().extend(0.0)).truncate();

			let target_dir = target - root;
			let target_perp = target_dir - (axis * axis.dot(target_dir));
			let target_perp_len = target_perp.magnitude();

			if target_perp_len < PERP_LENGTH_THRESHOLD { continue }

			let target_perp_norm = target_perp / target_perp_len;

			let end_dir = end - root;
			let end_perp = end_dir - (axis * axis.dot(end_dir));
			let end_perp_len = end_perp.magnitude();

			if end_perp_len < PERP_LENGTH_THRESHOLD { continue }

			let end_perp_norm = end_perp / end_perp_len;

			let cross = end_perp_norm.cross(target_perp_norm);
			let magnitude = cross.magnitude();
			let sign = if cross.dot(axis) > 0.0 { 1.0 } else { -1.0 };
			*angle += sign * magnitude.asin();

			// TODO: this assumption about Y being our offset direction needs to be put in a single place
			//
			let translation = Matrix4::from_translation(Vector3::new(0.0, joint.length, 0.0));
			let rotation    = Matrix4::from_axis_angle(joint.axis.to_vector3(), Rad(*angle));
			let transform   = rotation * translation;

			*current_transform = prev_transform * transform;
			reverse_accumulator = transform * reverse_accumulator;

			let total = prev_transform * reverse_accumulator;
			end = (total * Vector4::unit_w()).truncate();
		}
	}

	angles
}
<|endoftext|>


<commit_before>use clap;
use cobalt;

use error::*;

pub fn debug_command_args() -> clap::App<'static, 'static> {
    clap::SubCommand::with_name("debug")
        .about("Print site debug information")
        .subcommand(clap::SubCommand::with_name("highlight")
                        .about("Print syntax-highlight information")
                        .subcommand(clap::SubCommand::with_name("themes"))
                        .subcommand(clap::SubCommand::with_name("syntaxes")))
}

pub fn debug_command(matches: &clap::ArgMatches) -> Result<()> {
    match matches.subcommand() {
        ("highlight", Some(matches)) => {
            match matches.subcommand() {
                ("themes", _) => {
                    for name in cobalt::list_syntax_themes() {
                        println!("{}", name);
                    }
                }
                ("syntaxes", _) => {
                    for name in cobalt::list_syntaxes() {
                        println!("{}", name);
                    }
                }
                _ => bail!(matches.usage()),
            }
        }
        _ => bail!(matches.usage()),
    }

    Ok(())
}
<commit_msg>feat(debug): Report asset files<commit_after>use clap;
use cobalt;

use args;
use error::*;

pub fn debug_command_args() -> clap::App<'static, 'static> {
    clap::SubCommand::with_name("debug")
        .about("Print site debug information")
        .subcommand(clap::SubCommand::with_name("highlight")
                        .about("Print syntax-highlight information")
                        .subcommand(clap::SubCommand::with_name("themes"))
                        .subcommand(clap::SubCommand::with_name("syntaxes")))
        .subcommand(clap::SubCommand::with_name("files")
                        .about("Print files associated with a collection")
                        .args(&args::get_config_args())
                        .arg(clap::Arg::with_name("COLLECTION")
                                 .help("Collection name")
                                 .index(1)))
}

pub fn debug_command(matches: &clap::ArgMatches) -> Result<()> {
    match matches.subcommand() {
        ("highlight", Some(matches)) => {
            match matches.subcommand() {
                ("themes", _) => {
                    for name in cobalt::list_syntax_themes() {
                        println!("{}", name);
                    }
                }
                ("syntaxes", _) => {
                    for name in cobalt::list_syntaxes() {
                        println!("{}", name);
                    }
                }
                _ => bail!(matches.usage()),
            }
        }
        ("files", Some(matches)) => {
            let config = args::get_config(matches)?;
            let config = config.build()?;
            let collection = matches.value_of("COLLECTION");
            match collection {
                Some("assets") => {
                    for file_path in config.assets.files() {
                        println!("{:?}", file_path);
                    }
                }
                None => {
                    bail!("Must specify collection");
                }
                _ => {
                    bail!("Collection is not yet supported");
                }
            }
        }
        _ => bail!(matches.usage()),
    }

    Ok(())
}
<|endoftext|>