Skip to content

Commit a62fd3a

Browse files
authored
Rollup merge of rust-lang#70213 - eddyb:stalled-on-ty-or-const, r=nikomatsakis
traits/fulfill: allow `stalled_on` to track `ty::Const::Infer(_)` (unused yet). This PR addresses the representation side of rust-lang#70180, but only *actually collects* `ty::Infer`s via `Ty::walk` into `stalled_on` (collecting `ty::ConstKind::Infer`s requires rust-lang#70164). However, it should be enough to handle rust-lang#70107's needs (WF obligations are stalled only on the outermost type/const being an inference variable, no `walk`-ing is involved). This is my second attempt, see rust-lang#70181 for the previous one, which unacceptably regressed perf. r? @nikomatsakis cc @nnethercote
2 parents dd8ef75 + 78c178b commit a62fd3a

File tree

2 files changed

+121
-67
lines changed

2 files changed

+121
-67
lines changed

src/librustc_infer/infer/mod.rs

+94-40
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc::traits::select;
1919
use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
2020
use rustc::ty::fold::{TypeFoldable, TypeFolder};
2121
use rustc::ty::relate::RelateResult;
22-
use rustc::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
22+
use rustc::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
2323
pub use rustc::ty::IntVarValue;
2424
use rustc::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
2525
use rustc::ty::{ConstVid, FloatVid, IntVid, TyVid};
@@ -501,6 +501,7 @@ impl NLLRegionVariableOrigin {
501501
}
502502
}
503503

504+
// FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`.
504505
#[derive(Copy, Clone, Debug)]
505506
pub enum FixupError<'tcx> {
506507
UnresolvedIntTy(IntVid),
@@ -1347,8 +1348,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13471348
where
13481349
T: TypeFoldable<'tcx>,
13491350
{
1350-
let mut r = ShallowResolver::new(self);
1351-
value.fold_with(&mut r)
1351+
value.fold_with(&mut ShallowResolver { infcx: self })
13521352
}
13531353

13541354
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
@@ -1551,22 +1551,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
15511551
// variables, thus we don't need to substitute back the original values.
15521552
self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, span)
15531553
}
1554-
}
1555-
1556-
pub struct ShallowResolver<'a, 'tcx> {
1557-
infcx: &'a InferCtxt<'a, 'tcx>,
1558-
}
1559-
1560-
impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
1561-
#[inline(always)]
1562-
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
1563-
ShallowResolver { infcx }
1564-
}
15651554

15661555
/// If `typ` is a type variable of some kind, resolve it one level
15671556
/// (but do not resolve types found in the result). If `typ` is
15681557
/// not a type variable, just return it unmodified.
1569-
pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
1558+
// FIXME(eddyb) inline into `ShallowResolver::visit_ty`.
1559+
fn shallow_resolve_ty(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
15701560
match typ.kind {
15711561
ty::Infer(ty::TyVar(v)) => {
15721562
// Not entirely obvious: if `typ` is a type variable,
@@ -1580,69 +1570,133 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
15801570
// depth.
15811571
//
15821572
// Note: if these two lines are combined into one we get
1583-
// dynamic borrow errors on `self.infcx.inner`.
1584-
let known = self.infcx.inner.borrow_mut().type_variables.probe(v).known();
1585-
known.map(|t| self.fold_ty(t)).unwrap_or(typ)
1573+
// dynamic borrow errors on `self.inner`.
1574+
let known = self.inner.borrow_mut().type_variables.probe(v).known();
1575+
known.map(|t| self.shallow_resolve_ty(t)).unwrap_or(typ)
15861576
}
15871577

15881578
ty::Infer(ty::IntVar(v)) => self
1589-
.infcx
15901579
.inner
15911580
.borrow_mut()
15921581
.int_unification_table
15931582
.probe_value(v)
1594-
.map(|v| v.to_type(self.infcx.tcx))
1583+
.map(|v| v.to_type(self.tcx))
15951584
.unwrap_or(typ),
15961585

15971586
ty::Infer(ty::FloatVar(v)) => self
1598-
.infcx
15991587
.inner
16001588
.borrow_mut()
16011589
.float_unification_table
16021590
.probe_value(v)
1603-
.map(|v| v.to_type(self.infcx.tcx))
1591+
.map(|v| v.to_type(self.tcx))
16041592
.unwrap_or(typ),
16051593

16061594
_ => typ,
16071595
}
16081596
}
16091597

