Skip to content

Commit 40f73e7

Browse files
committed
traits/fulfill: allow stalled_on to track ty::Const::Infer(_) (unused yet).
1 parent d8448d2 commit 40f73e7

File tree

2 files changed

+96
-38
lines changed

2 files changed

+96
-38
lines changed

src/librustc_infer/infer/mod.rs

+74-11
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),
@@ -1608,14 +1609,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16081609
}
16091610
}
16101611

1611-
/// `infer_ty_changed(infer_ty)` is equivalent to `shallow_resolve(ty) != ty`
1612-
/// (where `ty.kind = ty::Infer(infer_ty)`), but more efficient. It's always
1612+
/// `ty_or_const_infer_var_changed` is equivalent to one of these two:
1613+
/// * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`)
1614+
/// * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`)
1615+
///
1616+
/// However, `ty_or_const_infer_var_changed` is more efficient. It's always
16131617
/// inlined, despite being large, because it has only two call sites that
1614-
/// are extremely hot.
1618+
/// are extremely hot (both in `traits::fulfill`'s checking of `stalled_on`
1619+
/// inference variables), and it handles both `Ty` and `ty::Const` without
1620+
/// having to resort to storing full `GenericArg`s in `stalled_on`.
16151621
#[inline(always)]
1616-
pub fn infer_ty_changed(&self, infer_ty: ty::InferTy) -> bool {
1617-
match infer_ty {
1618-
ty::TyVar(v) => {
1622+
pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool {
1623+
match infer_var {
1624+
TyOrConstInferVar::Ty(v) => {
16191625
use self::type_variable::TypeVariableValue;
16201626

16211627
// If `inlined_probe` returns a `Known` value, it never equals
@@ -1626,22 +1632,79 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16261632
}
16271633
}
16281634

1629-
ty::IntVar(v) => {
1635+
TyOrConstInferVar::TyInt(v) => {
16301636
// If `inlined_probe_value` returns a value it's always a
16311637
// `ty::Int(_)` or `ty::UInt(_)`, which never matches a
16321638
// `ty::Infer(_)`.
16331639
self.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some()
16341640
}
16351641

1636-
ty::FloatVar(v) => {
1637-
// If `inlined_probe_value` returns a value it's always a
1642+
TyOrConstInferVar::TyFloat(v) => {
1643+
// If `probe_value` returns a value it's always a
16381644
// `ty::Float(_)`, which never matches a `ty::Infer(_)`.
16391645
//
16401646
// Not `inlined_probe_value(v)` because this call site is colder.
16411647
self.inner.borrow_mut().float_unification_table.probe_value(v).is_some()
16421648
}
16431649

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

src/librustc_trait_selection/traits/fulfill.rs

+22-27
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::infer::InferCtxt;
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,7 @@ 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+
pub stalled_on: Vec<TyOrConstInferVar<'tcx>>,
7777
}
7878

7979
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -266,8 +266,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
266266
// Match arms are in order of frequency, which matters because this
267267
// code is so hot. 1 and 0 dominate; 2+ is fairly rare.
268268
1 => {
269-
let infer = pending_obligation.stalled_on[0];
270-
self.selcx.infcx().infer_ty_changed(infer)
269+
let infer_var = pending_obligation.stalled_on[0];
270+
self.selcx.infcx().ty_or_const_infer_var_changed(infer_var)
271271
}
272272
0 => {
273273
// In this case we haven't changed, but wish to make a change.
@@ -277,8 +277,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
277277
// This `for` loop was once a call to `all()`, but this lower-level
278278
// form was a perf win. See #64545 for details.
279279
(|| {
280-
for &infer in &pending_obligation.stalled_on {
281-
if self.selcx.infcx().infer_ty_changed(infer) {
280+
for &infer_var in &pending_obligation.stalled_on {
281+
if self.selcx.infcx().ty_or_const_infer_var_changed(infer_var) {
282282
return true;
283283
}
284284
}
@@ -309,13 +309,6 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
309309

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

312-
fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy {
313-
match ty.kind {
314-
ty::Infer(infer) => infer,
315-
_ => panic!(),
316-
}
317-
}
318-
319312
match obligation.predicate {
320313
ty::Predicate::Trait(ref data, _) => {
321314
let trait_obligation = obligation.with(data.clone());
@@ -467,7 +460,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
467460
obligation.cause.span,
468461
) {
469462
None => {
470-
pending_obligation.stalled_on = vec![infer_ty(ty)];
463+
pending_obligation.stalled_on =
464+
vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()];
471465
ProcessResult::Unchanged
472466
}
473467
Some(os) => ProcessResult::Changed(mk_pending(os)),
@@ -483,8 +477,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
483477
None => {
484478
// None means that both are unresolved.
485479
pending_obligation.stalled_on = vec![
486-
infer_ty(subtype.skip_binder().a),
487-
infer_ty(subtype.skip_binder().b),
480+
TyOrConstInferVar::maybe_from_ty(subtype.skip_binder().a).unwrap(),
481+
TyOrConstInferVar::maybe_from_ty(subtype.skip_binder().b).unwrap(),
488482
];
489483
ProcessResult::Unchanged
490484
}
@@ -534,20 +528,21 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
534528
}
535529
}
536530

537-
/// Returns the set of type variables contained in a trait ref
531+
/// Returns the set of type inference variables contained in a trait ref.
538532
fn trait_ref_type_vars<'a, 'tcx>(
539533
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
534+
trait_ref: ty::PolyTraitRef<'tcx>,
535+
) -> Vec<TyOrConstInferVar<'tcx>> {
536+
trait_ref
537+
.skip_binder() // ok b/c this check doesn't care about regions
538+
// FIXME(eddyb) walk over `GenericArg` to support const infer vars.
543539
.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-
})
540+
.map(|ty| selcx.infcx().resolve_vars_if_possible(&ty))
541+
// FIXME(eddyb) use `has_infer_types_or_const`.
542+
.filter(|ty| ty.has_infer_types())
543+
.flat_map(|ty| ty.walk())
544+
// FIXME(eddyb) use `TyOrConstInferVar::maybe_from_generic_arg`.
545+
.filter_map(TyOrConstInferVar::maybe_from_ty)
551546
.collect()
552547
}
553548

0 commit comments

Comments
 (0)