Skip to content

Commit 4d1fc22

Browse files
committed
stop using fresh inference vars
1 parent 9a963e3 commit 4d1fc22

File tree

6 files changed

+166
-153
lines changed

6 files changed

+166
-153
lines changed

compiler/rustc_middle/src/traits/select.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,24 @@
55
use self::EvaluationResult::*;
66

77
use super::{SelectionError, SelectionResult};
8-
use rustc_errors::ErrorGuaranteed;
9-
8+
use crate::traits::Canonical;
109
use crate::ty;
11-
10+
use rustc_errors::ErrorGuaranteed;
1211
use rustc_hir::def_id::DefId;
1312
use rustc_query_system::cache::Cache;
1413

1514
pub type SelectionCache<'tcx> = Cache<
1615
// This cache does not use `ParamEnvAnd` in its keys because `ParamEnv::and` can replace
1716
// caller bounds with an empty list if the `TraitPredicate` looks global, which may happen
1817
// after erasing lifetimes from the predicate.
19-
(ty::ParamEnv<'tcx>, ty::TraitPredicate<'tcx>),
18+
(ty::ParamEnv<'tcx>, Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>),
2019
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
2120
>;
2221

2322
pub type EvaluationCache<'tcx> = Cache<
2423
// See above: this cache does not use `ParamEnvAnd` in its keys due to sometimes incorrectly
2524
// caching with the wrong `ParamEnv`.
26-
(ty::ParamEnv<'tcx>, ty::PolyTraitPredicate<'tcx>),
25+
(ty::ParamEnv<'tcx>, Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>),
2726
EvaluationResult,
2827
>;
2928

compiler/rustc_middle/src/ty/_match.rs

+10-19
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
use crate::ty::error::TypeError;
22
use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
3-
use crate::ty::{self, InferConst, Ty, TyCtxt};
3+
use crate::ty::{self, Ty, TyCtxt};
44

5-
/// A type "A" *matches* "B" if the fresh types in B could be
6-
/// substituted with values so as to make it equal to A. Matching is
7-
/// intended to be used only on freshened types, and it basically
8-
/// indicates if the non-freshened versions of A and B could have been
9-
/// unified.
5+
/// A type "A" *matches* "B" if the inference variables in B could be
6+
/// substituted with values so as to make it equal to A.
7+
/// Matching basically indicates whether A would contain B.
108
///
119
/// It is only an approximation. If it yields false, unification would
1210
/// definitely fail, but a true result doesn't mean unification would
1311
/// succeed. This is because we don't track the "side-constraints" on
14-
/// type variables, nor do we track if the same freshened type appears
12+
/// type variables, nor do we track if the same inference variable appears
1513
/// more than once. To some extent these approximations could be
1614
/// fixed, given effort.
1715
///
@@ -69,16 +67,9 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
6967
}
7068

7169
match (a.kind(), b.kind()) {
72-
(
73-
_,
74-
&ty::Infer(ty::FreshTy(_))
75-
| &ty::Infer(ty::FreshIntTy(_))
76-
| &ty::Infer(ty::FreshFloatTy(_)),
77-
) => Ok(a),
78-
79-
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
80-
Err(TypeError::Sorts(relate::expected_found(self, a, b)))
81-
}
70+
(_, &ty::Infer(_)) => Ok(a),
71+
72+
(&ty::Infer(_), _) => Err(TypeError::Sorts(relate::expected_found(self, a, b))),
8273

8374
(&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()),
8475

@@ -97,11 +88,11 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
9788
}
9889

