Skip to content

Commit 9fa25a7

Browse files
committed
Auto merge of #42015 - nikomatsakis:chalk-trait-env-2, r=eddyb
remove interior mutability of type-flags We were previously using the flags on `Ty<'tcx>` instances to do some ad-hoc caching schemes around things like `is_sized()`, `is_freeze()`, and `moves_by_default()`. This PR replaces those schemes with a proper query; the query key is based on the pair of a `(ParameterEnvironment<'tcx>, Ty<'tcx>)` pair. This is also intended to be a preliminary template for what trait-selection and projection will eventually look like. I did some performance measurements. In the past, I observed a noticeable speedup (6%) for building rustc, but since I've rebased, the numbers appear to be more of a wash: | Crate | Before | After | Percentage | | --- | --- | --- | -- | | syntax | 167s | 166s | 0.6% faster | | rustc | 376s | 382s | 1.5% slower | Some advantages of this new scheme: - `is_sized` etc are proper queries - we get caching across generic fns, so long as trait environment is identical - dependency tracking is correct
2 parents 852b7cb + 83641a9 commit 9fa25a7

File tree

37 files changed

+427
-491
lines changed

37 files changed

+427
-491
lines changed

src/librustc/dep_graph/dep_node.rs

+10
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ pub enum DepNode<D: Clone + Debug> {
108108
SymbolName(D),
109109
SpecializationGraph(D),
110110
ObjectSafety(D),
111+
IsCopy(D),
112+
IsSized(D),
113+
IsFreeze(D),
114+
NeedsDrop(D),
111115

112116
// The set of impls for a given trait. Ultimately, it would be
113117
// nice to get more fine-grained here (e.g., to include a
@@ -159,6 +163,7 @@ pub enum DepNode<D: Clone + Debug> {
159163
// not a hotspot.
160164
ProjectionCache { def_ids: Vec<D> },
161165

166+
ParamEnv(D),
162167
DescribeDef(D),
163168
DefSpan(D),
164169
Stability(D),
@@ -233,6 +238,10 @@ impl<D: Clone + Debug> DepNode<D> {
233238
// they are always absolute.
234239
WorkProduct(ref id) => Some(WorkProduct(id.clone())),
235240

241+
IsCopy(ref d) => op(d).map(IsCopy),
242+
IsSized(ref d) => op(d).map(IsSized),
243+
IsFreeze(ref d) => op(d).map(IsFreeze),
244+
NeedsDrop(ref d) => op(d).map(NeedsDrop),
236245
Hir(ref d) => op(d).map(Hir),
237246
HirBody(ref d) => op(d).map(HirBody),
238247
MetaData(ref d) => op(d).map(MetaData),
@@ -284,6 +293,7 @@ impl<D: Clone + Debug> DepNode<D> {
284293
let def_ids: Option<Vec<E>> = def_ids.iter().map(op).collect();
285294
def_ids.map(|d| ProjectionCache { def_ids: d })
286295
}
296+
ParamEnv(ref d) => op(d).map(ParamEnv),
287297
DescribeDef(ref d) => op(d).map(DescribeDef),
288298
DefSpan(ref d) => op(d).map(DefSpan),
289299
Stability(ref d) => op(d).map(Stability),

src/librustc/infer/mod.rs

+19-21
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
161161
// For region variables.
162162
region_vars: RegionVarBindings<'a, 'gcx, 'tcx>,
163163

164-
pub parameter_environment: ty::ParameterEnvironment<'gcx>,
164+
pub param_env: ty::ParamEnv<'gcx>,
165165

166166
/// Caches the results of trait selection. This cache is used
167167
/// for things that have to do with the parameters in scope.
@@ -406,41 +406,41 @@ pub trait InferEnv<'a, 'tcx> {
406406
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
407407
-> (Option<&'a ty::TypeckTables<'tcx>>,
408408
Option<ty::TypeckTables<'tcx>>,
409-
Option<ty::ParameterEnvironment<'tcx>>);
409+
Option<ty::ParamEnv<'tcx>>);
410410
}
411411

412412
impl<'a, 'tcx> InferEnv<'a, 'tcx> for () {
413413
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
414414
-> (Option<&'a ty::TypeckTables<'tcx>>,
415415
Option<ty::TypeckTables<'tcx>>,
416-
Option<ty::ParameterEnvironment<'tcx>>) {
416+
Option<ty::ParamEnv<'tcx>>) {
417417
(None, None, None)
418418
}
419419
}
420420

421-
impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParameterEnvironment<'tcx> {
421+
impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParamEnv<'tcx> {
422422
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
423423
-> (Option<&'a ty::TypeckTables<'tcx>>,
424424
Option<ty::TypeckTables<'tcx>>,
425-
Option<ty::ParameterEnvironment<'tcx>>) {
425+
Option<ty::ParamEnv<'tcx>>) {
426426
(None, None, Some(self))
427427
}
428428
}
429429

430-
impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::TypeckTables<'tcx>, ty::ParameterEnvironment<'tcx>) {
430+
impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) {
431431
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
432432
-> (Option<&'a ty::TypeckTables<'tcx>>,
433433
Option<ty::TypeckTables<'tcx>>,
434-
Option<ty::ParameterEnvironment<'tcx>>) {
434+
Option<ty::ParamEnv<'tcx>>) {
435435
(Some(self.0), None, Some(self.1))
436436
}
437437
}
438438

439-
impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::TypeckTables<'tcx>, ty::ParameterEnvironment<'tcx>) {
439+
impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) {
440440
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
441441
-> (Option<&'a ty::TypeckTables<'tcx>>,
442442
Option<ty::TypeckTables<'tcx>>,
443-
Option<ty::ParameterEnvironment<'tcx>>) {
443+
Option<ty::ParamEnv<'tcx>>) {
444444
(None, Some(self.0), Some(self.1))
445445
}
446446
}
@@ -449,11 +449,11 @@ impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
449449
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
450450
-> (Option<&'a ty::TypeckTables<'tcx>>,
451451
Option<ty::TypeckTables<'tcx>>,
452-
Option<ty::ParameterEnvironment<'tcx>>) {
452+
Option<ty::ParamEnv<'tcx>>) {
453453
let def_id = tcx.hir.body_owner_def_id(self);
454454
(Some(tcx.typeck_tables_of(def_id)),
455455
None,
456-
Some(tcx.parameter_environment(def_id)))
456+
Some(tcx.param_env(def_id)))
457457
}
458458
}
459459

