|
| 1 | +use rustc_data_structures::fx::FxHashMap; |
| 2 | +use syntax_pos::Span; |
| 3 | + |
1 | 4 | use crate::hir::def_id::DefId; |
2 | 5 | use crate::hir; |
3 | 6 | use crate::hir::Node; |
4 | 7 | use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin}; |
5 | 8 | use crate::infer::outlives::free_region_map::FreeRegionRelations; |
6 | | -use rustc_data_structures::fx::FxHashMap; |
7 | 9 | use crate::traits::{self, PredicateObligation}; |
8 | 10 | use crate::ty::{self, Ty, TyCtxt, GenericParamDefKind}; |
9 | | -use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; |
10 | | -use crate::ty::outlives::Component; |
| 11 | +use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; |
11 | 12 | use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, UnpackedKind}; |
12 | 13 | use crate::util::nodemap::DefIdMap; |
13 | 14 |
|
@@ -373,58 +374,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { |
373 | 374 | let least_region = least_region.unwrap_or(self.tcx.lifetimes.re_static); |
374 | 375 | debug!("constrain_opaque_types: least_region={:?}", least_region); |
375 | 376 |
|
376 | | - // Require that the type `concrete_ty` outlives |
377 | | - // `least_region`, modulo any type parameters that appear |
378 | | - // in the type, which we ignore. This is because impl |
379 | | - // trait values are assumed to capture all the in-scope |
380 | | - // type parameters. This little loop here just invokes |
381 | | - // `outlives` repeatedly, draining all the nested |
382 | | - // obligations that result. |
383 | | - let mut types = vec![concrete_ty]; |
384 | | - let bound_region = |r| self.sub_regions(infer::CallReturn(span), least_region, r); |
385 | | - while let Some(ty) = types.pop() { |
386 | | - let mut components = smallvec![]; |
387 | | - self.tcx.push_outlives_components(ty, &mut components); |
388 | | - while let Some(component) = components.pop() { |
389 | | - match component { |
390 | | - Component::Region(r) => { |
391 | | - bound_region(r); |
392 | | - } |
393 | | - |
394 | | - Component::Param(_) => { |
395 | | - // ignore type parameters like `T`, they are captured |
396 | | - // implicitly by the `impl Trait` |
397 | | - } |
398 | | - |
399 | | - Component::UnresolvedInferenceVariable(_) => { |
400 | | - // we should get an error that more type |
401 | | - // annotations are needed in this case |
402 | | - self.tcx |
403 | | - .sess |
404 | | - .delay_span_bug(span, "unresolved inf var in opaque"); |
405 | | - } |
406 | | - |
407 | | - Component::Projection(ty::ProjectionTy { |
408 | | - substs, |
409 | | - item_def_id: _, |
410 | | - }) => { |
411 | | - for k in substs { |
412 | | - match k.unpack() { |
413 | | - UnpackedKind::Lifetime(lt) => bound_region(lt), |
414 | | - UnpackedKind::Type(ty) => types.push(ty), |
415 | | - UnpackedKind::Const(_) => { |
416 | | - // Const parameters don't impose constraints. |
417 | | - } |
418 | | - } |
419 | | - } |
420 | | - } |
421 | | - |
422 | | - Component::EscapingProjection(more_components) => { |
423 | | - components.extend(more_components); |
424 | | - } |
425 | | - } |
426 | | - } |
427 | | - } |
| 377 | + concrete_ty.visit_with(&mut OpaqueTypeOutlivesVisitor { |
| 378 | + infcx: self, |
| 379 | + least_region, |
| 380 | + span, |
| 381 | + }); |
428 | 382 | } |
429 | 383 |
|
430 | 384 | /// Given the fully resolved, instantiated type for an opaque |
@@ -502,6 +456,80 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { |
502 | 456 | } |
503 | 457 | } |
504 | 458 |
|
| 459 | +// Visitor that requires that (almost) all regions in the type visited outlive |
| 460 | +// `least_region`. We cannot use `push_outlives_components` because regions in |
| 461 | +// closure signatures are not included in their outlives components. We need to |
| 462 | +// ensure all regions outlive the given bound so that we don't end up with, |
| 463 | +// say, `ReScope` appearing in a return type and causing ICEs when other |
| 464 | +// functions end up with region constraints involving regions from other |
| 465 | +// functions. |
| 466 | +// |
| 467 | +// We also cannot use `for_each_free_region` because for closures it includes |
| 468 | +// the regions parameters from the enclosing item. |
| 469 | +// |
| 470 | +// We ignore any type parameters because impl trait values are assumed to |
| 471 | +// capture all the in-scope type parameters. |
| 472 | +struct OpaqueTypeOutlivesVisitor<'a, 'gcx, 'tcx> { |
| 473 | + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, |
| 474 | + least_region: ty::Region<'tcx>, |
| 475 | + span: Span, |
| 476 | +} |
| 477 | + |
| 478 | +impl<'tcx> TypeVisitor<'tcx> for OpaqueTypeOutlivesVisitor<'_, '_, 'tcx> |
| 479 | +{ |
| 480 | + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { |
| 481 | + t.skip_binder().visit_with(self); |
| 482 | + false // keep visiting |
| 483 | + } |
| 484 | + |
| 485 | + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { |
| 486 | + match *r { |
| 487 | + // ignore bound regions, keep visiting |
| 488 | + ty::ReLateBound(_, _) => false, |
| 489 | + _ => { |
| 490 | + self.infcx.sub_regions(infer::CallReturn(self.span), self.least_region, r); |
| 491 | + false |
| 492 | + } |
| 493 | + } |
| 494 | + } |
| 495 | + |
| 496 | + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { |
| 497 | + // We're only interested in types involving regions |
| 498 | + if !ty.flags.intersects(ty::TypeFlags::HAS_FREE_REGIONS) { |
| 499 | + return false; // keep visiting |
| 500 | + } |
| 501 | + |
| 502 | + match ty.sty { |
| 503 | + ty::Closure(def_id, ref substs) => { |
| 504 | + // Skip lifetime parameters of the enclosing item(s) |
| 505 | + |
| 506 | + for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) { |
| 507 | + upvar_ty.visit_with(self); |
| 508 | + } |
| 509 | + |
| 510 | + substs.closure_sig_ty(def_id, self.infcx.tcx).visit_with(self); |
| 511 | + } |
| 512 | + |
| 513 | + ty::Generator(def_id, ref substs, _) => { |
| 514 | + // Skip lifetime parameters of the enclosing item(s) |
| 515 | + // Also skip the witness type, because that has no free regions. |
| 516 | + |
| 517 | + for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) { |
| 518 | + upvar_ty.visit_with(self); |
| 519 | + } |
| 520 | + |
| 521 | + substs.return_ty(def_id, self.infcx.tcx).visit_with(self); |
| 522 | + substs.yield_ty(def_id, self.infcx.tcx).visit_with(self); |
| 523 | + } |
| 524 | + _ => { |
| 525 | + ty.super_visit_with(self); |
| 526 | + } |
| 527 | + } |
| 528 | + |
| 529 | + false |
| 530 | + } |
| 531 | +} |
| 532 | + |
505 | 533 | struct ReverseMapper<'cx, 'gcx: 'tcx, 'tcx: 'cx> { |
506 | 534 | tcx: TyCtxt<'cx, 'gcx, 'tcx>, |
507 | 535 |
|
@@ -563,8 +591,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> |
563 | 591 | // ignore `'static`, as that can appear anywhere |
564 | 592 | ty::ReStatic | |
565 | 593 |
|
566 | | - // ignore `ReScope`, as that can appear anywhere |
567 | | - // See `src/test/run-pass/issue-49556.rs` for example. |
| 594 | + // ignore `ReScope`, which may appear in impl Trait in bindings. |
568 | 595 | ty::ReScope(..) => return r, |
569 | 596 |
|
570 | 597 | _ => { } |
|
0 commit comments