9990
match (a.kind(), b.kind()) {
100-
(_, ty::ConstKind::Infer(InferConst::Fresh(_))) => {
91+
(_, ty::ConstKind::Infer(_)) => {
10192
return Ok(a);
10293
}
10394

104-
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
95+
(ty::ConstKind::Infer(_), _) => {
10596
return Err(TypeError::ConstMismatch(relate::expected_found(self, a, b)));
10697
}
10798

compiler/rustc_middle/src/ty/erase_regions.rs

+18
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,24 @@ impl<'tcx> TyCtxt<'tcx> {
3030
debug!("erase_regions = {:?}", value1);
3131
value1
3232
}
33+
34+
pub fn erase_regions_keep_static<T>(self, value: T) -> T
35+
where
36+
T: TypeFoldable<'tcx>,
37+
{
38+
if value.has_free_regions() {
39+
self.fold_regions(value, |r, _| match r.kind() {
40+
ty::ReLateBound(_, _) | ty::ReStatic => r,
41+
ty::ReEarlyBound(_)
42+
| ty::ReFree(_)
43+
| ty::ReVar(_)
44+
| ty::RePlaceholder(_)
45+
| ty::ReErased => self.lifetimes.re_erased,
46+
})
47+
} else {
48+
value
49+
}
50+
}
3351
}
3452

3553
struct RegionEraserVisitor<'tcx> {

compiler/rustc_trait_selection/src/traits/auto_trait.rs

+30-31
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::errors::UnableToConstructConstantValue;
77
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
88
use crate::infer::InferCtxt;
99
use crate::traits::project::ProjectAndUnifyResult;
10+
use rustc_middle::infer::canonical::{Canonical, OriginalQueryValues};
1011
use rustc_middle::mir::interpret::ErrorHandled;
1112
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
1213
use rustc_middle::ty::visit::TypeVisitable;
@@ -160,7 +161,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
160161
// SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
161162
//
162163
// We fix the first assumption by manually clearing out all of the InferCtxt's caches
163-
// in between calls to SelectionContext.select. This allows us to keep all of the
164+
// in between calls to `selcx.select`. This allows us to keep all of the
164165
// intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
165166
// them between calls.
166167
//
@@ -233,7 +234,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
233234
impl<'tcx> AutoTraitFinder<'tcx> {
234235
/// The core logic responsible for computing the bounds for our synthesized impl.
235236
///
236-
/// To calculate the bounds, we call `SelectionContext.select` in a loop. Like
237+
/// To calculate the bounds, we call `selcx.select` in a loop. Like
237238
/// `FulfillmentContext`, we recursively select the nested obligations of predicates we
238239
/// encounter. However, whenever we encounter an `UnimplementedError` involving a type
239240
/// parameter, we add it to our `ParamEnv`. Since our goal is to determine when a particular
@@ -277,7 +278,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
277278
ty: Ty<'tcx>,
278279
param_env: ty::ParamEnv<'tcx>,
279280
user_env: ty::ParamEnv<'tcx>,
280-
fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
281+
deduplicated_preds: &mut FxHashSet<Canonical<'tcx, ty::Predicate<'tcx>>>,
281282
only_projections: bool,
282283
) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> {
283284
let tcx = infcx.tcx;
@@ -286,10 +287,13 @@ impl<'tcx> AutoTraitFinder<'tcx> {
286287
// that are already in the `ParamEnv` (modulo regions): we already
287288
// know that they must hold.
288289
for predicate in param_env.caller_bounds() {
289-
fresh_preds.insert(self.clean_pred(infcx, predicate));
290+
deduplicated_preds.insert(
291+
infcx
292+
.canonicalize_query_keep_static(predicate, &mut OriginalQueryValues::default()),
293+
);
290294
}
291295

292-
let mut select = SelectionContext::new(&infcx);
296+
let mut selcx = SelectionContext::new(&infcx);
293297

294298
let mut already_visited = FxHashSet::default();
295299
let mut predicates = VecDeque::new();
@@ -320,7 +324,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
320324
// get rid of any inference variables.
321325
let obligation =
322326
infcx.resolve_vars_if_possible(Obligation::new(dummy_cause.clone(), new_env, pred));
323-
let result = select.select(&obligation);
327+
let result = selcx.select(&obligation);
324328

325329
match result {
326330
Ok(Some(ref impl_source)) => {
@@ -348,9 +352,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
348352
ty,
349353
obligations,
350354
&mut user_computed_preds,
351-
fresh_preds,
355+
deduplicated_preds,
352356
&mut predicates,
353-
&mut select,
357+
&mut selcx,
354358
only_projections,
355359
) {
356360
return None;
@@ -403,7 +407,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
403407
}
404408

405409
/// This method is designed to work around the following issue:
406-
/// When we compute auto trait bounds, we repeatedly call `SelectionContext.select`,
410+
/// When we compute auto trait bounds, we repeatedly call `selcx.select`,
407411
/// progressively building a `ParamEnv` based on the results we get.
408412
/// However, our usage of `SelectionContext` differs from its normal use within the compiler,
409413
/// in that we capture and re-reprocess predicates from `Unimplemented` errors.
@@ -624,19 +628,22 @@ impl<'tcx> AutoTraitFinder<'tcx> {
624628
ty: Ty<'_>,
625629
nested: impl Iterator<Item = Obligation<'tcx, ty::Predicate<'tcx>>>,
626630
computed_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
627-
fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
631+
deduplicated_preds: &mut FxHashSet<Canonical<'tcx, ty::Predicate<'tcx>>>,
628632
predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
629-
select: &mut SelectionContext<'_, 'tcx>,
633+
selcx: &mut SelectionContext<'_, 'tcx>,
630634
only_projections: bool,
631635
) -> bool {
632636
let dummy_cause = ObligationCause::dummy();
633637

634638
for obligation in nested {
635639
let is_new_pred =
636-
fresh_preds.insert(self.clean_pred(select.infcx(), obligation.predicate));
640+
deduplicated_preds.insert(selcx.infcx().canonicalize_query_keep_static(
641+
obligation.predicate,
642+
&mut OriginalQueryValues::default(),
643+
));
637644

638645
// Resolve any inference variables that we can, to help selection succeed
639-
let predicate = select.infcx().resolve_vars_if_possible(obligation.predicate);
646+
let predicate = selcx.infcx().resolve_vars_if_possible(obligation.predicate);
640647

641648
// We only add a predicate as a user-displayable bound if
642649
// it involves a generic parameter, and doesn't contain
@@ -744,7 +751,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
744751
// and turn them into an explicit negative impl for our type.
745752
debug!("Projecting and unifying projection predicate {:?}", predicate);
746753

747-
match project::poly_project_and_unify_type(select, &obligation.with(p)) {
754+
match project::poly_project_and_unify_type(selcx, &obligation.with(p)) {
748755
ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
749756
debug!(
750757
"evaluate_nested_obligations: Unable to unify predicate \
@@ -767,9 +774,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
767774
ty,
768775
v.into_iter(),
769776
computed_preds,
770-
fresh_preds,
777+
deduplicated_preds,
771778
predicates,
772-
select,
779+
selcx,
773780
only_projections,
774781
) {
775782
return false;
@@ -792,7 +799,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
792799
}
793800
ty::PredicateKind::RegionOutlives(binder) => {
794801
let binder = bound_predicate.rebind(binder);
795-
select.infcx().region_outlives_predicate(&dummy_cause, binder)
802+
selcx.infcx().region_outlives_predicate(&dummy_cause, binder)
796803
}
797804
ty::PredicateKind::TypeOutlives(binder) => {
798805
let binder = bound_predicate.rebind(binder);
@@ -801,14 +808,14 @@ impl<'tcx> AutoTraitFinder<'tcx> {
801808
binder.map_bound_ref(|pred| pred.0).no_bound_vars(),
802809
) {
803810
(None, Some(t_a)) => {
804-
select.infcx().register_region_obligation_with_cause(
811+
selcx.infcx().register_region_obligation_with_cause(
805812
t_a,
806-
select.infcx().tcx.lifetimes.re_static,
813+
selcx.infcx().tcx.lifetimes.re_static,
807814
&dummy_cause,
808815
);
809816
}
810817
(Some(ty::OutlivesPredicate(t_a, r_b)), _) => {
811-
select.infcx().register_region_obligation_with_cause(
818+
selcx.infcx().register_region_obligation_with_cause(
812819
t_a,
813820
r_b,
814821
&dummy_cause,
@@ -820,13 +827,13 @@ impl<'tcx> AutoTraitFinder<'tcx> {
820827
ty::PredicateKind::ConstEquate(c1, c2) => {
821828
let evaluate = |c: ty::Const<'tcx>| {
822829
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
823-
match select.infcx().const_eval_resolve(
830+
match selcx.infcx().const_eval_resolve(
824831
obligation.param_env,
825832
unevaluated,
826833
Some(obligation.cause.span),
827834
) {
828835
Ok(Some(valtree)) => {
829-
Ok(ty::Const::from_value(select.tcx(), valtree, c.ty()))
836+
Ok(ty::Const::from_value(selcx.tcx(), valtree, c.ty()))
830837
}
831838
Ok(None) => {
832839
let tcx = self.tcx;
@@ -847,7 +854,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
847854

848855
match (evaluate(c1), evaluate(c2)) {
849856
(Ok(c1), Ok(c2)) => {
850-
match select
857+
match selcx
851858
.infcx()
852859
.at(&obligation.cause, obligation.param_env)
853860
.eq(c1, c2)
@@ -874,14 +881,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
874881
}
875882
true
876883
}
877-
878-
pub fn clean_pred(
879-
&self,
880-
infcx: &InferCtxt<'_, 'tcx>,
881-
p: ty::Predicate<'tcx>,
882-
) -> ty::Predicate<'tcx> {
883-
infcx.freshen(p)
884-
}
885884
}
886885

887886
// Replaces all ReVars in a type with ty::Region's, using the provided map

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+9-17
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
//! candidates. See the [rustc dev guide] for more details.
66
//!
77
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
8+
use crate::traits;
9+
use crate::traits::coherence::Conflict;
10+
use crate::traits::query::evaluate_obligation::InferCtxtExt;
11+
use crate::traits::{util, SelectionResult};
12+
use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
813
use hir::LangItem;
914
use rustc_hir as hir;
1015
use rustc_hir::def_id::DefId;
@@ -15,12 +20,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
1520
use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
1621
use rustc_target::spec::abi::Abi;
1722

18-
use crate::traits;
19-
use crate::traits::coherence::Conflict;
20-
use crate::traits::query::evaluate_obligation::InferCtxtExt;
21-
use crate::traits::{util, SelectionResult};
22-
use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
23-
2423
use super::BuiltinImplConditions;
2524
use super::IntercrateAmbiguityCause;
2625
use super::OverflowError;
@@ -41,13 +40,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
4140
// separately rather than using `stack.fresh_trait_ref` --
4241
// this is because we want the unbound variables to be
4342
// replaced with fresh types starting from index 0.
44-
let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate);
45-
debug!(?cache_fresh_trait_pred);
43+
let cache_entry =
44+
self.canonicalize_for_cache(stack.obligation.param_env, stack.obligation.predicate);
4645
debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars());
4746

48-
if let Some(c) =
49-
self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred)
50-
{
47+
if let Some(c) = self.check_candidate_cache(cache_entry) {
5148
debug!("CACHE HIT");
5249
return c;
5350
}
@@ -62,12 +59,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
6259
self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
6360

6461
debug!("CACHE MISS");
65-
self.insert_candidate_cache(
66-
stack.obligation.param_env,
67-
cache_fresh_trait_pred,
68-
dep_node,
69-
candidate.clone(),
70-
);
62+
self.insert_candidate_cache(cache_entry, dep_node, candidate.clone());
7163
candidate
7264
}
7365

0 commit comments

Comments
 (0)