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-ty/src/infer/expr.rs | 4 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 10 | ||||
| -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 |
7 files changed, 109 insertions, 9 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-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 327975d766..0e3716eaa6 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -2007,7 +2007,7 @@ impl<'db> InferenceContext<'_, 'db> { }, None => None, }; - (arg_types.iter().collect(), expected_input_tys) + (arg_types.to_vec(), expected_input_tys) } _ => { // Otherwise, there's a mismatch, so clear out what we're expecting, and set @@ -2017,7 +2017,7 @@ impl<'db> InferenceContext<'_, 'db> { } } } else { - (formal_input_tys.to_vec(), expected_input_tys) + (formal_input_tys, expected_input_tys) }; // If there are no external expectations at the call site, just use the types from the function defn diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index afafede6b9..095b527cb0 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -62,6 +62,8 @@ diagnostics![AnyDiagnostic<'db> -> InactiveCode, IncoherentImpl, IncorrectCase, + IncorrectGenericsLen, + IncorrectGenericsOrder, InvalidCast<'db>, InvalidDeriveTarget, InvalidLhsOfAssignment, @@ -79,6 +81,7 @@ diagnostics![AnyDiagnostic<'db> -> NonExhaustiveLet, NonExhaustiveRecordExpr, NoSuchField, + PatternArgInExternFn, PrivateAssocItem, PrivateField, RemoveTrailingReturn, @@ -106,8 +109,6 @@ diagnostics![AnyDiagnostic<'db> -> GenericArgsProhibited, ParenthesizedGenericArgsWithoutFnTrait, BadRtn, - IncorrectGenericsLen, - IncorrectGenericsOrder, MissingLifetime, ElidedLifetimesInPath, TypeMustBeKnown<'db>, @@ -492,6 +493,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 df9f743224..60de634996 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 300a6e6c7f..7c07f8fd6c 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -57,6 +57,7 @@ mod handlers { pub(crate) mod non_exhaustive_let; pub(crate) mod non_exhaustive_record_expr; 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; @@ -487,6 +488,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) } |