@@ -465,7 +465,7 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
465465
arena: DroplessArena,
466466
fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
467467
tables: Option<&'a ty::TypeckTables<'gcx>>,
468-
param_env: Option<ty::ParameterEnvironment<'gcx>>,
468+
param_env: Option<ty::ParamEnv<'gcx>>,
469469
projection_mode: Reveal,
470470
}
471471

@@ -498,7 +498,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
498498
int_unification_table: RefCell::new(UnificationTable::new()),
499499
float_unification_table: RefCell::new(UnificationTable::new()),
500500
region_vars: RegionVarBindings::new(self),
501-
parameter_environment: param_env.unwrap(),
501+
param_env: param_env.unwrap(),
502502
selection_cache: traits::SelectionCache::new(),
503503
evaluation_cache: traits::EvaluationCache::new(),
504504
projection_cache: RefCell::new(traits::ProjectionCache::new()),
@@ -526,9 +526,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
526526
let tables = tables.map(InferTables::Interned).unwrap_or_else(|| {
527527
fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress)
528528
});
529-
let param_env = param_env.take().unwrap_or_else(|| {
530-
global_tcx.empty_parameter_environment()
531-
});
529+
let param_env = param_env.take().unwrap_or_else(|| ty::ParamEnv::empty());
532530
global_tcx.enter_local(arena, |tcx| f(InferCtxt {
533531
tcx: tcx,
534532
tables: tables,
@@ -537,7 +535,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
537535
int_unification_table: RefCell::new(UnificationTable::new()),
538536
float_unification_table: RefCell::new(UnificationTable::new()),
539537
region_vars: RegionVarBindings::new(tcx),
540-
parameter_environment: param_env,
538+
param_env: param_env,
541539
selection_cache: traits::SelectionCache::new(),
542540
evaluation_cache: traits::EvaluationCache::new(),
543541
reported_trait_errors: RefCell::new(FxHashSet()),
@@ -650,7 +648,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
650648
}
651649

652650
pub fn normalize_associated_type_in_env<T>(
653-
self, value: &T, env: &'a ty::ParameterEnvironment<'tcx>
651+
self, value: &T, env: ty::ParamEnv<'tcx>
654652
) -> T
655653
where T: TransNormalize<'tcx>
656654
{
@@ -662,7 +660,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
662660
return value;
663661
}
664662

665-
self.infer_ctxt(env.clone(), Reveal::All).enter(|infcx| {
663+
self.infer_ctxt(env, Reveal::All).enter(|infcx| {
666664
value.trans_normalize(&infcx)
667665
})
668666
}
@@ -1674,8 +1672,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
16741672
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
16751673
}
16761674

1677-
pub fn param_env(&self) -> &ty::ParameterEnvironment<'gcx> {
1678-
&self.parameter_environment
1675+
pub fn param_env(&self) -> ty::ParamEnv<'gcx> {
1676+
self.param_env
16791677
}
16801678

16811679
pub fn closure_kind(&self,

src/librustc/traits/README.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -418,16 +418,16 @@ before, and hence the cache lookup would succeed, yielding
418418
One subtle interaction is that the results of trait lookup will vary
419419
depending on what where clauses are in scope. Therefore, we actually
420420
have *two* caches, a local and a global cache. The local cache is
421-
attached to the `ParameterEnvironment` and the global cache attached
422-
to the `tcx`. We use the local cache whenever the result might depend
423-
on the where clauses that are in scope. The determination of which
424-
cache to use is done by the method `pick_candidate_cache` in
425-
`select.rs`. At the moment, we use a very simple, conservative rule:
426-
if there are any where-clauses in scope, then we use the local cache.
427-
We used to try and draw finer-grained distinctions, but that led to a
428-
serious of annoying and weird bugs like #22019 and #18290. This simple
429-
rule seems to be pretty clearly safe and also still retains a very
430-
high hit rate (~95% when compiling rustc).
421+
attached to the `ParamEnv` and the global cache attached to the
422+
`tcx`. We use the local cache whenever the result might depend on the
423+
where clauses that are in scope. The determination of which cache to
424+
use is done by the method `pick_candidate_cache` in `select.rs`. At
425+
the moment, we use a very simple, conservative rule: if there are any
426+
where-clauses in scope, then we use the local cache. We used to try
427+
and draw finer-grained distinctions, but that led to a serious of
428+
annoying and weird bugs like #22019 and #18290. This simple rule seems
429+
to be pretty clearly safe and also still retains a very high hit rate
430+
(~95% when compiling rustc).
431431

432432
# Specialization
433433

src/librustc/traits/mod.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,9 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
437437
/// Normalizes the parameter environment, reporting errors if they occur.
438438
pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
439439
region_context: DefId,
440-
unnormalized_env: ty::ParameterEnvironment<'tcx>,
440+
unnormalized_env: ty::ParamEnv<'tcx>,
441441
cause: ObligationCause<'tcx>)
442-
-> ty::ParameterEnvironment<'tcx>
442+
-> ty::ParamEnv<'tcx>
443443
{
444444
// I'm not wild about reporting errors here; I'd prefer to
445445
// have the errors get reported at a defined place (e.g.,
@@ -477,15 +477,15 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
477477
debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
478478
predicates);
479479

480-
let elaborated_env = unnormalized_env.with_caller_bounds(tcx.intern_predicates(&predicates));
480+
let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates));
481481

