Unnamed repository; edit this file 'description' to name the repository.
feat: add diagnostic for E0608
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 5 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 12 | ||||
| -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_index_into.rs | 77 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/mutability_errors.rs | 2 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 2 |
7 files changed, 107 insertions, 3 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 86a4f613b3..db437788c0 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -401,6 +401,11 @@ pub enum InferenceDiagnostic { expr: ExprId, found: StoredTy, }, + CannotIndexInto { + #[type_visitable(ignore)] + expr: ExprId, + found: StoredTy, + }, TypedHole { #[type_visitable(ignore)] expr: ExprId, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 3cff0ea896..0a1bfb41d8 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -729,8 +729,16 @@ impl<'db> InferenceContext<'_, 'db> { self.table.select_obligations_where_possible(); trait_element_ty } - // FIXME: Report an error. - None => self.types.types.error, + None => { + if self.lang_items.Index.is_some() && self.lang_items.Index_index.is_some() + { + self.push_diagnostic(InferenceDiagnostic::CannotIndexInto { + expr: tgt_expr, + found: base_t.store(), + }); + } + self.types.types.error + } } } Expr::Tuple { exprs, .. } => { diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 6500eb213c..393b404cde 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::CannotIndexInto { found: ty, .. } | InferenceDiagnostic::ExpectedFunction { found: ty, .. } | InferenceDiagnostic::ExpectedArrayOrSlicePat { found: ty, .. } | InferenceDiagnostic::UnresolvedField { receiver: ty, .. } diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index a399df8276..6b07834231 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -104,6 +104,7 @@ diagnostics![AnyDiagnostic<'db> -> AwaitOutsideOfAsync, BreakOutsideOfLoop, CannotBeDereferenced<'db>, + CannotIndexInto<'db>, CastToUnsized<'db>, ExpectedArrayOrSlicePat<'db>, ExpectedFunction<'db>, @@ -328,6 +329,12 @@ pub struct CannotBeDereferenced<'db> { } #[derive(Debug)] +pub struct CannotIndexInto<'db> { + pub expr: InFile<ExprOrPatPtr>, + pub found: Type<'db>, +} + +#[derive(Debug)] pub struct ExplicitDropMethodUse { pub expr_or_path: Either<InFile<AstPtr<ast::MethodCallExpr>>, InFile<AstPtr<ast::Path>>>, } @@ -947,6 +954,10 @@ impl<'db> AnyDiagnostic<'db> { let expr = expr_syntax(*expr)?; CannotBeDereferenced { expr, found: Type::new(db, def, found.as_ref()) }.into() } + InferenceDiagnostic::CannotIndexInto { expr, found } => { + let expr = expr_syntax(*expr)?; + CannotIndexInto { expr, found: Type::new(db, def, found.as_ref()) }.into() + } InferenceDiagnostic::TyDiagnostic { source, diag } => { let source_map = match source { InferenceTyDiagnosticSource::Body => source_map, diff --git a/crates/ide-diagnostics/src/handlers/cannot_index_into.rs b/crates/ide-diagnostics/src/handlers/cannot_index_into.rs new file mode 100644 index 0000000000..1e42313b4a --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/cannot_index_into.rs @@ -0,0 +1,77 @@ +use hir::HirDisplay; + +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: cannot-index-into +// +// This diagnostic is triggered if indexing is used on a type that cannot be +// indexed. +pub(crate) fn cannot_index_into( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::CannotIndexInto<'_>, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0608"), + format!( + "cannot index into a value of type `{}`", + d.found.display(ctx.sema.db, ctx.display_target) + ), + d.expr.map(Into::into), + ) + .stable() +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn cannot_index_into() { + check_diagnostics( + r#" +//- minicore: index +fn f() { + let x = 1i32; + let _ = x[0]; + //^^^^ error: cannot index into a value of type `i32` +} +"#, + ); + } + + #[test] + fn allows_array_indexing() { + check_diagnostics( + r#" +//- minicore: index, slice +fn f() { + let x = [1i32, 2]; + let _ = x[0]; +} +"#, + ); + } + + #[test] + fn allows_overloaded_indexing() { + check_diagnostics( + r#" +//- minicore: index +struct Bag(i32); + +impl core::ops::Index<usize> for Bag { + type Output = i32; + + fn index(&self, _: usize) -> &Self::Output { + &self.0 + } +} + +fn f(x: Bag) { + let _ = x[0]; +} +"#, + ); + } +} diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 31becd1d74..49aa6d7bd9 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -1313,7 +1313,7 @@ fn main() { fn regression_20662() { check_diagnostics( r#" -//- minicore: index +//- minicore: index, slice pub trait A: core::ops::IndexMut<usize> { type T: A; } diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index c8972316f9..11ee669af0 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -33,6 +33,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_index_into; pub(crate) mod duplicate_field; pub(crate) mod elided_lifetimes_in_path; pub(crate) mod expected_array_or_slice_pat; @@ -433,6 +434,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::CannotIndexInto(d) => handlers::cannot_index_into::cannot_index_into(&ctx, &d), AnyDiagnostic::CastToUnsized(d) => handlers::invalid_cast::cast_to_unsized(&ctx, &d), AnyDiagnostic::ExpectedArrayOrSlicePat(d) => handlers::expected_array_or_slice_pat::expected_array_or_slice_pat(&ctx, &d), AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d), |