Skip to content

Commit 338e764

Browse files
Combine TypeGeneralizer and Generalizer
1 parent 2913ad6 commit 338e764

File tree

4 files changed

+467
-588
lines changed

4 files changed

+467
-588
lines changed

compiler/rustc_infer/src/infer/combine.rs

+15-333
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,13 @@ use super::lub::Lub;
2828
use super::sub::Sub;
2929
use super::type_variable::TypeVariableValue;
3030
use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace};
31+
use crate::infer::generalize::{Generalization, Generalizer};
3132
use crate::traits::{Obligation, PredicateObligations};
32-
use rustc_data_structures::sso::SsoHashMap;
33-
use rustc_hir::def_id::DefId;
3433
use rustc_middle::infer::canonical::OriginalQueryValues;
3534
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
3635
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
37-
use rustc_middle::traits::ObligationCause;
3836
use rustc_middle::ty::error::{ExpectedFound, TypeError};
39-
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
40-
use rustc_middle::ty::subst::SubstsRef;
37+
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
4138
use rustc_middle::ty::{
4239
self, AliasKind, FallibleTypeFolder, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable,
4340
TypeSuperFoldable, TypeVisitableExt,
@@ -412,7 +409,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
412409
// `'?2` and `?3` are fresh region/type inference
413410
// variables. (Down below, we will relate `a_ty <: b_ty`,
414411
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
415-
let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
412+
let Generalization { value: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
416413
debug!(?b_ty);
417414
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
418415

@@ -456,11 +453,11 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
456453
/// - `for_vid` is a "root vid"
457454
#[instrument(skip(self), level = "trace", ret)]
458455
fn generalize(
459-
&self,
456+
&mut self,
460457
ty: Ty<'tcx>,
461458
for_vid: ty::TyVid,
462459
dir: RelationDir,
463-
) -> RelateResult<'tcx, Generalization<'tcx>> {
460+
) -> RelateResult<'tcx, Generalization<Ty<'tcx>>> {
464461
// Determine the ambient variance within which `ty` appears.
465462
// The surrounding equation is:
466463
//
@@ -476,31 +473,23 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
476473

477474
trace!(?ambient_variance);
478475

479-
let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
480-
v @ TypeVariableValue::Known { .. } => {
481-
bug!("instantiating {:?} which has a known value {:?}", for_vid, v,)
482-
}
483-
TypeVariableValue::Unknown { universe } => universe,
484-
};
476+
let for_universe = self.infcx.probe_ty_var(for_vid).unwrap_err();
477+
let for_vid_sub_root = self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid);
485478

486479
trace!(?for_universe);
487480
trace!(?self.trace);
488481

489-
let mut generalize = Generalizer {
482+
Generalizer {
490483
infcx: self.infcx,
491-
cause: &self.trace.cause,
492-
for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
493-
for_universe,
484+
delegate: self,
494485
ambient_variance,
495-
needs_wf: false,
486+
for_universe,
487+
for_vid_sub_root,
496488
root_ty: ty,
497-
param_env: self.param_env,
498-
cache: SsoHashMap::new(),
499-
};
500-
501-
let ty = generalize.relate(ty, ty)?;
502-
let needs_wf = generalize.needs_wf;
503-
Ok(Generalization { ty, needs_wf })
489+
cache: Default::default(),
490+
needs_wf: false,
491+
}
492+
.generalize(ty)
504493
}
505494

506495
pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
@@ -514,313 +503,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
514503
}
515504
}
516505