1610-
// `resolver.shallow_resolve_changed(ty)` is equivalent to
1611-
// `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always
1612-
// inlined, despite being large, because it has only two call sites that
1613-
// are extremely hot.
1598+
/// `ty_or_const_infer_var_changed` is equivalent to one of these two:
1599+
/// * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`)
1600+
/// * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`)
1601+
///
1602+
/// However, `ty_or_const_infer_var_changed` is more efficient. It's always
1603+
/// inlined, despite being large, because it has only two call sites that
1604+
/// are extremely hot (both in `traits::fulfill`'s checking of `stalled_on`
1605+
/// inference variables), and it handles both `Ty` and `ty::Const` without
1606+
/// having to resort to storing full `GenericArg`s in `stalled_on`.
16141607
#[inline(always)]
1615-
pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool {
1616-
match infer {
1617-
ty::TyVar(v) => {
1608+
pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool {
1609+
match infer_var {
1610+
TyOrConstInferVar::Ty(v) => {
16181611
use self::type_variable::TypeVariableValue;
16191612

1620-
// If `inlined_probe` returns a `Known` value its `kind` never
1621-
// matches `infer`.
1622-
match self.infcx.inner.borrow_mut().type_variables.inlined_probe(v) {
1613+
// If `inlined_probe` returns a `Known` value, it never equals
1614+
// `ty::Infer(ty::TyVar(v))`.
1615+
match self.inner.borrow_mut().type_variables.inlined_probe(v) {
16231616
TypeVariableValue::Unknown { .. } => false,
16241617
TypeVariableValue::Known { .. } => true,
16251618
}
16261619
}
16271620

1628-
ty::IntVar(v) => {
1629-
// If inlined_probe_value returns a value it's always a
1621+
TyOrConstInferVar::TyInt(v) => {
1622+
// If `inlined_probe_value` returns a value it's always a
16301623
// `ty::Int(_)` or `ty::UInt(_)`, which never matches a
16311624
// `ty::Infer(_)`.
1632-
self.infcx.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some()
1625+
self.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some()
16331626
}
16341627

1635-
ty::FloatVar(v) => {
1636-
// If inlined_probe_value returns a value it's always a
1628+
TyOrConstInferVar::TyFloat(v) => {
1629+
// If `probe_value` returns a value it's always a
16371630
// `ty::Float(_)`, which never matches a `ty::Infer(_)`.
16381631
//
16391632
// Not `inlined_probe_value(v)` because this call site is colder.
1640-
self.infcx.inner.borrow_mut().float_unification_table.probe_value(v).is_some()
1633+
self.inner.borrow_mut().float_unification_table.probe_value(v).is_some()
16411634
}
16421635

1643-
_ => unreachable!(),
1636+
TyOrConstInferVar::Const(v) => {
1637+
// If `probe_value` returns a `Known` value, it never equals
1638+
// `ty::ConstKind::Infer(ty::InferConst::Var(v))`.
1639+
//
1640+
// Not `inlined_probe_value(v)` because this call site is colder.
1641+
match self.inner.borrow_mut().const_unification_table.probe_value(v).val {
1642+
ConstVariableValue::Unknown { .. } => false,
1643+
ConstVariableValue::Known { .. } => true,
1644+
}
1645+
}
1646+
}
1647+
}
1648+
}
1649+
1650+
/// Helper for `ty_or_const_infer_var_changed` (see comment on that), currently
1651+
/// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
1652+
#[derive(Copy, Clone, Debug)]
1653+
pub enum TyOrConstInferVar<'tcx> {
1654+
/// Equivalent to `ty::Infer(ty::TyVar(_))`.
1655+
Ty(TyVid),
1656+
/// Equivalent to `ty::Infer(ty::IntVar(_))`.
1657+
TyInt(IntVid),
1658+
/// Equivalent to `ty::Infer(ty::FloatVar(_))`.
1659+
TyFloat(FloatVid),
1660+
1661+
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
1662+
Const(ConstVid<'tcx>),
1663+
}
1664+
1665+
impl TyOrConstInferVar<'tcx> {
1666+
/// Tries to extract an inference variable from a type or a constant, returns `None`
1667+
/// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and
1668+
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
1669+
pub fn maybe_from_generic_arg(arg: GenericArg<'tcx>) -> Option<Self> {
1670+
match arg.unpack() {
1671+
GenericArgKind::Type(ty) => Self::maybe_from_ty(ty),
1672+
GenericArgKind::Const(ct) => Self::maybe_from_const(ct),
1673+
GenericArgKind::Lifetime(_) => None,
16441674
}
16451675
}
1676+
1677+
/// Tries to extract an inference variable from a type, returns `None`
1678+
/// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`).
1679+
pub fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> {
1680+
match ty.kind {
1681+
ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)),
1682+
ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)),
1683+
ty::Infer(ty::FloatVar(v)) => Some(TyOrConstInferVar::TyFloat(v)),
1684+
_ => None,
1685+
}
1686+
}
1687+
1688+
/// Tries to extract an inference variable from a constant, returns `None`
1689+
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
1690+
pub fn maybe_from_const(ct: &'tcx ty::Const<'tcx>) -> Option<Self> {
1691+
match ct.val {
1692+
ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
1693+
_ => None,
1694+
}
1695+
}
1696+
}
1697+
1698+
struct ShallowResolver<'a, 'tcx> {
1699+
infcx: &'a InferCtxt<'a, 'tcx>,
16461700
}
16471701

16481702
impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
@@ -1651,7 +1705,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
16511705
}
16521706

16531707
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
1654-
self.shallow_resolve(ty)
1708+
self.infcx.shallow_resolve_ty(ty)
16551709
}
16561710

