Skip to content

Commit 195395e

Browse files
committed
Stop using identity args for opaque type wf checks and instead load the args from the single use of a RPIT in its parent function's return type
1 parent 4a71a05 commit 195395e

File tree

2 files changed

+132
-76
lines changed

2 files changed

+132
-76
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+113-76
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_hir::intravisit::Visitor;
1313
use rustc_hir::{ItemKind, Node, PathSegment};
1414
use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
1515
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
16-
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
16+
use rustc_infer::infer::{LateBoundRegionConversionTime, RegionVariableOrigin, TyCtxtInferExt};
1717
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
1818
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
1919
use rustc_middle::hir::nested_filter;
@@ -407,7 +407,38 @@ fn check_opaque_meets_bounds<'tcx>(
407407
.build();
408408
let ocx = ObligationCtxt::new(&infcx);
409409

410-
let args = GenericArgs::identity_for_item(tcx, def_id.to_def_id());
410+
let mut args = GenericArgs::identity_for_item(tcx, def_id.to_def_id());
411+
assert!(!args.has_escaping_bound_vars(), "{args:#?}");
412+
if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
413+
// Find use of the RPIT in the function signature and thus find the right args to
414+
// convert it into the parameter space of the function signature. This is needed,
415+
// because that's what `type_of` returns, against which we compare later.
416+
let ret = tcx.fn_sig(defining_use_anchor).instantiate_identity().output();
417+
418+
let a = ret
419+
.skip_binder()
420+
.visit_with(&mut FindOpaqueTypeArgs {
421+
tcx,
422+
opaque: def_id.to_def_id(),
423+
fn_def_id: defining_use_anchor.to_def_id(),
424+
seen: Default::default(),
425+
depth: ty::INNERMOST,
426+
})
427+
.break_value()
428+
.ok_or_else(|| {
429+
tcx.sess.delay_span_bug(
430+
tcx.def_span(defining_use_anchor),
431+
format!("return type of {defining_use_anchor:?} does not contain {def_id:?}"),
432+
)
433+
})?;
434+
let a = infcx.instantiate_binder_with_fresh_vars(
435+
span,
436+
LateBoundRegionConversionTime::HigherRankedType,
437+
ret.rebind(a),
438+
);
439+
assert!(!a.has_escaping_bound_vars(), "{a:#?}");
440+
args = ty::EarlyBinder::bind(args).instantiate(tcx, a);
441+
}
411442
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
412443

413444
// `ReErased` regions appear in the "parent_args" of closures/generators.
@@ -468,9 +499,10 @@ fn check_opaque_meets_bounds<'tcx>(
468499
}
469500
}
470501
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
471-
for (key, mut ty) in infcx.take_opaque_types() {
502+
for (mut key, mut ty) in infcx.take_opaque_types() {
472503
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
473-
sanity_check_found_hidden_type(tcx, key, ty.hidden_type, defining_use_anchor, origin)?;
504+
key = infcx.resolve_vars_if_possible(key);
505+
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
474506
}
475507
Ok(())
476508
}
@@ -479,8 +511,6 @@ fn sanity_check_found_hidden_type<'tcx>(
479511
tcx: TyCtxt<'tcx>,
480512
key: ty::OpaqueTypeKey<'tcx>,
481513
mut ty: ty::OpaqueHiddenType<'tcx>,
482-
defining_use_anchor: LocalDefId,
483-
origin: &hir::OpaqueTyOrigin,
484514
) -> Result<(), ErrorGuaranteed> {
485515
if ty.ty.is_ty_var() {
486516
// Nothing was actually constrained.
@@ -493,29 +523,23 @@ fn sanity_check_found_hidden_type<'tcx>(
493523
return Ok(());
494524
}
495525
}
526+
let strip_vars = |ty: Ty<'tcx>| {
527+
ty.fold_with(&mut BottomUpFolder {
528+
tcx,
529+
ty_op: |t| t,
530+
ct_op: |c| c,
531+
lt_op: |l| match l.kind() {
532+
RegionKind::ReVar(_) => tcx.lifetimes.re_erased,
533+
_ => l,
534+
},
535+
})
536+
};
496537
// Closures frequently end up containing erased lifetimes in their final representation.
497538
// These correspond to lifetime variables that never got resolved, so we patch this up here.
498-
ty.ty = ty.ty.fold_with(&mut BottomUpFolder {
499-
tcx,
500-
ty_op: |t| t,
501-
ct_op: |c| c,
502-
lt_op: |l| match l.kind() {
503-
RegionKind::ReVar(_) => tcx.lifetimes.re_erased,
504-
_ => l,
505-
},
506-
});
539+
ty.ty = strip_vars(ty.ty);
507540
// Get the hidden type.
508-
let mut hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
509-
if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
510-
if hidden_ty != ty.ty {
511-
hidden_ty = find_and_apply_rpit_args(
512-
tcx,
513-
hidden_ty,
514-
defining_use_anchor.to_def_id(),
515-
key.def_id.to_def_id(),
516-
)?;
517-
}
518-
}
541+
let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
542+
let hidden_ty = strip_vars(hidden_ty);
519543

