From 90cbd0bfb4dd973b69cbea9509073eba4a33f6ce Mon Sep 17 00:00:00 2001 From: Sky Date: Fri, 28 Jun 2024 14:05:45 -0400 Subject: [PATCH 01/15] impl FusedIterator and a size hint for the error sources iter --- library/core/src/error.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 150e4f3f31857..ca8983d4cbcfe 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -1008,8 +1008,15 @@ impl<'a> Iterator for Source<'a> { self.current = self.current.and_then(Error::source); current } + + fn size_hint(&self) -> (usize, Option) { + if self.current.is_some() { (1, None) } else { (0, Some(0)) } + } } +#[unstable(feature = "error_iter", issue = "58520")] +impl<'a> crate::iter::FusedIterator for Source<'a> {} + #[stable(feature = "error_by_ref", since = "1.51.0")] impl<'a, T: Error + ?Sized> Error for &'a T { #[allow(deprecated, deprecated_in_future)] From 321eba5e8fb56d7823b7feb0986528a7488eb10c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 8 Jul 2024 18:02:14 -0400 Subject: [PATCH 02/15] Update f16/f128 FIXMEs that needed (NEG_)INFINITY --- .../half-open-range-pats-semantics.rs | 42 ++++++++----------- .../half-open-range-pats-thir-lower-empty.rs | 8 +++- ...lf-open-range-pats-thir-lower-empty.stderr | 40 +++++++++++------- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs index 38ade060cb135..a89b229251287 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs @@ -45,9 +45,8 @@ fn range_to_inclusive() { // FIXME(f16_f128): remove gate when ABI issues are resolved #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { - // FIXME(f16_f128): enable infinity tests when constants are available - // assert!(yes!(f16::NEG_INFINITY, ..=f16::NEG_INFINITY)); - // assert!(yes!(f16::NEG_INFINITY, ..=1.0f16)); + assert!(yes!(f16::NEG_INFINITY, ..=f16::NEG_INFINITY)); + assert!(yes!(f16::NEG_INFINITY, ..=1.0f16)); assert!(yes!(1.5f16, ..=1.5f16)); assert!(!yes!(1.6f16, ..=-1.5f16)); } @@ -68,9 +67,8 @@ fn range_to_inclusive() { // FIXME(f16_f128): remove gate when ABI issues are resolved #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { - // FIXME(f16_f128): enable infinity tests when constants are available - // assert!(yes!(f128::NEG_INFINITY, ..=f128::NEG_INFINITY)); - // assert!(yes!(f128::NEG_INFINITY, ..=1.0f128)); + assert!(yes!(f128::NEG_INFINITY, ..=f128::NEG_INFINITY)); + assert!(yes!(f128::NEG_INFINITY, ..=1.0f128)); assert!(yes!(1.5f128, ..=1.5f128)); assert!(!yes!(1.6f128, ..=-1.5f128)); } @@ -111,8 +109,7 @@ fn range_to() { // FIXME(f16_f128): remove gate when ABI issues are resolved #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { - // FIXME(f16_f128): enable infinity tests when constants are available - // assert!(yes!(f16::NEG_INFINITY, ..1.0f16)); + assert!(yes!(f16::NEG_INFINITY, ..1.0f16)); assert!(!yes!(1.5f16, ..1.5f16)); const E16: f16 = 1.5f16 + f16::EPSILON; assert!(yes!(1.5f16, ..E16)); @@ -137,8 +134,7 @@ fn range_to() { // FIXME(f16_f128): remove gate when ABI issues are resolved #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { - // FIXME(f16_f128): enable infinity tests when constants are available - // assert!(yes!(f128::NEG_INFINITY, ..1.0f128)); + assert!(yes!(f128::NEG_INFINITY, ..1.0f128)); assert!(!yes!(1.5f128, ..1.5f128)); const E128: f128 = 1.5f128 + f128::EPSILON; assert!(yes!(1.5f128, ..E128)); @@ -181,15 +177,14 @@ fn range_from() { // FIXME(f16_f128): remove gate when ABI issues are resolved #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { - // FIXME(f16_f128): enable infinity tests when constants are available - // assert!(yes!(f16::NEG_INFINITY, f16::NEG_INFINITY..)); - // assert!(yes!(f16::INFINITY, f16::NEG_INFINITY..)); - // assert!(!yes!(f16::NEG_INFINITY, 1.0f16..)); - // assert!(yes!(f16::INFINITY, 1.0f16..)); + assert!(yes!(f16::NEG_INFINITY, f16::NEG_INFINITY..)); + assert!(yes!(f16::INFINITY, f16::NEG_INFINITY..)); + assert!(!yes!(f16::NEG_INFINITY, 1.0f16..)); + assert!(yes!(f16::INFINITY, 1.0f16..)); assert!(!yes!(1.0f16 - f16::EPSILON, 1.0f16..)); assert!(yes!(1.0f16, 1.0f16..)); - // assert!(yes!(f16::INFINITY, 1.0f16..)); - // assert!(yes!(f16::INFINITY, f16::INFINITY..)); + assert!(yes!(f16::INFINITY, 1.0f16..)); + assert!(yes!(f16::INFINITY, f16::INFINITY..)); } // f32; `X..` @@ -216,15 +211,14 @@ fn range_from() { // FIXME(f16_f128): remove gate when ABI issues are resolved #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { - // FIXME(f16_f128): enable infinity tests when constants are available - // assert!(yes!(f128::NEG_INFINITY, f128::NEG_INFINITY..)); - // assert!(yes!(f128::INFINITY, f128::NEG_INFINITY..)); - // assert!(!yes!(f128::NEG_INFINITY, 1.0f128..)); - // assert!(yes!(f128::INFINITY, 1.0f128..)); + assert!(yes!(f128::NEG_INFINITY, f128::NEG_INFINITY..)); + assert!(yes!(f128::INFINITY, f128::NEG_INFINITY..)); + assert!(!yes!(f128::NEG_INFINITY, 1.0f128..)); + assert!(yes!(f128::INFINITY, 1.0f128..)); assert!(!yes!(1.0f128 - f128::EPSILON, 1.0f128..)); assert!(yes!(1.0f128, 1.0f128..)); - // assert!(yes!(f128::INFINITY, 1.0f128..)); - // assert!(yes!(f128::INFINITY, f128::INFINITY..)); + assert!(yes!(f128::INFINITY, 1.0f128..)); + assert!(yes!(f128::INFINITY, f128::INFINITY..)); } } diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs index a35bb51acbca3..6a0115de01605 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs @@ -1,3 +1,6 @@ +#![feature(f128)] +#![feature(f16)] + macro_rules! m { ($s:expr, $($t:tt)+) => { match $s { $($t)+ => {} } @@ -27,11 +30,14 @@ fn main() { m!(0, ..i128::MIN); //~^ ERROR lower range bound must be less than upper - // FIXME(f16_f128): add tests when NEG_INFINITY is available + m!(0f16, ..f16::NEG_INFINITY); + //~^ ERROR lower range bound must be less than upper m!(0f32, ..f32::NEG_INFINITY); //~^ ERROR lower range bound must be less than upper m!(0f64, ..f64::NEG_INFINITY); //~^ ERROR lower range bound must be less than upper + m!(0f128, ..f128::NEG_INFINITY); + //~^ ERROR lower range bound must be less than upper m!('a', ..'\u{0}'); //~^ ERROR lower range bound must be less than upper diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr index fb2f1841a6dfc..f414a6bfd1830 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr @@ -1,81 +1,93 @@ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:8:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:11:11 | LL | m!(0, ..u8::MIN); | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:10:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:13:11 | LL | m!(0, ..u16::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:12:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:15:11 | LL | m!(0, ..u32::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11 | LL | m!(0, ..u64::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:16:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:19:11 | LL | m!(0, ..u128::MIN); | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:19:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:22:11 | LL | m!(0, ..i8::MIN); | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:21:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:24:11 | LL | m!(0, ..i16::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:26:11 | LL | m!(0, ..i32::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:25:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:28:11 | LL | m!(0, ..i64::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11 | LL | m!(0, ..i128::MIN); | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:31:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14 + | +LL | m!(0f16, ..f16::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^ + +error[E0579]: lower range bound must be less than upper + --> $DIR/half-open-range-pats-thir-lower-empty.rs:35:14 | LL | m!(0f32, ..f32::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:37:14 | LL | m!(0f64, ..f64::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:13 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:39:15 + | +LL | m!(0f128, ..f128::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0579]: lower range bound must be less than upper + --> $DIR/half-open-range-pats-thir-lower-empty.rs:42:13 | LL | m!('a', ..'\u{0}'); | ^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0579`. From ec662e7606c9d03de536bbf46dbdeb0d6140bc85 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:12:31 +0200 Subject: [PATCH 03/15] `#[doc(alias)]`'s doc: say that ASCII spaces are allowed --- src/doc/rustdoc/src/advanced-features.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 1733c8fc9a246..4a1c091625320 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -80,7 +80,8 @@ pub struct BigX; Then, when looking for it through the `rustdoc` search, if you enter "x" or "big", search will show the `BigX` struct first. -There are some limitations on the doc alias names though: you can't use `"` or whitespace. +There are some limitations on the doc alias names though: they cannot contain quotes (`'`, `"`) +or most whitespace. ASCII space is allowed if it does not start or end the alias. You can add multiple aliases at the same time by using a list: From 96a791662aa30320fa05c84535667d1ed58e42da Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 8 Jul 2024 18:04:01 -0400 Subject: [PATCH 04/15] Update a f16/f128 FIXME to be more accurate --- compiler/rustc_lint/src/types.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f3a904022e9ed..c0364b3571642 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -563,7 +563,8 @@ fn lint_literal<'tcx>( ty::Float(t) => { let is_infinite = match lit.node { ast::LitKind::Float(v, _) => match t { - // FIXME(f16_f128): add this check once we have library support + // FIXME(f16_f128): add this check once `is_infinite` is reliable (ABI + // issues resolved). ty::FloatTy::F16 => Ok(false), ty::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite), ty::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite), From 7097dbc50c086b652c37374cfbed6a40bf30efaf Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 9 Jul 2024 09:10:19 +0200 Subject: [PATCH 05/15] exhaustively destructure external constraints --- compiler/rustc_next_trait_solver/src/solve/mod.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 24055d6cd832b..c65c5851e9b4f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -48,12 +48,20 @@ enum GoalEvaluationKind { Nested, } +// FIXME(trait-system-refactor-initiative#117): we don't detect whether a response +// ended up pulling down any universes. fn has_no_inference_or_external_constraints( response: ty::Canonical>, ) -> bool { - response.value.external_constraints.region_constraints.is_empty() - && response.value.var_values.is_identity() - && response.value.external_constraints.opaque_types.is_empty() + let ExternalConstraintsData { + ref region_constraints, + ref opaque_types, + ref normalization_nested_goals, + } = *response.value.external_constraints; + response.value.var_values.is_identity() + && region_constraints.is_empty() + && opaque_types.is_empty() + && normalization_nested_goals.is_empty() } impl<'a, D, I> EvalCtxt<'a, D> From e38109d7f0e48a995c73a70a084630560bbcbcc0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 9 Jul 2024 09:22:58 +0200 Subject: [PATCH 06/15] use `update_parent_goal` for lazy updates --- .../src/solve/search_graph.rs | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 2cd3b10f56adb..f8a50913f05f8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -139,18 +139,11 @@ impl SearchGraph { self.mode } - /// Pops the highest goal from the stack, lazily updating the - /// the next goal in the stack. - /// - /// Directly popping from the stack instead of using this method - /// would cause us to not track overflow and recursion depth correctly. - fn pop_stack(&mut self) -> StackEntry { - let elem = self.stack.pop().unwrap(); - if let Some(last) = self.stack.raw.last_mut() { - last.reached_depth = last.reached_depth.max(elem.reached_depth); - last.encountered_overflow |= elem.encountered_overflow; + fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) { + if let Some(parent) = self.stack.raw.last_mut() { + parent.reached_depth = parent.reached_depth.max(reached_depth); + parent.encountered_overflow |= encountered_overflow; } - elem } pub(super) fn is_empty(&self) -> bool { @@ -364,7 +357,7 @@ impl SearchGraph { } debug!("canonical cycle overflow"); - let current_entry = self.pop_stack(); + let current_entry = self.stack.pop().unwrap(); debug_assert!(current_entry.has_been_used.is_empty()); let result = Self::response_no_constraints(cx, input, Certainty::overflow(false)); (current_entry, result) @@ -372,6 +365,8 @@ impl SearchGraph { let proof_tree = inspect.finalize_canonical_goal_evaluation(cx); + self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow); + // We're now done with this goal. In case this goal is involved in a larger cycle // do not remove it from the provisional cache and update its provisional result. // We only add the root of cycles to the global cache. @@ -441,14 +436,9 @@ impl SearchGraph { } } - // Update the reached depth of the current goal to make sure - // its state is the same regardless of whether we've used the - // global cache or not. + // Adjust the parent goal as if we actually computed this goal. let reached_depth = self.stack.next_index().plus(additional_depth); - if let Some(last) = self.stack.raw.last_mut() { - last.reached_depth = last.reached_depth.max(reached_depth); - last.encountered_overflow |= encountered_overflow; - } + self.update_parent_goal(reached_depth, encountered_overflow); Some(result) } @@ -477,7 +467,7 @@ impl SearchGraph { F: FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, { let result = prove_goal(self, inspect); - let stack_entry = self.pop_stack(); + let stack_entry = self.stack.pop().unwrap(); debug_assert_eq!(stack_entry.input, input); // If the current goal is not the root of a cycle, we are done. From fd9a92542cb85bf8a0d3948f26a8d81fbd16093c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 5 Jul 2024 09:16:00 +0000 Subject: [PATCH 07/15] Automatically taint when reporting errors from ItemCtxt --- compiler/rustc_hir_analysis/src/collect.rs | 8 +- .../src/hir_ty_lowering/bounds.rs | 39 +++--- .../src/hir_ty_lowering/errors.rs | 43 +++---- .../src/hir_ty_lowering/generics.rs | 42 +++--- .../src/hir_ty_lowering/lint.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 57 ++++----- .../src/hir_ty_lowering/object_safety.rs | 4 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 4 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 4 + .../rustc_hir_typeck/src/method/confirm.rs | 4 +- .../associated-types-eq-expr-path.rs | 5 +- .../associated-types-eq-expr-path.stderr | 22 +--- .../assoc_const_as_type_argument.rs | 1 - .../assoc_const_as_type_argument.stderr | 18 +-- .../const-arg-in-const-arg.min.stderr | 120 ++++++------------ .../const-generics/const-arg-in-const-arg.rs | 4 - .../issues/issue-62878.min.stderr | 30 +---- tests/ui/const-generics/issues/issue-62878.rs | 2 - ...const-expression-suggest-missing-braces.rs | 1 - ...t-expression-suggest-missing-braces.stderr | 38 ++---- .../min_const_generics/macro-fail.rs | 3 - .../min_const_generics/macro-fail.stderr | 61 ++------- .../const-generics/suggest_const_for_array.rs | 2 - .../suggest_const_for_array.stderr | 31 +---- .../generic-function-item-where-type.rs | 1 - .../generic-function-item-where-type.stderr | 11 +- 26 files changed, 183 insertions(+), 374 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 843e4d41e001e..f83d74ecd3887 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -18,7 +18,9 @@ use rustc_ast::Recovered; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228}; +use rustc_errors::{ + struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, StashKey, E0228, +}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, walk_generics, Visitor}; @@ -370,6 +372,10 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.tcx } + fn dcx(&self) -> DiagCtxtHandle<'_> { + self.tcx.dcx().taintable_handle(&self.tainted_by_errors) + } + fn item_def_id(&self) -> LocalDefId { self.item_def_id } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 802215b2843ee..a1feef9e15b7e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -76,7 +76,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } if unbounds.len() > 1 { - tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds { + self.dcx().emit_err(errors::MultipleRelaxedDefaultBounds { spans: unbounds.iter().map(|ptr| ptr.span).collect(), }); } @@ -90,7 +90,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { continue; } // There was a `?Trait` bound, but it was not `?Sized`; warn. - tcx.dcx().span_warn( + self.dcx().span_warn( unbound.span, "relaxing a default bound only does something for `?Sized`; \ all other traits are not bound by default", @@ -310,7 +310,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { duplicates .entry(assoc_item.def_id) .and_modify(|prev_span| { - tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified { + self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified { span: constraint.span, prev_span: *prev_span, item_name: constraint.ident, @@ -338,7 +338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .into(), ty::GenericParamDefKind::Type { .. } => { let guar = *emitted_bad_param_err.get_or_insert_with(|| { - tcx.dcx().emit_err( + self.dcx().emit_err( crate::errors::ReturnTypeNotationIllegalParam::Type { span: path_span, param_span: tcx.def_span(param.def_id), @@ -349,7 +349,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } ty::GenericParamDefKind::Const { .. } => { let guar = *emitted_bad_param_err.get_or_insert_with(|| { - tcx.dcx().emit_err( + self.dcx().emit_err( crate::errors::ReturnTypeNotationIllegalParam::Const { span: path_span, param_span: tcx.def_span(param.def_id), @@ -371,7 +371,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { alias_ty.into() } else { - return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { + return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { span: constraint.span, ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output), fn_span: tcx.hir().span_if_local(assoc_item.def_id), @@ -417,7 +417,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let ty = alias_term .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args)); let ty = - check_assoc_const_binding_type(tcx, constraint.ident, ty, constraint.hir_id); + check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id); tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); } @@ -426,7 +426,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match constraint.kind { hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => { - return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound { + return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound { span: constraint.span, })); } @@ -462,7 +462,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { late_bound_in_term, |br_name| { struct_span_code_err!( - tcx.dcx(), + self.dcx(), constraint.span, E0582, "binding for associated type `{}` references {}, \ @@ -519,7 +519,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// [^1]: . fn check_assoc_const_binding_type<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &dyn HirTyLowerer<'tcx>, assoc_const: Ident, ty: ty::Binder<'tcx, Ty<'tcx>>, hir_id: hir::HirId, @@ -536,13 +536,14 @@ fn check_assoc_const_binding_type<'tcx>( } let mut collector = GenericParamAndBoundVarCollector { - tcx, + cx, params: Default::default(), vars: Default::default(), depth: ty::INNERMOST, }; let mut guar = ty.visit_with(&mut collector).break_value(); + let tcx = cx.tcx(); let ty_note = ty .make_suggestable(tcx, false, None) .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty }); @@ -556,7 +557,7 @@ fn check_assoc_const_binding_type<'tcx>( for index in collector.params { let param = generics.param_at(index as _, tcx); let is_self_param = param.name == rustc_span::symbol::kw::SelfUpper; - guar.get_or_insert(tcx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding { + guar.get_or_insert(cx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding { span: assoc_const.span, assoc_const, param_name: param.name, @@ -574,7 +575,7 @@ fn check_assoc_const_binding_type<'tcx>( })); } for (var_def_id, var_name) in collector.vars { - guar.get_or_insert(tcx.dcx().emit_err( + guar.get_or_insert(cx.dcx().emit_err( crate::errors::EscapingBoundVarInTyOfAssocConstBinding { span: assoc_const.span, assoc_const, @@ -590,14 +591,14 @@ fn check_assoc_const_binding_type<'tcx>( Ty::new_error(tcx, guar) } -struct GenericParamAndBoundVarCollector<'tcx> { - tcx: TyCtxt<'tcx>, +struct GenericParamAndBoundVarCollector<'a, 'tcx> { + cx: &'a dyn HirTyLowerer<'tcx>, params: FxIndexSet, vars: FxIndexSet<(DefId, Symbol)>, depth: ty::DebruijnIndex, } -impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'tcx> { +impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 'tcx> { type Result = ControlFlow; fn visit_binder>>( @@ -620,7 +621,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'tcx> ty::BoundTyKind::Param(def_id, name) => (def_id, name), ty::BoundTyKind::Anon => { let reported = self - .tcx + .cx .dcx() .delayed_bug(format!("unexpected anon bound ty: {:?}", bt.var)); return ControlFlow::Break(reported); @@ -643,7 +644,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'tcx> ty::BrNamed(def_id, name) => (def_id, name), ty::BrAnon | ty::BrEnv => { let guar = self - .tcx + .cx .dcx() .delayed_bug(format!("unexpected bound region kind: {:?}", br.kind)); return ControlFlow::Break(guar); @@ -661,7 +662,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'tcx> self.params.insert(param.index); } ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => { - let guar = self.tcx.dcx().delayed_bug("unexpected escaping late-bound const var"); + let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var"); return ControlFlow::Break(guar); } _ if ct.has_param() || ct.has_bound_vars() => return ct.super_visit_with(self), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 2d240699105d6..d8bbe403f1f50 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -46,7 +46,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; } - self.tcx().dcx().emit_err(MissingTypeParams { + self.dcx().emit_err(MissingTypeParams { span, def_span: self.tcx().def_span(def_id), span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(), @@ -109,7 +109,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if is_impl { let trait_name = self.tcx().def_path_str(trait_def_id); - self.tcx().dcx().emit_err(ManualImplementation { span, trait_name }); + self.dcx().emit_err(ManualImplementation { span, trait_name }); } } @@ -156,7 +156,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if is_dummy { err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span }); - return tcx.dcx().emit_err(err); + return self.dcx().emit_err(err); } let all_candidate_names: Vec<_> = all_candidates() @@ -174,7 +174,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_kind: assoc_kind_str, suggested_name, }); - return tcx.dcx().emit_err(err); + return self.dcx().emit_err(err); } // If we didn't find a good item in the supertraits (or couldn't get @@ -239,10 +239,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_kind: assoc_kind_str, suggested_name, }); - return tcx.dcx().emit_err(err); + return self.dcx().emit_err(err); } - let mut err = tcx.dcx().create_err(err); + let mut err = self.dcx().create_err(err); if suggest_constraining_type_param( tcx, generics, @@ -264,7 +264,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } return err.emit(); } - return tcx.dcx().emit_err(err); + return self.dcx().emit_err(err); } } @@ -291,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span }); } - tcx.dcx().emit_err(err) + self.dcx().emit_err(err) } fn complain_about_assoc_kind_mismatch( @@ -347,7 +347,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { (ident.span, None, assoc_kind, assoc_item.kind) }; - tcx.dcx().emit_err(errors::AssocKindMismatch { + self.dcx().emit_err(errors::AssocKindMismatch { span, expected: super::assoc_kind_str(expected), got: super::assoc_kind_str(got), @@ -366,8 +366,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { traits: &[String], name: Symbol, ) -> ErrorGuaranteed { - let mut err = - struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type"); + let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type"); if self .tcx() .resolutions(()) @@ -475,7 +474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> ErrorGuaranteed { let mut err = struct_span_code_err!( - self.tcx().dcx(), + self.dcx(), name.span, E0034, "multiple applicable items in scope" @@ -576,7 +575,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), name.span, E0220, "associated type `{name}` not found for `{self_ty}` in the current scope" @@ -662,7 +661,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds.sort(); bounds.dedup(); - let mut err = tcx.dcx().struct_span_err( + let mut err = self.dcx().struct_span_err( name.span, format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied") ); @@ -829,7 +828,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_bound_spans.sort(); let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), trait_bound_spans, E0191, "the value of the associated type{} {} must be specified", @@ -1012,7 +1011,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .next() { let reported = - struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type") + struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type") .with_span_suggestion_verbose( ident2.span.to(ident3.span), format!("there is an associated function with a similar name: `{name}`"), @@ -1120,7 +1119,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let last_span = *arg_spans.last().unwrap(); let span: MultiSpan = arg_spans.into(); let mut err = struct_span_code_err!( - self.tcx().dcx(), + self.dcx(), span, E0109, "{kind} arguments are not allowed on {this_type}", @@ -1139,11 +1138,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, regular_traits: &Vec>, ) -> ErrorGuaranteed { - let tcx = self.tcx(); let first_trait = ®ular_traits[0]; let additional_trait = ®ular_traits[1]; let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), additional_trait.bottom().1, E0225, "only auto traits can be used as additional traits in a trait object" @@ -1186,7 +1184,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .find(|&trait_ref| tcx.is_trait_alias(trait_ref)) .map(|trait_ref| tcx.def_span(trait_ref)); let reported = - tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }); + self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }); self.set_tainted_by_errors(reported); reported } @@ -1194,11 +1192,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Emit an error for the given associated item constraint. pub fn prohibit_assoc_item_constraint( - tcx: TyCtxt<'_>, + cx: &dyn HirTyLowerer<'_>, constraint: &hir::AssocItemConstraint<'_>, segment: Option<(DefId, &hir::PathSegment<'_>, Span)>, ) -> ErrorGuaranteed { - let mut err = tcx.dcx().create_err(AssocItemConstraintsNotAllowedHere { + let tcx = cx.tcx(); + let mut err = cx.dcx().create_err(AssocItemConstraintsNotAllowedHere { span: constraint.span, fn_trait_expansion: if let Some((_, segment, span)) = segment && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 90836f0a54f45..b1c77db9f3700 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -1,4 +1,4 @@ -use super::IsMethodCall; +use super::{HirTyLowerer, IsMethodCall}; use crate::errors::wrong_number_of_generic_args::{GenericArgsInfo, WrongNumberOfGenericArgs}; use crate::hir_ty_lowering::{ errors::prohibit_assoc_item_constraint, ExplicitLateBound, GenericArgCountMismatch, @@ -13,7 +13,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; use rustc_middle::ty::{ - self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt, + self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, }; use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS; use rustc_span::symbol::{kw, sym}; @@ -22,15 +22,16 @@ use smallvec::SmallVec; /// Report an error that a generic argument did not match the generic parameter that was /// expected. fn generic_arg_mismatch_err( - tcx: TyCtxt<'_>, + cx: &dyn HirTyLowerer<'_>, arg: &GenericArg<'_>, param: &GenericParamDef, possible_ordering_error: bool, help: Option, ) -> ErrorGuaranteed { + let tcx = cx.tcx(); let sess = tcx.sess; let mut err = struct_span_code_err!( - tcx.dcx(), + cx.dcx(), arg.span(), E0747, "{} provided when a {} was expected", @@ -171,7 +172,7 @@ fn generic_arg_mismatch_err( /// - `inferred_kind`: if no parameter was provided, and inference /// is enabled, then creates a suitable inference variable. pub fn lower_generic_args<'tcx: 'a, 'a>( - tcx: TyCtxt<'tcx>, + cx: &dyn HirTyLowerer<'tcx>, def_id: DefId, parent_args: &[ty::GenericArg<'tcx>], has_self: bool, @@ -179,6 +180,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( arg_count: &GenericArgCountResult, ctx: &mut impl GenericArgsLowerer<'a, 'tcx>, ) -> GenericArgsRef<'tcx> { + let tcx = cx.tcx(); // Collect the segments of the path; we need to instantiate arguments // for parameters throughout the entire path (wherever there are // generic parameters). @@ -326,7 +328,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( param_types_present.dedup(); generic_arg_mismatch_err( - tcx, + cx, arg, param, !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()), @@ -381,7 +383,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( assert_eq!(kind, "lifetime"); let (provided_arg, param) = force_infer_lt.expect("lifetimes ought to have been inferred"); - generic_arg_mismatch_err(tcx, provided_arg, param, false, None); + generic_arg_mismatch_err(cx, provided_arg, param, false, None); } break; @@ -405,7 +407,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( /// Checks that the correct number of generic arguments have been provided. /// Used specifically for function calls. pub fn check_generic_arg_count_for_call( - tcx: TyCtxt<'_>, + cx: &dyn HirTyLowerer<'_>, def_id: DefId, generics: &ty::Generics, seg: &hir::PathSegment<'_>, @@ -416,14 +418,14 @@ pub fn check_generic_arg_count_for_call( IsMethodCall::No => GenericArgPosition::Value, }; let has_self = generics.parent.is_none() && generics.has_self; - check_generic_arg_count(tcx, def_id, seg, generics, gen_pos, has_self) + check_generic_arg_count(cx, def_id, seg, generics, gen_pos, has_self) } /// Checks that the correct number of generic arguments have been provided. /// This is used both for datatypes and function calls. -#[instrument(skip(tcx, gen_pos), level = "debug")] +#[instrument(skip(cx, gen_pos), level = "debug")] pub(crate) fn check_generic_arg_count( - tcx: TyCtxt<'_>, + cx: &dyn HirTyLowerer<'_>, def_id: DefId, seg: &hir::PathSegment<'_>, gen_params: &ty::Generics, @@ -456,11 +458,11 @@ pub(crate) fn check_generic_arg_count( if gen_pos != GenericArgPosition::Type && let Some(c) = gen_args.constraints.first() { - prohibit_assoc_item_constraint(tcx, c, None); + prohibit_assoc_item_constraint(cx, c, None); } let explicit_late_bound = - prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos); + prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos); let mut invalid_args = vec![]; @@ -486,8 +488,8 @@ pub(crate) fn check_generic_arg_count( GenericArgsInfo::MissingLifetimes { num_missing_args } }; - let reported = tcx.dcx().emit_err(WrongNumberOfGenericArgs::new( - tcx, + let reported = cx.dcx().emit_err(WrongNumberOfGenericArgs::new( + cx.tcx(), gen_args_info, seg, gen_params, @@ -571,9 +573,9 @@ pub(crate) fn check_generic_arg_count( debug!(?gen_args_info); let reported = gen_args.has_err().unwrap_or_else(|| { - tcx.dcx() + cx.dcx() .create_err(WrongNumberOfGenericArgs::new( - tcx, + cx.tcx(), gen_args_info, seg, gen_params, @@ -621,7 +623,7 @@ pub(crate) fn check_generic_arg_count( /// Prohibits explicit lifetime arguments if late-bound lifetime parameters /// are present. This is used both for datatypes and function calls. pub(crate) fn prohibit_explicit_late_bound_lifetimes( - tcx: TyCtxt<'_>, + cx: &dyn HirTyLowerer<'_>, def: &ty::Generics, args: &hir::GenericArgs<'_>, position: GenericArgPosition, @@ -642,13 +644,13 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( if position == GenericArgPosition::Value && args.num_lifetime_params() != param_counts.lifetimes { - struct_span_code_err!(tcx.dcx(), span, E0794, "{}", msg) + struct_span_code_err!(cx.dcx(), span, E0794, "{}", msg) .with_span_note(span_late, note) .emit(); } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note); - tcx.node_span_lint( + cx.tcx().node_span_lint( LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].hir_id(), multispan, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 240a749de96a6..1ba45067ec8c9 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -60,7 +60,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let msg = "trait objects must include the `dyn` keyword"; let label = "add `dyn` keyword before this trait"; let mut diag = - rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg); + rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg); if self_ty.span.can_be_used_for_suggestions() && !self.maybe_suggest_impl_trait(self_ty, &mut diag) { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 02db0352daafa..e8a4ab103bd2b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -28,7 +28,8 @@ use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{ - codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError, + codes::*, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, + FatalError, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -102,6 +103,8 @@ pub enum RegionInferReason<'a> { pub trait HirTyLowerer<'tcx> { fn tcx(&self) -> TyCtxt<'tcx>; + fn dcx(&self) -> DiagCtxtHandle<'_>; + /// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered. fn item_def_id(&self) -> LocalDefId; @@ -323,7 +326,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::BoundConstness::NotConst, ); if let Some(c) = item_segment.args().constraints.first() { - prohibit_assoc_item_constraint(self.tcx(), c, Some((def_id, item_segment, span))); + prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span))); } args } @@ -394,7 +397,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } let mut arg_count = check_generic_arg_count( - tcx, + self, def_id, segment, generics, @@ -562,7 +565,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { && generics.has_self && !tcx.has_attr(def_id, sym::const_trait) { - let reported = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { + let reported = self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span, modifier: constness.as_str(), }); @@ -579,7 +582,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { incorrect_args: &arg_count.correct, }; let args = lower_generic_args( - tcx, + self, def_id, parent_args, self_ty.is_some(), @@ -609,7 +612,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::BoundConstness::NotConst, ); if let Some(c) = item_segment.args().constraints.first() { - prohibit_assoc_item_constraint(self.tcx(), c, Some((item_def_id, item_segment, span))); + prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span))); } args } @@ -715,7 +718,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // would not be well-formed! if polarity != ty::PredicatePolarity::Positive { assert!( - self.tcx().dcx().has_errors().is_some(), + self.dcx().has_errors().is_some(), "negative trait bounds should not have assoc item constraints", ); continue; @@ -761,11 +764,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { constness, ); if let Some(c) = trait_segment.args().constraints.first() { - prohibit_assoc_item_constraint( - self.tcx(), - c, - Some((trait_def_id, trait_segment, span)), - ); + prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span))); } ty::TraitRef::new_from_args(self.tcx(), trait_def_id, generic_args) } @@ -887,7 +886,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let assoc_kind_str = assoc_kind_str(assoc_kind); let ty_param_name = &ty_param_name.to_string(); - let mut err = tcx.dcx().create_err(crate::errors::AmbiguousAssocItem { + let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem { span, assoc_kind: assoc_kind_str, assoc_name, @@ -1059,7 +1058,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // trait reference. let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else { // A cycle error occurred, most likely. - tcx.dcx().span_bug(span, "expected cycle error"); + self.dcx().span_bug(span, "expected cycle error"); }; self.probe_single_bound_for_assoc_item( @@ -1089,10 +1088,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let reported = if variant_resolution.is_some() { // Variant in type position let msg = format!("expected type, found variant `{assoc_ident}`"); - tcx.dcx().span_err(span, msg) + self.dcx().span_err(span, msg) } else if qself_ty.is_enum() { let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), assoc_ident.span, E0599, "no variant named `{}` found for enum `{}`", @@ -1133,7 +1132,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { // `::Assoc` makes no sense. struct_span_code_err!( - tcx.dcx(), + self.dcx(), tcx.def_span(alias_ty.def_id), E0667, "`impl Trait` is not allowed in path parameters" @@ -1404,7 +1403,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); if !tcx.visibility(item_def_id).is_accessible_from(scope, tcx) { - let reported = tcx.dcx().emit_err(crate::errors::AssocItemIsPrivate { + let reported = self.dcx().emit_err(crate::errors::AssocItemIsPrivate { span, kind: tcx.def_descr(item_def_id), name: ident, @@ -1564,7 +1563,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for segment in segments { // Only emit the first error to avoid overloading the user with error messages. if let Some(c) = segment.args().constraints.first() { - return Err(prohibit_assoc_item_constraint(self.tcx(), c, None)); + return Err(prohibit_assoc_item_constraint(self, c, None)); } } @@ -1824,7 +1823,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `AlwaysApplicable` impl needs a `T: ?Sized` bound for // this to compile if we were to normalize here. if forbid_generic && ty.has_param() { - let mut err = tcx.dcx().struct_span_err( + let mut err = self.dcx().struct_span_err( path.span, "generic `Self` types are currently not permitted in anonymous constants", ); @@ -1894,7 +1893,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); Ty::new_error( self.tcx(), - self.tcx().dcx().span_delayed_bug(span, "incorrect resolution for `Self`"), + self.dcx().span_delayed_bug(span, "incorrect resolution for `Self`"), ) } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), @@ -1967,7 +1966,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let sig_span = self.tcx().def_span(sig_id); let mut try_emit = |descr| { if emit { - self.tcx().dcx().emit_err(crate::errors::NotSupportedDelegation { + self.dcx().emit_err(crate::errors::NotSupportedDelegation { span, descr, callee_span: sig_span, @@ -2017,7 +2016,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Ty<'tcx> { if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output) { - let e = self.tcx().dcx().span_delayed_bug(span, "not supported delegation case"); + let e = self.dcx().span_delayed_bug(span, "not supported delegation case"); self.set_tainted_by_errors(e); return Ty::new_error(self.tcx(), e); }; @@ -2183,7 +2182,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let ty = self.lower_ty(ty); let pat_ty = match pat.kind { hir::PatKind::Wild => { - let err = tcx.dcx().emit_err(WildPatTy { span: pat.span }); + let err = self.dcx().emit_err(WildPatTy { span: pat.span }); Ty::new_error(tcx, err) } hir::PatKind::Range(start, end, include_end) => { @@ -2363,7 +2362,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { struct_span_code_err!( - tcx.dcx(), + self.dcx(), decl.output.span(), E0581, "return type references {}, which is not constrained by the fn input types", @@ -2414,11 +2413,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } #[instrument(level = "trace", skip(self, generate_err))] - fn validate_late_bound_regions( - &self, + fn validate_late_bound_regions<'cx>( + &'cx self, constrained_regions: FxHashSet, referenced_regions: FxHashSet, - generate_err: impl Fn(&str) -> Diag<'tcx>, + generate_err: impl Fn(&str) -> Diag<'cx>, ) { for br in referenced_regions.difference(&constrained_regions) { let br_name = match *br { @@ -2484,7 +2483,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // error. let r = derived_region_bounds[0]; if derived_region_bounds[1..].iter().any(|r1| r != *r1) { - self.set_tainted_by_errors(tcx.dcx().emit_err(AmbiguousLifetimeBound { span })); + self.dcx().emit_err(AmbiguousLifetimeBound { span }); } Some(r) } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index df69c1938dd75..bbb37be5c9f3f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -236,7 +236,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_misc_error(tcx).into() } else if arg.walk().any(|arg| arg == dummy_self.into()) { references_self = true; - let guar = tcx.dcx().span_delayed_bug( + let guar = self.dcx().span_delayed_bug( span, "trait object trait bounds reference `Self`", ); @@ -263,7 +263,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if references_self { let def_id = i.bottom().0.def_id(); let reported = struct_span_code_err!( - tcx.dcx(), + self.dcx(), i.bottom().1, E0038, "the {} `{}` cannot be made into an object", diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 5450243417f7f..f74859e4d9a16 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parameter's value explicitly, so we have to do some error- // checking here. let arg_count = - check_generic_arg_count_for_call(tcx, def_id, generics, seg, IsMethodCall::No); + check_generic_arg_count_for_call(self, def_id, generics, seg, IsMethodCall::No); if let ExplicitLateBound::Yes = arg_count.explicit_late_bound { explicit_late_bound = ExplicitLateBound::Yes; @@ -1375,7 +1375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let args_raw = self_ctor_args.unwrap_or_else(|| { lower_generic_args( - tcx, + self, def_id, &[], has_self, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index da68da029b417..1de2935ecaf73 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -217,6 +217,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { self.tcx } + fn dcx(&self) -> DiagCtxtHandle<'_> { + self.root_ctxt.dcx() + } + fn item_def_id(&self) -> LocalDefId { self.body_id } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 02844bcadac6e..e574fde14fb0a 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -354,7 +354,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let generics = self.tcx.generics_of(pick.item.def_id); let arg_count_correct = check_generic_arg_count_for_call( - self.tcx, + self.fcx, pick.item.def_id, generics, seg, @@ -425,7 +425,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { } let args = lower_generic_args( - self.tcx, + self.fcx, pick.item.def_id, parent_args, false, diff --git a/tests/ui/associated-types/associated-types-eq-expr-path.rs b/tests/ui/associated-types/associated-types-eq-expr-path.rs index 67831f913039a..3179811274e81 100644 --- a/tests/ui/associated-types/associated-types-eq-expr-path.rs +++ b/tests/ui/associated-types/associated-types-eq-expr-path.rs @@ -7,11 +7,12 @@ trait Foo { impl Foo for isize { type A = usize; - fn bar() -> isize { 42 } + fn bar() -> isize { + 42 + } } pub fn main() { let x: isize = Foo::::bar(); //~^ ERROR associated item constraints are not allowed here - //~| ERROR cannot call } diff --git a/tests/ui/associated-types/associated-types-eq-expr-path.stderr b/tests/ui/associated-types/associated-types-eq-expr-path.stderr index 4f28b3cb2de33..bbe021fbc55f0 100644 --- a/tests/ui/associated-types/associated-types-eq-expr-path.stderr +++ b/tests/ui/associated-types/associated-types-eq-expr-path.stderr @@ -1,25 +1,9 @@ error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-expr-path.rs:14:26 + --> $DIR/associated-types-eq-expr-path.rs:16:26 | LL | let x: isize = Foo::::bar(); | ^^^^^^^^^ associated item constraint not allowed here -error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type - --> $DIR/associated-types-eq-expr-path.rs:14:20 - | -LL | fn bar() -> isize; - | ------------------ `Foo::bar` defined here -... -LL | let x: isize = Foo::::bar(); - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait - | -help: use the fully-qualified path to the only available implementation - | -LL - let x: isize = Foo::::bar(); -LL + let x: isize = >::bar(); - | - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0229, E0790. -For more information about an error, try `rustc --explain E0229`. +For more information about this error, try `rustc --explain E0229`. diff --git a/tests/ui/const-generics/assoc_const_as_type_argument.rs b/tests/ui/const-generics/assoc_const_as_type_argument.rs index bec6102417c5f..ffc7f116a94ef 100644 --- a/tests/ui/const-generics/assoc_const_as_type_argument.rs +++ b/tests/ui/const-generics/assoc_const_as_type_argument.rs @@ -8,7 +8,6 @@ fn foo() { bar::<::ASSOC>(); //~^ ERROR: expected associated type, found associated constant `Trait::ASSOC` //~| ERROR: unresolved item provided when a constant was expected - //~| ERROR type annotations needed } fn main() {} diff --git a/tests/ui/const-generics/assoc_const_as_type_argument.stderr b/tests/ui/const-generics/assoc_const_as_type_argument.stderr index 53edc19b28ca2..ac00954613506 100644 --- a/tests/ui/const-generics/assoc_const_as_type_argument.stderr +++ b/tests/ui/const-generics/assoc_const_as_type_argument.stderr @@ -15,19 +15,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | bar::<{ ::ASSOC }>(); | + + -error[E0284]: type annotations needed - --> $DIR/assoc_const_as_type_argument.rs:8:5 - | -LL | bar::<::ASSOC>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar` - | -note: required by a const generic parameter in `bar` - --> $DIR/assoc_const_as_type_argument.rs:5:8 - | -LL | fn bar() {} - | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0284, E0575, E0747. -For more information about an error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0575, E0747. +For more information about an error, try `rustc --explain E0575`. diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr index 2ea9d6b35b451..ce7fce2599360 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr @@ -17,7 +17,7 @@ LL | let _: [u8; bar::()]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:19:23 + --> $DIR/const-arg-in-const-arg.rs:18:23 | LL | let _: [u8; faz::<'a>(&())]; | ^^ cannot perform const operation using `'a` @@ -26,7 +26,7 @@ LL | let _: [u8; faz::<'a>(&())]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:21:23 + --> $DIR/const-arg-in-const-arg.rs:20:23 | LL | let _: [u8; baz::<'a>(&())]; | ^^ cannot perform const operation using `'a` @@ -35,7 +35,7 @@ LL | let _: [u8; baz::<'a>(&())]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:22:23 + --> $DIR/const-arg-in-const-arg.rs:21:23 | LL | let _: [u8; faz::<'b>(&())]; | ^^ cannot perform const operation using `'b` @@ -44,7 +44,7 @@ LL | let _: [u8; faz::<'b>(&())]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:24:23 + --> $DIR/const-arg-in-const-arg.rs:23:23 | LL | let _: [u8; baz::<'b>(&())]; | ^^ cannot perform const operation using `'b` @@ -53,7 +53,7 @@ LL | let _: [u8; baz::<'b>(&())]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:27:23 + --> $DIR/const-arg-in-const-arg.rs:26:23 | LL | let _ = [0; bar::()]; | ^ cannot perform const operation using `N` @@ -62,7 +62,7 @@ LL | let _ = [0; bar::()]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:30:23 + --> $DIR/const-arg-in-const-arg.rs:28:23 | LL | let _ = [0; faz::<'a>(&())]; | ^^ cannot perform const operation using `'a` @@ -71,7 +71,7 @@ LL | let _ = [0; faz::<'a>(&())]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:32:23 + --> $DIR/const-arg-in-const-arg.rs:30:23 | LL | let _ = [0; baz::<'a>(&())]; | ^^ cannot perform const operation using `'a` @@ -80,7 +80,7 @@ LL | let _ = [0; baz::<'a>(&())]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:33:23 + --> $DIR/const-arg-in-const-arg.rs:31:23 | LL | let _ = [0; faz::<'b>(&())]; | ^^ cannot perform const operation using `'b` @@ -89,7 +89,7 @@ LL | let _ = [0; faz::<'b>(&())]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:35:23 + --> $DIR/const-arg-in-const-arg.rs:33:23 | LL | let _ = [0; baz::<'b>(&())]; | ^^ cannot perform const operation using `'b` @@ -98,7 +98,7 @@ LL | let _ = [0; baz::<'b>(&())]; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:36:24 + --> $DIR/const-arg-in-const-arg.rs:34:24 | LL | let _: Foo<{ foo::() }>; | ^ cannot perform const operation using `T` @@ -107,7 +107,7 @@ LL | let _: Foo<{ foo::() }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:37:24 + --> $DIR/const-arg-in-const-arg.rs:35:24 | LL | let _: Foo<{ bar::() }>; | ^ cannot perform const operation using `N` @@ -116,7 +116,7 @@ LL | let _: Foo<{ bar::() }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:40:24 + --> $DIR/const-arg-in-const-arg.rs:37:24 | LL | let _: Foo<{ faz::<'a>(&()) }>; | ^^ cannot perform const operation using `'a` @@ -125,7 +125,7 @@ LL | let _: Foo<{ faz::<'a>(&()) }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:42:24 + --> $DIR/const-arg-in-const-arg.rs:39:24 | LL | let _: Foo<{ baz::<'a>(&()) }>; | ^^ cannot perform const operation using `'a` @@ -134,7 +134,7 @@ LL | let _: Foo<{ baz::<'a>(&()) }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:43:24 + --> $DIR/const-arg-in-const-arg.rs:40:24 | LL | let _: Foo<{ faz::<'b>(&()) }>; | ^^ cannot perform const operation using `'b` @@ -143,7 +143,7 @@ LL | let _: Foo<{ faz::<'b>(&()) }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:45:24 + --> $DIR/const-arg-in-const-arg.rs:42:24 | LL | let _: Foo<{ baz::<'b>(&()) }>; | ^^ cannot perform const operation using `'b` @@ -152,7 +152,7 @@ LL | let _: Foo<{ baz::<'b>(&()) }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:46:27 + --> $DIR/const-arg-in-const-arg.rs:43:27 | LL | let _ = Foo::<{ foo::() }>; | ^ cannot perform const operation using `T` @@ -161,7 +161,7 @@ LL | let _ = Foo::<{ foo::() }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:47:27 + --> $DIR/const-arg-in-const-arg.rs:44:27 | LL | let _ = Foo::<{ bar::() }>; | ^ cannot perform const operation using `N` @@ -170,7 +170,7 @@ LL | let _ = Foo::<{ bar::() }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:50:27 + --> $DIR/const-arg-in-const-arg.rs:46:27 | LL | let _ = Foo::<{ faz::<'a>(&()) }>; | ^^ cannot perform const operation using `'a` @@ -179,7 +179,7 @@ LL | let _ = Foo::<{ faz::<'a>(&()) }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:52:27 + --> $DIR/const-arg-in-const-arg.rs:48:27 | LL | let _ = Foo::<{ baz::<'a>(&()) }>; | ^^ cannot perform const operation using `'a` @@ -188,7 +188,7 @@ LL | let _ = Foo::<{ baz::<'a>(&()) }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:53:27 + --> $DIR/const-arg-in-const-arg.rs:49:27 | LL | let _ = Foo::<{ faz::<'b>(&()) }>; | ^^ cannot perform const operation using `'b` @@ -197,7 +197,7 @@ LL | let _ = Foo::<{ faz::<'b>(&()) }>; = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/const-arg-in-const-arg.rs:55:27 + --> $DIR/const-arg-in-const-arg.rs:51:27 | LL | let _ = Foo::<{ baz::<'b>(&()) }>; | ^^ cannot perform const operation using `'b` @@ -216,20 +216,8 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _: [u8; bar::<{ N }>()]; | + + -error[E0284]: type annotations needed - --> $DIR/const-arg-in-const-arg.rs:16:17 - | -LL | let _: [u8; bar::()]; - | ^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar` - | -note: required by a const generic parameter in `bar` - --> $DIR/const-arg-in-const-arg.rs:9:14 - | -LL | const fn bar() -> usize { N } - | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar` - error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:19:23 + --> $DIR/const-arg-in-const-arg.rs:18:23 | LL | let _: [u8; faz::<'a>(&())]; | ^^ @@ -241,7 +229,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:22:23 + --> $DIR/const-arg-in-const-arg.rs:21:23 | LL | let _: [u8; faz::<'b>(&())]; | ^^ @@ -253,7 +241,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error[E0747]: unresolved item provided when a constant was expected - --> $DIR/const-arg-in-const-arg.rs:37:24 + --> $DIR/const-arg-in-const-arg.rs:35:24 | LL | let _: Foo<{ bar::() }>; | ^ @@ -263,20 +251,8 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _: Foo<{ bar::<{ N }>() }>; | + + -error[E0284]: type annotations needed - --> $DIR/const-arg-in-const-arg.rs:37:18 - | -LL | let _: Foo<{ bar::() }>; - | ^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar` - | -note: required by a const generic parameter in `bar` - --> $DIR/const-arg-in-const-arg.rs:9:14 - | -LL | const fn bar() -> usize { N } - | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar` - error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:40:24 + --> $DIR/const-arg-in-const-arg.rs:37:24 | LL | let _: Foo<{ faz::<'a>(&()) }>; | ^^ @@ -288,7 +264,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:43:24 + --> $DIR/const-arg-in-const-arg.rs:40:24 | LL | let _: Foo<{ faz::<'b>(&()) }>; | ^^ @@ -300,7 +276,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error: constant expression depends on a generic parameter - --> $DIR/const-arg-in-const-arg.rs:26:17 + --> $DIR/const-arg-in-const-arg.rs:25:17 | LL | let _ = [0; foo::()]; | ^^^^^^^^^^ @@ -308,7 +284,7 @@ LL | let _ = [0; foo::()]; = note: this may fail depending on what value the parameter takes error[E0747]: unresolved item provided when a constant was expected - --> $DIR/const-arg-in-const-arg.rs:27:23 + --> $DIR/const-arg-in-const-arg.rs:26:23 | LL | let _ = [0; bar::()]; | ^ @@ -318,20 +294,8 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _ = [0; bar::<{ N }>()]; | + + -error[E0284]: type annotations needed - --> $DIR/const-arg-in-const-arg.rs:27:17 - | -LL | let _ = [0; bar::()]; - | ^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar` - | -note: required by a const generic parameter in `bar` - --> $DIR/const-arg-in-const-arg.rs:9:14 - | -LL | const fn bar() -> usize { N } - | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar` - error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:30:23 + --> $DIR/const-arg-in-const-arg.rs:28:23 | LL | let _ = [0; faz::<'a>(&())]; | ^^ @@ -343,7 +307,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:33:23 + --> $DIR/const-arg-in-const-arg.rs:31:23 | LL | let _ = [0; faz::<'b>(&())]; | ^^ @@ -355,7 +319,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error[E0747]: unresolved item provided when a constant was expected - --> $DIR/const-arg-in-const-arg.rs:47:27 + --> $DIR/const-arg-in-const-arg.rs:44:27 | LL | let _ = Foo::<{ bar::() }>; | ^ @@ -365,20 +329,8 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _ = Foo::<{ bar::<{ N }>() }>; | + + -error[E0284]: type annotations needed - --> $DIR/const-arg-in-const-arg.rs:47:21 - | -LL | let _ = Foo::<{ bar::() }>; - | ^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar` - | -note: required by a const generic parameter in `bar` - --> $DIR/const-arg-in-const-arg.rs:9:14 - | -LL | const fn bar() -> usize { N } - | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar` - error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:50:27 + --> $DIR/const-arg-in-const-arg.rs:46:27 | LL | let _ = Foo::<{ faz::<'a>(&()) }>; | ^^ @@ -390,7 +342,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:53:27 + --> $DIR/const-arg-in-const-arg.rs:49:27 | LL | let _ = Foo::<{ faz::<'b>(&()) }>; | ^^ @@ -401,7 +353,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: aborting due to 40 previous errors +error: aborting due to 36 previous errors -Some errors have detailed explanations: E0284, E0747, E0794. -For more information about an error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0747, E0794. +For more information about an error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/const-arg-in-const-arg.rs b/tests/ui/const-generics/const-arg-in-const-arg.rs index b95c63309f782..27b74489fe8e0 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.rs +++ b/tests/ui/const-generics/const-arg-in-const-arg.rs @@ -15,7 +15,6 @@ fn test<'a, 'b, T, const N: usize>() where &'b (): Sized { let _: [u8; foo::()]; //[min]~ ERROR generic parameters may not let _: [u8; bar::()]; //[min]~ ERROR generic parameters may not //[min]~^ ERROR unresolved item provided when a constant was expected - //[min]~| ERROR type annotations needed let _: [u8; faz::<'a>(&())]; //[min]~ ERROR generic parameters may not //[min]~^ ERROR cannot specify lifetime arguments let _: [u8; baz::<'a>(&())]; //[min]~ ERROR generic parameters may not @@ -26,7 +25,6 @@ fn test<'a, 'b, T, const N: usize>() where &'b (): Sized { let _ = [0; foo::()]; //[min]~ ERROR constant expression depends on a generic parameter let _ = [0; bar::()]; //[min]~ ERROR generic parameters may not //[min]~^ ERROR unresolved item provided when a constant was expected - //[min]~| ERROR type annotations needed let _ = [0; faz::<'a>(&())]; //[min]~ ERROR generic parameters may not //[min]~^ ERROR cannot specify lifetime arguments let _ = [0; baz::<'a>(&())]; //[min]~ ERROR generic parameters may not @@ -36,7 +34,6 @@ fn test<'a, 'b, T, const N: usize>() where &'b (): Sized { let _: Foo<{ foo::() }>; //[min]~ ERROR generic parameters may not let _: Foo<{ bar::() }>; //[min]~ ERROR generic parameters may not //[min]~^ ERROR unresolved item provided when a constant was expected - //[min]~| ERROR type annotations needed let _: Foo<{ faz::<'a>(&()) }>; //[min]~ ERROR generic parameters may not //[min]~^ ERROR cannot specify lifetime arguments let _: Foo<{ baz::<'a>(&()) }>; //[min]~ ERROR generic parameters may not @@ -46,7 +43,6 @@ fn test<'a, 'b, T, const N: usize>() where &'b (): Sized { let _ = Foo::<{ foo::() }>; //[min]~ ERROR generic parameters may not let _ = Foo::<{ bar::() }>; //[min]~ ERROR generic parameters may not //[min]~^ ERROR unresolved item provided when a constant was expected - //[min]~| ERROR type annotations needed let _ = Foo::<{ faz::<'a>(&()) }>; //[min]~ ERROR generic parameters may not //[min]~^ ERROR cannot specify lifetime arguments let _ = Foo::<{ baz::<'a>(&()) }>; //[min]~ ERROR generic parameters may not diff --git a/tests/ui/const-generics/issues/issue-62878.min.stderr b/tests/ui/const-generics/issues/issue-62878.min.stderr index 3fd50bbe29803..5205726d73845 100644 --- a/tests/ui/const-generics/issues/issue-62878.min.stderr +++ b/tests/ui/const-generics/issues/issue-62878.min.stderr @@ -30,31 +30,7 @@ help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable LL + #![feature(generic_arg_infer)] | -error[E0284]: type annotations needed - --> $DIR/issue-62878.rs:10:5 - | -LL | foo::<_, { [1] }>(); - | ^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `foo` - | -note: required by a const generic parameter in `foo` - --> $DIR/issue-62878.rs:5:8 - | -LL | fn foo() {} - | ^^^^^^^^^^^^^^ required by this const generic parameter in `foo` - -error[E0284]: type annotations needed - --> $DIR/issue-62878.rs:10:5 - | -LL | foo::<_, { [1] }>(); - | ^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `A` declared on the function `foo` - | -note: required by a const generic parameter in `foo` - --> $DIR/issue-62878.rs:5:24 - | -LL | fn foo() {} - | ^^^^^^^^^^^^^^^^ required by this const generic parameter in `foo` - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0284, E0747, E0770. -For more information about an error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0747, E0770. +For more information about an error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/issues/issue-62878.rs b/tests/ui/const-generics/issues/issue-62878.rs index c784e95edd824..0b5269df85ee1 100644 --- a/tests/ui/const-generics/issues/issue-62878.rs +++ b/tests/ui/const-generics/issues/issue-62878.rs @@ -9,6 +9,4 @@ fn foo() {} fn main() { foo::<_, { [1] }>(); //[min]~^ ERROR: type provided when a constant was expected - //[min]~| ERROR type annotations needed - //[min]~| ERROR type annotations needed } diff --git a/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs b/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs index 497c020bde43e..e12e07a28e763 100644 --- a/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs +++ b/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs @@ -12,7 +12,6 @@ fn b() { //~^ ERROR expected trait, found constant `BAR` //~| ERROR expected trait, found constant `BAR` //~| ERROR type provided when a constant was expected - //~| ERROR type annotations needed } fn c() { foo::<3 + 3>(); //~ ERROR expressions must be enclosed in braces diff --git a/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr b/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr index c2ba517f60960..d9bcc523b1fc4 100644 --- a/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr +++ b/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr @@ -10,7 +10,7 @@ LL | foo::<{ BAR + 3 }>(); | + + error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/const-expression-suggest-missing-braces.rs:18:11 + --> $DIR/const-expression-suggest-missing-braces.rs:17:11 | LL | foo::<3 + 3>(); | ^^^^^ @@ -21,7 +21,7 @@ LL | foo::<{ 3 + 3 }>(); | + + error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:21:15 + --> $DIR/const-expression-suggest-missing-braces.rs:20:15 | LL | foo::(); | ^ expected one of `,` or `>` @@ -32,7 +32,7 @@ LL | foo::<{ BAR - 3 }>(); | + + error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:24:15 + --> $DIR/const-expression-suggest-missing-braces.rs:23:15 | LL | foo::(); | ^ expected one of `,` or `>` @@ -43,7 +43,7 @@ LL | foo::<{ BAR - BAR }>(); | + + error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/const-expression-suggest-missing-braces.rs:27:11 + --> $DIR/const-expression-suggest-missing-braces.rs:26:11 | LL | foo::<100 - BAR>(); | ^^^^^^^^^ @@ -54,7 +54,7 @@ LL | foo::<{ 100 - BAR }>(); | + + error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:30:19 + --> $DIR/const-expression-suggest-missing-braces.rs:29:19 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -65,7 +65,7 @@ LL | foo::<{ bar() }>(); | + + error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:33:21 + --> $DIR/const-expression-suggest-missing-braces.rs:32:21 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -76,7 +76,7 @@ LL | foo::<{ bar::() }>(); | + + error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:36:21 + --> $DIR/const-expression-suggest-missing-braces.rs:35:21 | LL | foo::() + BAR>(); | ^ expected one of `,` or `>` @@ -87,7 +87,7 @@ LL | foo::<{ bar::() + BAR }>(); | + + error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:39:21 + --> $DIR/const-expression-suggest-missing-braces.rs:38:21 | LL | foo::() - BAR>(); | ^ expected one of `,` or `>` @@ -98,7 +98,7 @@ LL | foo::<{ bar::() - BAR }>(); | + + error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:42:15 + --> $DIR/const-expression-suggest-missing-braces.rs:41:15 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -109,7 +109,7 @@ LL | foo::<{ BAR - bar::() }>(); | + + error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:45:15 + --> $DIR/const-expression-suggest-missing-braces.rs:44:15 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -137,19 +137,7 @@ error[E0747]: type provided when a constant was expected LL | foo::(); | ^^^^^^^^^ -error[E0284]: type annotations needed - --> $DIR/const-expression-suggest-missing-braces.rs:11:5 - | -LL | foo::(); - | ^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the function `foo` - | -note: required by a const generic parameter in `foo` - --> $DIR/const-expression-suggest-missing-braces.rs:1:8 - | -LL | fn foo() {} - | ^^^^^^^^^^^^^^ required by this const generic parameter in `foo` - -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors -Some errors have detailed explanations: E0284, E0404, E0747. -For more information about an error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0404, E0747. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.rs b/tests/ui/const-generics/min_const_generics/macro-fail.rs index 25726490c2cca..8cfa5293cc28f 100644 --- a/tests/ui/const-generics/min_const_generics/macro-fail.rs +++ b/tests/ui/const-generics/min_const_generics/macro-fail.rs @@ -16,7 +16,6 @@ fn make_marker() -> impl Marker { //~| ERROR: type provided when a constant was expected Example:: //~^ ERROR: type provided when a constant was expected - //~| ERROR type annotations needed } fn from_marker(_: impl Marker<{ @@ -37,10 +36,8 @@ fn main() { let _fail = Example::; //~^ ERROR: type provided when a constant - //~| ERROR type annotations needed let _fail = Example::; //~^ ERROR unexpected end of macro invocation //~| ERROR: type provided when a constant was expected - //~| ERROR type annotations needed } diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.stderr b/tests/ui/const-generics/min_const_generics/macro-fail.stderr index 4e183fe5b1c55..34764982bb046 100644 --- a/tests/ui/const-generics/min_const_generics/macro-fail.stderr +++ b/tests/ui/const-generics/min_const_generics/macro-fail.stderr @@ -1,5 +1,5 @@ error: expected type, found `{` - --> $DIR/macro-fail.rs:31:27 + --> $DIR/macro-fail.rs:30:27 | LL | fn make_marker() -> impl Marker { | ---------------------- @@ -13,7 +13,7 @@ LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info) error: expected type, found `{` - --> $DIR/macro-fail.rs:31:27 + --> $DIR/macro-fail.rs:30:27 | LL | Example:: | ---------------------- @@ -41,7 +41,7 @@ LL | let _fail = Example::; = note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: unexpected end of macro invocation - --> $DIR/macro-fail.rs:42:25 + --> $DIR/macro-fail.rs:40:25 | LL | macro_rules! gimme_a_const { | -------------------------- when calling this macro @@ -50,7 +50,7 @@ LL | let _fail = Example::; | ^^^^^^^^^^^^^^^^ missing tokens in macro arguments | note: while trying to match meta-variable `$rusty:ident` - --> $DIR/macro-fail.rs:31:8 + --> $DIR/macro-fail.rs:30:8 | LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} | ^^^^^^^^^^^^^ @@ -75,63 +75,18 @@ error[E0747]: type provided when a constant was expected LL | Example:: | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0284]: type annotations needed - --> $DIR/macro-fail.rs:17:3 - | -LL | Example:: - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the struct `Example` - | -note: required by a const generic parameter in `Example` - --> $DIR/macro-fail.rs:1:16 - | -LL | struct Example; - | ^^^^^^^^^^^^^^ required by this const generic parameter in `Example` - error[E0747]: type provided when a constant was expected - --> $DIR/macro-fail.rs:38:25 + --> $DIR/macro-fail.rs:37:25 | LL | let _fail = Example::; | ^^^^^^^^^^^^^^^^^ error[E0747]: type provided when a constant was expected - --> $DIR/macro-fail.rs:42:25 + --> $DIR/macro-fail.rs:40:25 | LL | let _fail = Example::; | ^^^^^^^^^^^^^^^^ -error[E0284]: type annotations needed for `Example<_>` - --> $DIR/macro-fail.rs:38:7 - | -LL | let _fail = Example::; - | ^^^^^ ---------------------------- type must be known at this point - | -note: required by a const generic parameter in `Example` - --> $DIR/macro-fail.rs:1:16 - | -LL | struct Example; - | ^^^^^^^^^^^^^^ required by this const generic parameter in `Example` -help: consider giving `_fail` an explicit type, where the value of const parameter `N` is specified - | -LL | let _fail: Example = Example::; - | ++++++++++++ - -error[E0284]: type annotations needed for `Example<_>` - --> $DIR/macro-fail.rs:42:7 - | -LL | let _fail = Example::; - | ^^^^^ --------------------------- type must be known at this point - | -note: required by a const generic parameter in `Example` - --> $DIR/macro-fail.rs:1:16 - | -LL | struct Example; - | ^^^^^^^^^^^^^^ required by this const generic parameter in `Example` -help: consider giving `_fail` an explicit type, where the value of const parameter `N` is specified - | -LL | let _fail: Example = Example::; - | ++++++++++++ - -error: aborting due to 12 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0284, E0747. -For more information about an error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/suggest_const_for_array.rs b/tests/ui/const-generics/suggest_const_for_array.rs index 4d29d0693759f..b52fd152f976a 100644 --- a/tests/ui/const-generics/suggest_const_for_array.rs +++ b/tests/ui/const-generics/suggest_const_for_array.rs @@ -5,8 +5,6 @@ fn example() {} fn other() { example::<[usize; 3]>(); //~^ ERROR type provided when a const - //~| ERROR type annotations needed example::<[usize; 4 + 5]>(); //~^ ERROR type provided when a const - //~| ERROR type annotations needed } diff --git a/tests/ui/const-generics/suggest_const_for_array.stderr b/tests/ui/const-generics/suggest_const_for_array.stderr index c867914070bb7..f0ad8368e5d71 100644 --- a/tests/ui/const-generics/suggest_const_for_array.stderr +++ b/tests/ui/const-generics/suggest_const_for_array.stderr @@ -5,36 +5,11 @@ LL | example::<[usize; 3]>(); | ^^^^^^^^^^ help: array type provided where a `usize` was expected, try: `{ 3 }` error[E0747]: type provided when a constant was expected - --> $DIR/suggest_const_for_array.rs:9:15 + --> $DIR/suggest_const_for_array.rs:8:15 | LL | example::<[usize; 4 + 5]>(); | ^^^^^^^^^^^^^^ help: array type provided where a `usize` was expected, try: `{ 4 + 5 }` -error[E0284]: type annotations needed - --> $DIR/suggest_const_for_array.rs:6:5 - | -LL | example::<[usize; 3]>(); - | ^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `example` - | -note: required by a const generic parameter in `example` - --> $DIR/suggest_const_for_array.rs:3:12 - | -LL | fn example() {} - | ^^^^^^^^^^^^^^ required by this const generic parameter in `example` - -error[E0284]: type annotations needed - --> $DIR/suggest_const_for_array.rs:9:5 - | -LL | example::<[usize; 4 + 5]>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `example` - | -note: required by a const generic parameter in `example` - --> $DIR/suggest_const_for_array.rs:3:12 - | -LL | fn example() {} - | ^^^^^^^^^^^^^^ required by this const generic parameter in `example` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0284, E0747. -For more information about an error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/generics/generic-function-item-where-type.rs b/tests/ui/generics/generic-function-item-where-type.rs index 0e36018389e96..e1b0578cadbe9 100644 --- a/tests/ui/generics/generic-function-item-where-type.rs +++ b/tests/ui/generics/generic-function-item-where-type.rs @@ -3,5 +3,4 @@ fn foo() {} fn main() { foo::
() //~^ ERROR constant provided when a type was expected - //~| ERROR type annotations needed } diff --git a/tests/ui/generics/generic-function-item-where-type.stderr b/tests/ui/generics/generic-function-item-where-type.stderr index 5b0c9a8ee6df5..00e62843cb4b6 100644 --- a/tests/ui/generics/generic-function-item-where-type.stderr +++ b/tests/ui/generics/generic-function-item-where-type.stderr @@ -7,13 +7,6 @@ LL | foo::
() = help: `main` is a function item, not a type = help: function item types cannot be named directly -error[E0282]: type annotations needed - --> $DIR/generic-function-item-where-type.rs:4:5 - | -LL | foo::
() - | ^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `foo` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0282, E0747. -For more information about an error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0747`. From aece06482ebc7fae6044420e2d98f92101553c6f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 5 Jul 2024 10:05:58 +0000 Subject: [PATCH 08/15] Remove HirTyLowerer::set_tainted_by_errors, since it is now redundant --- compiler/rustc_hir_analysis/src/collect.rs | 92 ++++++++++++------- .../rustc_hir_analysis/src/collect/type_of.rs | 27 ++++-- .../src/hir_ty_lowering/errors.rs | 43 +++------ .../src/hir_ty_lowering/mod.rs | 22 +---- .../src/hir_ty_lowering/object_safety.rs | 3 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 6 +- 6 files changed, 97 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f83d74ecd3887..890f5d8a07476 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -163,7 +163,7 @@ pub struct CollectItemTypesVisitor<'tcx> { /// and suggest adding type parameters in the appropriate place, taking into consideration any and /// all already existing generic type parameters to avoid suggesting a name that is already in use. pub(crate) fn placeholder_type_error<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &dyn HirTyLowerer<'tcx>, generics: Option<&hir::Generics<'_>>, placeholder_types: Vec, suggest: bool, @@ -174,21 +174,21 @@ pub(crate) fn placeholder_type_error<'tcx>( return; } - placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind) + placeholder_type_error_diag(cx, generics, placeholder_types, vec![], suggest, hir_ty, kind) .emit(); } -pub(crate) fn placeholder_type_error_diag<'tcx>( - tcx: TyCtxt<'tcx>, +pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>( + cx: &'cx dyn HirTyLowerer<'tcx>, generics: Option<&hir::Generics<'_>>, placeholder_types: Vec, additional_spans: Vec, suggest: bool, hir_ty: Option<&hir::Ty<'_>>, kind: &'static str, -) -> Diag<'tcx> { +) -> Diag<'cx> { if placeholder_types.is_empty() { - return bad_placeholder(tcx, additional_spans, kind); + return bad_placeholder(cx, additional_spans, kind); } let params = generics.map(|g| g.params).unwrap_or_default(); @@ -212,7 +212,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( } let mut err = - bad_placeholder(tcx, placeholder_types.into_iter().chain(additional_spans).collect(), kind); + bad_placeholder(cx, placeholder_types.into_iter().chain(additional_spans).collect(), kind); // Suggest, but only if it is not a function in const or static if suggest { @@ -226,7 +226,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( // Check if parent is const or static is_const_or_static = matches!( - tcx.parent_hir_node(hir_ty.hir_id), + cx.tcx().parent_hir_node(hir_ty.hir_id), Node::Item(&hir::Item { kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), .. @@ -269,7 +269,16 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(item); - placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr()); + let icx = ItemCtxt::new(tcx, item.owner_id.def_id); + + placeholder_type_error( + icx.lowerer(), + Some(generics), + visitor.0, + suggest, + None, + item.kind.descr(), + ); } impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { @@ -331,15 +340,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { /////////////////////////////////////////////////////////////////////////// // Utility types and common code for the above passes. -fn bad_placeholder<'tcx>( - tcx: TyCtxt<'tcx>, +fn bad_placeholder<'cx, 'tcx>( + cx: &'cx dyn HirTyLowerer<'tcx>, mut spans: Vec, kind: &'static str, -) -> Diag<'tcx> { +) -> Diag<'cx> { let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") }; spans.sort(); - tcx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind }) + cx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind }) } impl<'tcx> ItemCtxt<'tcx> { @@ -383,14 +392,13 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { if let RegionInferReason::BorrowedObjectLifetimeDefault = reason { let e = struct_span_code_err!( - self.tcx().dcx(), + self.dcx(), span, E0228, "the lifetime bound for this object type cannot be deduced \ from context; please supply an explicit bound" ) .emit(); - self.set_tainted_by_errors(e); ty::Region::new_error(self.tcx(), e) } else { // This indicates an illegal lifetime in a non-assoc-trait position @@ -515,10 +523,6 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { None } - fn set_tainted_by_errors(&self, err: ErrorGuaranteed) { - self.tainted_by_errors.set(Some(err)); - } - fn lower_fn_sig( &self, decl: &hir::FnDecl<'tcx>, @@ -576,7 +580,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. let mut diag = crate::collect::placeholder_type_error_diag( - tcx, + self, generics, visitor.0, infer_replacements.iter().map(|(s, _)| *s).collect(), @@ -596,7 +600,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { ); } - self.set_tainted_by_errors(diag.emit()); + diag.emit(); } (input_tys, output_ty) @@ -645,6 +649,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { let it = tcx.hir().item(item_id); debug!(item = %it.ident, id = %it.hir_id()); let def_id = item_id.owner_id.def_id; + let icx = ItemCtxt::new(tcx, def_id); match &it.kind { // These don't define types. @@ -669,7 +674,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_foreign_item(item); placeholder_type_error( - tcx, + icx.lowerer(), None, visitor.0, false, @@ -748,7 +753,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(it); - placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr()); + placeholder_type_error( + icx.lowerer(), + None, + visitor.0, + false, + None, + it.kind.descr(), + ); } } @@ -766,6 +778,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { let trait_item = tcx.hir().trait_item(trait_item_id); let def_id = trait_item_id.owner_id; tcx.ensure().generics_of(def_id); + let icx = ItemCtxt::new(tcx, def_id.def_id); match trait_item.kind { hir::TraitItemKind::Fn(..) => { @@ -782,7 +795,14 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { // Account for `const C: _;`. let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant"); + placeholder_type_error( + icx.lowerer(), + None, + visitor.0, + false, + None, + "associated constant", + ); } } @@ -793,7 +813,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { // Account for `type T = _;`. let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); + placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type"); } hir::TraitItemKind::Type(_, None) => { @@ -804,7 +824,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); + placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type"); } }; @@ -817,6 +837,7 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); let impl_item = tcx.hir().impl_item(impl_item_id); + let icx = ItemCtxt::new(tcx, def_id.def_id); match impl_item.kind { hir::ImplItemKind::Fn(..) => { tcx.ensure().codegen_fn_attrs(def_id); @@ -827,14 +848,21 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_impl_item(impl_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); + placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type"); } hir::ImplItemKind::Const(ty, _) => { // Account for `const T: _ = ..;` if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_impl_item(impl_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant"); + placeholder_type_error( + icx.lowerer(), + None, + visitor.0, + false, + None, + "associated constant", + ); } } } @@ -1385,7 +1413,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn .. }) | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => { - infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx) + infer_return_ty_for_fn_sig(sig, generics, def_id, &icx) } ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => { @@ -1402,7 +1430,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn None, ) } else { - infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx) + infer_return_ty_for_fn_sig(sig, generics, def_id, &icx) } } @@ -1455,12 +1483,12 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn } fn infer_return_ty_for_fn_sig<'tcx>( - tcx: TyCtxt<'tcx>, sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'_>, def_id: LocalDefId, icx: &ItemCtxt<'tcx>, ) -> ty::PolyFnSig<'tcx> { + let tcx = icx.tcx; let hir_id = tcx.local_def_id_to_hir_id(def_id); match sig.decl.output.get_infer_ret_ty() { @@ -1492,7 +1520,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( let mut visitor = HirPlaceholderCollector::default(); visitor.visit_ty(ty); - let mut diag = bad_placeholder(tcx, visitor.0, "return type"); + let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type"); let ret_ty = fn_sig.output(); // Don't leak types into signatures unless they're nameable! // For example, if a function returns itself, we don't want that diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 1e2b0c4323385..974dd415f464c 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -12,6 +12,7 @@ use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; use crate::errors::TypeofReservedKeywordUsed; +use crate::hir_ty_lowering::HirTyLowerer; use super::bad_placeholder; use super::ItemCtxt; @@ -357,7 +358,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ .and_then(|body_id| { ty.is_suggestable_infer_ty().then(|| { infer_placeholder_type( - tcx, + icx.lowerer(), def_id, body_id, ty.span, @@ -381,7 +382,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ImplItemKind::Const(ty, body_id) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( - tcx, + icx.lowerer(), def_id, body_id, ty.span, @@ -405,7 +406,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ItemKind::Static(ty, .., body_id) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( - tcx, + icx.lowerer(), def_id, body_id, ty.span, @@ -418,7 +419,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } ItemKind::Const(ty, _, body_id) => { if ty.is_suggestable_infer_ty() { - infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant") + infer_placeholder_type( + icx.lowerer(), + def_id, + body_id, + ty.span, + item.ident, + "constant", + ) } else { icx.lower_ty(ty) } @@ -559,21 +567,22 @@ pub(super) fn type_of_opaque( } } -fn infer_placeholder_type<'a>( - tcx: TyCtxt<'a>, +fn infer_placeholder_type<'tcx>( + cx: &dyn HirTyLowerer<'tcx>, def_id: LocalDefId, body_id: hir::BodyId, span: Span, item_ident: Ident, kind: &'static str, -) -> Ty<'a> { +) -> Ty<'tcx> { + let tcx = cx.tcx(); let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id); // If this came from a free `const` or `static mut?` item, // then the user may have written e.g. `const A = 42;`. // In this case, the parser has stashed a diagnostic for // us to improve in typeck so we do that now. - let guar = tcx + let guar = cx .dcx() .try_steal_modify_and_emit_err(span, StashKey::ItemNoType, |err| { if !ty.references_error() { @@ -602,7 +611,7 @@ fn infer_placeholder_type<'a>( } }) .unwrap_or_else(|| { - let mut diag = bad_placeholder(tcx, vec![span], kind); + let mut diag = bad_placeholder(cx, vec![span], kind); if !ty.references_error() { if let Some(ty) = ty.make_suggestable(tcx, false, None) { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index d8bbe403f1f50..983924a4b0873 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -462,9 +462,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } } - let reported = err.emit(); - self.set_tainted_by_errors(reported); - reported + err.emit() } pub(crate) fn complain_about_ambiguous_inherent_assoc_ty( @@ -481,9 +479,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); err.span_label(name.span, format!("multiple `{name}` found")); self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span); - let reported = err.emit(); - self.set_tainted_by_errors(reported); - reported + err.emit() } // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate. @@ -973,7 +969,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - self.set_tainted_by_errors(err.emit()); + err.emit(); } /// On ambiguous associated type, look for an associated function whose name matches the @@ -1010,17 +1006,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .filter_by_name_unhygienic(Symbol::intern(&name)) .next() { - let reported = - struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type") - .with_span_suggestion_verbose( - ident2.span.to(ident3.span), - format!("there is an associated function with a similar name: `{name}`"), - name, - Applicability::MaybeIncorrect, - ) - .emit(); - self.set_tainted_by_errors(reported); - Err(reported) + Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type") + .with_span_suggestion_verbose( + ident2.span.to(ident3.span), + format!("there is an associated function with a similar name: `{name}`"), + name, + Applicability::MaybeIncorrect, + ) + .emit()) } else { Ok(()) } @@ -1129,9 +1122,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.span_label(span, format!("not allowed on {what}")); } generics_args_err_extend(self.tcx(), segments, &mut err, err_extend); - let reported = err.emit(); - self.set_tainted_by_errors(reported); - reported + err.emit() } pub fn report_trait_object_addition_traits_error( @@ -1167,9 +1158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for more information on them, visit \ ", ); - let reported = err.emit(); - self.set_tainted_by_errors(reported); - reported + err.emit() } pub fn report_trait_object_with_no_traits_error( @@ -1183,10 +1172,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|&(trait_ref, _)| trait_ref.def_id()) .find(|&trait_ref| tcx.is_trait_alias(trait_ref)) .map(|trait_ref| tcx.def_span(trait_ref)); - let reported = - self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }); - self.set_tainted_by_errors(reported); - reported + + self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }) } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index e8a4ab103bd2b..0482277975cac 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -180,12 +180,6 @@ pub trait HirTyLowerer<'tcx> { /// The inference context of the lowering context if applicable. fn infcx(&self) -> Option<&InferCtxt<'tcx>>; - /// Taint the context with errors. - /// - /// Invoke this when you encounter an error from some prior pass like name resolution. - /// This is used to help suppress derived errors typeck might otherwise report. - fn set_tainted_by_errors(&self, e: ErrorGuaranteed); - /// Convenience method for coercing the lowering context into a trait object type. /// /// Most lowering routines are defined on the trait object type directly @@ -405,10 +399,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty.is_some(), ); - if let Err(err) = &arg_count.correct { - self.set_tainted_by_errors(err.reported); - } - // Skip processing if type has no generic parameters. // Traits always have `Self` as a generic parameter, which means they will not return early // here and so associated item constraints will be handled regardless of whether there are @@ -569,7 +559,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, modifier: constness.as_str(), }); - self.set_tainted_by_errors(reported); arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] }); } @@ -876,7 +865,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, constraint, ); - self.set_tainted_by_errors(reported); return Err(reported); }; debug!(?bound); @@ -959,7 +947,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { )); } let reported = err.emit(); - self.set_tainted_by_errors(reported); if !where_bounds.is_empty() { return Err(reported); } @@ -1152,7 +1139,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_ident.name, ) }; - self.set_tainted_by_errors(reported); return Err(reported); } }; @@ -1403,13 +1389,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); if !tcx.visibility(item_def_id).is_accessible_from(scope, tcx) { - let reported = self.dcx().emit_err(crate::errors::AssocItemIsPrivate { + self.dcx().emit_err(crate::errors::AssocItemIsPrivate { span, kind: tcx.def_descr(item_def_id), name: ident, defined_here_label: tcx.def_span(item_def_id), }); - self.set_tainted_by_errors(reported); } tcx.check_stability(item_def_id, Some(block), span, None); @@ -1835,7 +1820,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.span_note(impl_.self_ty.span, "not a concrete type"); } let reported = err.emit(); - self.set_tainted_by_errors(reported); Ty::new_error(tcx, reported) } else { ty @@ -1882,7 +1866,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .tcx() .dcx() .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted"); - self.set_tainted_by_errors(e); Ty::new_error(self.tcx(), e) } Res::Def(..) => { @@ -2017,7 +2000,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output) { let e = self.dcx().span_delayed_bug(span, "not supported delegation case"); - self.set_tainted_by_errors(e); return Ty::new_error(self.tcx(), e); }; let sig = self.tcx().fn_sig(sig_id); @@ -2442,7 +2424,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.note("consider introducing a named lifetime parameter"); } - self.set_tainted_by_errors(err.emit()); + err.emit(); } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index bbb37be5c9f3f..af8fbc9b987d1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -262,7 +262,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if references_self { let def_id = i.bottom().0.def_id(); - let reported = struct_span_code_err!( + struct_span_code_err!( self.dcx(), i.bottom().1, E0038, @@ -275,7 +275,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .error_msg(), ) .emit(); - self.set_tainted_by_errors(reported); } ty::ExistentialTraitRef { def_id: trait_ref.def_id, args } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 1de2935ecaf73..b5796fbd48a88 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -5,7 +5,7 @@ mod checks; mod inspect_obligations; mod suggestions; -use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; +use rustc_errors::DiagCtxtHandle; use crate::coercion::DynamicCoerceMany; use crate::fallback::DivergingFallbackBehavior; @@ -342,10 +342,6 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { Some(&self.infcx) } - fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { - self.infcx.set_tainted_by_errors(e) - } - fn lower_fn_sig( &self, decl: &rustc_hir::FnDecl<'tcx>, From dd175feb25bc09484a74994a1b80af290eeb6509 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 9 Jul 2024 09:39:13 +0200 Subject: [PATCH 09/15] cycle_participants to nested_goals --- .../src/solve/search_graph.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index f8a50913f05f8..69d52dcad7a59 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -71,7 +71,7 @@ struct StackEntry { /// C :- D /// D :- C /// ``` - cycle_participants: HashSet>, + nested_goals: HashSet>, /// Starts out as `None` and gets set when rerunning this /// goal in case we encounter a cycle. provisional_result: Option>, @@ -215,8 +215,8 @@ impl SearchGraph { let current_cycle_root = &mut stack[current_root.as_usize()]; for entry in cycle_participants { entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head)); - current_cycle_root.cycle_participants.insert(entry.input); - current_cycle_root.cycle_participants.extend(mem::take(&mut entry.cycle_participants)); + current_cycle_root.nested_goals.insert(entry.input); + current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals)); } } @@ -335,7 +335,7 @@ impl SearchGraph { non_root_cycle_participant: None, encountered_overflow: false, has_been_used: HasBeenUsed::empty(), - cycle_participants: Default::default(), + nested_goals: Default::default(), provisional_result: None, }; assert_eq!(self.stack.push(entry), depth); @@ -389,7 +389,7 @@ impl SearchGraph { // // We must not use the global cache entry of a root goal if a cycle // participant is on the stack. This is necessary to prevent unstable - // results. See the comment of `StackEntry::cycle_participants` for + // results. See the comment of `StackEntry::nested_goals` for // more details. self.global_cache(cx).insert( cx, @@ -397,7 +397,7 @@ impl SearchGraph { proof_tree, reached_depth, final_entry.encountered_overflow, - final_entry.cycle_participants, + final_entry.nested_goals, dep_node, result, ) @@ -544,27 +544,27 @@ impl SearchGraph { non_root_cycle_participant, encountered_overflow: _, has_been_used, - ref cycle_participants, + ref nested_goals, provisional_result, } = *entry; let cache_entry = provisional_cache.get(&entry.input).unwrap(); assert_eq!(cache_entry.stack_depth, Some(depth)); if let Some(head) = non_root_cycle_participant { assert!(head < depth); - assert!(cycle_participants.is_empty()); + assert!(nested_goals.is_empty()); assert_ne!(stack[head].has_been_used, HasBeenUsed::empty()); let mut current_root = head; while let Some(parent) = stack[current_root].non_root_cycle_participant { current_root = parent; } - assert!(stack[current_root].cycle_participants.contains(&input)); + assert!(stack[current_root].nested_goals.contains(&input)); } - if !cycle_participants.is_empty() { + if !nested_goals.is_empty() { assert!(provisional_result.is_some() || !has_been_used.is_empty()); for entry in stack.iter().take(depth.as_usize()) { - assert_eq!(cycle_participants.get(&entry.input), None); + assert_eq!(nested_goals.get(&entry.input), None); } } } From 7af825fea4fea17d0b58fcd8c1f2b6fa11638cfb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Jul 2024 16:23:01 -0400 Subject: [PATCH 10/15] Split out overflow handling into its own module --- .../src/error_reporting/traits/mod.rs | 2 + .../src/error_reporting/traits/overflow.rs | 197 ++++++++++++++++++ .../traits/type_err_ctxt_ext.rs | 182 +--------------- .../src/solve/normalize.rs | 2 +- .../src/traits/fulfill.rs | 2 +- .../src/traits/normalize.rs | 2 +- .../src/traits/query/normalize.rs | 2 +- .../src/traits/select/mod.rs | 2 +- compiler/rustc_traits/src/codegen.rs | 2 +- .../src/normalize_projection_ty.rs | 2 +- 10 files changed, 208 insertions(+), 187 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 438b25056c338..7d334d623cc24 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -3,6 +3,7 @@ pub mod ambiguity; mod infer_ctxt_ext; pub mod on_unimplemented; +mod overflow; pub mod suggestions; mod type_err_ctxt_ext; @@ -17,6 +18,7 @@ use rustc_span::Span; use std::ops::ControlFlow; pub use self::infer_ctxt_ext::*; +pub use self::overflow::*; pub use self::type_err_ctxt_ext::*; // When outputting impl candidates, prefer showing those that are more similar. diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs new file mode 100644 index 0000000000000..061a5a4be2075 --- /dev/null +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -0,0 +1,197 @@ +use std::fmt; + +use rustc_errors::{ + struct_span_code_err, Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, E0275, +}; +use rustc_hir::def::Namespace; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::traits::{Obligation, PredicateObligation}; +use rustc_macros::extension; +use rustc_middle::ty::print::{FmtPrinter, Print}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_session::Limit; +use rustc_span::Span; +use rustc_type_ir::Upcast; + +use super::InferCtxtPrivExt; +use crate::error_reporting::traits::suggestions::TypeErrCtxtExt; + +pub enum OverflowCause<'tcx> { + DeeplyNormalize(ty::AliasTerm<'tcx>), + TraitSolver(ty::Predicate<'tcx>), +} + +pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( + tcx: TyCtxt<'tcx>, + err: &mut Diag<'_, G>, +) { + let suggested_limit = match tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; + err.help(format!( + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + suggested_limit, + tcx.crate_name(LOCAL_CRATE), + )); +} + +#[extension(pub trait TypeErrCtxtOverflowExt<'a, 'tcx>)] +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + /// Reports that an overflow has occurred and halts compilation. We + /// halt compilation unconditionally because it is important that + /// overflows never be masked -- they basically represent computations + /// whose result could not be truly determined and thus we can't say + /// if the program type checks or not -- and they are unusual + /// occurrences in any case. + fn report_overflow_error( + &self, + cause: OverflowCause<'tcx>, + span: Span, + suggest_increasing_limit: bool, + mutate: impl FnOnce(&mut Diag<'_>), + ) -> ! { + let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit); + mutate(&mut err); + err.emit(); + FatalError.raise(); + } + + fn build_overflow_error( + &self, + cause: OverflowCause<'tcx>, + span: Span, + suggest_increasing_limit: bool, + ) -> Diag<'a> { + fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String + where + T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>, + { + let s = value.to_string(); + if s.len() > 50 { + // We don't need to save the type to a file, we will be talking about this type already + // in a separate note when we explain the obligation, so it will be available that way. + let mut cx: FmtPrinter<'_, '_> = + FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6)); + value.print(&mut cx).unwrap(); + cx.into_buffer() + } else { + s + } + } + + let mut err = match cause { + OverflowCause::DeeplyNormalize(alias_term) => { + let alias_term = self.resolve_vars_if_possible(alias_term); + let kind = alias_term.kind(self.tcx).descr(); + let alias_str = with_short_path(self.tcx, alias_term); + struct_span_code_err!( + self.dcx(), + span, + E0275, + "overflow normalizing the {kind} `{alias_str}`", + ) + } + OverflowCause::TraitSolver(predicate) => { + let predicate = self.resolve_vars_if_possible(predicate); + match predicate.kind().skip_binder() { + ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) + | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { + struct_span_code_err!( + self.dcx(), + span, + E0275, + "overflow assigning `{a}` to `{b}`", + ) + } + _ => { + let pred_str = with_short_path(self.tcx, predicate); + struct_span_code_err!( + self.dcx(), + span, + E0275, + "overflow evaluating the requirement `{pred_str}`", + ) + } + } + } + }; + + if suggest_increasing_limit { + suggest_new_overflow_limit(self.tcx, &mut err); + } + + err + } + + /// Reports that an overflow has occurred and halts compilation. We + /// halt compilation unconditionally because it is important that + /// overflows never be masked -- they basically represent computations + /// whose result could not be truly determined and thus we can't say + /// if the program type checks or not -- and they are unusual + /// occurrences in any case. + fn report_overflow_obligation( + &self, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool, + ) -> ! + where + T: Upcast, ty::Predicate<'tcx>> + Clone, + { + let predicate = obligation.predicate.clone().upcast(self.tcx); + let predicate = self.resolve_vars_if_possible(predicate); + self.report_overflow_error( + OverflowCause::TraitSolver(predicate), + obligation.cause.span, + suggest_increasing_limit, + |err| { + self.note_obligation_cause_code( + obligation.cause.body_id, + err, + predicate, + obligation.param_env, + obligation.cause.code(), + &mut vec![], + &mut Default::default(), + ); + }, + ); + } + + /// Reports that a cycle was detected which led to overflow and halts + /// compilation. This is equivalent to `report_overflow_obligation` except + /// that we can give a more helpful error message (and, in particular, + /// we do not suggest increasing the overflow limit, which is not + /// going to help). + fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { + let cycle = self.resolve_vars_if_possible(cycle.to_owned()); + assert!(!cycle.is_empty()); + + debug!(?cycle, "report_overflow_error_cycle"); + + // The 'deepest' obligation is most likely to have a useful + // cause 'backtrace' + self.report_overflow_obligation( + cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), + false, + ); + } + + fn report_overflow_no_abort( + &self, + obligation: PredicateObligation<'tcx>, + suggest_increasing_limit: bool, + ) -> ErrorGuaranteed { + let obligation = self.resolve_vars_if_possible(obligation); + let mut err = self.build_overflow_error( + OverflowCause::TraitSolver(obligation.predicate), + obligation.cause.span, + suggest_increasing_limit, + ); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + err.emit() + } +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs index 7843a95d9667e..ee5f4f44251c0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs @@ -3,6 +3,7 @@ use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt; +use crate::error_reporting::traits::overflow::TypeErrCtxtOverflowExt; use crate::error_reporting::traits::to_pretty_impl_header; use crate::error_reporting::traits::{ambiguity, ambiguity::CandidateSource::*}; use crate::errors::{ @@ -23,7 +24,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart}; -use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey}; +use rustc_errors::{Diag, ErrorGuaranteed, StashKey}; use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; @@ -46,12 +47,9 @@ use rustc_middle::ty::{ TypeVisitableExt, Upcast, }; use rustc_middle::{bug, span_bug}; -use rustc_session::Limit; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::sym; use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP}; use std::borrow::Cow; -use std::fmt; use std::iter; use super::{ @@ -61,27 +59,6 @@ use super::{ pub use rustc_infer::traits::error_reporting::*; -pub enum OverflowCause<'tcx> { - DeeplyNormalize(ty::AliasTerm<'tcx>), - TraitSolver(ty::Predicate<'tcx>), -} - -pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( - tcx: TyCtxt<'tcx>, - err: &mut Diag<'_, G>, -) { - let suggested_limit = match tcx.recursion_limit() { - Limit(0) => Limit(2), - limit => limit * 2, - }; - err.help(format!( - "consider increasing the recursion limit by adding a \ - `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", - suggested_limit, - tcx.crate_name(LOCAL_CRATE), - )); -} - #[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn report_fulfillment_errors( @@ -204,161 +181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors")) } - /// Reports that an overflow has occurred and halts compilation. We - /// halt compilation unconditionally because it is important that - /// overflows never be masked -- they basically represent computations - /// whose result could not be truly determined and thus we can't say - /// if the program type checks or not -- and they are unusual - /// occurrences in any case. - fn report_overflow_error( - &self, - cause: OverflowCause<'tcx>, - span: Span, - suggest_increasing_limit: bool, - mutate: impl FnOnce(&mut Diag<'_>), - ) -> ! { - let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit); - mutate(&mut err); - err.emit(); - FatalError.raise(); - } - - fn build_overflow_error( - &self, - cause: OverflowCause<'tcx>, - span: Span, - suggest_increasing_limit: bool, - ) -> Diag<'a> { - fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String - where - T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>, - { - let s = value.to_string(); - if s.len() > 50 { - // We don't need to save the type to a file, we will be talking about this type already - // in a separate note when we explain the obligation, so it will be available that way. - let mut cx: FmtPrinter<'_, '_> = - FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6)); - value.print(&mut cx).unwrap(); - cx.into_buffer() - } else { - s - } - } - - let mut err = match cause { - OverflowCause::DeeplyNormalize(alias_term) => { - let alias_term = self.resolve_vars_if_possible(alias_term); - let kind = alias_term.kind(self.tcx).descr(); - let alias_str = with_short_path(self.tcx, alias_term); - struct_span_code_err!( - self.dcx(), - span, - E0275, - "overflow normalizing the {kind} `{alias_str}`", - ) - } - OverflowCause::TraitSolver(predicate) => { - let predicate = self.resolve_vars_if_possible(predicate); - match predicate.kind().skip_binder() { - ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) - | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { - struct_span_code_err!( - self.dcx(), - span, - E0275, - "overflow assigning `{a}` to `{b}`", - ) - } - _ => { - let pred_str = with_short_path(self.tcx, predicate); - struct_span_code_err!( - self.dcx(), - span, - E0275, - "overflow evaluating the requirement `{pred_str}`", - ) - } - } - } - }; - - if suggest_increasing_limit { - suggest_new_overflow_limit(self.tcx, &mut err); - } - - err - } - - /// Reports that an overflow has occurred and halts compilation. We - /// halt compilation unconditionally because it is important that - /// overflows never be masked -- they basically represent computations - /// whose result could not be truly determined and thus we can't say - /// if the program type checks or not -- and they are unusual - /// occurrences in any case. - fn report_overflow_obligation( - &self, - obligation: &Obligation<'tcx, T>, - suggest_increasing_limit: bool, - ) -> ! - where - T: Upcast, ty::Predicate<'tcx>> + Clone, - { - let predicate = obligation.predicate.clone().upcast(self.tcx); - let predicate = self.resolve_vars_if_possible(predicate); - self.report_overflow_error( - OverflowCause::TraitSolver(predicate), - obligation.cause.span, - suggest_increasing_limit, - |err| { - self.note_obligation_cause_code( - obligation.cause.body_id, - err, - predicate, - obligation.param_env, - obligation.cause.code(), - &mut vec![], - &mut Default::default(), - ); - }, - ); - } - - /// Reports that a cycle was detected which led to overflow and halts - /// compilation. This is equivalent to `report_overflow_obligation` except - /// that we can give a more helpful error message (and, in particular, - /// we do not suggest increasing the overflow limit, which is not - /// going to help). - fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { - let cycle = self.resolve_vars_if_possible(cycle.to_owned()); - assert!(!cycle.is_empty()); - - debug!(?cycle, "report_overflow_error_cycle"); - - // The 'deepest' obligation is most likely to have a useful - // cause 'backtrace' - self.report_overflow_obligation( - cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), - false, - ); - } - - fn report_overflow_no_abort( - &self, - obligation: PredicateObligation<'tcx>, - suggest_increasing_limit: bool, - ) -> ErrorGuaranteed { - let obligation = self.resolve_vars_if_possible(obligation); - let mut err = self.build_overflow_error( - OverflowCause::TraitSolver(obligation.predicate), - obligation.cause.span, - suggest_increasing_limit, - ); - self.note_obligation_cause(&mut err, &obligation); - self.point_at_returns_when_relevant(&mut err, &obligation); - err.emit() - } - /// The `root_obligation` parameter should be the `root_obligation` field /// from a `FulfillmentError`. If no `FulfillmentError` is available, /// then it should be the same as `obligation`. diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index bda2137fa7368..ca313590265d2 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; use std::marker::PhantomData; -use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtExt}; +use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtOverflowExt}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError}; use rustc_data_structures::stack::ensure_sufficient_stack; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 6f7e69798ee92..5597c8be59258 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,4 +1,4 @@ -use crate::error_reporting::traits::TypeErrCtxtExt; +use crate::error_reporting::traits::TypeErrCtxtOverflowExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; use crate::traits::normalize::normalize_with_depth_to; use rustc_data_structures::captures::Captures; diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index a34fd80446785..dda3aaaf71e82 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -3,7 +3,7 @@ use super::SelectionContext; use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; use crate::error_reporting::traits::OverflowCause; -use crate::error_reporting::traits::TypeErrCtxtExt; +use crate::error_reporting::traits::TypeErrCtxtOverflowExt; use crate::solve::NextSolverError; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index da4e4fef3cf78..c11e86abef8a4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -3,7 +3,7 @@ //! `normalize_canonicalized_projection_ty` query when it encounters projections. use crate::error_reporting::traits::OverflowCause; -use crate::error_reporting::traits::TypeErrCtxtExt; +use crate::error_reporting::traits::TypeErrCtxtOverflowExt; use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 1e55b2d015003..2c4ffdabf140e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -18,7 +18,7 @@ use super::{ TraitQueryMode, }; -use crate::error_reporting::traits::TypeErrCtxtExt; +use crate::error_reporting::traits::TypeErrCtxtOverflowExt; use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::normalize_with_depth; diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 51ac7b2c7ac1b..3ee5fd876ff57 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -7,7 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, Unimplemented, diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 85d84983d28fa..2d70fdc3935fb 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -2,7 +2,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{ normalize::NormalizationResult, CanonicalAliasGoal, NoSolution, From cd68a28daa460e04875a16b9677117af93046979 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Jul 2024 16:44:00 -0400 Subject: [PATCH 11/15] Move some stuff into the ambiguity and suggestion modules --- .../src/error_reporting/traits/ambiguity.rs | 568 ++++++++++++++- .../src/error_reporting/traits/mod.rs | 58 -- .../src/error_reporting/traits/suggestions.rs | 169 +++++ .../traits/type_err_ctxt_ext.rs | 681 +----------------- 4 files changed, 742 insertions(+), 734 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index e6cb28df593af..c301deac6164d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -1,10 +1,27 @@ +use std::ops::ControlFlow; + +use rustc_errors::{ + struct_span_code_err, Applicability, Diag, MultiSpan, StashKey, E0283, E0284, E0790, +}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor as _; +use rustc_hir::LangItem; +use rustc_infer::infer::error_reporting::{TypeAnnotationNeeded, TypeErrCtxt}; use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt}; use rustc_infer::traits::util::elaborate; -use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation}; -use rustc_middle::ty; -use rustc_span::{Span, DUMMY_SP}; +use rustc_infer::traits::{ + Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, +}; +use rustc_macros::extension; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _}; +use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; +use crate::error_reporting::traits::suggestions::TypeErrCtxtExt as _; +use crate::error_reporting::traits::{ + to_pretty_impl_header, FindExprBySpan, InferCtxtPrivExt as _, +}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::ObligationCtxt; @@ -134,3 +151,548 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( ambiguities } + +#[extension(pub trait TypeErrCtxtAmbiguityExt<'a, 'tcx>)] +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + #[instrument(skip(self), level = "debug")] + fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed { + // Unable to successfully determine, probably means + // insufficient type information, but could mean + // ambiguous impls. The latter *ought* to be a + // coherence violation, so we don't report it here. + + let predicate = self.resolve_vars_if_possible(obligation.predicate); + let span = obligation.cause.span; + + debug!(?predicate, obligation.cause.code = ?obligation.cause.code()); + + // Ambiguity errors are often caused as fallout from earlier errors. + // We ignore them if this `infcx` is tainted in some cases below. + + let bound_predicate = predicate.kind(); + let mut err = match bound_predicate.skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { + let trait_ref = bound_predicate.rebind(data.trait_ref); + debug!(?trait_ref); + + if let Err(e) = predicate.error_reported() { + return e; + } + + if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) { + // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case + // other `Foo` impls are incoherent. + return guar; + } + + // This is kind of a hack: it frequently happens that some earlier + // error prevents types from being fully inferred, and then we get + // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we + // could just skip over all checks where the self-ty is an + // inference variable, but I was afraid that there might be an + // inference variable created, registered as an obligation, and + // then never forced by writeback, and hence by skipping here we'd + // be ignoring the fact that we don't KNOW the type works + // out. Though even that would probably be harmless, given that + // we're only talking about builtin traits, which are known to be + // inhabited. We used to check for `self.tcx.sess.has_errors()` to + // avoid inundating the user with unnecessary errors, but we now + // check upstream for type errors and don't add the obligations to + // begin with in those cases. + if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { + match self.tainted_by_errors() { + None => { + let err = self.emit_inference_failure_err( + obligation.cause.body_id, + span, + trait_ref.self_ty().skip_binder().into(), + TypeAnnotationNeeded::E0282, + false, + ); + return err.stash(span, StashKey::MaybeForgetReturn).unwrap(); + } + Some(e) => return e, + } + } + + // Typically, this ambiguity should only happen if + // there are unresolved type inference variables + // (otherwise it would suggest a coherence + // failure). But given #21974 that is not necessarily + // the case -- we can have multiple where clauses that + // are only distinguished by a region, which results + // in an ambiguity even when all types are fully + // known, since we don't dispatch based on region + // relationships. + + // Pick the first generic parameter that still contains inference variables as the one + // we're going to emit an error for. If there are none (see above), fall back to + // a more general error. + let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer()); + + let mut err = if let Some(arg) = arg { + self.emit_inference_failure_err( + obligation.cause.body_id, + span, + arg, + TypeAnnotationNeeded::E0283, + true, + ) + } else { + struct_span_code_err!( + self.dcx(), + span, + E0283, + "type annotations needed: cannot satisfy `{}`", + predicate, + ) + }; + + let mut ambiguities = compute_applicable_impls_for_diagnostics( + self.infcx, + &obligation.with(self.tcx, trait_ref), + ); + let has_non_region_infer = + trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer()); + // It doesn't make sense to talk about applicable impls if there are more than a + // handful of them. If there are a lot of them, but only a few of them have no type + // params, we only show those, as they are more likely to be useful/intended. + if ambiguities.len() > 5 { + let infcx = self.infcx; + if !ambiguities.iter().all(|option| match option { + CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0, + CandidateSource::ParamEnv(_) => true, + }) { + // If not all are blanket impls, we filter blanked impls out. + ambiguities.retain(|option| match option { + CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0, + CandidateSource::ParamEnv(_) => true, + }); + } + } + if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer { + if let Some(e) = self.tainted_by_errors() + && arg.is_none() + { + // If `arg.is_none()`, then this is probably two param-env + // candidates or impl candidates that are equal modulo lifetimes. + // Therefore, if we've already emitted an error, just skip this + // one, since it's not particularly actionable. + err.cancel(); + return e; + } + self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate); + } else { + if let Some(e) = self.tainted_by_errors() { + err.cancel(); + return e; + } + err.note(format!("cannot satisfy `{predicate}`")); + let impl_candidates = + self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap()); + if impl_candidates.len() < 40 { + self.report_similar_impl_candidates( + impl_candidates.as_slice(), + trait_ref, + obligation.cause.body_id, + &mut err, + false, + obligation.param_env, + ); + } + } + + if let ObligationCauseCode::WhereClause(def_id, _) + | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code() + { + self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); + } + + if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack()) + && let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) + { + let mut expr_finder = FindExprBySpan::new(span, self.tcx); + expr_finder.visit_expr(&body.value); + + if let Some(hir::Expr { + kind: + hir::ExprKind::Call( + hir::Expr { + kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), + .. + }, + _, + ) + | hir::ExprKind::Path(hir::QPath::Resolved(None, path)), + .. + }) = expr_finder.result + && let [ + .., + trait_path_segment @ hir::PathSegment { + res: Res::Def(DefKind::Trait, trait_id), + .. + }, + hir::PathSegment { + ident: assoc_item_name, + res: Res::Def(_, item_id), + .. + }, + ] = path.segments + && data.trait_ref.def_id == *trait_id + && self.tcx.trait_of_item(*item_id) == Some(*trait_id) + && let None = self.tainted_by_errors() + { + let (verb, noun) = match self.tcx.associated_item(item_id).kind { + ty::AssocKind::Const => ("refer to the", "constant"), + ty::AssocKind::Fn => ("call", "function"), + // This is already covered by E0223, but this following single match + // arm doesn't hurt here. + ty::AssocKind::Type => ("refer to the", "type"), + }; + + // Replace the more general E0283 with a more specific error + err.cancel(); + err = self.dcx().struct_span_err( + span, + format!( + "cannot {verb} associated {noun} on trait without specifying the \ + corresponding `impl` type", + ), + ); + err.code(E0790); + + if let Some(local_def_id) = data.trait_ref.def_id.as_local() + && let hir::Node::Item(hir::Item { + ident: trait_name, + kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), + .. + }) = self.tcx.hir_node_by_def_id(local_def_id) + && let Some(method_ref) = trait_item_refs + .iter() + .find(|item_ref| item_ref.ident == *assoc_item_name) + { + err.span_label( + method_ref.span, + format!("`{trait_name}::{assoc_item_name}` defined here"), + ); + } + + err.span_label(span, format!("cannot {verb} associated {noun} of trait")); + + let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id); + + if let Some(impl_def_id) = + trait_impls.non_blanket_impls().values().flatten().next() + { + let non_blanket_impl_count = + trait_impls.non_blanket_impls().values().flatten().count(); + // If there is only one implementation of the trait, suggest using it. + // Otherwise, use a placeholder comment for the implementation. + let (message, self_type) = if non_blanket_impl_count == 1 { + ( + "use the fully-qualified path to the only available \ + implementation", + format!( + "{}", + self.tcx.type_of(impl_def_id).instantiate_identity() + ), + ) + } else { + ( + "use a fully-qualified path to a specific available \ + implementation", + "/* self type */".to_string(), + ) + }; + let mut suggestions = + vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))]; + if let Some(generic_arg) = trait_path_segment.args { + let between_span = + trait_path_segment.ident.span.between(generic_arg.span_ext); + // get rid of :: between Trait and + // must be '::' between them, otherwise the parser won't accept the code + suggestions.push((between_span, "".to_string())); + suggestions + .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string())); + } else { + suggestions.push(( + trait_path_segment.ident.span.shrink_to_hi(), + ">".to_string(), + )); + } + err.multipart_suggestion( + message, + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + }; + + err + } + + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + + if let Err(e) = arg.error_reported() { + return e; + } + if let Some(e) = self.tainted_by_errors() { + return e; + } + + self.emit_inference_failure_err( + obligation.cause.body_id, + span, + arg, + TypeAnnotationNeeded::E0282, + false, + ) + } + + ty::PredicateKind::Subtype(data) => { + if let Err(e) = data.error_reported() { + return e; + } + if let Some(e) = self.tainted_by_errors() { + return e; + } + let ty::SubtypePredicate { a_is_expected: _, a, b } = data; + // both must be type variables, or the other would've been instantiated + assert!(a.is_ty_var() && b.is_ty_var()); + self.emit_inference_failure_err( + obligation.cause.body_id, + span, + a.into(), + TypeAnnotationNeeded::E0282, + true, + ) + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { + if let Err(e) = predicate.error_reported() { + return e; + } + if let Some(e) = self.tainted_by_errors() { + return e; + } + + if let Err(guar) = + self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_term.def_id)) + { + // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case + // other `Foo` impls are incoherent. + return guar; + } + let arg = data + .projection_term + .args + .iter() + .chain(Some(data.term.into_arg())) + .find(|g| g.has_non_region_infer()); + if let Some(arg) = arg { + self.emit_inference_failure_err( + obligation.cause.body_id, + span, + arg, + TypeAnnotationNeeded::E0284, + true, + ) + .with_note(format!("cannot satisfy `{predicate}`")) + } else { + // If we can't find a generic parameter, just print a generic error + struct_span_code_err!( + self.dcx(), + span, + E0284, + "type annotations needed: cannot satisfy `{}`", + predicate, + ) + .with_span_label(span, format!("cannot satisfy `{predicate}`")) + } + } + + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => { + if let Err(e) = predicate.error_reported() { + return e; + } + if let Some(e) = self.tainted_by_errors() { + return e; + } + let arg = data.walk().find(|g| g.is_non_region_infer()); + if let Some(arg) = arg { + let err = self.emit_inference_failure_err( + obligation.cause.body_id, + span, + arg, + TypeAnnotationNeeded::E0284, + true, + ); + err + } else { + // If we can't find a generic parameter, just print a generic error + struct_span_code_err!( + self.dcx(), + span, + E0284, + "type annotations needed: cannot satisfy `{}`", + predicate, + ) + .with_span_label(span, format!("cannot satisfy `{predicate}`")) + } + } + + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self + .emit_inference_failure_err( + obligation.cause.body_id, + span, + ct.into(), + TypeAnnotationNeeded::E0284, + true, + ), + ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) + if term.is_infer() => + { + if let Some(e) = self.tainted_by_errors() { + return e; + } + struct_span_code_err!( + self.dcx(), + span, + E0284, + "type annotations needed: cannot normalize `{alias}`", + ) + .with_span_label(span, format!("cannot normalize `{alias}`")) + } + + _ => { + if let Some(e) = self.tainted_by_errors() { + return e; + } + struct_span_code_err!( + self.dcx(), + span, + E0284, + "type annotations needed: cannot satisfy `{}`", + predicate, + ) + .with_span_label(span, format!("cannot satisfy `{predicate}`")) + } + }; + self.note_obligation_cause(&mut err, obligation); + err.emit() + } + + fn annotate_source_of_ambiguity( + &self, + err: &mut Diag<'_>, + ambiguities: &[CandidateSource], + predicate: ty::Predicate<'tcx>, + ) { + let mut spans = vec![]; + let mut crates = vec![]; + let mut post = vec![]; + let mut has_param_env = false; + for ambiguity in ambiguities { + match ambiguity { + CandidateSource::DefId(impl_def_id) => match self.tcx.span_of_impl(*impl_def_id) { + Ok(span) => spans.push(span), + Err(name) => { + crates.push(name); + if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) { + post.push(header); + } + } + }, + CandidateSource::ParamEnv(span) => { + has_param_env = true; + spans.push(*span); + } + } + } + let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect(); + crate_names.sort(); + crate_names.dedup(); + post.sort(); + post.dedup(); + + if self.tainted_by_errors().is_some() + && (crate_names.len() == 1 + && spans.len() == 0 + && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) + || predicate.visit_with(&mut HasNumericInferVisitor).is_break()) + { + // Avoid complaining about other inference issues for expressions like + // `42 >> 1`, where the types are still `{integer}`, but we want to + // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too? + // NOTE(eddyb) this was `.cancel()`, but `err` + // is borrowed, so we can't fully defuse it. + err.downgrade_to_delayed_bug(); + return; + } + + let msg = format!( + "multiple `impl`s{} satisfying `{}` found", + if has_param_env { " or `where` clauses" } else { "" }, + predicate + ); + let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) { + format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::>().join("\n"),) + } else if post.len() == 1 { + format!(": `{}`", post[0]) + } else { + String::new() + }; + + match (spans.len(), crates.len(), crate_names.len()) { + (0, 0, 0) => { + err.note(format!("cannot satisfy `{predicate}`")); + } + (0, _, 1) => { + err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,)); + } + (0, _, _) => { + err.note(format!( + "{} in the following crates: {}{}", + msg, + crate_names.join(", "), + post, + )); + } + (_, 0, 0) => { + let span: MultiSpan = spans.into(); + err.span_note(span, msg); + } + (_, 1, 1) => { + let span: MultiSpan = spans.into(); + err.span_note(span, msg); + err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,)); + } + _ => { + let span: MultiSpan = spans.into(); + err.span_note(span, msg); + err.note(format!( + "and more `impl`s found in the following crates: {}{}", + crate_names.join(", "), + post, + )); + } + } + } +} + +struct HasNumericInferVisitor; + +impl<'tcx> ty::TypeVisitor> for HasNumericInferVisitor { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + } +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 7d334d623cc24..e776248e68476 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -15,7 +15,6 @@ use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode, Pred use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; -use std::ops::ControlFlow; pub use self::infer_ctxt_ext::*; pub use self::overflow::*; @@ -91,49 +90,6 @@ impl<'v> Visitor<'v> for FindExprBySpan<'v> { } } -/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting -/// `param: ?Sized` would be a valid constraint. -struct FindTypeParam { - param: rustc_span::Symbol, - invalid_spans: Vec, - nested: bool, -} - -impl<'v> Visitor<'v> for FindTypeParam { - fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) { - // Skip where-clauses, to avoid suggesting indirection for type parameters found there. - } - - fn visit_ty(&mut self, ty: &hir::Ty<'_>) { - // We collect the spans of all uses of the "bare" type param, like in `field: T` or - // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be - // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized` - // obligations like `Box` and `Vec`, but we perform no extra analysis for those cases - // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors - // in that case should make what happened clear enough. - match ty.kind { - hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {} - hir::TyKind::Path(hir::QPath::Resolved(None, path)) - if path.segments.len() == 1 && path.segments[0].ident.name == self.param => - { - if !self.nested { - debug!(?ty, "FindTypeParam::visit_ty"); - self.invalid_spans.push(ty.span); - } - } - hir::TyKind::Path(_) => { - let prev = self.nested; - self.nested = true; - hir::intravisit::walk_ty(self, ty); - self.nested = prev; - } - _ => { - hir::intravisit::walk_ty(self, ty); - } - } - } -} - /// Summarizes information #[derive(Clone)] pub enum ArgKind { @@ -165,20 +121,6 @@ impl ArgKind { } } -struct HasNumericInferVisitor; - -impl<'tcx> ty::TypeVisitor> for HasNumericInferVisitor { - type Result = ControlFlow<()>; - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - } -} - #[derive(Copy, Clone)] pub enum DefIdOrName { DefId(DefId), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index fdc6db4abec0b..11a2b1d323379 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4623,6 +4623,132 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } } + + #[instrument(level = "debug", skip_all)] + fn suggest_unsized_bound_if_applicable( + &self, + err: &mut Diag<'_>, + obligation: &PredicateObligation<'tcx>, + ) { + let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = + obligation.predicate.kind().skip_binder() + else { + return; + }; + let (ObligationCauseCode::WhereClause(item_def_id, span) + | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) = + *obligation.cause.code().peel_derives() + else { + return; + }; + if span.is_dummy() { + return; + } + debug!(?pred, ?item_def_id, ?span); + + let (Some(node), true) = ( + self.tcx.hir().get_if_local(item_def_id), + self.tcx.is_lang_item(pred.def_id(), LangItem::Sized), + ) else { + return; + }; + + let Some(generics) = node.generics() else { + return; + }; + let sized_trait = self.tcx.lang_items().sized_trait(); + debug!(?generics.params); + debug!(?generics.predicates); + let Some(param) = generics.params.iter().find(|param| param.span == span) else { + return; + }; + // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit + // `Sized` bound is there intentionally and we don't need to suggest relaxing it. + let explicitly_sized = generics + .bounds_for_param(param.def_id) + .flat_map(|bp| bp.bounds) + .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); + if explicitly_sized { + return; + } + debug!(?param); + match node { + hir::Node::Item( + item @ hir::Item { + // Only suggest indirection for uses of type parameters in ADTs. + kind: + hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..), + .. + }, + ) => { + if self.suggest_indirection_for_unsized(err, item, param) { + return; + } + } + _ => {} + }; + + // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`. + let (span, separator, open_paren_sp) = + if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) { + (s, " +", open_paren_sp) + } else { + (param.name.ident().span.shrink_to_hi(), ":", None) + }; + + let mut suggs = vec![]; + let suggestion = format!("{separator} ?Sized"); + + if let Some(open_paren_sp) = open_paren_sp { + suggs.push((open_paren_sp, "(".to_string())); + suggs.push((span, format!("){suggestion}"))); + } else { + suggs.push((span, suggestion)); + } + + err.multipart_suggestion_verbose( + "consider relaxing the implicit `Sized` restriction", + suggs, + Applicability::MachineApplicable, + ); + } + + fn suggest_indirection_for_unsized( + &self, + err: &mut Diag<'_>, + item: &hir::Item<'tcx>, + param: &hir::GenericParam<'tcx>, + ) -> bool { + // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a + // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S(T);` + // is not. Look for invalid "bare" parameter uses, and suggest using indirection. + let mut visitor = + FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false }; + visitor.visit_item(item); + if visitor.invalid_spans.is_empty() { + return false; + } + let mut multispan: MultiSpan = param.span.into(); + multispan.push_span_label( + param.span, + format!("this could be changed to `{}: ?Sized`...", param.name.ident()), + ); + for sp in visitor.invalid_spans { + multispan.push_span_label( + sp, + format!("...if indirection were used here: `Box<{}>`", param.name.ident()), + ); + } + err.span_help( + multispan, + format!( + "you could relax the implicit `Sized` bound on `{T}` if it were \ + used through indirection like `&{T}` or `Box<{T}>`", + T = param.name.ident(), + ), + ); + true + } } /// Add a hint to add a missing borrow or remove an unnecessary one. @@ -5126,3 +5252,46 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec) { (ty, refs) } + +/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting +/// `param: ?Sized` would be a valid constraint. +struct FindTypeParam { + param: rustc_span::Symbol, + invalid_spans: Vec, + nested: bool, +} + +impl<'v> Visitor<'v> for FindTypeParam { + fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) { + // Skip where-clauses, to avoid suggesting indirection for type parameters found there. + } + + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + // We collect the spans of all uses of the "bare" type param, like in `field: T` or + // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be + // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized` + // obligations like `Box` and `Vec`, but we perform no extra analysis for those cases + // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors + // in that case should make what happened clear enough. + match ty.kind { + hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {} + hir::TyKind::Path(hir::QPath::Resolved(None, path)) + if path.segments.len() == 1 && path.segments[0].ident.name == self.param => + { + if !self.nested { + debug!(?ty, "FindTypeParam::visit_ty"); + self.invalid_spans.push(ty.span); + } + } + hir::TyKind::Path(_) => { + let prev = self.nested; + self.nested = true; + hir::intravisit::walk_ty(self, ty); + self.nested = prev; + } + _ => { + hir::intravisit::walk_ty(self, ty); + } + } + } +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs index ee5f4f44251c0..dec3b26420c24 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs @@ -1,15 +1,12 @@ -// ignore-tidy-filelength :( - +use super::ambiguity::TypeErrCtxtAmbiguityExt as _; use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt; use crate::error_reporting::traits::overflow::TypeErrCtxtOverflowExt; -use crate::error_reporting::traits::to_pretty_impl_header; -use crate::error_reporting::traits::{ambiguity, ambiguity::CandidateSource::*}; use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, }; -use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; +use crate::infer::error_reporting::TyCategory; use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -23,13 +20,13 @@ use core::ops::ControlFlow; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; -use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart}; +use rustc_errors::{pluralize, struct_span_code_err, Applicability, StringPart}; use rustc_errors::{Diag, ErrorGuaranteed, StashKey}; -use rustc_hir::def::{DefKind, Namespace, Res}; +use rustc_hir::def::Namespace; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; +use rustc_hir::Node; use rustc_hir::{self as hir, LangItem}; -use rustc_hir::{GenericParam, Item, Node}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; use rustc_macros::extension; @@ -43,8 +40,7 @@ use rustc_middle::ty::print::{ PrintTraitRefExt as _, }; use rustc_middle::ty::{ - self, SubtypePredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable, - TypeVisitableExt, Upcast, + self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; @@ -53,8 +49,7 @@ use std::borrow::Cow; use std::iter; use super::{ - ArgKind, CandidateSimilarity, FindExprBySpan, FindTypeParam, GetSafeTransmuteErrorAndReason, - HasNumericInferVisitor, ImplCandidate, UnsatisfiedConst, + ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst, }; pub use rustc_infer::traits::error_reporting::*; @@ -956,7 +951,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } /// When the `E` of the resulting `Result` in an expression `foo().bar().baz()?`, - /// identify thoe method chain sub-expressions that could or could not have been annotated + /// identify those method chain sub-expressions that could or could not have been annotated /// with `?`. fn try_conversion_context( &self, @@ -2172,536 +2167,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred) } - #[instrument(skip(self), level = "debug")] - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed { - // Unable to successfully determine, probably means - // insufficient type information, but could mean - // ambiguous impls. The latter *ought* to be a - // coherence violation, so we don't report it here. - - let predicate = self.resolve_vars_if_possible(obligation.predicate); - let span = obligation.cause.span; - - debug!(?predicate, obligation.cause.code = ?obligation.cause.code()); - - // Ambiguity errors are often caused as fallout from earlier errors. - // We ignore them if this `infcx` is tainted in some cases below. - - let bound_predicate = predicate.kind(); - let mut err = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { - let trait_ref = bound_predicate.rebind(data.trait_ref); - debug!(?trait_ref); - - if let Err(e) = predicate.error_reported() { - return e; - } - - if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) { - // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case - // other `Foo` impls are incoherent. - return guar; - } - - // This is kind of a hack: it frequently happens that some earlier - // error prevents types from being fully inferred, and then we get - // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we - // could just skip over all checks where the self-ty is an - // inference variable, but I was afraid that there might be an - // inference variable created, registered as an obligation, and - // then never forced by writeback, and hence by skipping here we'd - // be ignoring the fact that we don't KNOW the type works - // out. Though even that would probably be harmless, given that - // we're only talking about builtin traits, which are known to be - // inhabited. We used to check for `self.tcx.sess.has_errors()` to - // avoid inundating the user with unnecessary errors, but we now - // check upstream for type errors and don't add the obligations to - // begin with in those cases. - if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { - match self.tainted_by_errors() { - None => { - let err = self.emit_inference_failure_err( - obligation.cause.body_id, - span, - trait_ref.self_ty().skip_binder().into(), - ErrorCode::E0282, - false, - ); - return err.stash(span, StashKey::MaybeForgetReturn).unwrap(); - } - Some(e) => return e, - } - } - - // Typically, this ambiguity should only happen if - // there are unresolved type inference variables - // (otherwise it would suggest a coherence - // failure). But given #21974 that is not necessarily - // the case -- we can have multiple where clauses that - // are only distinguished by a region, which results - // in an ambiguity even when all types are fully - // known, since we don't dispatch based on region - // relationships. - - // Pick the first generic parameter that still contains inference variables as the one - // we're going to emit an error for. If there are none (see above), fall back to - // a more general error. - let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer()); - - let mut err = if let Some(arg) = arg { - self.emit_inference_failure_err( - obligation.cause.body_id, - span, - arg, - ErrorCode::E0283, - true, - ) - } else { - struct_span_code_err!( - self.dcx(), - span, - E0283, - "type annotations needed: cannot satisfy `{}`", - predicate, - ) - }; - - let mut ambiguities = ambiguity::compute_applicable_impls_for_diagnostics( - self.infcx, - &obligation.with(self.tcx, trait_ref), - ); - let has_non_region_infer = - trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer()); - // It doesn't make sense to talk about applicable impls if there are more than a - // handful of them. If there are a lot of them, but only a few of them have no type - // params, we only show those, as they are more likely to be useful/intended. - if ambiguities.len() > 5 { - let infcx = self.infcx; - if !ambiguities.iter().all(|option| match option { - DefId(did) => infcx.tcx.generics_of(*did).count() == 0, - ParamEnv(_) => true, - }) { - // If not all are blanket impls, we filter blanked impls out. - ambiguities.retain(|option| match option { - DefId(did) => infcx.tcx.generics_of(*did).count() == 0, - ParamEnv(_) => true, - }); - } - } - if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer { - if let Some(e) = self.tainted_by_errors() - && arg.is_none() - { - // If `arg.is_none()`, then this is probably two param-env - // candidates or impl candidates that are equal modulo lifetimes. - // Therefore, if we've already emitted an error, just skip this - // one, since it's not particularly actionable. - err.cancel(); - return e; - } - self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate); - } else { - if let Some(e) = self.tainted_by_errors() { - err.cancel(); - return e; - } - err.note(format!("cannot satisfy `{predicate}`")); - let impl_candidates = - self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap()); - if impl_candidates.len() < 40 { - self.report_similar_impl_candidates( - impl_candidates.as_slice(), - trait_ref, - obligation.cause.body_id, - &mut err, - false, - obligation.param_env, - ); - } - } - - if let ObligationCauseCode::WhereClause(def_id, _) - | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code() - { - self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); - } - - if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack()) - && let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) - { - let mut expr_finder = FindExprBySpan::new(span, self.tcx); - expr_finder.visit_expr(&body.value); - - if let Some(hir::Expr { - kind: - hir::ExprKind::Call( - hir::Expr { - kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), - .. - }, - _, - ) - | hir::ExprKind::Path(hir::QPath::Resolved(None, path)), - .. - }) = expr_finder.result - && let [ - .., - trait_path_segment @ hir::PathSegment { - res: Res::Def(DefKind::Trait, trait_id), - .. - }, - hir::PathSegment { - ident: assoc_item_name, - res: Res::Def(_, item_id), - .. - }, - ] = path.segments - && data.trait_ref.def_id == *trait_id - && self.tcx.trait_of_item(*item_id) == Some(*trait_id) - && let None = self.tainted_by_errors() - { - let (verb, noun) = match self.tcx.associated_item(item_id).kind { - ty::AssocKind::Const => ("refer to the", "constant"), - ty::AssocKind::Fn => ("call", "function"), - // This is already covered by E0223, but this following single match - // arm doesn't hurt here. - ty::AssocKind::Type => ("refer to the", "type"), - }; - - // Replace the more general E0283 with a more specific error - err.cancel(); - err = self.dcx().struct_span_err( - span, - format!( - "cannot {verb} associated {noun} on trait without specifying the \ - corresponding `impl` type", - ), - ); - err.code(E0790); - - if let Some(local_def_id) = data.trait_ref.def_id.as_local() - && let hir::Node::Item(hir::Item { - ident: trait_name, - kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), - .. - }) = self.tcx.hir_node_by_def_id(local_def_id) - && let Some(method_ref) = trait_item_refs - .iter() - .find(|item_ref| item_ref.ident == *assoc_item_name) - { - err.span_label( - method_ref.span, - format!("`{trait_name}::{assoc_item_name}` defined here"), - ); - } - - err.span_label(span, format!("cannot {verb} associated {noun} of trait")); - - let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id); - - if let Some(impl_def_id) = - trait_impls.non_blanket_impls().values().flatten().next() - { - let non_blanket_impl_count = - trait_impls.non_blanket_impls().values().flatten().count(); - // If there is only one implementation of the trait, suggest using it. - // Otherwise, use a placeholder comment for the implementation. - let (message, self_type) = if non_blanket_impl_count == 1 { - ( - "use the fully-qualified path to the only available \ - implementation", - format!( - "{}", - self.tcx.type_of(impl_def_id).instantiate_identity() - ), - ) - } else { - ( - "use a fully-qualified path to a specific available \ - implementation", - "/* self type */".to_string(), - ) - }; - let mut suggestions = - vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))]; - if let Some(generic_arg) = trait_path_segment.args { - let between_span = - trait_path_segment.ident.span.between(generic_arg.span_ext); - // get rid of :: between Trait and - // must be '::' between them, otherwise the parser won't accept the code - suggestions.push((between_span, "".to_string())); - suggestions - .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string())); - } else { - suggestions.push(( - trait_path_segment.ident.span.shrink_to_hi(), - ">".to_string(), - )); - } - err.multipart_suggestion( - message, - suggestions, - Applicability::MaybeIncorrect, - ); - } - } - }; - - err - } - - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { - // Same hacky approach as above to avoid deluging user - // with error messages. - - if let Err(e) = arg.error_reported() { - return e; - } - if let Some(e) = self.tainted_by_errors() { - return e; - } - - self.emit_inference_failure_err( - obligation.cause.body_id, - span, - arg, - ErrorCode::E0282, - false, - ) - } - - ty::PredicateKind::Subtype(data) => { - if let Err(e) = data.error_reported() { - return e; - } - if let Some(e) = self.tainted_by_errors() { - return e; - } - let SubtypePredicate { a_is_expected: _, a, b } = data; - // both must be type variables, or the other would've been instantiated - assert!(a.is_ty_var() && b.is_ty_var()); - self.emit_inference_failure_err( - obligation.cause.body_id, - span, - a.into(), - ErrorCode::E0282, - true, - ) - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { - if let Err(e) = predicate.error_reported() { - return e; - } - if let Some(e) = self.tainted_by_errors() { - return e; - } - - if let Err(guar) = - self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_term.def_id)) - { - // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case - // other `Foo` impls are incoherent. - return guar; - } - let arg = data - .projection_term - .args - .iter() - .chain(Some(data.term.into_arg())) - .find(|g| g.has_non_region_infer()); - if let Some(arg) = arg { - self.emit_inference_failure_err( - obligation.cause.body_id, - span, - arg, - ErrorCode::E0284, - true, - ) - .with_note(format!("cannot satisfy `{predicate}`")) - } else { - // If we can't find a generic parameter, just print a generic error - struct_span_code_err!( - self.dcx(), - span, - E0284, - "type annotations needed: cannot satisfy `{}`", - predicate, - ) - .with_span_label(span, format!("cannot satisfy `{predicate}`")) - } - } - - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => { - if let Err(e) = predicate.error_reported() { - return e; - } - if let Some(e) = self.tainted_by_errors() { - return e; - } - let arg = data.walk().find(|g| g.is_non_region_infer()); - if let Some(arg) = arg { - let err = self.emit_inference_failure_err( - obligation.cause.body_id, - span, - arg, - ErrorCode::E0284, - true, - ); - err - } else { - // If we can't find a generic parameter, just print a generic error - struct_span_code_err!( - self.dcx(), - span, - E0284, - "type annotations needed: cannot satisfy `{}`", - predicate, - ) - .with_span_label(span, format!("cannot satisfy `{predicate}`")) - } - } - - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self - .emit_inference_failure_err( - obligation.cause.body_id, - span, - ct.into(), - ErrorCode::E0284, - true, - ), - ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) - if term.is_infer() => - { - if let Some(e) = self.tainted_by_errors() { - return e; - } - struct_span_code_err!( - self.dcx(), - span, - E0284, - "type annotations needed: cannot normalize `{alias}`", - ) - .with_span_label(span, format!("cannot normalize `{alias}`")) - } - - _ => { - if let Some(e) = self.tainted_by_errors() { - return e; - } - struct_span_code_err!( - self.dcx(), - span, - E0284, - "type annotations needed: cannot satisfy `{}`", - predicate, - ) - .with_span_label(span, format!("cannot satisfy `{predicate}`")) - } - }; - self.note_obligation_cause(&mut err, obligation); - err.emit() - } - - fn annotate_source_of_ambiguity( - &self, - err: &mut Diag<'_>, - ambiguities: &[ambiguity::CandidateSource], - predicate: ty::Predicate<'tcx>, - ) { - let mut spans = vec![]; - let mut crates = vec![]; - let mut post = vec![]; - let mut has_param_env = false; - for ambiguity in ambiguities { - match ambiguity { - ambiguity::CandidateSource::DefId(impl_def_id) => { - match self.tcx.span_of_impl(*impl_def_id) { - Ok(span) => spans.push(span), - Err(name) => { - crates.push(name); - if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) { - post.push(header); - } - } - } - } - ambiguity::CandidateSource::ParamEnv(span) => { - has_param_env = true; - spans.push(*span); - } - } - } - let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect(); - crate_names.sort(); - crate_names.dedup(); - post.sort(); - post.dedup(); - - if self.tainted_by_errors().is_some() - && (crate_names.len() == 1 - && spans.len() == 0 - && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) - || predicate.visit_with(&mut HasNumericInferVisitor).is_break()) - { - // Avoid complaining about other inference issues for expressions like - // `42 >> 1`, where the types are still `{integer}`, but we want to - // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too? - // NOTE(eddyb) this was `.cancel()`, but `err` - // is borrowed, so we can't fully defuse it. - err.downgrade_to_delayed_bug(); - return; - } - - let msg = format!( - "multiple `impl`s{} satisfying `{}` found", - if has_param_env { " or `where` clauses" } else { "" }, - predicate - ); - let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) { - format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::>().join("\n"),) - } else if post.len() == 1 { - format!(": `{}`", post[0]) - } else { - String::new() - }; - - match (spans.len(), crates.len(), crate_names.len()) { - (0, 0, 0) => { - err.note(format!("cannot satisfy `{predicate}`")); - } - (0, _, 1) => { - err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,)); - } - (0, _, _) => { - err.note(format!( - "{} in the following crates: {}{}", - msg, - crate_names.join(", "), - post, - )); - } - (_, 0, 0) => { - let span: MultiSpan = spans.into(); - err.span_note(span, msg); - } - (_, 1, 1) => { - let span: MultiSpan = spans.into(); - err.span_note(span, msg); - err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,)); - } - _ => { - let span: MultiSpan = spans.into(); - err.span_note(span, msg); - err.note(format!( - "and more `impl`s found in the following crates: {}{}", - crate_names.join(", "), - post, - )); - } - } - } - /// Returns `true` if the trait predicate may apply for *some* assignment /// to the type parameters. fn predicate_can_apply( @@ -2769,136 +2234,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - #[instrument(level = "debug", skip_all)] - fn suggest_unsized_bound_if_applicable( - &self, - err: &mut Diag<'_>, - obligation: &PredicateObligation<'tcx>, - ) { - let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = - obligation.predicate.kind().skip_binder() - else { - return; - }; - let (ObligationCauseCode::WhereClause(item_def_id, span) - | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) = - *obligation.cause.code().peel_derives() - else { - return; - }; - if span.is_dummy() { - return; - } - debug!(?pred, ?item_def_id, ?span); - - let (Some(node), true) = ( - self.tcx.hir().get_if_local(item_def_id), - self.tcx.is_lang_item(pred.def_id(), LangItem::Sized), - ) else { - return; - }; - self.maybe_suggest_unsized_generics(err, span, node); - } - - #[instrument(level = "debug", skip_all)] - fn maybe_suggest_unsized_generics(&self, err: &mut Diag<'_>, span: Span, node: Node<'tcx>) { - let Some(generics) = node.generics() else { - return; - }; - let sized_trait = self.tcx.lang_items().sized_trait(); - debug!(?generics.params); - debug!(?generics.predicates); - let Some(param) = generics.params.iter().find(|param| param.span == span) else { - return; - }; - // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit - // `Sized` bound is there intentionally and we don't need to suggest relaxing it. - let explicitly_sized = generics - .bounds_for_param(param.def_id) - .flat_map(|bp| bp.bounds) - .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); - if explicitly_sized { - return; - } - debug!(?param); - match node { - hir::Node::Item( - item @ hir::Item { - // Only suggest indirection for uses of type parameters in ADTs. - kind: - hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..), - .. - }, - ) => { - if self.maybe_indirection_for_unsized(err, item, param) { - return; - } - } - _ => {} - }; - - // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`. - let (span, separator, open_paren_sp) = - if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) { - (s, " +", open_paren_sp) - } else { - (param.name.ident().span.shrink_to_hi(), ":", None) - }; - - let mut suggs = vec![]; - let suggestion = format!("{separator} ?Sized"); - - if let Some(open_paren_sp) = open_paren_sp { - suggs.push((open_paren_sp, "(".to_string())); - suggs.push((span, format!("){suggestion}"))); - } else { - suggs.push((span, suggestion)); - } - - err.multipart_suggestion_verbose( - "consider relaxing the implicit `Sized` restriction", - suggs, - Applicability::MachineApplicable, - ); - } - - fn maybe_indirection_for_unsized( - &self, - err: &mut Diag<'_>, - item: &Item<'tcx>, - param: &GenericParam<'tcx>, - ) -> bool { - // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a - // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S(T);` - // is not. Look for invalid "bare" parameter uses, and suggest using indirection. - let mut visitor = - FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false }; - visitor.visit_item(item); - if visitor.invalid_spans.is_empty() { - return false; - } - let mut multispan: MultiSpan = param.span.into(); - multispan.push_span_label( - param.span, - format!("this could be changed to `{}: ?Sized`...", param.name.ident()), - ); - for sp in visitor.invalid_spans { - multispan.push_span_label( - sp, - format!("...if indirection were used here: `Box<{}>`", param.name.ident()), - ); - } - err.span_help( - multispan, - format!( - "you could relax the implicit `Sized` bound on `{T}` if it were \ - used through indirection like `&{T}` or `Box<{T}>`", - T = param.name.ident(), - ), - ); - true - } - fn is_recursive_obligation( &self, obligated_types: &mut Vec>, From bbbff806038eeb178a7984820f498a03baff02f1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Jul 2024 16:58:18 -0400 Subject: [PATCH 12/15] Split out fulfillment error reporting a bit more --- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- ..._err_ctxt_ext.rs => fulfillment_errors.rs} | 204 +---------------- .../error_reporting/traits/infer_ctxt_ext.rs | 4 +- .../src/error_reporting/traits/mod.rs | 215 +++++++++++++++++- .../traits/on_unimplemented.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 2 +- 6 files changed, 221 insertions(+), 208 deletions(-) rename compiler/rustc_trait_selection/src/error_reporting/traits/{type_err_ctxt_ext.rs => fulfillment_errors.rs} (93%) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index d1b99aae25b1d..5e2a68e1f02db 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -59,7 +59,7 @@ use rustc_span::symbol::sym; use rustc_span::{BytePos, DesugaringKind, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtSelectionErrExt as _; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs similarity index 93% rename from compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs rename to compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index dec3b26420c24..f7ec5f1ff325f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1,8 +1,6 @@ -use super::ambiguity::TypeErrCtxtAmbiguityExt as _; use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt; -use crate::error_reporting::traits::overflow::TypeErrCtxtOverflowExt; use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, }; @@ -12,12 +10,12 @@ use crate::infer::{self, InferCtxt}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::NormalizeExt; use crate::traits::{ - elaborate, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, - ObligationCause, ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation, - SelectionError, SignatureMismatch, TraitNotObjectSafe, + elaborate, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode, + ObligationCtxt, Overflow, PredicateObligation, SelectionError, SignatureMismatch, + TraitNotObjectSafe, }; use core::ops::ControlFlow; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{pluralize, struct_span_code_err, Applicability, StringPart}; @@ -44,9 +42,8 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; -use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP}; +use rustc_span::{BytePos, Span, Symbol, DUMMY_SP}; use std::borrow::Cow; -use std::iter; use super::{ ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst, @@ -54,128 +51,8 @@ use super::{ pub use rustc_infer::traits::error_reporting::*; -#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] +#[extension(pub trait TypeErrCtxtSelectionErrExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - fn report_fulfillment_errors( - &self, - mut errors: Vec>, - ) -> ErrorGuaranteed { - self.sub_relations - .borrow_mut() - .add_constraints(self, errors.iter().map(|e| e.obligation.predicate)); - - #[derive(Debug)] - struct ErrorDescriptor<'tcx> { - predicate: ty::Predicate<'tcx>, - index: Option, // None if this is an old error - } - - let mut error_map: FxIndexMap<_, Vec<_>> = self - .reported_trait_errors - .borrow() - .iter() - .map(|(&span, predicates)| { - ( - span, - predicates - .0 - .iter() - .map(|&predicate| ErrorDescriptor { predicate, index: None }) - .collect(), - ) - }) - .collect(); - - // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics - // with more relevant type information and hide redundant E0282 errors. - errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) - if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) => - { - 1 - } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, - ty::PredicateKind::Coerce(_) => 2, - _ => 0, - }); - - for (index, error) in errors.iter().enumerate() { - // We want to ignore desugarings here: spans are equivalent even - // if one is the result of a desugaring and the other is not. - let mut span = error.obligation.cause.span; - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(_) = expn_data.kind { - span = expn_data.call_site; - } - - error_map.entry(span).or_default().push(ErrorDescriptor { - predicate: error.obligation.predicate, - index: Some(index), - }); - } - - // We do this in 2 passes because we want to display errors in order, though - // maybe it *is* better to sort errors by span or something. - let mut is_suppressed = vec![false; errors.len()]; - for (_, error_set) in error_map.iter() { - // We want to suppress "duplicate" errors with the same span. - for error in error_set { - if let Some(index) = error.index { - // Suppress errors that are either: - // 1) strictly implied by another error. - // 2) implied by an error with a smaller index. - for error2 in error_set { - if error2.index.is_some_and(|index2| is_suppressed[index2]) { - // Avoid errors being suppressed by already-suppressed - // errors, to prevent all errors from being suppressed - // at once. - continue; - } - - if self.error_implies(error2.predicate, error.predicate) - && !(error2.index >= error.index - && self.error_implies(error.predicate, error2.predicate)) - { - info!("skipping {:?} (implied by {:?})", error, error2); - is_suppressed[index] = true; - break; - } - } - } - } - } - - let mut reported = None; - - for from_expansion in [false, true] { - for (error, suppressed) in iter::zip(&errors, &is_suppressed) { - if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { - let guar = self.report_fulfillment_error(error); - self.infcx.set_tainted_by_errors(guar); - reported = Some(guar); - // We want to ignore desugarings here: spans are equivalent even - // if one is the result of a desugaring and the other is not. - let mut span = error.obligation.cause.span; - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(_) = expn_data.kind { - span = expn_data.call_site; - } - self.reported_trait_errors - .borrow_mut() - .entry(span) - .or_insert_with(|| (vec![], guar)) - .0 - .push(error.obligation.predicate); - } - } - } - - // It could be that we don't report an error because we have seen an `ErrorReported` from - // another source. We should probably be able to fix most of these, but some are delayed - // bugs that get a proper error after this function. - reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors")) - } - /// The `root_obligation` parameter should be the `root_obligation` field /// from a `FulfillmentError`. If no `FulfillmentError` is available, /// then it should be the same as `obligation`. @@ -803,7 +680,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.point_at_returns_when_relevant(&mut err, &obligation); err.emit() } +} +#[extension(pub(super) trait TypeErrCtxtExt<'a, 'tcx>)] +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn apply_do_not_recommend(&self, obligation: &mut PredicateObligation<'tcx>) -> bool { let mut base_cause = obligation.cause.code().clone(); let mut applied_do_not_recommend = false; @@ -1324,72 +1204,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - #[instrument(skip(self), level = "debug")] - fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed { - let mut error = FulfillmentError { - obligation: error.obligation.clone(), - code: error.code.clone(), - root_obligation: error.root_obligation.clone(), - }; - if matches!( - error.code, - FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented) - | FulfillmentErrorCode::Project(_) - ) && self.apply_do_not_recommend(&mut error.obligation) - { - error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented); - } - - match error.code { - FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error( - error.obligation.clone(), - &error.root_obligation, - selection_error, - ), - FulfillmentErrorCode::Project(ref e) => { - self.report_projection_error(&error.obligation, e) - } - FulfillmentErrorCode::Ambiguity { overflow: None } => { - self.maybe_report_ambiguity(&error.obligation) - } - FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => { - self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit) - } - FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self - .report_mismatched_types( - &error.obligation.cause, - expected_found.expected, - expected_found.found, - *err, - ) - .emit(), - FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => { - let mut diag = self.report_mismatched_consts( - &error.obligation.cause, - expected_found.expected, - expected_found.found, - *err, - ); - let code = error.obligation.cause.code().peel_derives().peel_match_impls(); - if let ObligationCauseCode::WhereClause(..) - | ObligationCauseCode::WhereClauseInExpr(..) = code - { - self.note_obligation_cause_code( - error.obligation.cause.body_id, - &mut diag, - error.obligation.predicate, - error.obligation.param_env, - code, - &mut vec![], - &mut Default::default(), - ); - } - diag.emit() - } - FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle), - } - } - #[instrument(level = "debug", skip_all)] fn report_projection_error( &self, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/infer_ctxt_ext.rs index 34da8e576ce86..e8d7e80ac562c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/infer_ctxt_ext.rs @@ -1,3 +1,5 @@ +// FIXME(error_reporting): This should be made into private methods on `TypeErrCtxt`. + use crate::infer::InferCtxt; use crate::traits::{Obligation, ObligationCause, ObligationCtxt}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag}; @@ -9,8 +11,6 @@ use rustc_span::{Span, DUMMY_SP}; use super::ArgKind; -pub use rustc_infer::traits::error_reporting::*; - #[extension(pub trait InferCtxtExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { /// Given some node representing a fn-like thing in the HIR map, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index e776248e68476..2131e236401ef 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -1,24 +1,34 @@ -// ignore-tidy-filelength :( - pub mod ambiguity; +mod fulfillment_errors; mod infer_ctxt_ext; pub mod on_unimplemented; mod overflow; pub mod suggestions; -mod type_err_ctxt_ext; -use rustc_data_structures::fx::FxIndexSet; -use rustc_hir as hir; +use std::iter; + +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode, PredicateObligation}; +use rustc_hir::{self as hir, LangItem}; +use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::traits::{ + Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, +}; +use rustc_macros::extension; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, ExpnKind, Span}; + +use ambiguity::TypeErrCtxtAmbiguityExt as _; +use fulfillment_errors::TypeErrCtxtExt as _; +use suggestions::TypeErrCtxtExt as _; +use crate::traits::{FulfillmentError, FulfillmentErrorCode}; + +pub use self::fulfillment_errors::*; pub use self::infer_ctxt_ext::*; pub use self::overflow::*; -pub use self::type_err_ctxt_ext::*; // When outputting impl candidates, prefer showing those that are more similar. // @@ -127,6 +137,195 @@ pub enum DefIdOrName { Name(&'static str), } +#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + fn report_fulfillment_errors( + &self, + mut errors: Vec>, + ) -> ErrorGuaranteed { + self.sub_relations + .borrow_mut() + .add_constraints(self, errors.iter().map(|e| e.obligation.predicate)); + + #[derive(Debug)] + struct ErrorDescriptor<'tcx> { + predicate: ty::Predicate<'tcx>, + index: Option, // None if this is an old error + } + + let mut error_map: FxIndexMap<_, Vec<_>> = self + .reported_trait_errors + .borrow() + .iter() + .map(|(&span, predicates)| { + ( + span, + predicates + .0 + .iter() + .map(|&predicate| ErrorDescriptor { predicate, index: None }) + .collect(), + ) + }) + .collect(); + + // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics + // with more relevant type information and hide redundant E0282 errors. + errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) + if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) => + { + 1 + } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, + ty::PredicateKind::Coerce(_) => 2, + _ => 0, + }); + + for (index, error) in errors.iter().enumerate() { + // We want to ignore desugarings here: spans are equivalent even + // if one is the result of a desugaring and the other is not. + let mut span = error.obligation.cause.span; + let expn_data = span.ctxt().outer_expn_data(); + if let ExpnKind::Desugaring(_) = expn_data.kind { + span = expn_data.call_site; + } + + error_map.entry(span).or_default().push(ErrorDescriptor { + predicate: error.obligation.predicate, + index: Some(index), + }); + } + + // We do this in 2 passes because we want to display errors in order, though + // maybe it *is* better to sort errors by span or something. + let mut is_suppressed = vec![false; errors.len()]; + for (_, error_set) in error_map.iter() { + // We want to suppress "duplicate" errors with the same span. + for error in error_set { + if let Some(index) = error.index { + // Suppress errors that are either: + // 1) strictly implied by another error. + // 2) implied by an error with a smaller index. + for error2 in error_set { + if error2.index.is_some_and(|index2| is_suppressed[index2]) { + // Avoid errors being suppressed by already-suppressed + // errors, to prevent all errors from being suppressed + // at once. + continue; + } + + if self.error_implies(error2.predicate, error.predicate) + && !(error2.index >= error.index + && self.error_implies(error.predicate, error2.predicate)) + { + info!("skipping {:?} (implied by {:?})", error, error2); + is_suppressed[index] = true; + break; + } + } + } + } + } + + let mut reported = None; + + for from_expansion in [false, true] { + for (error, suppressed) in iter::zip(&errors, &is_suppressed) { + if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { + let guar = self.report_fulfillment_error(error); + self.infcx.set_tainted_by_errors(guar); + reported = Some(guar); + // We want to ignore desugarings here: spans are equivalent even + // if one is the result of a desugaring and the other is not. + let mut span = error.obligation.cause.span; + let expn_data = span.ctxt().outer_expn_data(); + if let ExpnKind::Desugaring(_) = expn_data.kind { + span = expn_data.call_site; + } + self.reported_trait_errors + .borrow_mut() + .entry(span) + .or_insert_with(|| (vec![], guar)) + .0 + .push(error.obligation.predicate); + } + } + } + + // It could be that we don't report an error because we have seen an `ErrorReported` from + // another source. We should probably be able to fix most of these, but some are delayed + // bugs that get a proper error after this function. + reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors")) + } + + #[instrument(skip(self), level = "debug")] + fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed { + let mut error = FulfillmentError { + obligation: error.obligation.clone(), + code: error.code.clone(), + root_obligation: error.root_obligation.clone(), + }; + if matches!( + error.code, + FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented) + | FulfillmentErrorCode::Project(_) + ) && self.apply_do_not_recommend(&mut error.obligation) + { + error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented); + } + + match error.code { + FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error( + error.obligation.clone(), + &error.root_obligation, + selection_error, + ), + FulfillmentErrorCode::Project(ref e) => { + self.report_projection_error(&error.obligation, e) + } + FulfillmentErrorCode::Ambiguity { overflow: None } => { + self.maybe_report_ambiguity(&error.obligation) + } + FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => { + self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit) + } + FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self + .report_mismatched_types( + &error.obligation.cause, + expected_found.expected, + expected_found.found, + *err, + ) + .emit(), + FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => { + let mut diag = self.report_mismatched_consts( + &error.obligation.cause, + expected_found.expected, + expected_found.found, + *err, + ); + let code = error.obligation.cause.code().peel_derives().peel_match_impls(); + if let ObligationCauseCode::WhereClause(..) + | ObligationCauseCode::WhereClauseInExpr(..) = code + { + self.note_obligation_cause_code( + error.obligation.cause.body_id, + &mut diag, + error.obligation.predicate, + error.obligation.param_env, + code, + &mut vec![], + &mut Default::default(), + ); + } + diag.emit() + } + FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle), + } + } +} + /// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a /// string. pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 83c6798ba2ed1..e90fe8fb94dd2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -1,5 +1,5 @@ use super::{ObligationCauseCode, PredicateObligation}; -use crate::error_reporting::traits::type_err_ctxt_ext::InferCtxtPrivExt; +use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 11a2b1d323379..2cf808f962f08 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -44,7 +44,7 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; -use crate::error_reporting::traits::type_err_ctxt_ext::InferCtxtPrivExt; +use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt; use crate::infer::InferCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_middle::ty::print::{ From 43254672bdef83fa9d69da3b875bd79f249f62f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 5 Jul 2024 19:32:17 +0000 Subject: [PATCH 13/15] Use verbose style when suggesting changing `const` with `let` --- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_resolve/src/diagnostics.rs | 5 ++- compiler/rustc_resolve/src/errors.rs | 4 +- tests/ui/asm/parse-error.stderr | 40 ++++++++++++------- tests/ui/asm/type-check-1.stderr | 24 ++++++----- tests/ui/asm/x86_64/x86_64_parse_error.stderr | 24 ++++++----- .../legacy-const-generics-bad.stderr | 7 +++- tests/ui/consts/issue-3521.stderr | 8 ++-- tests/ui/consts/issue-91560.stderr | 16 +++++--- .../ui/consts/non-const-value-in-const.stderr | 17 +++++--- tests/ui/error-codes/E0435.stderr | 7 +++- tests/ui/issues/issue-27433.stderr | 9 +++-- tests/ui/issues/issue-3521-2.stderr | 9 +++-- .../issue-3668-2.stderr | 9 +++-- .../issue-3668.stderr | 9 +++-- tests/ui/issues/issue-44239.stderr | 8 ++-- tests/ui/parser/suggest-assoc-const.stderr | 7 +++- tests/ui/repeat-expr/repeat_count.stderr | 7 +++- .../type-dependent-def-issue-49241.stderr | 9 +++-- tests/ui/typeof/issue-42060.stderr | 14 +++++-- 20 files changed, 153 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index abb6b51cebd68..511caa9daea94 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -796,7 +796,7 @@ impl<'a> Parser<'a> { self.dcx().struct_span_err(non_item_span, "non-item in item list"); self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); if is_let { - err.span_suggestion( + err.span_suggestion_verbose( non_item_span, "consider using `const` instead of `let` for associated const", "const", diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index ffd495aa9857e..f879e548f2754 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -836,11 +836,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let ((with, with_label), without) = match sp { Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => { - let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32))); + let sp = sp + .with_lo(BytePos(sp.lo().0 - (current.len() as u32))) + .until(ident.span); ( (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion { span: sp, - ident, suggestion, current, }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})), diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 0620f3d709eb2..a4bdd62acbbda 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -242,13 +242,13 @@ pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> { #[derive(Subdiagnostic)] #[suggestion( resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion, - code = "{suggestion} {ident}", + code = "{suggestion} ", + style = "verbose", applicability = "maybe-incorrect" )] pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> { #[primary_span] pub(crate) span: Span, - pub(crate) ident: Ident, pub(crate) suggestion: &'a str, pub(crate) current: &'a str, } diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index 80ee5191dbbe9..8030face1d253 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -371,47 +371,57 @@ LL | global_asm!("{}", label {}); error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:71:44 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:74:55 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:31 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar = 0; + | ~~~~~ error: aborting due to 64 previous errors diff --git a/tests/ui/asm/type-check-1.stderr b/tests/ui/asm/type-check-1.stderr index 07a609c52139e..deba9e0fc544b 100644 --- a/tests/ui/asm/type-check-1.stderr +++ b/tests/ui/asm/type-check-1.stderr @@ -1,29 +1,35 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:41:26 | -LL | let x = 0; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | asm!("{}", const x); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:44:36 | -LL | let x = 0; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | asm!("{}", const const_foo(x)); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:47:36 | -LL | let x = 0; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | asm!("{}", const const_bar(x)); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x = 0; + | ~~~~~ error: invalid `sym` operand --> $DIR/type-check-1.rs:49:24 diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr index f2854ae512851..95b86d533fa87 100644 --- a/tests/ui/asm/x86_64/x86_64_parse_error.stderr +++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr @@ -15,29 +15,35 @@ LL | asm!("{1}", in("eax") foo, const bar); error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:13:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:15:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("eax") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar = 0; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:17:42 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{1}", in("eax") foo, const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar = 0; + | ~~~~~ error: aborting due to 5 previous errors diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr index 83c71e07253b3..6285d47807109 100644 --- a/tests/ui/const-generics/legacy-const-generics-bad.stderr +++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr @@ -1,10 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/legacy-const-generics-bad.rs:7:35 | -LL | let a = 1; - | ----- help: consider using `const` instead of `let`: `const a` LL | legacy_const_generics::foo(0, a, 2); | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const a = 1; + | ~~~~~ error: generic parameters may not be used in const operations --> $DIR/legacy-const-generics-bad.rs:12:35 diff --git a/tests/ui/consts/issue-3521.stderr b/tests/ui/consts/issue-3521.stderr index 70ce9b2d6a08a..c0e4cdc5a94ce 100644 --- a/tests/ui/consts/issue-3521.stderr +++ b/tests/ui/consts/issue-3521.stderr @@ -1,11 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3521.rs:8:15 | -LL | let foo: isize = 100; - | ------- help: consider using `const` instead of `let`: `const foo` -... LL | Bar = foo | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: isize = 100; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-91560.stderr b/tests/ui/consts/issue-91560.stderr index e1b5d4cacf8e3..37c8f50d49434 100644 --- a/tests/ui/consts/issue-91560.stderr +++ b/tests/ui/consts/issue-91560.stderr @@ -1,20 +1,24 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-91560.rs:10:19 | -LL | let mut length: usize = 2; - | -------------- help: consider using `const` instead of `let`: `const length` -LL | LL | let arr = [0; length]; | ^^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const length: usize = 2; + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-91560.rs:17:19 | -LL | let length: usize = 2; - | ------------ help: consider using `const` instead of `let`: `const length` -LL | LL | let arr = [0; length]; | ^^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const length: usize = 2; + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/consts/non-const-value-in-const.stderr b/tests/ui/consts/non-const-value-in-const.stderr index 0ce4b4b705334..ee9ac16fe42b8 100644 --- a/tests/ui/consts/non-const-value-in-const.stderr +++ b/tests/ui/consts/non-const-value-in-const.stderr @@ -2,18 +2,23 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/non-const-value-in-const.rs:3:20 | LL | const Y: i32 = x; - | ------- ^ non-constant value - | | - | help: consider using `let` instead of `const`: `let Y` + | ^ non-constant value + | +help: consider using `let` instead of `const` + | +LL | let Y: i32 = x; + | ~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/non-const-value-in-const.rs:6:17 | -LL | let x = 5; - | ----- help: consider using `const` instead of `let`: `const x` -... LL | let _ = [0; x]; | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const x = 5; + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/error-codes/E0435.stderr b/tests/ui/error-codes/E0435.stderr index 68d6ddba2a107..1ebb997639447 100644 --- a/tests/ui/error-codes/E0435.stderr +++ b/tests/ui/error-codes/E0435.stderr @@ -1,10 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/E0435.rs:5:17 | -LL | let foo: usize = 42; - | ------- help: consider using `const` instead of `let`: `const foo` LL | let _: [u8; foo]; | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: usize = 42; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-27433.stderr b/tests/ui/issues/issue-27433.stderr index aba8e612858a2..f6d5fc2b768f5 100644 --- a/tests/ui/issues/issue-27433.stderr +++ b/tests/ui/issues/issue-27433.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-27433.rs:5:23 | LL | const FOO : u32 = foo; - | --------- ^^^ non-constant value - | | - | help: consider using `let` instead of `const`: `let FOO` + | ^^^ non-constant value + | +help: consider using `let` instead of `const` + | +LL | let FOO : u32 = foo; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3521-2.stderr b/tests/ui/issues/issue-3521-2.stderr index 0be0e93c19e64..a12241cb1dfd5 100644 --- a/tests/ui/issues/issue-3521-2.stderr +++ b/tests/ui/issues/issue-3521-2.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3521-2.rs:5:23 | LL | static y: isize = foo + 1; - | -------- ^^^ non-constant value - | | - | help: consider using `let` instead of `static`: `let y` + | ^^^ non-constant value + | +help: consider using `let` instead of `static` + | +LL | let y: isize = foo + 1; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr index 3676f388891eb..9661dbf2f62fa 100644 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr +++ b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3668-2.rs:4:27 | LL | static child: isize = x + 1; - | ------------ ^ non-constant value - | | - | help: consider using `let` instead of `static`: `let child` + | ^ non-constant value + | +help: consider using `let` instead of `static` + | +LL | let child: isize = x + 1; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr index d761b2d87db4e..7fad45f4b1a25 100644 --- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr +++ b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-3668.rs:8:34 | LL | static childVal: Box

