Unnamed repository; edit this file 'description' to name the repository.
feat: add diagnostic for E0033
WaterWhisperer 10 days ago
parent 462d95c · commit 8eaf7af
-rw-r--r--crates/hir-ty/src/infer.rs5
-rw-r--r--crates/hir-ty/src/infer/pat.rs25
-rw-r--r--crates/hir-ty/src/infer/unify.rs1
-rw-r--r--crates/hir/src/diagnostics.rs11
-rw-r--r--crates/ide-diagnostics/src/handlers/cannot_implicitly_deref_trait_object.rs53
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
6 files changed, 85 insertions, 12 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 7e5fdfdd81..2df2789a2e 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -405,6 +405,11 @@ pub enum InferenceDiagnostic {
expr: ExprId,
found: StoredTy,
},
+ CannotImplicitlyDerefTraitObject {
+ #[type_visitable(ignore)]
+ pat: PatId,
+ found: StoredTy,
+ },
CannotIndexInto {
#[type_visitable(ignore)]
expr: ExprId,
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index f1af8a0b73..c36c29d6c7 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -959,22 +959,23 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
local_ty
}
- fn check_dereferenceable(&self, expected: Ty<'db>, inner: PatId) -> Result<(), ()> {
+ fn check_dereferenceable(
+ &mut self,
+ expected: Ty<'db>,
+ pat: PatId,
+ inner: PatId,
+ ) -> Result<(), ()> {
if let Pat::Bind { .. } = self.store[inner]
&& let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
&& let TyKind::Dynamic(..) = pointee_ty.kind()
{
// This is "x = dyn SomeTrait" being reduced from
// "let &x = &dyn SomeTrait" or "let box x = Box<dyn SomeTrait>", an error.
- // FIXME: Emit an error. rustc emits this message:
- const _CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\
-This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
-pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \
-this type has no compile-time size. Therefore, all accesses to trait types must be through \
-pointers. If you encounter this error you should try to avoid dereferencing the pointer.
-
-You can read more about trait objects in the Trait Objects section of the Reference: \
-https://doc.rust-lang.org/reference/types.html#trait-objects";
+ self.push_diagnostic(InferenceDiagnostic::CannotImplicitlyDerefTraitObject {
+ pat,
+ found: expected.store(),
+ });
+ return Err(());
}
Ok(())
}
@@ -1260,7 +1261,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
) -> Ty<'db> {
let interner = self.interner();
let (box_ty, inner_ty) = self
- .check_dereferenceable(expected, inner)
+ .check_dereferenceable(expected, pat, inner)
.map(|()| {
// Here, `demand::subtype` is good enough, but I don't
// think any errors can be introduced by using `demand::eqtype`.
@@ -1473,7 +1474,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects";
}
}
- let (ref_ty, inner_ty) = match self.check_dereferenceable(expected, inner) {
+ let (ref_ty, inner_ty) = match self.check_dereferenceable(expected, pat, inner) {
Ok(()) => {
// `demand::subtype` would be good enough, but using `eqtype` turns
// out to be equally general. See (note_1) for details.
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 393b404cde..4c808714d9 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -578,6 +578,7 @@ pub(super) mod resolve_completely {
self.resolve_completely(diagnostic);
if let InferenceDiagnostic::CannotBeDereferenced { found: ty, .. }
+ | InferenceDiagnostic::CannotImplicitlyDerefTraitObject { found: ty, .. }
| InferenceDiagnostic::CannotIndexInto { found: ty, .. }
| InferenceDiagnostic::ExpectedFunction { found: ty, .. }
| InferenceDiagnostic::ExpectedArrayOrSlicePat { found: ty, .. }
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index f5b1463f6f..f3188c9aad 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -104,6 +104,7 @@ diagnostics![AnyDiagnostic<'db> ->
AwaitOutsideOfAsync,
BreakOutsideOfLoop,
CannotBeDereferenced<'db>,
+ CannotImplicitlyDerefTraitObject<'db>,
CannotIndexInto<'db>,
CastToUnsized<'db>,
ExpectedArrayOrSlicePat<'db>,
@@ -335,6 +336,12 @@ pub struct CannotBeDereferenced<'db> {
}
#[derive(Debug)]
+pub struct CannotImplicitlyDerefTraitObject<'db> {
+ pub pat: InFile<ExprOrPatPtr>,
+ pub found: Type<'db>,
+}
+
+#[derive(Debug)]
pub struct CannotIndexInto<'db> {
pub expr: InFile<ExprOrPatPtr>,
pub found: Type<'db>,
@@ -973,6 +980,10 @@ impl<'db> AnyDiagnostic<'db> {
let expr = expr_syntax(*expr)?;
CannotBeDereferenced { expr, found: new_ty(found.as_ref()) }.into()
}
+ InferenceDiagnostic::CannotImplicitlyDerefTraitObject { pat, found } => {
+ let pat = pat_syntax(*pat)?.map(Into::into);
+ CannotImplicitlyDerefTraitObject { pat, found: new_ty(found.as_ref()) }.into()
+ }
InferenceDiagnostic::CannotIndexInto { expr, found } => {
let expr = expr_syntax(*expr)?;
CannotIndexInto { expr, found: new_ty(found.as_ref()) }.into()
diff --git a/crates/ide-diagnostics/src/handlers/cannot_implicitly_deref_trait_object.rs b/crates/ide-diagnostics/src/handlers/cannot_implicitly_deref_trait_object.rs
new file mode 100644
index 0000000000..eca14144dd
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/cannot_implicitly_deref_trait_object.rs
@@ -0,0 +1,53 @@
+use hir::HirDisplay;
+
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: cannot-implicitly-deref-trait-object
+//
+// This diagnostic is triggered when a pointer to a trait object is implicitly
+// dereferenced by a pattern.
+pub(crate) fn cannot_implicitly_deref_trait_object(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::CannotImplicitlyDerefTraitObject<'_>,
+) -> Diagnostic {
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcHardError("E0033"),
+ format!(
+ "type `{}` cannot be dereferenced",
+ d.found.display(ctx.sema.db, ctx.display_target)
+ ),
+ d.pat.map(Into::into),
+ )
+ .stable()
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn trait_object_pattern_deref() {
+ check_diagnostics(
+ r#"
+trait Trait {}
+
+fn f(x: &dyn Trait) {
+ let &ref _y = x;
+ //^^^^^^^ error: type `&(dyn Trait + 'static)` cannot be dereferenced
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn allows_sized_ref_pattern_deref() {
+ check_diagnostics(
+ r#"
+fn f(x: &i32) {
+ let &ref _y = x;
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 18251bc8a2..aec68b55c7 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -34,6 +34,7 @@ mod handlers {
pub(crate) mod bad_rtn;
pub(crate) mod break_outside_of_loop;
pub(crate) mod cannot_be_dereferenced;
+ pub(crate) mod cannot_implicitly_deref_trait_object;
pub(crate) mod cannot_index_into;
pub(crate) mod duplicate_field;
pub(crate) mod elided_lifetimes_in_path;
@@ -436,6 +437,7 @@ pub fn semantic_diagnostics(
let d = match diag {
AnyDiagnostic::AwaitOutsideOfAsync(d) => handlers::await_outside_of_async::await_outside_of_async(&ctx, &d),
AnyDiagnostic::CannotBeDereferenced(d) => handlers::cannot_be_dereferenced::cannot_be_dereferenced(&ctx, &d),
+ AnyDiagnostic::CannotImplicitlyDerefTraitObject(d) => handlers::cannot_implicitly_deref_trait_object::cannot_implicitly_deref_trait_object(&ctx, &d),
AnyDiagnostic::CannotIndexInto(d) => handlers::cannot_index_into::cannot_index_into(&ctx, &d),
AnyDiagnostic::CastToUnsized(d) => handlers::invalid_cast::cast_to_unsized(&ctx, &d),
AnyDiagnostic::ArrayPatternWithoutFixedLength(d) => {