520544
// If the hidden types differ, emit a type mismatch diagnostic.
521545
if hidden_ty == ty.ty {
@@ -563,67 +587,80 @@ fn sanity_check_found_hidden_type<'tcx>(
563587
/// x
564588
/// }
565589
/// ```
566-
fn find_and_apply_rpit_args<'tcx>(
590+
struct FindOpaqueTypeArgs<'tcx> {
567591
tcx: TyCtxt<'tcx>,
568-
mut hidden_ty: Ty<'tcx>,
569-
function: DefId,
570592
opaque: DefId,
571-
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
572-
// Find use of the RPIT in the function signature and thus find the right args to
573-
// convert it into the parameter space of the function signature. This is needed,
574-
// because that's what `type_of` returns, against which we compare later.
575-
let ret = tcx.fn_sig(function).instantiate_identity().output();
576-
struct Visitor<'tcx> {
577-
tcx: TyCtxt<'tcx>,
578-
opaque: DefId,
579-
seen: FxHashSet<DefId>,
593+
seen: FxHashSet<DefId>,
594+
fn_def_id: DefId,
595+
depth: ty::DebruijnIndex,
596+
}
597+
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FindOpaqueTypeArgs<'tcx> {
598+
type BreakTy = GenericArgsRef<'tcx>;
599+
600+
#[instrument(level = "trace", skip(self), ret)]
601+
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
602+
&mut self,
603+
t: &ty::Binder<'tcx, T>,
604+
) -> ControlFlow<Self::BreakTy> {
605+
self.depth.shift_in(1);
606+
let binder = t.super_visit_with(self);
607+
self.depth.shift_out(1);
608+
binder
580609
}
581-
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
582-
type BreakTy = GenericArgsRef<'tcx>;
583610

584-
#[instrument(level = "trace", skip(self), ret)]
585-
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
586-
trace!("{:#?}", t.kind());
587-
match t.kind() {
588-
ty::Alias(ty::Opaque, alias) => {
589-
trace!(?alias.def_id);
590-
if alias.def_id == self.opaque {
591-
return ControlFlow::Break(alias.args);
592-
} else if self.seen.insert(alias.def_id) {
593-
for clause in self
594-
.tcx
595-
.explicit_item_bounds(alias.def_id)
596-
.iter_instantiated_copied(self.tcx, alias.args)
597-
{
598-
trace!(?clause);
599-
clause.visit_with(self)?;
611+
#[instrument(level = "trace", skip(self), ret)]
612+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
613+
trace!("{:#?}", t.kind());
614+
match t.kind() {
615+
ty::Alias(ty::Opaque, alias) => {
616+
trace!(?alias.def_id);
617+
if alias.def_id == self.opaque {
618+
let args = self.tcx.fold_regions(alias.args, |re, depth| {
619+
if let ty::ReLateBound(index, bv) = re.kind() {
620+
if depth != ty::INNERMOST {
621+
return ty::Region::new_error_with_message(
622+
self.tcx,
623+
self.tcx.def_span(self.opaque),
624+
"opaque type behind meaningful binders are not supported yet",
625+
);
626+
}
627+
ty::Region::new_late_bound(
628+
self.tcx,
629+
index.shifted_out_to_binder(self.depth),
630+
bv,
631+
)
632+
} else {
633+
re
600634
}
635+
});
636+
return ControlFlow::Break(args);
637+
} else if self.seen.insert(alias.def_id) {
638+
for clause in self
639+
.tcx
640+
.explicit_item_bounds(alias.def_id)
641+
.iter_instantiated_copied(self.tcx, alias.args)
642+
{
643+
trace!(?clause);
644+
clause.visit_with(self)?;
601645
}
602646
}
603-
ty::Alias(ty::Weak, alias) => {
604-
self.tcx
605-
.type_of(alias.def_id)
606-
.instantiate(self.tcx, alias.args)
607-
.visit_with(self)?;
647+
}
648+
ty::Alias(ty::Projection, alias) => {
649+
if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = self.tcx.opt_rpitit_info(alias.def_id) && fn_def_id == self.fn_def_id {
650+
self.tcx.type_of(alias.def_id).instantiate(self.tcx, alias.args).visit_with(self)?;
608651
}
609-
_ => (),
610652
}
611-
612-
t.super_visit_with(self)
653+
ty::Alias(ty::Weak, alias) => {
654+
self.tcx
655+
.type_of(alias.def_id)
656+
.instantiate(self.tcx, alias.args)
657+
.visit_with(self)?;
658+
}
659+
_ => (),
613660
}
661+
662+
t.super_visit_with(self)
614663
}
615-
if let ControlFlow::Break(args) =
616-
ret.visit_with(&mut Visitor { tcx, opaque, seen: Default::default() })
617-
{
618-
trace!(?args);
619-
trace!("expected: {hidden_ty:#?}");
620-
hidden_ty = ty::EarlyBinder::bind(hidden_ty).instantiate(tcx, args);
621-
trace!("expected: {hidden_ty:#?}");
622-
} else {
623-
tcx.sess
624-
.delay_span_bug(tcx.def_span(function), format!("{ret:?} does not contain {opaque:?}"));
625-
}
626-
Ok(hidden_ty)
627664
}
628665

629666
fn is_enum_of_nonnullable_ptr<'tcx>(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//check-pass
2+
3+
pub struct Key;
4+
#[derive(Clone)]
5+
pub struct Value;
6+
7+
use std::collections::HashMap;
8+
9+
pub struct DiagnosticBuilder<'db> {
10+
inner: HashMap<&'db Key, Vec<&'db Value>>,
11+
}
12+
13+
impl<'db> DiagnosticBuilder<'db> {
14+
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (&'db Key, impl Iterator<Item = &'a Value>)> {
15+
self.inner.iter().map(|(key, values)| (*key, values.iter().map(|v| *v)))
16+
}
17+
}
18+
19+
fn main() {}

0 commit comments

Comments
 (0)