Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[beta] backports #77490

Merged
merged 9 commits into from
Oct 3, 2020
Merged
3 changes: 3 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3424,6 +3424,7 @@ dependencies = [
name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
"arrayvec",
"bitflags",
"cfg-if",
"crossbeam-utils 0.7.2",
Expand Down Expand Up @@ -3599,6 +3600,7 @@ dependencies = [
name = "rustc_infer"
version = "0.0.0"
dependencies = [
"arrayvec",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
Expand Down Expand Up @@ -3738,6 +3740,7 @@ dependencies = [
name = "rustc_middle"
version = "0.0.0"
dependencies = [
"arrayvec",
"bitflags",
"byteorder",
"chalk-ir",
Expand Down
4 changes: 2 additions & 2 deletions src/ci/shared.sh
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ function ciCommandAddPath {
if isAzurePipelines; then
echo "##vso[task.prependpath]${path}"
elif isGitHubActions; then
echo "::add-path::${path}"
echo "${path}" >> "${GITHUB_PATH}"
else
echo "ciCommandAddPath only works inside CI!"
exit 1
Expand All @@ -122,7 +122,7 @@ function ciCommandSetEnv {
if isAzurePipelines; then
echo "##vso[task.setvariable variable=${name}]${value}"
elif isGitHubActions; then
echo "::set-env name=${name}::${value}"
echo "${name}=${value}" >> "${GITHUB_ENV}"
else
echo "ciCommandSetEnv only works inside CI!"
exit 1
Expand Down
1 change: 1 addition & 0 deletions src/librustc_data_structures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ path = "lib.rs"
doctest = false

[dependencies]
arrayvec = { version = "0.5.1", default-features = false }
ena = "0.14"
indexmap = "1.5.1"
tracing = "0.1"
Expand Down
12 changes: 7 additions & 5 deletions src/librustc_data_structures/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,24 +85,26 @@ pub mod sorted_map;
pub mod stable_set;
#[macro_use]
pub mod stable_hasher;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod sharded;
pub mod stack;
pub mod sync;
pub mod thin_vec;
pub mod tiny_list;
pub mod transitive_relation;
pub use ena::undo_log;
pub use ena::unify;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod mini_map;
pub mod tagged_ptr;
pub mod temp_dir;

pub use ena::undo_log;
pub use ena::unify;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
Expand Down
61 changes: 61 additions & 0 deletions src/librustc_data_structures/mini_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::fx::FxHashMap;
use arrayvec::ArrayVec;

use std::hash::Hash;

/// Small-storage-optimized implementation of a map
/// made specifically for caching results.
///
/// Stores elements in a small array up to a certain length
/// and switches to `HashMap` when that length is exceeded.
pub enum MiniMap<K, V> {
Array(ArrayVec<[(K, V); 8]>),
Map(FxHashMap<K, V>),
}

impl<K: Eq + Hash, V> MiniMap<K, V> {
/// Creates an empty `MiniMap`.
pub fn new() -> Self {
MiniMap::Array(ArrayVec::new())
}

/// Inserts or updates value in the map.
pub fn insert(&mut self, key: K, value: V) {
match self {
MiniMap::Array(array) => {
for pair in array.iter_mut() {
if pair.0 == key {
pair.1 = value;
return;
}
}
if let Err(error) = array.try_push((key, value)) {
let mut map: FxHashMap<K, V> = array.drain(..).collect();
let (key, value) = error.element();
map.insert(key, value);
*self = MiniMap::Map(map);
}
}
MiniMap::Map(map) => {
map.insert(key, value);
}
}
}

/// Return value by key if any.
pub fn get(&self, key: &K) -> Option<&V> {
match self {
MiniMap::Array(array) => {
for pair in array {
if pair.0 == *key {
return Some(&pair.1);
}
}
return None;
}
MiniMap::Map(map) => {
return map.get(key);
}
}
}
}
6 changes: 3 additions & 3 deletions src/librustc_errors/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -959,15 +959,15 @@ impl EmitterWriter {
'_',
line_offset + pos,
width_offset + depth,
code_offset + annotation.start_col - left,
(code_offset + annotation.start_col).saturating_sub(left),
style,
);
}
_ if self.teach => {
buffer.set_style_range(
line_offset,
code_offset + annotation.start_col - left,
code_offset + annotation.end_col - left,
(code_offset + annotation.start_col).saturating_sub(left),
(code_offset + annotation.end_col).saturating_sub(left),
style,
annotation.is_primary,
);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_index/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ path = "lib.rs"
doctest = false

[dependencies]
arrayvec = "0.5.1"
arrayvec = { version = "0.5.1", default-features = false }
rustc_serialize = { path = "../librustc_serialize" }
rustc_macros = { path = "../librustc_macros" }
1 change: 1 addition & 0 deletions src/librustc_infer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ rustc_serialize = { path = "../librustc_serialize" }
rustc_span = { path = "../librustc_span" }
rustc_target = { path = "../librustc_target" }
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
arrayvec = { version = "0.5.1", default-features = false }
rustc_ast = { path = "../librustc_ast" }
14 changes: 12 additions & 2 deletions src/librustc_infer/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use super::{InferCtxt, MiscVariable, TypeTrace};
use crate::traits::{Obligation, PredicateObligations};

use rustc_ast as ast;
use rustc_data_structures::mini_map::MiniMap;
use rustc_hir::def_id::DefId;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
Expand Down Expand Up @@ -379,6 +380,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
needs_wf: false,
root_ty: ty,
param_env: self.param_env,
cache: MiniMap::new(),
};

let ty = match generalize.relate(ty, ty) {
Expand Down Expand Up @@ -438,6 +440,8 @@ struct Generalizer<'cx, 'tcx> {
root_ty: Ty<'tcx>,

param_env: ty::ParamEnv<'tcx>,

cache: MiniMap<Ty<'tcx>, RelateResult<'tcx, Ty<'tcx>>>,
}

/// Result from a generalization operation. This includes
Expand Down Expand Up @@ -535,13 +539,16 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==

if let Some(result) = self.cache.get(&t) {
return result.clone();
}
debug!("generalize: t={:?}", t);

// Check to see whether the type we are generalizing references
// any other type variable related to `vid` via
// subtyping. This is basically our "occurs check", preventing
// us from creating infinitely sized types.
match t.kind {
let result = match t.kind {
ty::Infer(ty::TyVar(vid)) => {
let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid);
Expand Down Expand Up @@ -598,7 +605,10 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
Ok(t)
}
_ => relate::super_relate_tys(self, t, t),
}
};

self.cache.insert(t, result.clone());
return result;
}

fn regions(
Expand Down
40 changes: 28 additions & 12 deletions src/librustc_infer/infer/outlives/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::infer::{GenericKind, VerifyBound};
use rustc_data_structures::captures::Captures;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::walk::MiniSet;
use rustc_middle::ty::{self, Ty, TyCtxt};

/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
Expand Down Expand Up @@ -31,16 +32,23 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// Returns a "verify bound" that encodes what we know about
/// `generic` and the regions it outlives.
pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
let mut visited = MiniSet::new();
match generic {
GenericKind::Param(param_ty) => self.param_bound(param_ty),
GenericKind::Projection(projection_ty) => self.projection_bound(projection_ty),
GenericKind::Projection(projection_ty) => {
self.projection_bound(projection_ty, &mut visited)
}
}
}

fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
fn type_bound(
&self,
ty: Ty<'tcx>,
visited: &mut MiniSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
match ty.kind {
ty::Param(p) => self.param_bound(p),
ty::Projection(data) => self.projection_bound(data),
ty::Projection(data) => self.projection_bound(data, visited),
ty::FnDef(_, substs) => {
// HACK(eddyb) ignore lifetimes found shallowly in `substs`.
// This is inconsistent with `ty::Adt` (including all substs),
Expand All @@ -50,9 +58,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
let mut bounds = substs
.iter()
.filter_map(|child| match child.unpack() {
GenericArgKind::Type(ty) => Some(self.type_bound(ty)),
GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)),
GenericArgKind::Lifetime(_) => None,
GenericArgKind::Const(_) => Some(self.recursive_bound(child)),
GenericArgKind::Const(_) => Some(self.recursive_bound(child, visited)),
})
.filter(|bound| {
// Remove bounds that must hold, since they are not interesting.
Expand All @@ -66,7 +74,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
),
}
}
_ => self.recursive_bound(ty.into()),
_ => self.recursive_bound(ty.into(), visited),
}
}

Expand Down Expand Up @@ -137,7 +145,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
self.declared_projection_bounds_from_trait(projection_ty)
}

pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyBound<'tcx> {
pub fn projection_bound(
&self,
projection_ty: ty::ProjectionTy<'tcx>,
visited: &mut MiniSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
debug!("projection_bound(projection_ty={:?})", projection_ty);

let projection_ty_as_ty =
Expand Down Expand Up @@ -166,21 +178,25 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {

// see the extensive comment in projection_must_outlive
let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
let recursive_bound = self.recursive_bound(ty.into());
let recursive_bound = self.recursive_bound(ty.into(), visited);

VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
}

fn recursive_bound(&self, parent: GenericArg<'tcx>) -> VerifyBound<'tcx> {
fn recursive_bound(
&self,
parent: GenericArg<'tcx>,
visited: &mut MiniSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
let mut bounds = parent
.walk_shallow()
.walk_shallow(visited)
.filter_map(|child| match child.unpack() {
GenericArgKind::Type(ty) => Some(self.type_bound(ty)),
GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)),
GenericArgKind::Lifetime(lt) => {
// Ignore late-bound regions.
if !lt.is_late_bound() { Some(VerifyBound::OutlivedBy(lt)) } else { None }
}
GenericArgKind::Const(_) => Some(self.recursive_bound(child)),
GenericArgKind::Const(_) => Some(self.recursive_bound(child, visited)),
})
.filter(|bound| {
// Remove bounds that must hold, since they are not interesting.
Expand Down
1 change: 1 addition & 0 deletions src/librustc_middle/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ rustc_span = { path = "../librustc_span" }
byteorder = { version = "1.3" }
chalk-ir = "0.14.0"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
arrayvec = { version = "0.5.1", default-features = false }
measureme = "0.7.1"
rustc_session = { path = "../librustc_session" }
Loading