482482
tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| {
483483
let predicates = match fully_normalize(
484484
&infcx, cause,
485-
// You would really want to pass infcx.parameter_environment.caller_bounds here,
485+
// You would really want to pass infcx.param_env.caller_bounds here,
486486
// but that is an interned slice, and fully_normalize takes &T and returns T, so
487487
// without further refactoring, a slice can't be used. Luckily, we still have the
488-
// predicate vector from which we created the ParameterEnvironment in infcx, so we
488+
// predicate vector from which we created the ParamEnv in infcx, so we
489489
// can pass that instead. It's roundabout and a bit brittle, but this code path
490490
// ought to be refactored anyway, and until then it saves us from having to copy.
491491
&predicates,
@@ -494,7 +494,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
494494
Err(errors) => {
495495
infcx.report_fulfillment_errors(&errors);
496496
// An unnormalized env is better than nothing.
497-
return infcx.parameter_environment;
497+
return infcx.param_env;
498498
}
499499
};
500500

@@ -516,19 +516,19 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
516516
// all things considered.
517517
tcx.sess.span_err(span, &fixup_err.to_string());
518518
// An unnormalized env is better than nothing.
519-
return infcx.parameter_environment;
519+
return infcx.param_env;
520520
}
521521
};
522522

523523
let predicates = match tcx.lift_to_global(&predicates) {
524524
Some(predicates) => predicates,
525-
None => return infcx.parameter_environment
525+
None => return infcx.param_env
526526
};
527527

