Skip to content

Commit e83fb4c

Browse files
committed
method-resolution: emit error for method calls with illegal Sized bound
Resolves a FIXME at hir-ty/src/method_resolution.rs:151 in lookup_method_including_private that previously allowed calls like `x.cant_call()` on a `&dyn Foo` receiver to type-check without diagnostic when `cant_call(&self) where Self: Sized`, even though the `Self: Sized` predicate cannot be satisfied by the trait object. The existing predicates_require_illegal_sized_bound check in confirm.rs already correctly identifies this case (it iterates elaborated predicates and looks for `Self: Sized` clauses with a `TyKind::Dynamic` self type). Adds an InferenceDiagnostic::MethodCallIllegalSizedBound variant, plumbs the cooked diagnostic through hir, and renders it as RustcHardError E0277. Tests: trait-object call with Sized-bounded method errors; trait-object call to dyn-safe method does not; concrete-type call to a Sized-bounded method does not. Part of #22140. Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
1 parent 6eb7777 commit e83fb4c

5 files changed

Lines changed: 95 additions & 2 deletions

File tree

crates/hir-ty/src/infer.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,10 @@ pub enum InferenceDiagnostic {
438438
#[type_visitable(ignore)]
439439
def: GenericDefId,
440440
},
441+
MethodCallIllegalSizedBound {
442+
#[type_visitable(ignore)]
443+
call_expr: ExprId,
444+
},
441445
MethodCallIncorrectGenericsOrder {
442446
#[type_visitable(ignore)]
443447
expr: ExprId,

crates/hir-ty/src/method_resolution.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use stdx::impl_from;
3535
use triomphe::Arc;
3636

3737
use crate::{
38-
Span, all_super_traits,
38+
InferenceDiagnostic, Span, all_super_traits,
3939
db::HirDatabase,
4040
infer::{InferenceContext, unify::InferenceTable},
4141
lower::GenericPredicates,
@@ -148,7 +148,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
148148
debug!("result = {:?}", result);
149149

150150
if result.illegal_sized_bound {
151-
// FIXME: Report an error.
151+
self.push_diagnostic(InferenceDiagnostic::MethodCallIllegalSizedBound { call_expr });
152152
}
153153

154154
self.write_expr_adj(receiver, result.adjustments);

crates/hir/src/diagnostics.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ diagnostics![AnyDiagnostic<'db> ->
120120
MacroError,
121121
MacroExpansionParseError,
122122
MalformedDerive,
123+
MethodCallIllegalSizedBound,
123124
MismatchedArgCount,
124125
MismatchedTupleStructPatArgCount,
125126
MissingFields,
@@ -595,6 +596,11 @@ pub struct InvalidLhsOfAssignment {
595596
pub lhs: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
596597
}
597598

599+
#[derive(Debug)]
600+
pub struct MethodCallIllegalSizedBound {
601+
pub call_expr: InFile<ExprOrPatPtr>,
602+
}
603+
598604
#[derive(Debug)]
599605
pub struct PatternArgInExternFn {
600606
pub node: InFile<AstPtr<ast::Pat>>,
@@ -984,6 +990,9 @@ impl<'db> AnyDiagnostic<'db> {
984990
let lhs = expr_syntax(lhs)?;
985991
InvalidLhsOfAssignment { lhs }.into()
986992
}
993+
&InferenceDiagnostic::MethodCallIllegalSizedBound { call_expr } => {
994+
MethodCallIllegalSizedBound { call_expr: expr_syntax(call_expr)? }.into()
995+
}
987996
&InferenceDiagnostic::TypeMustBeKnown { at_point, ref top_term } => {
988997
let at_point = span_syntax(at_point)?;
989998
let top_term = top_term.as_ref().map(|top_term| match top_term.as_ref().kind() {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
2+
3+
// Diagnostic: method-call-illegal-sized-bound
4+
//
5+
// This diagnostic is triggered when a method is called on a trait-object
6+
// receiver but the method's predicates require `Self: Sized`, which the
7+
// trait object cannot satisfy.
8+
pub(crate) fn method_call_illegal_sized_bound(
9+
ctx: &DiagnosticsContext<'_, '_>,
10+
d: &hir::MethodCallIllegalSizedBound,
11+
) -> Diagnostic {
12+
Diagnostic::new_with_syntax_node_ptr(
13+
ctx,
14+
DiagnosticCode::RustcHardError("E0277"),
15+
"the method cannot be invoked on a trait object because its `Self: Sized` bound is not satisfied",
16+
d.call_expr.map(|it| it.into()),
17+
)
18+
.stable()
19+
}
20+
21+
#[cfg(test)]
22+
mod tests {
23+
use crate::tests::check_diagnostics;
24+
25+
#[test]
26+
fn sized_bound_method_on_trait_object_errors() {
27+
check_diagnostics(
28+
r#"
29+
//- minicore: sized
30+
trait Foo {
31+
fn cant_call(&self) where Self: Sized;
32+
}
33+
34+
fn f(x: &dyn Foo) {
35+
x.cant_call();
36+
//^^^^^^^^^^^^^ error: the method cannot be invoked on a trait object because its `Self: Sized` bound is not satisfied
37+
}
38+
"#,
39+
);
40+
}
41+
42+
#[test]
43+
fn method_without_sized_bound_on_trait_object_does_not_error() {
44+
check_diagnostics(
45+
r#"
46+
//- minicore: sized
47+
trait Foo {
48+
fn dyn_safe(&self);
49+
}
50+
51+
fn f(x: &dyn Foo) {
52+
x.dyn_safe();
53+
}
54+
"#,
55+
);
56+
}
57+
58+
#[test]
59+
fn sized_bound_method_on_concrete_type_does_not_error() {
60+
check_diagnostics(
61+
r#"
62+
//- minicore: sized
63+
trait Foo {
64+
fn cant_dispatch(&self) where Self: Sized;
65+
}
66+
67+
struct S;
68+
impl Foo for S {
69+
fn cant_dispatch(&self) {}
70+
}
71+
72+
fn f(s: &S) {
73+
s.cant_dispatch();
74+
}
75+
"#,
76+
);
77+
}
78+
}

crates/ide-diagnostics/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ mod handlers {
5050
pub(crate) mod invalid_range_pat_type;
5151
pub(crate) mod macro_error;
5252
pub(crate) mod malformed_derive;
53+
pub(crate) mod method_call_illegal_sized_bound;
5354
pub(crate) mod mismatched_arg_count;
5455
pub(crate) mod mismatched_array_pat_len;
5556
pub(crate) mod missing_fields;
@@ -454,6 +455,7 @@ pub fn semantic_diagnostics(
454455
continue;
455456
},
456457
AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
458+
AnyDiagnostic::MethodCallIllegalSizedBound(d) => handlers::method_call_illegal_sized_bound::method_call_illegal_sized_bound(&ctx, &d),
457459
AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
458460
AnyDiagnostic::MismatchedArrayPatLen(d) => handlers::mismatched_array_pat_len::mismatched_array_pat_len(&ctx, &d),
459461
AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),

0 commit comments

Comments
 (0)