Skip to content

Commit 2147146

Browse files
Merge pull request #22145 from ada4a/diag-E0735
feat: add diagnostic for E0735
2 parents 322fc57 + f71d1fe commit 2147146

7 files changed

Lines changed: 71 additions & 12 deletions

File tree

crates/hir-ty/src/lower/diagnostics.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ pub enum PathLoweringDiagnostic {
8181
def: GenericDefId,
8282
expected_count: u32,
8383
},
84+
/// Generic defaults are not allowed to refer to `Self`.
85+
GenericDefaultRefersToSelf {
86+
/// Index of the `Self` segment.
87+
segment: u32,
88+
},
8489
}
8590

8691
#[derive(Debug, Clone, Copy, PartialEq, Eq)]

crates/hir-ty/src/lower/path.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,10 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
300300
prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy);
301301

302302
if self.ctx.lowering_param_default.is_some() {
303-
// Generic defaults are not allowed to refer to `Self`.
304-
// FIXME: Emit an error.
303+
let segment = self.current_segment_u32();
304+
self.on_diagnostic(PathLoweringDiagnostic::GenericDefaultRefersToSelf {
305+
segment,
306+
});
305307
return false;
306308
}
307309
}

crates/hir-ty/src/tests.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,12 @@ fn check_impl(
8888
let file_range = FileRange { file_id, range };
8989
if only_types {
9090
types.insert(file_range, expected);
91-
} else if expected.starts_with("type: ") {
92-
types.insert(file_range, expected.trim_start_matches("type: ").to_owned());
91+
} else if let Some(ty) = expected.strip_prefix("type: ") {
92+
types.insert(file_range, ty.to_owned());
9393
} else if expected.starts_with("expected") {
9494
mismatches.insert(file_range, expected);
95-
} else if expected.starts_with("adjustments:") {
96-
adjustments.insert(
97-
file_range,
98-
expected.trim_start_matches("adjustments:").trim().to_owned(),
99-
);
95+
} else if let Some(adjs) = expected.strip_prefix("adjustments:") {
96+
adjustments.insert(file_range, adjs.trim().to_owned());
10097
} else {
10198
panic!("unexpected annotation: {expected} @ {range:?}");
10299
}

crates/hir-ty/src/tests/diagnostics.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use crate::tests::check_no_mismatches;
2-
3-
use super::check;
1+
use super::{check, check_no_mismatches};
42

53
#[test]
64
fn function_return_type_mismatch_1() {

crates/hir/src/diagnostics.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ diagnostics![AnyDiagnostic<'db> ->
5757
BreakOutsideOfLoop,
5858
CastToUnsized<'db>,
5959
ExpectedFunction<'db>,
60+
GenericDefaultRefersToSelf,
6061
InactiveCode,
6162
IncoherentImpl,
6263
IncorrectCase,
@@ -465,6 +466,12 @@ pub struct IncorrectGenericsOrder {
465466
pub expected_kind: GenericArgKind,
466467
}
467468

469+
#[derive(Debug)]
470+
pub struct GenericDefaultRefersToSelf {
471+
/// The `Self` segment.
472+
pub segment: InFile<AstPtr<ast::PathSegment>>,
473+
}
474+
468475
impl<'db> AnyDiagnostic<'db> {
469476
pub(crate) fn body_validation_diagnostic(
470477
db: &'db dyn HirDatabase,
@@ -888,6 +895,11 @@ impl<'db> AnyDiagnostic<'db> {
888895
}
889896
.into()
890897
}
898+
PathLoweringDiagnostic::GenericDefaultRefersToSelf { segment } => {
899+
let segment = hir_segment_to_ast_segment(&path.value, segment)?;
900+
let segment = path.with_value(AstPtr::new(&segment));
901+
GenericDefaultRefersToSelf { segment }.into()
902+
}
891903
})
892904
}
893905

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
2+
3+
// Diagnostic: generic-default-refers-to-self
4+
//
5+
// This diagnostic is shown when a generic default refers to `Self`
6+
pub(crate) fn generic_default_refers_to_self(
7+
ctx: &DiagnosticsContext<'_>,
8+
d: &hir::GenericDefaultRefersToSelf,
9+
) -> Diagnostic {
10+
Diagnostic::new_with_syntax_node_ptr(
11+
ctx,
12+
DiagnosticCode::RustcHardError("E0735"),
13+
"generic parameters cannot use `Self` in their defaults",
14+
d.segment.map(Into::into),
15+
)
16+
.stable()
17+
}
18+
19+
#[cfg(test)]
20+
mod tests {
21+
use crate::tests::check_diagnostics;
22+
23+
#[test]
24+
fn plain_self() {
25+
check_diagnostics(
26+
r#"
27+
struct Foo<T = Self>(T);
28+
// ^^^^ error: generic parameters cannot use `Self` in their defaults
29+
"#,
30+
);
31+
}
32+
33+
#[test]
34+
fn self_as_generic() {
35+
check_diagnostics(
36+
r#"
37+
struct Wrapper<T>(T);
38+
struct Foo<T = Wrapper<Self>>(T);
39+
// ^^^^ error: generic parameters cannot use `Self` in their defaults
40+
"#,
41+
);
42+
}
43+
}

crates/ide-diagnostics/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ mod handlers {
3535
pub(crate) mod elided_lifetimes_in_path;
3636
pub(crate) mod expected_function;
3737
pub(crate) mod generic_args_prohibited;
38+
pub(crate) mod generic_default_refers_to_self;
3839
pub(crate) mod inactive_code;
3940
pub(crate) mod incoherent_impl;
4041
pub(crate) mod incorrect_case;
@@ -477,6 +478,7 @@ pub fn semantic_diagnostics(
477478
AnyDiagnostic::IncorrectGenericsOrder(d) => handlers::incorrect_generics_order::incorrect_generics_order(&ctx, &d),
478479
AnyDiagnostic::MissingLifetime(d) => handlers::missing_lifetime::missing_lifetime(&ctx, &d),
479480
AnyDiagnostic::ElidedLifetimesInPath(d) => handlers::elided_lifetimes_in_path::elided_lifetimes_in_path(&ctx, &d),
481+
AnyDiagnostic::GenericDefaultRefersToSelf(d) => handlers::generic_default_refers_to_self::generic_default_refers_to_self(&ctx, &d),
480482
};
481483
res.push(d)
482484
}

0 commit comments

Comments
 (0)