16571711
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {

src/librustc_trait_selection/traits/fulfill.rs

+27-27
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::infer::{InferCtxt, ShallowResolver};
1+
use crate::infer::{InferCtxt, TyOrConstInferVar};
22
use rustc::ty::error::ExpectedFound;
33
use rustc::ty::{self, ToPolyTraitRef, Ty, TypeFoldable};
44
use rustc_data_structures::obligation_forest::ProcessResult;
@@ -73,7 +73,10 @@ pub struct FulfillmentContext<'tcx> {
7373
#[derive(Clone, Debug)]
7474
pub struct PendingPredicateObligation<'tcx> {
7575
pub obligation: PredicateObligation<'tcx>,
76-
pub stalled_on: Vec<ty::InferTy>,
76+
// FIXME(eddyb) look into whether this could be a `SmallVec`.
77+
// Judging by the comment in `process_obligation`, the 1-element case
78+
// is common so this could be a `SmallVec<[TyOrConstInferVar<'tcx>; 1]>`.
79+
pub stalled_on: Vec<TyOrConstInferVar<'tcx>>,
7780
}
7881

7982
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -266,8 +269,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
266269
// Match arms are in order of frequency, which matters because this
267270
// code is so hot. 1 and 0 dominate; 2+ is fairly rare.
268271
1 => {
269-
let infer = pending_obligation.stalled_on[0];
270-
ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer)
272+
let infer_var = pending_obligation.stalled_on[0];
273+
self.selcx.infcx().ty_or_const_infer_var_changed(infer_var)
271274
}
272275
0 => {
273276
// In this case we haven't changed, but wish to make a change.
@@ -277,8 +280,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
277280
// This `for` loop was once a call to `all()`, but this lower-level
278281
// form was a perf win. See #64545 for details.
279282
(|| {
280-
for &infer in &pending_obligation.stalled_on {
281-
if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) {
283+
for &infer_var in &pending_obligation.stalled_on {
284+
if self.selcx.infcx().ty_or_const_infer_var_changed(infer_var) {
282285
return true;
283286
}
284287
}
@@ -309,13 +312,6 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
309312

310313
debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
311314

312-
fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy {
313-
match ty.kind {
314-
ty::Infer(infer) => infer,
315-
_ => panic!(),
316-
}
317-
}
318-
319315
match obligation.predicate {
320316
ty::Predicate::Trait(ref data, _) => {
321317
let trait_obligation = obligation.with(data.clone());
@@ -467,7 +463,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
467463
obligation.cause.span,
468464
) {
469465
None => {
470-
pending_obligation.stalled_on = vec![infer_ty(ty)];
466+
pending_obligation.stalled_on =
467+
vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()];
471468
ProcessResult::Unchanged
472469
}
473470
Some(os) => ProcessResult::Changed(mk_pending(os)),
@@ -483,8 +480,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
483480
None => {
484481
// None means that both are unresolved.
485482
pending_obligation.stalled_on = vec![
486-
infer_ty(subtype.skip_binder().a),
487-
infer_ty(subtype.skip_binder().b),
483+
TyOrConstInferVar::maybe_from_ty(subtype.skip_binder().a).unwrap(),
484+
TyOrConstInferVar::maybe_from_ty(subtype.skip_binder().b).unwrap(),
488485
];
489486
ProcessResult::Unchanged
490487
}
@@ -534,20 +531,23 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
534531
}
535532
}
536533

537-
/// Returns the set of type variables contained in a trait ref
534+
/// Returns the set of type inference variables contained in a trait ref.
538535
fn trait_ref_type_vars<'a, 'tcx>(
539536
selcx: &mut SelectionContext<'a, 'tcx>,
540-
t: ty::PolyTraitRef<'tcx>,
541-
) -> Vec<ty::InferTy> {
542-
t.skip_binder() // ok b/c this check doesn't care about regions
537+
trait_ref: ty::PolyTraitRef<'tcx>,
538+
) -> Vec<TyOrConstInferVar<'tcx>> {
539+
trait_ref
540+
.skip_binder() // ok b/c this check doesn't care about regions
541+
// FIXME(eddyb) walk over `GenericArg` to support const infer vars.
543542
.input_types()
544-
.map(|t| selcx.infcx().resolve_vars_if_possible(&t))
545-
.filter(|t| t.has_infer_types())
546-
.flat_map(|t| t.walk())
547-
.filter_map(|t| match t.kind {
548-
ty::Infer(infer) => Some(infer),
549-
_ => None,
550-
})
543+
.map(|ty| selcx.infcx().resolve_vars_if_possible(&ty))
544+
// FIXME(eddyb) try using `maybe_walk` to skip *all* subtrees that
545+
// don't contain inference variables, not just the outermost level.
546+
// FIXME(eddyb) use `has_infer_types_or_const`.
547+
.filter(|ty| ty.has_infer_types())
548+
.flat_map(|ty| ty.walk())
549+
// FIXME(eddyb) use `TyOrConstInferVar::maybe_from_generic_arg`.
550+
.filter_map(TyOrConstInferVar::maybe_from_ty)
551551
.collect()
552552
}
553553

0 commit comments

Comments
 (0)