528528
debug!("normalize_param_env_or_error: resolved predicates={:?}",
529529
predicates);
530530

531-
infcx.parameter_environment.with_caller_bounds(tcx.intern_predicates(&predicates))
531+
ty::ParamEnv::new(tcx.intern_predicates(&predicates))
532532
})
533533
}
534534

src/librustc/traits/select.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
315315
self.infcx.tcx
316316
}
317317

318-
pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'gcx> {
318+
pub fn param_env(&self) -> ty::ParamEnv<'gcx> {
319319
self.infcx.param_env()
320320
}
321321

src/librustc/traits/specialize/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
180180
}
181181

182182
// create a parameter environment corresponding to a (skolemized) instantiation of impl1
183-
let penv = tcx.parameter_environment(impl1_def_id);
183+
let penv = tcx.param_env(impl1_def_id);
184184
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
185185

186186
// Create a infcx, taking the predicates of impl1 as assumptions:
@@ -250,7 +250,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
250250
source_trait_ref,
251251
target_trait_ref,
252252
errors,
253-
infcx.parameter_environment.caller_bounds);
253+
infcx.param_env.caller_bounds);
254254
Err(())
255255
}
256256

src/librustc/ty/context.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
138138
let flags = super::flags::FlagComputation::for_sty(&st);
139139
let ty_struct = TyS {
140140
sty: st,
141-
flags: Cell::new(flags.flags),
141+
flags: flags.flags,
142142
region_depth: flags.depth,
143143
};
144144

@@ -978,8 +978,8 @@ macro_rules! sty_debug_print {
978978
ty::TyError => /* unimportant */ continue,
979979
$(ty::$variant(..) => &mut $variant,)*
980980
};
981-
let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER);
982-
let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER);
981+
let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
982+
let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
983983

984984
variant.total += 1;
985985
total.total += 1;

src/librustc/ty/flags.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ impl FlagComputation {
167167
}
168168

169169
fn add_ty(&mut self, ty: Ty) {
170-
self.add_flags(ty.flags.get());
170+
self.add_flags(ty.flags);
171171
self.add_depth(ty.region_depth);
172172
}
173173

src/librustc/ty/fold.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -625,9 +625,8 @@ struct HasTypeFlagsVisitor {
625625

626626
impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
627627
fn visit_ty(&mut self, t: Ty) -> bool {
628-
let flags = t.flags.get();
629-
debug!("HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, flags, self.flags);
630-
flags.intersects(self.flags)
628+
debug!("HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, t.flags, self.flags);
629+
t.flags.intersects(self.flags)
631630
}
632631

633632
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {

src/librustc/ty/layout.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1079,7 +1079,7 @@ impl<'a, 'gcx, 'tcx> Layout {
10791079
let ptr_layout = |pointee: Ty<'gcx>| {
10801080
let non_zero = !ty.is_unsafe_ptr();
10811081
let pointee = infcx.normalize_projections(pointee);
1082-
if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) {
1082+
if pointee.is_sized(tcx, infcx.param_env, DUMMY_SP) {
10831083
Ok(Scalar { value: Pointer, non_zero: non_zero })
10841084
} else {
10851085
let unsized_part = tcx.struct_tail(pointee);
@@ -1268,11 +1268,11 @@ impl<'a, 'gcx, 'tcx> Layout {
12681268
let kind = if def.is_enum() || def.variants[0].fields.len() == 0{
12691269
StructKind::AlwaysSizedUnivariant
12701270
} else {
1271-
let param_env = tcx.parameter_environment(def.did);
1271+
let param_env = tcx.param_env(def.did);
12721272
let fields = &def.variants[0].fields;
12731273
let last_field = &fields[fields.len()-1];
12741274
let always_sized = tcx.type_of(last_field.did)
1275-
.is_sized(tcx, &param_env, DUMMY_SP);
1275+
.is_sized(tcx, param_env, DUMMY_SP);
12761276
if !always_sized { StructKind::MaybeUnsizedUnivariant }
12771277
else { StructKind::AlwaysSizedUnivariant }
12781278
};

0 commit comments

Comments
 (0)