Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 5 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/pat.rs | 25 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/unify.rs | 1 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 11 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/cannot_implicitly_deref_trait_object.rs | 53 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 2 |
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) => { |