diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index e9751a23f1218..c4435070ba6c7 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -102,6 +102,14 @@ impl<'tcx> Arena<'tcx> { } } + #[inline] + pub fn alloc_slice(&self, value: &[T]) -> &mut [T] { + if value.len() == 0 { + return &mut [] + } + self.dropless.alloc_slice(value) + } + pub fn alloc_from_iter< T: ArenaAllocatable, I: IntoIterator diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 1861420b408b6..fbe79925a88db 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -245,13 +245,13 @@ rustc_queries! { /// Get a map with the variance of every item; use `item_variance` /// instead. - query crate_variances(_: CrateNum) -> Lrc { + query crate_variances(_: CrateNum) -> Lrc> { desc { "computing the variances for items in this crate" } } /// Maps from def-id of a type or region parameter to its /// (inferred) variance. - query variances_of(_: DefId) -> Lrc> {} + query variances_of(_: DefId) -> &'tcx [ty::Variance] {} } TypeChecking { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 67be228d232e1..0b862db89a6b6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -330,15 +330,11 @@ pub enum Variance { /// `tcx.variances_of()` to get the variance for a *particular* /// item. #[derive(HashStable)] -pub struct CrateVariancesMap { +pub struct CrateVariancesMap<'tcx> { /// For each item with generics, maps to a vector of the variance /// of its generics. If an item has no generics, it will have no /// entry. - pub variances: FxHashMap>>, - - /// An empty vector, useful for cloning. - #[stable_hasher(ignore)] - pub empty_variance: Lrc>, + pub variances: FxHashMap, } impl Variance { diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 810bd10c8f4f7..601226182ed62 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -60,7 +60,7 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized { b_subst); let opt_variances = self.tcx().variances_of(item_def_id); - relate_substs(self, Some(&opt_variances), a_subst, b_subst) + relate_substs(self, Some(opt_variances), a_subst, b_subst) } /// Switch variance for the purpose of relating `a` and `b`. @@ -122,7 +122,7 @@ impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> { } pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, - variances: Option<&Vec>, + variances: Option<&[ty::Variance]>, a_subst: SubstsRef<'tcx>, b_subst: SubstsRef<'tcx>) -> RelateResult<'tcx, SubstsRef<'tcx>> diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 1a1b933ccf311..483fd64245b0b 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -106,7 +106,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, let _ = cdata; tcx.calculate_dtor(def_id, &mut |_,_| Ok(())) } - variances_of => { Lrc::new(cdata.get_item_variances(def_id.index)) } + variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) } associated_item_def_ids => { let mut result = vec![]; cdata.each_child_of_item(def_id.index, diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 9b9a6bace96b1..88ee1d79f5435 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -36,7 +36,7 @@ pub fn provide(providers: &mut Providers<'_>) { } fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) - -> Lrc { + -> Lrc> { assert_eq!(crate_num, LOCAL_CRATE); let mut arena = arena::TypedArena::default(); let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &mut arena); @@ -45,7 +45,7 @@ fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) } fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) - -> Lrc> { + -> &'tcx [ty::Variance] { let id = tcx.hir().as_local_hir_id(item_def_id).expect("expected local def-id"); let unsupported = || { // Variance not relevant. @@ -88,6 +88,6 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) let crate_map = tcx.crate_variances(LOCAL_CRATE); crate_map.variances.get(&item_def_id) - .unwrap_or(&crate_map.empty_variance) - .clone() + .map(|p| *p) + .unwrap_or(&[]) } diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index b783bbfad16e9..8edf3c52ccc22 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -8,7 +8,6 @@ use rustc::hir::def_id::DefId; use rustc::ty; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lrc; use super::constraints::*; use super::terms::*; @@ -23,7 +22,9 @@ struct SolveContext<'a, 'tcx: 'a> { solutions: Vec, } -pub fn solve_constraints(constraints_cx: ConstraintContext<'_, '_>) -> ty::CrateVariancesMap { +pub fn solve_constraints<'tcx>( + constraints_cx: ConstraintContext<'_, 'tcx> +) -> ty::CrateVariancesMap<'tcx> { let ConstraintContext { terms_cx, constraints, .. } = constraints_cx; let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()]; @@ -41,9 +42,8 @@ pub fn solve_constraints(constraints_cx: ConstraintContext<'_, '_>) -> ty::Crate }; solutions_cx.solve(); let variances = solutions_cx.create_map(); - let empty_variance = Lrc::new(Vec::new()); - ty::CrateVariancesMap { variances, empty_variance } + ty::CrateVariancesMap { variances } } impl<'a, 'tcx> SolveContext<'a, 'tcx> { @@ -78,7 +78,23 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } } - fn create_map(&self) -> FxHashMap>> { + fn enforce_const_invariance(&self, generics: &ty::Generics, variances: &mut [ty::Variance]) { + let tcx = self.terms_cx.tcx; + + // Make all const parameters invariant. + for param in generics.params.iter() { + if let ty::GenericParamDefKind::Const = param.kind { + variances[param.index as usize] = ty::Invariant; + } + } + + // Make all the const parameters in the parent invariant (recursively). + if let Some(def_id) = generics.parent { + self.enforce_const_invariance(tcx.generics_of(def_id), variances); + } + } + + fn create_map(&self) -> FxHashMap { let tcx = self.terms_cx.tcx; let solutions = &self.solutions; @@ -87,26 +103,21 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { let generics = tcx.generics_of(def_id); let count = generics.count(); - let mut variances = solutions[start..(start + count)].to_vec(); - debug!("id={} variances={:?}", id, variances); + let variances = tcx.arena.alloc_slice(&solutions[start..(start + count)]); // Const parameters are always invariant. - for (idx, param) in generics.params.iter().enumerate() { - if let ty::GenericParamDefKind::Const = param.kind { - variances[idx] = ty::Invariant; - } - } + self.enforce_const_invariance(generics, variances); // Functions are permitted to have unused generic parameters: make those invariant. if let ty::FnDef(..) = tcx.type_of(def_id).sty { - for variance in &mut variances { + for variance in variances.iter_mut() { if *variance == ty::Bivariant { *variance = ty::Invariant; } } } - (def_id, Lrc::new(variances)) + (def_id, &*variances) }).collect() }