Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//! Get the version string of the toolchain.

use anyhow::Context;
use rustc_hash::FxHashMap;
use semver::Version;
use toolchain::Tool;

use crate::{toolchain_info::QueryConfig, utf8_stdout};

pub(crate) fn get(
    config: QueryConfig<'_>,
    extra_env: &FxHashMap<String, String>,
) -> Result<Option<Version>, anyhow::Error> {
    let (mut cmd, prefix) = match config {
        QueryConfig::Cargo(sysroot, cargo_toml) => {
            (sysroot.tool(Tool::Cargo, cargo_toml.parent()), "cargo ")
        }
        QueryConfig::Rustc(sysroot, current_dir) => {
            (sysroot.tool(Tool::Rustc, current_dir), "rustc ")
        }
    };
    cmd.envs(extra_env);
    cmd.arg("--version");
    let out = utf8_stdout(&mut cmd).with_context(|| format!("Failed to query rust toolchain version via `{cmd:?}`, is your toolchain setup correctly?"))?;

    let version =
        out.strip_prefix(prefix).and_then(|it| Version::parse(it.split_whitespace().next()?).ok());
    if version.is_none() {
        tracing::warn!("Failed to parse `{cmd:?}` output `{out}` as a semver version");
    }
    anyhow::Ok(version)
}

#[cfg(test)]
mod tests {
    use paths::{AbsPathBuf, Utf8PathBuf};

    use crate::{ManifestPath, Sysroot};

    use super::*;

    #[test]
    fn cargo() {
        let manifest_path = concat!(env!("CARGO_MANIFEST_DIR"), "/Cargo.toml");
        let sysroot = Sysroot::empty();
        let manifest_path =
            ManifestPath::try_from(AbsPathBuf::assert(Utf8PathBuf::from(manifest_path))).unwrap();
        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path);
        assert!(get(cfg, &FxHashMap::default()).is_ok());
    }

    #[test]
    fn rustc() {
        let sysroot = Sysroot::empty();
        let cfg = QueryConfig::Rustc(&sysroot, env!("CARGO_MANIFEST_DIR").as_ref());
        assert!(get(cfg, &FxHashMap::default()).is_ok());
    }
}
59' href='#n159'>159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
use hir::IncorrectGenericsLenKind;

// Diagnostic: incorrect-generics-len
//
// This diagnostic is triggered if the number of generic arguments does not match their declaration.
pub(crate) fn incorrect_generics_len(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::IncorrectGenericsLen,
) -> Diagnostic {
    let owner_description = d.def.description();
    let expected = d.expected;
    let provided = d.provided;
    let kind_description = match d.kind {
        IncorrectGenericsLenKind::Lifetimes => "lifetime",
        IncorrectGenericsLenKind::TypesAndConsts => "generic",
    };
    let message = format!(
        "this {owner_description} takes {expected} {kind_description} argument{} \
            but {provided} {kind_description} argument{} {} supplied",
        if expected == 1 { "" } else { "s" },
        if provided == 1 { "" } else { "s" },
        if provided == 1 { "was" } else { "were" },
    );
    Diagnostic::new_with_syntax_node_ptr(
        ctx,
        DiagnosticCode::RustcHardError("E0107"),
        message,
        d.generics_or_segment.map(Into::into),
    )
    .experimental()
}

#[cfg(test)]
mod tests {
    use crate::tests::check_diagnostics;

    #[test]
    fn partially_specified_generics() {
        check_diagnostics(
            r#"
struct Bar<T, U>(T, U);

fn foo() {
    let _ = Bar::<()>;
            // ^^^^^^ error: this struct takes 2 generic arguments but 1 generic argument was supplied
}

        "#,
        );
    }

    #[test]
    fn enum_variant() {
        check_diagnostics(
            r#"
enum Enum<T, U> {
    Variant(T, U),
}

fn foo() {
    let _ = Enum::<()>::Variant;
             // ^^^^^^ error: this enum takes 2 generic arguments but 1 generic argument was supplied
    let _ = Enum::Variant::<()>;
                      // ^^^^^^ error: this enum takes 2 generic arguments but 1 generic argument was supplied
}

        "#,
        );
    }

    #[test]
    fn lifetimes() {
        check_diagnostics(
            r#"
struct Foo<'a, 'b>(&'a &'b ());

fn foo(Foo(_): Foo) -> Foo {
    let _: Foo = Foo(&&());
    let _: Foo::<> = Foo::<>(&&());
    let _: Foo::<'static>
           // ^^^^^^^^^^^ error: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
                          = Foo::<'static>(&&());
                            // ^^^^^^^^^^^ error: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
    |_: Foo| -> Foo {loop{}};

    loop {}
}

        "#,
        );
    }

    #[test]
    fn no_error_for_elided_lifetimes() {
        check_diagnostics(
            r#"
struct Foo<'a>(&'a ());

fn foo(_v: &()) -> Foo { loop {} }
        "#,
        );
    }

    #[test]
    fn errs_for_elided_lifetimes_if_lifetimes_are_explicitly_provided() {
        check_diagnostics(
            r#"
struct Foo<'a, 'b>(&'a &'b ());

fn foo(_v: Foo<'_>
           // ^^^^ error: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
) -> Foo<'static> { loop {} }
     // ^^^^^^^^^ error: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
        "#,
        );
    }

    #[test]
    fn types_and_consts() {
        check_diagnostics(
            r#"
struct Foo<'a, T>(&'a T);
fn foo(_v: Foo) {}
        // ^^^ error: this struct takes 1 generic argument but 0 generic arguments were supplied

struct Bar<T, const N: usize>(T);
fn bar() {
    let _ = Bar::<()>;
            // ^^^^^^ error: this struct takes 2 generic arguments but 1 generic argument was supplied
}
        "#,
        );
    }

    #[test]
    fn respects_defaults() {
        check_diagnostics(
            r#"
struct Foo<T = (), const N: usize = 0>(T);
fn foo(_v: Foo) {}

struct Bar<T, const N: usize = 0>(T);
fn bar(_v: Bar<()>) {}
        "#,
        );
    }

    #[test]
    fn constant() {
        check_diagnostics(
            r#"
const CONST: i32 = 0;
fn baz() {
    let _ = CONST::<()>;
              // ^^^^^^ error: this constant takes 0 generic arguments but 1 generic argument was supplied
}
        "#,
        );
    }

    #[test]
    fn assoc_type() {
        check_diagnostics(
            r#"
trait Trait {
    type Assoc;
}

fn foo<T: Trait<Assoc<i32> = bool>>() {}
                  // ^^^^^ error: this type alias takes 0 generic arguments but 1 generic argument was supplied
        "#,
        );
    }

    #[test]
    fn regression_19669() {
        check_diagnostics(
            r#"
//- minicore: from
fn main() {
    let _: i32 = Into::into(0);
}
"#,
        );
    }
}