Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/expr_store.rs1
-rw-r--r--crates/hir-def/src/expr_store/lower.rs12
-rw-r--r--crates/hir-ty/src/infer/expr.rs4
-rw-r--r--crates/hir/src/diagnostics.rs10
-rw-r--r--crates/hir/src/lib.rs3
-rw-r--r--crates/ide-diagnostics/src/handlers/pattern_arg_in_extern_fn.rs86
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
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)
}