diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
5 files changed, 68 insertions, 31 deletions
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 e31ff8b8729..aa153d3607b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -820,16 +820,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. }) && obligation.cause.span.can_be_used_for_suggestions() { + let (span, sugg) = if let Some(snippet) = + self.tcx.sess.source_map().span_to_snippet(obligation.cause.span).ok() + && snippet.starts_with("|") + { + (obligation.cause.span, format!("({snippet})({args})")) + } else { + (obligation.cause.span.shrink_to_hi(), format!("({args})")) + }; + // When the obligation error has been ensured to have been caused by // an argument, the `obligation.cause.span` points at the expression // of the argument, so we can provide a suggestion. Otherwise, we give // a more general note. - err.span_suggestion_verbose( - obligation.cause.span.shrink_to_hi(), - msg, - format!("({args})"), - Applicability::HasPlaceholders, - ); + err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders); } else if let DefIdOrName::DefId(def_id) = def_id_or_name { let name = match self.tcx.hir_get_if_local(def_id) { Some(hir::Node::Expr(hir::Expr { diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 70a08f34f33..bc7bdd372ba 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -4,8 +4,8 @@ use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::ty::{ - self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, TyCtxt, TypeVisitableExt, - TypingMode, fold_regions, + self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, Ty, TyCtxt, + TypeVisitableExt, TypingMode, fold_regions, }; use rustc_span::{ErrorGuaranteed, Span}; @@ -14,22 +14,22 @@ use crate::regions::OutlivesEnvironmentBuildExt; use crate::traits::ObligationCtxt; #[derive(Debug)] -pub enum InvalidOpaqueTypeArgs<'tcx> { - AlreadyReported(ErrorGuaranteed), +pub enum NonDefiningUseReason<'tcx> { + Tainted(ErrorGuaranteed), NotAParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_index: usize, span: Span }, DuplicateParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_indices: Vec<usize>, span: Span }, } -impl From<ErrorGuaranteed> for InvalidOpaqueTypeArgs<'_> { +impl From<ErrorGuaranteed> for NonDefiningUseReason<'_> { fn from(guar: ErrorGuaranteed) -> Self { - InvalidOpaqueTypeArgs::AlreadyReported(guar) + NonDefiningUseReason::Tainted(guar) } } -impl<'tcx> InvalidOpaqueTypeArgs<'tcx> { +impl<'tcx> NonDefiningUseReason<'tcx> { pub fn report(self, infcx: &InferCtxt<'tcx>) -> ErrorGuaranteed { let tcx = infcx.tcx; match self { - InvalidOpaqueTypeArgs::AlreadyReported(guar) => guar, - InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index, span } => { + NonDefiningUseReason::Tainted(guar) => guar, + NonDefiningUseReason::NotAParam { opaque_type_key, param_index, span } => { let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let opaque_param = opaque_generics.param_at(param_index, tcx); let kind = opaque_param.kind.descr(); @@ -40,7 +40,7 @@ impl<'tcx> InvalidOpaqueTypeArgs<'tcx> { param_span: tcx.def_span(opaque_param.def_id), }) } - InvalidOpaqueTypeArgs::DuplicateParam { opaque_type_key, param_indices, span } => { + NonDefiningUseReason::DuplicateParam { opaque_type_key, param_indices, span } => { let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let descr = opaque_generics.param_at(param_indices[0], tcx).kind.descr(); let spans: Vec<_> = param_indices @@ -58,15 +58,17 @@ impl<'tcx> InvalidOpaqueTypeArgs<'tcx> { } /// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter]. +/// With the new solver, uses which fail this check are simply treated as non-defining +/// and we only emit an error if no defining use exists. /// /// [rustc-dev-guide chapter]: /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html -pub fn check_opaque_type_parameter_valid<'tcx>( +pub fn opaque_type_has_defining_use_args<'tcx>( infcx: &InferCtxt<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>, span: Span, defining_scope_kind: DefiningScopeKind, -) -> Result<(), InvalidOpaqueTypeArgs<'tcx>> { +) -> Result<(), NonDefiningUseReason<'tcx>> { let tcx = infcx.tcx; let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); @@ -105,13 +107,13 @@ pub fn check_opaque_type_parameter_valid<'tcx>( } else { // Prevent `fn foo() -> Foo<u32>` from being defining. opaque_env.param_is_error(i)?; - return Err(InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index: i, span }); + return Err(NonDefiningUseReason::NotAParam { opaque_type_key, param_index: i, span }); } } for (_, param_indices) in seen_params { if param_indices.len() > 1 { - return Err(InvalidOpaqueTypeArgs::DuplicateParam { + return Err(NonDefiningUseReason::DuplicateParam { opaque_type_key, param_indices, span, @@ -206,3 +208,27 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { canonical_args } } + +pub fn report_item_does_not_constrain_error<'tcx>( + tcx: TyCtxt<'tcx>, + item_def_id: LocalDefId, + def_id: LocalDefId, + non_defining_use: Option<(OpaqueTypeKey<'tcx>, Span)>, +) -> ErrorGuaranteed { + let span = tcx.def_ident_span(item_def_id).unwrap_or_else(|| tcx.def_span(item_def_id)); + let opaque_type_span = tcx.def_span(def_id); + let opaque_type_name = tcx.def_path_str(def_id); + + let mut err = + tcx.dcx().struct_span_err(span, format!("item does not constrain `{opaque_type_name}`")); + err.note("consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`"); + err.span_note(opaque_type_span, "this opaque type is supposed to be constrained"); + if let Some((key, span)) = non_defining_use { + let opaque_ty = Ty::new_opaque(tcx, key.def_id.into(), key.args); + err.span_note( + span, + format!("this use of `{opaque_ty}` does not have unique universal generic arguments"), + ); + } + err.emit() +} diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3f628d80662..575e0472e0e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -252,7 +252,9 @@ where // inside of an opaque type, e.g. if there's `Opaque = (?x, ?x)` in the // storage, we can also rely on structural identity of `?x` even if we // later uniquify it in MIR borrowck. - if infcx.in_hir_typeck && obligation.has_non_region_infer() { + if infcx.in_hir_typeck + && (obligation.has_non_region_infer() || obligation.has_free_regions()) + { infcx.push_hir_typeck_potentially_region_dependent_goal(obligation); } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 0ca2d216228..6ce68507d65 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -1,6 +1,7 @@ use std::fmt; use rustc_errors::ErrorGuaranteed; +use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{TyCtxt, TypeFoldable}; @@ -42,13 +43,14 @@ where fn fully_perform( self, infcx: &InferCtxt<'tcx>, + root_def_id: LocalDefId, span: Span, ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> { if cfg!(debug_assertions) { info!("fully_perform({:?})", self); } - Ok(scrape_region_constraints(infcx, self.closure, self.description, span)?.0) + Ok(scrape_region_constraints(infcx, root_def_id, self.description, span, self.closure)?.0) } } @@ -62,9 +64,10 @@ impl<F> fmt::Debug for CustomTypeOp<F> { /// constraints that result, creating query-region-constraints. pub fn scrape_region_constraints<'tcx, Op, R>( infcx: &InferCtxt<'tcx>, - op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>, + root_def_id: LocalDefId, name: &'static str, span: Span, + op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>, ) -> Result<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>), ErrorGuaranteed> where R: TypeFoldable<TyCtxt<'tcx>>, @@ -94,6 +97,8 @@ where let errors = ocx.select_all_or_error(); if errors.is_empty() { Ok(value) + } else if let Err(guar) = infcx.tcx.check_potentially_region_dependent_goals(root_def_id) { + Err(guar) } else { Err(infcx .dcx() diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 018e9748cf0..4b8bf868123 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -1,6 +1,7 @@ use std::fmt; use rustc_errors::ErrorGuaranteed; +use rustc_hir::def_id::LocalDefId; use rustc_infer::traits::PredicateObligations; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{ParamEnvAnd, TyCtxt, TypeFoldable}; @@ -37,6 +38,7 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug { fn fully_perform( self, infcx: &InferCtxt<'tcx>, + root_def_id: LocalDefId, span: Span, ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed>; } @@ -140,6 +142,7 @@ where fn fully_perform( self, infcx: &InferCtxt<'tcx>, + root_def_id: LocalDefId, span: Span, ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> { // In the new trait solver, query type ops are performed locally. This @@ -152,9 +155,10 @@ where if infcx.next_trait_solver() { return Ok(scrape_region_constraints( infcx, - |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self, span), + root_def_id, "query type op", span, + |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self, span), )? .0); } @@ -166,19 +170,15 @@ where // we sometimes end up with `Opaque<'a> = Opaque<'b>` instead of an actual hidden type. In that case we don't register a // hidden type but just equate the lifetimes. Thus we need to scrape the region constraints even though we're also manually // collecting region constraints via `region_constraints`. - let (mut output, _) = scrape_region_constraints( - infcx, - |ocx| { + let (mut output, _) = + scrape_region_constraints(infcx, root_def_id, "fully_perform", span, |ocx| { let (output, ei, obligations, _) = Q::fully_perform_into(self, infcx, &mut region_constraints, span)?; error_info = ei; ocx.register_obligations(obligations); Ok(output) - }, - "fully_perform", - span, - )?; + })?; output.error_info = error_info; if let Some(QueryRegionConstraints { outlives, assumptions }) = output.constraints { region_constraints.outlives.extend(outlives.iter().cloned()); |
