diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_borrowck/messages.ftl | 6 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/region_infer/opaque_types.rs | 96 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/session_diagnostics.rs | 13 |
3 files changed, 95 insertions, 20 deletions
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index f2ca509e14b..587536e1f9a 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -132,6 +132,12 @@ borrowck_moved_due_to_usage_in_operator = *[false] operator } +borrowck_opaque_type_lifetime_mismatch = + opaque type used twice with different lifetimes + .label = lifetime `{$arg}` used here + .prev_lifetime_label = lifetime `{$prev}` previously used here + .note = if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types + borrowck_opaque_type_non_generic_param = expected generic {$kind} parameter, found `{$ty}` .label = {STREQ($ty, "'static") -> diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 8a172233037..bea9be24028 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -9,17 +9,77 @@ use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_macros::extension; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; +use rustc_middle::ty::RegionVid; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::ObligationCtxt; +use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::session_diagnostics::NonGenericOpaqueTypeParam; use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { + fn universal_name(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> { + let scc = self.constraint_sccs.scc(vid); + self.scc_values + .universal_regions_outlived_by(scc) + .find_map(|lb| self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)) + } + + fn generic_arg_to_region(&self, arg: ty::GenericArg<'tcx>) -> Option<RegionVid> { + let region = arg.as_region()?; + + if let ty::RePlaceholder(..) = region.kind() { + None + } else { + Some(self.to_region_vid(region)) + } + } + + /// Check that all opaque types have the same region parameters if they have the same + /// non-region parameters. This is necessary because within the new solver we perform various query operations + /// modulo regions, and thus could unsoundly select some impls that don't hold. + fn check_unique( + &self, + infcx: &InferCtxt<'tcx>, + opaque_ty_decls: &FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, + ) { + for (i, (a, a_ty)) in opaque_ty_decls.iter().enumerate() { + for (b, b_ty) in opaque_ty_decls.iter().skip(i + 1) { + if a.def_id != b.def_id { + continue; + } + // Non-lifetime params differ -> ok + if infcx.tcx.erase_regions(a.args) != infcx.tcx.erase_regions(b.args) { + continue; + } + trace!(?a, ?b); + for (a, b) in a.args.iter().zip(b.args) { + trace!(?a, ?b); + let Some(r1) = self.generic_arg_to_region(a) else { + continue; + }; + let Some(r2) = self.generic_arg_to_region(b) else { + continue; + }; + if self.eval_equal(r1, r2) { + continue; + } + + infcx.dcx().emit_err(LifetimeMismatchOpaqueParam { + arg: self.universal_name(r1).unwrap().into(), + prev: self.universal_name(r2).unwrap().into(), + span: a_ty.span, + prev_span: b_ty.span, + }); + } + } + } + } + /// Resolve any opaque types that were encountered while borrow checking /// this item. This is then used to get the type in the `type_of` query. /// @@ -65,6 +125,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx: &InferCtxt<'tcx>, opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> { + self.check_unique(infcx, &opaque_ty_decls); + let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default(); let member_constraints: FxIndexMap<_, _> = self @@ -80,26 +142,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut arg_regions = vec![self.universal_regions.fr_static]; - let to_universal_region = |vid, arg_regions: &mut Vec<_>| { - trace!(?vid); - let scc = self.constraint_sccs.scc(vid); - trace!(?scc); - match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| { - self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?) - }) { - Some(region) => { - let vid = self.universal_regions.to_region_vid(region); - arg_regions.push(vid); - region - } - None => { - arg_regions.push(vid); - ty::Region::new_error_with_message( - infcx.tcx, - concrete_type.span, - "opaque type with non-universal region args", - ) - } + let to_universal_region = |vid, arg_regions: &mut Vec<_>| match self.universal_name(vid) + { + Some(region) => { + let vid = self.universal_regions.to_region_vid(region); + arg_regions.push(vid); + region + } + None => { + arg_regions.push(vid); + ty::Region::new_error_with_message( + infcx.tcx, + concrete_type.span, + "opaque type with non-universal region args", + ) } }; diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 77021ae4321..40c2ef1c91e 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -304,6 +304,19 @@ pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { pub param_span: Span, } +#[derive(Diagnostic)] +#[diag(borrowck_opaque_type_lifetime_mismatch)] +pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> { + pub arg: GenericArg<'tcx>, + pub prev: GenericArg<'tcx>, + #[primary_span] + #[label] + #[note] + pub span: Span, + #[label(borrowck_prev_lifetime_label)] + pub prev_span: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum CaptureReasonLabel<'a> { #[label(borrowck_moved_due_to_call)] |