517-
struct Generalizer<'cx, 'tcx> {
518-
infcx: &'cx InferCtxt<'tcx>,
519-
520-
/// The span, used when creating new type variables and things.
521-
cause: &'cx ObligationCause<'tcx>,
522-
523-
/// The vid of the type variable that is in the process of being
524-
/// instantiated; if we find this within the type we are folding,
525-
/// that means we would have created a cyclic type.
526-
for_vid_sub_root: ty::TyVid,
527-
528-
/// The universe of the type variable that is in the process of
529-
/// being instantiated. Any fresh variables that we create in this
530-
/// process should be in that same universe.
531-
for_universe: ty::UniverseIndex,
532-
533-
/// Track the variance as we descend into the type.
534-
ambient_variance: ty::Variance,
535-
536-
/// See the field `needs_wf` in `Generalization`.
537-
needs_wf: bool,
538-
539-
/// The root type that we are generalizing. Used when reporting cycles.
540-
root_ty: Ty<'tcx>,
541-
542-
param_env: ty::ParamEnv<'tcx>,
543-
544-
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
545-
}
546-
547-
/// Result from a generalization operation. This includes
548-
/// not only the generalized type, but also a bool flag
549-
/// indicating whether further WF checks are needed.
550-
#[derive(Debug)]
551-
struct Generalization<'tcx> {
552-
ty: Ty<'tcx>,
553-
554-
/// If true, then the generalized type may not be well-formed,
555-
/// even if the source type is well-formed, so we should add an
556-
/// additional check to enforce that it is. This arises in
557-
/// particular around 'bivariant' type parameters that are only
558-
/// constrained by a where-clause. As an example, imagine a type:
559-
///
560-
/// struct Foo<A, B> where A: Iterator<Item = B> {
561-
/// data: A
562-
/// }
563-
///
564-
/// here, `A` will be covariant, but `B` is
565-
/// unconstrained. However, whatever it is, for `Foo` to be WF, it
566-
/// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`,
567-
/// then after generalization we will wind up with a type like
568-
/// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C,
569-
/// ?D>` (or `>:`), we will wind up with the requirement that `?A
570-
/// <: ?C`, but no particular relationship between `?B` and `?D`
571-
/// (after all, we do not know the variance of the normalized form
572-
/// of `A::Item` with respect to `A`). If we do nothing else, this
573-
/// may mean that `?D` goes unconstrained (as in #41677). So, in
574-
/// this scenario where we create a new type variable in a
575-
/// bivariant context, we set the `needs_wf` flag to true. This
576-
/// will force the calling code to check that `WF(Foo<?C, ?D>)`
577-
/// holds, which in turn implies that `?C::Item == ?D`. So once
578-
/// `?C` is constrained, that should suffice to restrict `?D`.
579-
needs_wf: bool,
580-
}
581-
582-
impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
583-
fn tcx(&self) -> TyCtxt<'tcx> {
584-
self.infcx.tcx
585-
}
586-
587-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
588-
self.param_env
589-
}
590-
591-
fn tag(&self) -> &'static str {
592-
"Generalizer"
593-
}
594-
595-
fn a_is_expected(&self) -> bool {
596-
true
597-
}
598-
599-
fn binders<T>(
600-
&mut self,
601-
a: ty::Binder<'tcx, T>,
602-
b: ty::Binder<'tcx, T>,
603-
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
604-
where
605-
T: Relate<'tcx>,
606-
{
607-
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
608-
}
609-
610-
fn relate_item_substs(
611-
&mut self,
612-
item_def_id: DefId,
613-
a_subst: SubstsRef<'tcx>,
614-
b_subst: SubstsRef<'tcx>,
615-
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
616-
if self.ambient_variance == ty::Variance::Invariant {
617-
// Avoid fetching the variance if we are in an invariant
618-
// context; no need, and it can induce dependency cycles
619-
// (e.g., #41849).
620-
relate::relate_substs(self, a_subst, b_subst)
621-
} else {
622-
let tcx = self.tcx();
623-
let opt_variances = tcx.variances_of(item_def_id);
624-
relate::relate_substs_with_variances(
625-
self,
626-
item_def_id,
627-
&opt_variances,
628-
a_subst,
629-
b_subst,
630-
true,
631-
)
632-
}
633-
}
634-
635-
fn relate_with_variance<T: Relate<'tcx>>(
636-
&mut self,
637-
variance: ty::Variance,
638-
_info: ty::VarianceDiagInfo<'tcx>,
639-
a: T,
640-
b: T,
641-
) -> RelateResult<'tcx, T> {
642-
let old_ambient_variance = self.ambient_variance;
643-
self.ambient_variance = self.ambient_variance.xform(variance);
644-
645-
let result = self.relate(a, b);
646-
self.ambient_variance = old_ambient_variance;
647-
result
648-
}
649-
650-
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
651-
assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
652-
653-
if let Some(&result) = self.cache.get(&t) {
654-
return Ok(result);
655-
}
656-
debug!("generalize: t={:?}", t);
657-
658-
// Check to see whether the type we are generalizing references
659-
// any other type variable related to `vid` via
660-
// subtyping. This is basically our "occurs check", preventing
661-
// us from creating infinitely sized types.
662-
let result = match *t.kind() {
663-
ty::Infer(ty::TyVar(vid)) => {
664-
let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
665-
let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid);
666-
if sub_vid == self.for_vid_sub_root {
667-
// If sub-roots are equal, then `for_vid` and
668-
// `vid` are related via subtyping.
669-
Err(TypeError::CyclicTy(self.root_ty))
670-
} else {
671-
let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid);
672-
match probe {
673-
TypeVariableValue::Known { value: u } => {
674-
debug!("generalize: known value {:?}", u);
675-
self.relate(u, u)
676-
}
677-
TypeVariableValue::Unknown { universe } => {
678-
match self.ambient_variance {
679-
// Invariant: no need to make a fresh type variable.
680-
ty::Invariant => {
681-
if self.for_universe.can_name(universe) {
682-
return Ok(t);
683-
}
684-
}
685-
686-
// Bivariant: make a fresh var, but we
687-
// may need a WF predicate. See
688-
// comment on `needs_wf` field for
689-
// more info.
690-
ty::Bivariant => self.needs_wf = true,
691-
692-
// Co/contravariant: this will be
693-
// sufficiently constrained later on.
694-
ty::Covariant | ty::Contravariant => (),
695-
}
696-
697-
let origin =
698-
*self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
699-
let new_var_id = self
700-
.infcx
701-
.inner
702-
.borrow_mut()
703-
.type_variables()
704-
.new_var(self.for_universe, origin);
705-
let u = self.tcx().mk_ty_var(new_var_id);
706-
707-
// Record that we replaced `vid` with `new_var_id` as part of a generalization
708-
// operation. This is needed to detect cyclic types. To see why, see the
709-
// docs in the `type_variables` module.
710-
self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id);
711-
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
712-
Ok(u)
713-
}
714-
}
715-
}
716-
}
717-
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
718-
// No matter what mode we are in,
719-
// integer/floating-point types must be equal to be
720-
// relatable.
721-
Ok(t)
722-
}
723-
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
724-
let s = self.relate(substs, substs)?;
725-
Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) })
726-
}
727-
_ => relate::super_relate_tys(self, t, t),
728-
}?;
729-
730-
self.cache.insert(t, result);
731-
Ok(result)
732-
}
733-
734-
fn regions(
735-
&mut self,
736-
r: ty::Region<'tcx>,
737-
r2: ty::Region<'tcx>,
738-
) -> RelateResult<'tcx, ty::Region<'tcx>> {
739-
assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
740-
741-
debug!("generalize: regions r={:?}", r);
742-
743-
match *r {
744-
// Never make variables for regions bound within the type itself,
745-
// nor for erased regions.
746-
ty::ReLateBound(..) | ty::ReErased => {
747-
return Ok(r);
748-
}
749-
750-
ty::ReError(_) => {
751-
return Ok(r);
752-
}
753-
754-
ty::RePlaceholder(..)
755-
| ty::ReVar(..)
756-
| ty::ReStatic
757-
| ty::ReEarlyBound(..)
758-
| ty::ReFree(..) => {
759-
// see common code below
760-
}
761-
}
762-
763-
// If we are in an invariant context, we can re-use the region
764-
// as is, unless it happens to be in some universe that we
765-
// can't name. (In the case of a region *variable*, we could
766-
// use it if we promoted it into our universe, but we don't
767-
// bother.)
768-
if let ty::Invariant = self.ambient_variance {
769-
let r_universe = self.infcx.universe_of_region(r);
770-
if self.for_universe.can_name(r_universe) {
771-
return Ok(r);
772-
}
773-
}
774-
775-
// FIXME: This is non-ideal because we don't give a
776-
// very descriptive origin for this region variable.
777-
Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe))
778-
}
779-
780-
fn consts(
781-
&mut self,
782-
c: ty::Const<'tcx>,
783-
c2: ty::Const<'tcx>,
784-
) -> RelateResult<'tcx, ty::Const<'tcx>> {
785-
assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
786-
787-
match c.kind() {
788-
ty::ConstKind::Infer(InferConst::Var(vid)) => {
789-
let mut inner = self.infcx.inner.borrow_mut();
790-
let variable_table = &mut inner.const_unification_table();
791-
let var_value = variable_table.probe_value(vid);
792-
match var_value.val {
793-
ConstVariableValue::Known { value: u } => {
794-
drop(inner);
795-
self.relate(u, u)
796-
}
797-
ConstVariableValue::Unknown { universe } => {
798-
if self.for_universe.can_name(universe) {
799-
Ok(c)
800-
} else {
801-
let new_var_id = variable_table.new_key(ConstVarValue {
802-
origin: var_value.origin,
803-
val: ConstVariableValue::Unknown { universe: self.for_universe },
804-
});
805-
Ok(self.tcx().mk_const(new_var_id, c.ty()))
806-
}
807-
}
808-
}
809-
}
810-
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
811-
let substs = self.relate_with_variance(
812-
ty::Variance::Invariant,
813-
ty::VarianceDiagInfo::default(),
814-
substs,
815-
substs,
816-
)?;
817-
Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty()))
818-
}
819-
_ => relate::super_relate_consts(self, c, c),
820-
}
821-
}
822-
}
823-
824506
pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
825507
/// Register obligations that must hold in order for this relation to hold
826508
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);

0 commit comments

Comments
 (0)