Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-def/src/expr_store.rs | 1 | ||||
| -rw-r--r-- | crates/hir-def/src/expr_store/lower.rs | 12 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 6 | ||||
| -rw-r--r-- | crates/hir/src/lib.rs | 3 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/pattern_arg_in_extern_fn.rs | 86 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 2 |
6 files changed, 105 insertions, 5 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs index 51951896f2..f72419a3ae 100644 --- a/crates/hir-def/src/expr_store.rs +++ b/crates/hir-def/src/expr_store.rs @@ -303,6 +303,7 @@ pub enum ExpressionStoreDiagnostics { UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, AwaitOutsideOfAsync { node: InFile<AstPtr<ast::AwaitExpr>>, location: String }, UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, + PatternArgInExternFn { node: InFile<AstPtr<ast::Pat>> }, } impl ExpressionStoreBuilder { diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 5c8e87c0e3..b86fad0420 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -2482,9 +2482,7 @@ impl<'db> ExprCollector<'db> { let Some(pat) = pat else { return self.missing_pat() }; match &pat { - ast::Pat::IdentPat(bp) => { - // FIXME: Emit an error if `!bp.is_simple_ident()`. - + ast::Pat::IdentPat(bp) if bp.is_simple_ident() => { let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); let hygiene = bp .name() @@ -2496,8 +2494,12 @@ impl<'db> ExprCollector<'db> { self.add_definition_to_binding(binding, pat); pat } - // FIXME: Emit an error. - _ => self.missing_pat(), + _ => { + self.store.diagnostics.push(ExpressionStoreDiagnostics::PatternArgInExternFn { + node: self.expander.in_file(AstPtr::new(&pat)), + }); + self.missing_pat() + } } } diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 32f0ac3dad..b2edac6c32 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -80,6 +80,7 @@ diagnostics![AnyDiagnostic<'db> -> NeedMut, NonExhaustiveLet, NoSuchField, + PatternArgInExternFn, PrivateAssocItem, PrivateField, RemoveTrailingReturn, @@ -486,6 +487,11 @@ pub struct InvalidLhsOfAssignment { pub lhs: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>, } +#[derive(Debug)] +pub struct PatternArgInExternFn { + pub node: InFile<AstPtr<ast::Pat>>, +} + impl<'db> AnyDiagnostic<'db> { pub(crate) fn body_validation_diagnostic( db: &'db dyn HirDatabase, diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8cc82113b3..20fae4fb0d 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2388,6 +2388,9 @@ fn expr_store_diagnostics<'db>( ExpressionStoreDiagnostics::UndeclaredLabel { node, name } => { UndeclaredLabel { node: *node, name: name.clone() }.into() } + ExpressionStoreDiagnostics::PatternArgInExternFn { node } => { + PatternArgInExternFn { node: *node }.into() + } }); } diff --git a/crates/ide-diagnostics/src/handlers/pattern_arg_in_extern_fn.rs b/crates/ide-diagnostics/src/handlers/pattern_arg_in_extern_fn.rs new file mode 100644 index 0000000000..36031865fc --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/pattern_arg_in_extern_fn.rs @@ -0,0 +1,86 @@ +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: pattern-arg-in-extern-fn +// +// This diagnostic is triggered if a pattern was declared as an argument in a foreign function declaration. +pub(crate) fn pattern_arg_in_extern_fn( + ctx: &DiagnosticsContext<'_>, + d: &hir::PatternArgInExternFn, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0130"), + "patterns aren't allowed in foreign function declarations", + d.node.map(Into::into), + ) + .stable() +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn tuple_pattern() { + check_diagnostics( + r#" +unsafe extern { fn foo((a, b): (u32, u32)); } + // ^^^^^^ error: patterns aren't allowed in foreign function declarations + "#, + ); + } + + #[test] + fn struct_pattern() { + check_diagnostics( + r#" +struct Foo(u32, u32); +unsafe extern { fn foo(Foo(a, b): Foo); } + // ^^^^^^^^^ error: patterns aren't allowed in foreign function declarations + "#, + ); + + check_diagnostics( + r#" +struct Foo{ bar: u32, baz: u32 } +unsafe extern { fn foo(Foo { bar, baz }: Foo); } + // ^^^^^^^^^^^^^^^^ error: patterns aren't allowed in foreign function declarations + "#, + ); + } + + #[test] + fn pattern_is_second_arg() { + check_diagnostics( + r#" +struct Foo(u32, u32); +unsafe extern { fn foo(okay: u32, Foo(a, b): Foo); } + // ^^^^^^^^^ error: patterns aren't allowed in foreign function declarations + "#, + ); + } + + #[test] + fn non_simple_ident() { + check_diagnostics( + r#" +unsafe extern { fn foo(ref a: u32); } + // ^^^^^ error: patterns aren't allowed in foreign function declarations + "#, + ); + + check_diagnostics( + r#" +unsafe extern { fn foo(mut a: u32); } + // ^^^^^ error: patterns aren't allowed in foreign function declarations + "#, + ); + + check_diagnostics( + r#" +unsafe extern { fn foo(a @ _: u32); } + // ^^^^^ error: patterns aren't allowed in foreign function declarations + "#, + ); + } +} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index a083447335..adc32564aa 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -56,6 +56,7 @@ mod handlers { pub(crate) mod no_such_field; pub(crate) mod non_exhaustive_let; pub(crate) mod parenthesized_generic_args_without_fn_trait; + pub(crate) mod pattern_arg_in_extern_fn; pub(crate) mod private_assoc_item; pub(crate) mod private_field; pub(crate) mod remove_trailing_return; @@ -483,6 +484,7 @@ pub fn semantic_diagnostics( AnyDiagnostic::GenericDefaultRefersToSelf(d) => handlers::generic_default_refers_to_self::generic_default_refers_to_self(&ctx, &d), AnyDiagnostic::InvalidLhsOfAssignment(d) => handlers::invalid_lhs_of_assignment::invalid_lhs_of_assignment(&ctx, &d), AnyDiagnostic::TypeMustBeKnown(d) => handlers::type_must_be_known::type_must_be_known(&ctx, &d), + AnyDiagnostic::PatternArgInExternFn(d) => handlers::pattern_arg_in_extern_fn::pattern_arg_in_extern_fn(&ctx, &d), }; res.push(d) } |