|
1 |
| -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; |
| 1 | +use rustc_data_structures::fx::FxIndexMap; |
2 | 2 | use rustc_errors::ErrorGuaranteed;
|
3 | 3 | use rustc_hir::def::DefKind;
|
4 | 4 | use rustc_hir::def_id::LocalDefId;
|
5 | 5 | use rustc_hir::OpaqueTyOrigin;
|
6 |
| -use rustc_infer::infer::InferCtxt; |
7 | 6 | use rustc_infer::infer::TyCtxtInferExt as _;
|
| 7 | +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; |
8 | 8 | use rustc_infer::traits::{Obligation, ObligationCause};
|
9 | 9 | use rustc_middle::traits::DefiningAnchor;
|
10 | 10 | use rustc_middle::ty::visit::TypeVisitableExt;
|
@@ -66,85 +66,60 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
66 | 66 | ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
|
67 | 67 | let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
|
68 | 68 |
|
69 |
| - let member_constraints: FxIndexMap<_, _> = self |
70 |
| - .member_constraints |
71 |
| - .all_indices() |
72 |
| - .map(|ci| (self.member_constraints[ci].key, ci)) |
73 |
| - .collect(); |
74 |
| - debug!(?member_constraints); |
75 |
| - |
76 | 69 | for (opaque_type_key, concrete_type) in opaque_ty_decls {
|
77 |
| - let args = opaque_type_key.args; |
78 |
| - debug!(?concrete_type, ?args); |
| 70 | + debug!(?opaque_type_key, ?concrete_type); |
79 | 71 |
|
80 |
| - let mut subst_regions = vec![self.universal_regions.fr_static]; |
| 72 | + let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> = |
| 73 | + vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)]; |
81 | 74 |
|
82 |
| - let to_universal_region = |vid, subst_regions: &mut Vec<_>| { |
83 |
| - trace!(?vid); |
84 |
| - let scc = self.constraint_sccs.scc(vid); |
85 |
| - trace!(?scc); |
86 |
| - match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| { |
87 |
| - self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?) |
88 |
| - }) { |
89 |
| - Some(region) => { |
90 |
| - let vid = self.universal_regions.to_region_vid(region); |
91 |
| - subst_regions.push(vid); |
92 |
| - region |
| 75 | + let opaque_type_key = |
| 76 | + opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| { |
| 77 | + let scc = self.constraint_sccs.scc(self.to_region_vid(region)); |
| 78 | + let vid = self.scc_representatives[scc]; |
| 79 | + let named = match self.definitions[vid].origin { |
| 80 | + NllRegionVariableOrigin::FreeRegion => self |
| 81 | + .universal_regions |
| 82 | + .universal_regions() |
| 83 | + .filter(|&ur| { |
| 84 | + use crate::universal_regions::RegionClassification as Class; |
| 85 | + matches!( |
| 86 | + self.universal_regions.region_classification(ur), |
| 87 | + Some(Class::Global | Class::Local) |
| 88 | + ) |
| 89 | + }) |
| 90 | + .filter(|&ur| ur != self.universal_regions.fr_fn_body) |
| 91 | + .find(|&ur| self.universal_region_relations.equal(vid, ur)) |
| 92 | + .map(|ur| self.definitions[ur].external_name.unwrap()), |
| 93 | + NllRegionVariableOrigin::Placeholder(placeholder) => { |
| 94 | + Some(ty::Region::new_placeholder(infcx.tcx, placeholder)) |
| 95 | + } |
| 96 | + NllRegionVariableOrigin::Existential { .. } => None, |
93 | 97 | }
|
94 |
| - None => { |
95 |
| - subst_regions.push(vid); |
| 98 | + .unwrap_or_else(|| { |
96 | 99 | ty::Region::new_error_with_message(
|
97 | 100 | infcx.tcx,
|
98 | 101 | concrete_type.span,
|
99 | 102 | "opaque type with non-universal region args",
|
100 | 103 | )
|
101 |
| - } |
102 |
| - } |
103 |
| - }; |
| 104 | + }); |
104 | 105 |
|
105 |
| - // Start by inserting universal regions from the member_constraint choice regions. |
106 |
| - // This will ensure they get precedence when folding the regions in the concrete type. |
107 |
| - if let Some(&ci) = member_constraints.get(&opaque_type_key) { |
108 |
| - for &vid in self.member_constraints.choice_regions(ci) { |
109 |
| - to_universal_region(vid, &mut subst_regions); |
110 |
| - } |
111 |
| - } |
112 |
| - debug!(?subst_regions); |
113 |
| - |
114 |
| - // Next, insert universal regions from args, so we can translate regions that appear |
115 |
| - // in them but are not subject to member constraints, for instance closure args. |
116 |
| - let universal_args = infcx.tcx.fold_regions(args, |region, _| { |
117 |
| - if let ty::RePlaceholder(..) = region.kind() { |
118 |
| - // Higher kinded regions don't need remapping, they don't refer to anything outside of this the args. |
119 |
| - return region; |
120 |
| - } |
| 106 | + arg_regions.push((vid, named)); |
| 107 | + named |
| 108 | + }); |
| 109 | + debug!(?opaque_type_key, ?arg_regions); |
| 110 | + |
| 111 | + let concrete_type = infcx.tcx.fold_regions(concrete_type, |region, _| { |
121 | 112 | let vid = self.to_region_vid(region);
|
122 |
| - to_universal_region(vid, &mut subst_regions) |
| 113 | + arg_regions |
| 114 | + .iter() |
| 115 | + .find(|&&(ur_vid, _)| self.eval_equal(vid, ur_vid)) |
| 116 | + .map(|&(_, ur_name)| ur_name) |
| 117 | + .unwrap_or(infcx.tcx.lifetimes.re_erased) |
123 | 118 | });
|
124 |
| - debug!(?universal_args); |
125 |
| - debug!(?subst_regions); |
126 |
| - |
127 |
| - // Deduplicate the set of regions while keeping the chosen order. |
128 |
| - let subst_regions = subst_regions.into_iter().collect::<FxIndexSet<_>>(); |
129 |
| - debug!(?subst_regions); |
130 |
| - |
131 |
| - let universal_concrete_type = |
132 |
| - infcx.tcx.fold_regions(concrete_type, |region, _| match *region { |
133 |
| - ty::ReVar(vid) => subst_regions |
134 |
| - .iter() |
135 |
| - .find(|ur_vid| self.eval_equal(vid, **ur_vid)) |
136 |
| - .and_then(|ur_vid| self.definitions[*ur_vid].external_name) |
137 |
| - .unwrap_or(infcx.tcx.lifetimes.re_erased), |
138 |
| - _ => region, |
139 |
| - }); |
140 |
| - debug!(?universal_concrete_type); |
| 119 | + debug!(?concrete_type); |
141 | 120 |
|
142 |
| - let opaque_type_key = |
143 |
| - OpaqueTypeKey { def_id: opaque_type_key.def_id, args: universal_args }; |
144 |
| - let ty = infcx.infer_opaque_definition_from_instantiation( |
145 |
| - opaque_type_key, |
146 |
| - universal_concrete_type, |
147 |
| - ); |
| 121 | + let ty = |
| 122 | + infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type); |
148 | 123 | // Sometimes two opaque types are the same only after we remap the generic parameters
|
149 | 124 | // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
|
150 | 125 | // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
|
@@ -365,38 +340,33 @@ fn check_opaque_type_well_formed<'tcx>(
|
365 | 340 | }
|
366 | 341 | }
|
367 | 342 |
|
368 |
| -fn check_opaque_type_parameter_valid( |
369 |
| - tcx: TyCtxt<'_>, |
370 |
| - opaque_type_key: OpaqueTypeKey<'_>, |
| 343 | +fn check_opaque_type_parameter_valid<'tcx>( |
| 344 | + tcx: TyCtxt<'tcx>, |
| 345 | + opaque_type_key: OpaqueTypeKey<'tcx>, |
371 | 346 | span: Span,
|
372 | 347 | ) -> Result<(), ErrorGuaranteed> {
|
373 |
| - let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id); |
374 |
| - let is_ty_alias = match opaque_ty_hir.expect_opaque_ty().origin { |
375 |
| - OpaqueTyOrigin::TyAlias { .. } => true, |
376 |
| - OpaqueTyOrigin::AsyncFn(..) | OpaqueTyOrigin::FnReturn(..) => false, |
377 |
| - }; |
378 |
| - |
| 348 | + let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); |
379 | 349 | let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
380 | 350 | let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
|
381 |
| - for (i, arg) in opaque_type_key.args.iter().enumerate() { |
| 351 | + for (i, arg) in opaque_type_key.iter_captured_args(tcx) { |
382 | 352 | if let Err(guar) = arg.error_reported() {
|
383 | 353 | return Err(guar);
|
384 | 354 | }
|
385 | 355 |
|
386 | 356 | let arg_is_param = match arg.unpack() {
|
387 | 357 | GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
|
388 |
| - GenericArgKind::Lifetime(lt) if is_ty_alias => { |
| 358 | + GenericArgKind::Lifetime(lt) => { |
389 | 359 | matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
|
| 360 | + || (lt.is_static() && opaque_env.param_equal_static(i)) |
390 | 361 | }
|
391 |
| - // FIXME(#113916): we can't currently check for unique lifetime params, |
392 |
| - // see that issue for more. We will also have to ignore unused lifetime |
393 |
| - // params for RPIT, but that's comparatively trivial ✨ |
394 |
| - GenericArgKind::Lifetime(_) => continue, |
395 | 362 | GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
|
396 | 363 | };
|
397 | 364 |
|
398 | 365 | if arg_is_param {
|
399 |
| - seen_params.entry(arg).or_default().push(i); |
| 366 | + let seen_where = seen_params.entry(arg).or_default(); |
| 367 | + if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) { |
| 368 | + seen_where.push(i); |
| 369 | + } |
400 | 370 | } else {
|
401 | 371 | // Prevent `fn foo() -> Foo<u32>` from being defining.
|
402 | 372 | let opaque_param = opaque_generics.param_at(i, tcx);
|
@@ -428,3 +398,81 @@ fn check_opaque_type_parameter_valid(
|
428 | 398 |
|
429 | 399 | Ok(())
|
430 | 400 | }
|
| 401 | + |
| 402 | +struct LazyOpaqueTyEnv<'tcx> { |
| 403 | + tcx: TyCtxt<'tcx>, |
| 404 | + def_id: LocalDefId, |
| 405 | + canonical_args: std::cell::Cell<Option<ty::GenericArgsRef<'tcx>>>, |
| 406 | +} |
| 407 | + |
| 408 | +impl<'tcx> LazyOpaqueTyEnv<'tcx> { |
| 409 | + pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { |
| 410 | + Self { tcx, def_id, canonical_args: std::cell::Cell::new(None) } |
| 411 | + } |
| 412 | + |
| 413 | + pub fn param_equal_static(&self, param_index: usize) -> bool { |
| 414 | + self.get_canonical_args()[param_index].expect_region().is_static() |
| 415 | + } |
| 416 | + |
| 417 | + pub fn params_equal(&self, param1: usize, param2: usize) -> bool { |
| 418 | + let canonical_args = self.get_canonical_args(); |
| 419 | + canonical_args[param1] == canonical_args[param2] |
| 420 | + } |
| 421 | + |
| 422 | + fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> { |
| 423 | + use rustc_hir as hir; |
| 424 | + use rustc_infer::infer::outlives::env::OutlivesEnvironment; |
| 425 | + use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; |
| 426 | + |
| 427 | + if let Some(canonical_args) = self.canonical_args.get() { |
| 428 | + return canonical_args; |
| 429 | + } |
| 430 | + |
| 431 | + let &Self { tcx, def_id, .. } = self; |
| 432 | + let origin = tcx.opaque_type_origin(def_id); |
| 433 | + let defining_use_anchor = match origin { |
| 434 | + hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, |
| 435 | + hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id), |
| 436 | + }; |
| 437 | + let param_env = tcx.param_env(defining_use_anchor); |
| 438 | + |
| 439 | + let infcx = tcx.infer_ctxt().build(); |
| 440 | + let ocx = ObligationCtxt::new(&infcx); |
| 441 | + |
| 442 | + let args = match origin { |
| 443 | + hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => { |
| 444 | + GenericArgs::identity_for_item(tcx, parent).extend_to( |
| 445 | + tcx, |
| 446 | + def_id.to_def_id(), |
| 447 | + |param, _| { |
| 448 | + tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into() |
| 449 | + }, |
| 450 | + ) |
| 451 | + } |
| 452 | + hir::OpaqueTyOrigin::TyAlias { .. } => GenericArgs::identity_for_item(tcx, def_id), |
| 453 | + }; |
| 454 | + |
| 455 | + let wf_tys = ocx.assumed_wf_types(param_env, defining_use_anchor).unwrap_or_else(|_| { |
| 456 | + tcx.sess.delay_span_bug(tcx.def_span(def_id), "error getting implied bounds"); |
| 457 | + Default::default() |
| 458 | + }); |
| 459 | + let implied_bounds = infcx.implied_bounds_tys(param_env, defining_use_anchor, wf_tys); |
| 460 | + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); |
| 461 | + |
| 462 | + let mut seen = vec![tcx.lifetimes.re_static]; |
| 463 | + let canonical_args = tcx.fold_regions(args, |r1, _| { |
| 464 | + if let Some(&r2) = seen.iter().find(|&&r2| { |
| 465 | + let free_regions = outlives_env.free_region_map(); |
| 466 | + free_regions.sub_free_regions(tcx, r1, r2) |
| 467 | + && free_regions.sub_free_regions(tcx, r2, r1) |
| 468 | + }) { |
| 469 | + r2 |
| 470 | + } else { |
| 471 | + seen.push(r1); |
| 472 | + r1 |
| 473 | + } |
| 474 | + }); |
| 475 | + self.canonical_args.set(Some(canonical_args)); |
| 476 | + canonical_args |
| 477 | + } |
| 478 | +} |
0 commit comments