Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22372 from MavenRain/fix-illegal-sized-bound
method-resolution: emit error for method calls with illegal Sized b…
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 4 | ||||
| -rw-r--r-- | crates/hir-ty/src/method_resolution.rs | 4 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 9 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/method_call_illegal_sized_bound.rs | 78 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 2 |
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), |