= self.child.get(); - | --------------- ^^^^ non-constant value - | | - | help: consider using `let` instead of `static`: `let childVal` + | ^^^^ non-constant value + | +help: consider using `let` instead of `static` + | +LL | let childVal: Box

= self.child.get(); + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-44239.stderr b/tests/ui/issues/issue-44239.stderr index 633fb177b75df..1a047d4c63b69 100644 --- a/tests/ui/issues/issue-44239.stderr +++ b/tests/ui/issues/issue-44239.stderr @@ -1,11 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-44239.rs:8:26 | -LL | let n: usize = 0; - | ----- help: consider using `const` instead of `let`: `const n` -... LL | const N: usize = n; | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const n: usize = 0; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/suggest-assoc-const.stderr b/tests/ui/parser/suggest-assoc-const.stderr index 6e29fad98d466..70ebeded31374 100644 --- a/tests/ui/parser/suggest-assoc-const.stderr +++ b/tests/ui/parser/suggest-assoc-const.stderr @@ -2,7 +2,12 @@ error: non-item in item list --> $DIR/suggest-assoc-const.rs:5:5 | LL | let _X: i32; - | ^^^ help: consider using `const` instead of `let` for associated const: `const` + | ^^^ + | +help: consider using `const` instead of `let` for associated const + | +LL | const _X: i32; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index 8a1ed8f3b9c7c..9b5afc557357a 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -1,10 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/repeat_count.rs:5:17 | -LL | let n = 1; - | ----- help: consider using `const` instead of `let`: `const n` LL | let a = [0; n]; | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const n = 1; + | ~~~~~ error[E0308]: mismatched types --> $DIR/repeat_count.rs:7:17 diff --git a/tests/ui/type/type-dependent-def-issue-49241.stderr b/tests/ui/type/type-dependent-def-issue-49241.stderr index 15d47cca3d202..cf372dc59681e 100644 --- a/tests/ui/type/type-dependent-def-issue-49241.stderr +++ b/tests/ui/type/type-dependent-def-issue-49241.stderr @@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-dependent-def-issue-49241.rs:3:22 | LL | const l: usize = v.count(); - | ------- ^ non-constant value - | | - | help: consider using `let` instead of `const`: `let l` + | ^ non-constant value + | +help: consider using `let` instead of `const` + | +LL | let l: usize = v.count(); + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/typeof/issue-42060.stderr b/tests/ui/typeof/issue-42060.stderr index effcbe4d7f3e8..7af65633f71d9 100644 --- a/tests/ui/typeof/issue-42060.stderr +++ b/tests/ui/typeof/issue-42060.stderr @@ -1,18 +1,24 @@ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:3:23 | -LL | let thing = (); - | --------- help: consider using `const` instead of `let`: `const thing` LL | let other: typeof(thing) = thing; | ^^^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const thing = (); + | ~~~~~ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:9:13 | -LL | let q = 1; - | ----- help: consider using `const` instead of `let`: `const q` LL | ::N | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const q = 1; + | ~~~~~ error[E0516]: `typeof` is a reserved keyword but unimplemented --> $DIR/issue-42060.rs:3:16 From a57dfdb2db83f1f7e5fd91cd743673012fc74a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 8 Jul 2024 19:43:20 +0000 Subject: [PATCH 14/15] Account for `let foo = expr`; to suggest `const foo: Ty = expr;` --- compiler/rustc_resolve/src/diagnostics.rs | 8 +++- compiler/rustc_resolve/src/errors.rs | 10 +++-- compiler/rustc_resolve/src/ident.rs | 44 ++++++++++++++----- compiler/rustc_resolve/src/lib.rs | 11 ++--- tests/ui/asm/parse-error.stderr | 20 ++++----- tests/ui/asm/type-check-1.stderr | 12 ++--- tests/ui/asm/x86_64/x86_64_parse_error.stderr | 12 ++--- .../legacy-const-generics-bad.stderr | 4 +- .../ui/consts/non-const-value-in-const.stderr | 4 +- tests/ui/issues/issue-27433.fixed | 2 +- tests/ui/issues/issue-27433.rs | 2 +- tests/ui/repeat-expr/repeat_count.stderr | 4 +- tests/ui/typeof/issue-42060.stderr | 8 ++-- 13 files changed, 85 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index f879e548f2754..09221041031a2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -819,7 +819,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span }) } - ResolutionError::AttemptToUseNonConstantValueInConstant(ident, suggestion, current) => { + ResolutionError::AttemptToUseNonConstantValueInConstant { + ident, + suggestion, + current, + type_span, + } => { // let foo =... // ^^^ given this Span // ------- get this Span to have an applicable suggestion @@ -844,6 +849,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { span: sp, suggestion, current, + type_span, }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})), None, ) diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index a4bdd62acbbda..79c76e7a976a7 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -240,16 +240,18 @@ pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> { } #[derive(Subdiagnostic)] -#[suggestion( +#[multipart_suggestion( resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion, - code = "{suggestion} ", style = "verbose", - applicability = "maybe-incorrect" + applicability = "has-placeholders" )] pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> { - #[primary_span] + // #[primary_span] + #[suggestion_part(code = "{suggestion} ")] pub(crate) span: Span, pub(crate) suggestion: &'a str, + #[suggestion_part(code = ": /* Type */")] + pub(crate) type_span: Option, pub(crate) current: &'a str, } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7d531385e2120..f1934ff184bc3 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1178,21 +1178,41 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(span) = finalize { let (span, resolution_error) = match item { None if rib_ident.as_str() == "self" => (span, LowercaseSelf), - None => ( - rib_ident.span, - AttemptToUseNonConstantValueInConstant( - original_rib_ident_def, - "const", - "let", - ), - ), + None => { + // If we have a `let name = expr;`, we have the span for + // `name` and use that to see if it is followed by a type + // specifier. If not, then we know we need to suggest + // `const name: Ty = expr;`. This is a heuristic, it will + // break down in the presence of macros. + let sm = self.tcx.sess.source_map(); + let type_span = match sm.span_look_ahead( + original_rib_ident_def.span, + ":", + None, + ) { + None => { + Some(original_rib_ident_def.span.shrink_to_hi()) + } + Some(_) => None, + }; + ( + rib_ident.span, + AttemptToUseNonConstantValueInConstant { + ident: original_rib_ident_def, + suggestion: "const", + current: "let", + type_span, + }, + ) + } Some((ident, kind)) => ( span, - AttemptToUseNonConstantValueInConstant( + AttemptToUseNonConstantValueInConstant { ident, - "let", - kind.as_str(), - ), + suggestion: "let", + current: kind.as_str(), + type_span: None, + }, ), }; self.report_error(span, resolution_error); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7cb5a3fb2fd15..3dcb83d65b029 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -236,11 +236,12 @@ enum ResolutionError<'a> { /// Error E0434: can't capture dynamic environment in a fn item. CannotCaptureDynamicEnvironmentInFnItem, /// Error E0435: attempt to use a non-constant value in a constant. - AttemptToUseNonConstantValueInConstant( - Ident, - /* suggestion */ &'static str, - /* current */ &'static str, - ), + AttemptToUseNonConstantValueInConstant { + ident: Ident, + suggestion: &'static str, + current: &'static str, + type_span: Option, + }, /// Error E0530: `X` bindings cannot shadow `Y`s. BindingShadowsSomethingUnacceptable { shadowing_binding: PatternSource, diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index 8030face1d253..1999cd09aa3b5 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -376,8 +376,8 @@ LL | asm!("{}", options(), const foo); | help: consider using `const` instead of `let` | -LL | const foo = 0; - | ~~~~~ +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:71:44 @@ -387,8 +387,8 @@ LL | asm!("{}", clobber_abi("C"), const foo); | help: consider using `const` instead of `let` | -LL | const foo = 0; - | ~~~~~ +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:74:55 @@ -398,8 +398,8 @@ LL | asm!("{}", options(), clobber_abi("C"), const foo); | help: consider using `const` instead of `let` | -LL | const foo = 0; - | ~~~~~ +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:31 @@ -409,8 +409,8 @@ LL | asm!("{a}", a = const foo, a = const bar); | help: consider using `const` instead of `let` | -LL | const foo = 0; - | ~~~~~ +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:76:46 @@ -420,8 +420,8 @@ LL | asm!("{a}", a = const foo, a = const bar); | help: consider using `const` instead of `let` | -LL | const bar = 0; - | ~~~~~ +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: aborting due to 64 previous errors diff --git a/tests/ui/asm/type-check-1.stderr b/tests/ui/asm/type-check-1.stderr index deba9e0fc544b..1852623211813 100644 --- a/tests/ui/asm/type-check-1.stderr +++ b/tests/ui/asm/type-check-1.stderr @@ -6,8 +6,8 @@ LL | asm!("{}", const x); | help: consider using `const` instead of `let` | -LL | const x = 0; - | ~~~~~ +LL | const x: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:44:36 @@ -17,8 +17,8 @@ LL | asm!("{}", const const_foo(x)); | help: consider using `const` instead of `let` | -LL | const x = 0; - | ~~~~~ +LL | const x: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/type-check-1.rs:47:36 @@ -28,8 +28,8 @@ LL | asm!("{}", const const_bar(x)); | help: consider using `const` instead of `let` | -LL | const x = 0; - | ~~~~~ +LL | const x: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: invalid `sym` operand --> $DIR/type-check-1.rs:49:24 diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr index 95b86d533fa87..9751f7b09d0eb 100644 --- a/tests/ui/asm/x86_64/x86_64_parse_error.stderr +++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr @@ -20,8 +20,8 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | help: consider using `const` instead of `let` | -LL | const bar = 0; - | ~~~~~ +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:15:46 @@ -31,8 +31,8 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | help: consider using `const` instead of `let` | -LL | const bar = 0; - | ~~~~~ +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/x86_64_parse_error.rs:17:42 @@ -42,8 +42,8 @@ LL | asm!("{1}", in("eax") foo, const bar); | help: consider using `const` instead of `let` | -LL | const bar = 0; - | ~~~~~ +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr index 6285d47807109..e9ea22e472c18 100644 --- a/tests/ui/const-generics/legacy-const-generics-bad.stderr +++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr @@ -6,8 +6,8 @@ LL | legacy_const_generics::foo(0, a, 2); | help: consider using `const` instead of `let` | -LL | const a = 1; - | ~~~~~ +LL | const a: /* Type */ = 1; + | ~~~~~ ++++++++++++ error: generic parameters may not be used in const operations --> $DIR/legacy-const-generics-bad.rs:12:35 diff --git a/tests/ui/consts/non-const-value-in-const.stderr b/tests/ui/consts/non-const-value-in-const.stderr index ee9ac16fe42b8..654b573544c2e 100644 --- a/tests/ui/consts/non-const-value-in-const.stderr +++ b/tests/ui/consts/non-const-value-in-const.stderr @@ -17,8 +17,8 @@ LL | let _ = [0; x]; | help: consider using `const` instead of `let` | -LL | const x = 5; - | ~~~~~ +LL | const x: /* Type */ = 5; + | ~~~~~ ++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-27433.fixed b/tests/ui/issues/issue-27433.fixed index ff6704e393b5b..f847b698976a0 100644 --- a/tests/ui/issues/issue-27433.fixed +++ b/tests/ui/issues/issue-27433.fixed @@ -3,5 +3,5 @@ fn main() { let foo = 42u32; #[allow(unused_variables, non_snake_case)] let FOO : u32 = foo; - //~^ ERROR attempt to use a non-constant value in a constant + //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/issues/issue-27433.rs b/tests/ui/issues/issue-27433.rs index 2a34b43f58d22..9bbc5bcbb459d 100644 --- a/tests/ui/issues/issue-27433.rs +++ b/tests/ui/issues/issue-27433.rs @@ -3,5 +3,5 @@ fn main() { let foo = 42u32; #[allow(unused_variables, non_snake_case)] const FOO : u32 = foo; - //~^ ERROR attempt to use a non-constant value in a constant + //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index 9b5afc557357a..350ac287507a3 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -6,8 +6,8 @@ LL | let a = [0; n]; | help: consider using `const` instead of `let` | -LL | const n = 1; - | ~~~~~ +LL | const n: /* Type */ = 1; + | ~~~~~ ++++++++++++ error[E0308]: mismatched types --> $DIR/repeat_count.rs:7:17 diff --git a/tests/ui/typeof/issue-42060.stderr b/tests/ui/typeof/issue-42060.stderr index 7af65633f71d9..86ba9432384b2 100644 --- a/tests/ui/typeof/issue-42060.stderr +++ b/tests/ui/typeof/issue-42060.stderr @@ -6,8 +6,8 @@ LL | let other: typeof(thing) = thing; | help: consider using `const` instead of `let` | -LL | const thing = (); - | ~~~~~ +LL | const thing: /* Type */ = (); + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/issue-42060.rs:9:13 @@ -17,8 +17,8 @@ LL | ::N | help: consider using `const` instead of `let` | -LL | const q = 1; - | ~~~~~ +LL | const q: /* Type */ = 1; + | ~~~~~ ++++++++++++ error[E0516]: `typeof` is a reserved keyword but unimplemented --> $DIR/issue-42060.rs:3:16 From 6405df54a0db150d383d3839c2e655e645a18fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Jul 2024 17:27:08 +0000 Subject: [PATCH 15/15] Fix aarch64 test --- tests/ui/asm/aarch64/parse-error.stderr | 65 ++++++++++++++++--------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr index 539c134472fda..bf6062f9163c3 100644 --- a/tests/ui/asm/aarch64/parse-error.stderr +++ b/tests/ui/asm/aarch64/parse-error.stderr @@ -313,74 +313,91 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:47:44 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:50:55 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{}", options(), clobber_abi("C"), const foo); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:52:31 | -LL | let mut foo = 0; - | ----------- help: consider using `const` instead of `let`: `const foo` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const foo: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:52:46 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:59:45 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:61:45 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:63:41 | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... LL | asm!("{1}", in("x0") foo, const bar); | ^^^ non-constant value + | +help: consider using `const` instead of `let` + | +LL | const bar: /* Type */ = 0; + | ~~~~~ ++++++++++++ + error: aborting due to 57 previous errors