Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs')
-rw-r--r--crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs187
1 files changed, 187 insertions, 0 deletions
diff --git a/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
new file mode 100644
index 0000000000..17c7f75880
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
@@ -0,0 +1,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);
+}
+"#,
+ );
+ }
+}