Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/infer.rs4
-rw-r--r--crates/hir-ty/src/method_resolution.rs4
-rw-r--r--crates/hir/src/diagnostics.rs9
-rw-r--r--crates/ide-diagnostics/src/handlers/method_call_illegal_sized_bound.rs78
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
5 files changed, 95 insertions, 2 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 6aa647694e..3f90a78cc2 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -438,6 +438,10 @@ pub enum InferenceDiagnostic {
#[type_visitable(ignore)]
def: GenericDefId,
},
+ MethodCallIllegalSizedBound {
+ #[type_visitable(ignore)]
+ call_expr: ExprId,
+ },
MethodCallIncorrectGenericsOrder {
#[type_visitable(ignore)]
expr: ExprId,
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 5e90e371fc..9e0188fd26 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -35,7 +35,7 @@ use stdx::impl_from;
use triomphe::Arc;
use crate::{
- Span, all_super_traits,
+ InferenceDiagnostic, Span, all_super_traits,
db::HirDatabase,
infer::{InferenceContext, unify::InferenceTable},
lower::GenericPredicates,
@@ -148,7 +148,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
debug!("result = {:?}", result);
if result.illegal_sized_bound {
- // FIXME: Report an error.
+ self.push_diagnostic(InferenceDiagnostic::MethodCallIllegalSizedBound { call_expr });
}
self.write_expr_adj(receiver, result.adjustments);
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 9e4b929dd5..7e4853539d 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -120,6 +120,7 @@ diagnostics![AnyDiagnostic<'db> ->
MacroError,
MacroExpansionParseError,
MalformedDerive,
+ MethodCallIllegalSizedBound,
MismatchedArgCount,
MismatchedTupleStructPatArgCount,
MissingFields,
@@ -596,6 +597,11 @@ pub struct InvalidLhsOfAssignment {
}
#[derive(Debug)]
+pub struct MethodCallIllegalSizedBound {
+ pub call_expr: InFile<ExprOrPatPtr>,
+}
+
+#[derive(Debug)]
pub struct PatternArgInExternFn {
pub node: InFile<AstPtr<ast::Pat>>,
}
@@ -984,6 +990,9 @@ impl<'db> AnyDiagnostic<'db> {
let lhs = expr_syntax(lhs)?;
InvalidLhsOfAssignment { lhs }.into()
}
+ &InferenceDiagnostic::MethodCallIllegalSizedBound { call_expr } => {
+ MethodCallIllegalSizedBound { call_expr: expr_syntax(call_expr)? }.into()
+ }
&InferenceDiagnostic::TypeMustBeKnown { at_point, ref top_term } => {
let at_point = span_syntax(at_point)?;
let top_term = top_term.as_ref().map(|top_term| match top_term.as_ref().kind() {
diff --git a/crates/ide-diagnostics/src/handlers/method_call_illegal_sized_bound.rs b/crates/ide-diagnostics/src/handlers/method_call_illegal_sized_bound.rs
new file mode 100644
index 0000000000..0a0ac8627c
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/method_call_illegal_sized_bound.rs
@@ -0,0 +1,78 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: method-call-illegal-sized-bound
+//
+// This diagnostic is triggered when a method is called on a trait-object
+// receiver but the method's predicates require `Self: Sized`, which the
+// trait object cannot satisfy.
+pub(crate) fn method_call_illegal_sized_bound(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::MethodCallIllegalSizedBound,
+) -> Diagnostic {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0277"),
+ "the method cannot be invoked on a trait object because its `Self: Sized` bound is not satisfied",
+ d.call_expr.map(|it| it.into()),
+ )
+ .stable()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn sized_bound_method_on_trait_object_errors() {
+ check_diagnostics(
+ r#"
+//- minicore: sized
+trait Foo {
+ fn cant_call(&self) where Self: Sized;
+}
+
+fn f(x: &dyn Foo) {
+ x.cant_call();
+ //^^^^^^^^^^^^^ error: the method cannot be invoked on a trait object because its `Self: Sized` bound is not satisfied
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn method_without_sized_bound_on_trait_object_does_not_error() {
+ check_diagnostics(
+ r#"
+//- minicore: sized
+trait Foo {
+ fn dyn_safe(&self);
+}
+
+fn f(x: &dyn Foo) {
+ x.dyn_safe();
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn sized_bound_method_on_concrete_type_does_not_error() {
+ check_diagnostics(
+ r#"
+//- minicore: sized
+trait Foo {
+ fn cant_dispatch(&self) where Self: Sized;
+}
+
+struct S;
+impl Foo for S {
+ fn cant_dispatch(&self) {}
+}
+
+fn f(s: &S) {
+ s.cant_dispatch();
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 0809054a2e..0880002cba 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -50,6 +50,7 @@ mod handlers {
pub(crate) mod invalid_range_pat_type;
pub(crate) mod macro_error;
pub(crate) mod malformed_derive;
+ pub(crate) mod method_call_illegal_sized_bound;
pub(crate) mod mismatched_arg_count;
pub(crate) mod mismatched_array_pat_len;
pub(crate) mod missing_fields;
@@ -454,6 +455,7 @@ pub fn semantic_diagnostics(
continue;
},
AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
+ AnyDiagnostic::MethodCallIllegalSizedBound(d) => handlers::method_call_illegal_sized_bound::method_call_illegal_sized_bound(&ctx, &d),
AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
AnyDiagnostic::MismatchedArrayPatLen(d) => handlers::mismatched_array_pat_len::mismatched_array_pat_len(&ctx, &d),
AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),