1
Fork 0

Auto merge of #109692 - Nilstrieb:rollup-hq65rps, r=Nilstrieb

Rollup of 8 pull requests

Successful merges:

 - #91793 (socket ancillary data implementation for FreeBSD (from 13 and above).)
 - #92284 (Change advance(_back)_by to return the remainder instead of the number of processed elements)
 - #102472 (stop special-casing `'static` in evaluation)
 - #108480 (Use Rayon's TLV directly)
 - #109321 (Erase impl regions when checking for impossible to eagerly monomorphize items)
 - #109470 (Correctly substitute GAT's type used in `normalize_param_env` in `check_type_bounds`)
 - #109562 (Update ar_archive_writer to 0.1.3)
 - #109629 (remove obsolete `givens` from regionck)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-28 15:18:16 +00:00
commit 478cbb42b7
77 changed files with 1011 additions and 745 deletions

View file

@ -235,9 +235,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.9.2"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",

View file

@ -25,7 +25,7 @@ target-lexicon = "0.12.0"
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
indexmap = "1.9.1"
indexmap = "1.9.3"
libloading = { version = "0.7.3", optional = true }
once_cell = "1.10.0"
smallvec = "1.8.1"

View file

@ -110,7 +110,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
// FIXME use ArArchiveBuilder on most targets again once reading thin archives is
// implemented
if true || sess.target.arch == "wasm32" || sess.target.arch == "wasm64" {
if true {
Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
} else {
Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols))

View file

@ -10,12 +10,12 @@ arrayvec = { version = "0.7", default-features = false }
bitflags = "1.2.1"
cfg-if = "1.0"
ena = "0.14.2"
indexmap = { version = "1.9.1" }
indexmap = { version = "1.9.3" }
jobserver_crate = { version = "0.1.13", package = "jobserver" }
libc = "0.2"
measureme = "10.0.0"
rayon-core = { version = "0.4.0", package = "rustc-rayon-core", optional = true }
rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc-rayon = { version = "0.5.0", optional = true }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc-hash = "1.1.0"
rustc_index = { path = "../rustc_index", package = "rustc_index" }
@ -51,4 +51,4 @@ features = [
memmap2 = "0.2.1"
[features]
rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rayon", "rayon-core"]
rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rustc-rayon", "rustc-rayon-core"]

View file

@ -330,7 +330,6 @@ fn compare_method_predicate_entailment<'tcx>(
// lifetime parameters.
let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
Some(infcx),
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()),
);
infcx.process_registered_region_obligations(
@ -727,7 +726,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// lifetime parameters.
let outlives_environment = OutlivesEnvironment::with_bounds(
param_env,
Some(infcx),
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
);
infcx
@ -1876,14 +1874,17 @@ pub(super) fn check_type_bounds<'tcx>(
impl_ty: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorGuaranteed> {
let param_env = tcx.param_env(impl_ty.def_id);
let container_id = impl_ty.container_id(tcx);
// Given
//
// impl<A, B> Foo<u32> for (A, B) {
// type Bar<C> =...
// type Bar<C> = Wrapper<A, B, C>
// }
//
// - `impl_trait_ref` would be `<(A, B) as Foo<u32>>`
// - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
// - `normalize_impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
// - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>`
// - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
// the *trait* with the generic associated type parameters (as bound vars).
//
@ -1912,56 +1913,46 @@ pub(super) fn check_type_bounds<'tcx>(
// Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
// elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
// the trait (notably, that X: Eq and T: Family).
let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
let mut substs = smallvec::SmallVec::with_capacity(defs.count());
if let Some(def_id) = defs.parent {
let parent_defs = tcx.generics_of(def_id);
InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
tcx.mk_param_from_def(param)
});
}
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
smallvec::SmallVec::with_capacity(defs.count());
InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
GenericParamDefKind::Type { .. } => {
let kind = ty::BoundTyKind::Param(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Ty(kind);
bound_vars.push(bound_var);
tcx.mk_bound(
ty::INNERMOST,
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
GenericParamDefKind::Lifetime => {
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Region(kind);
bound_vars.push(bound_var);
tcx.mk_re_late_bound(
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
tcx.mk_const(
ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
tcx.type_of(param.def_id).subst_identity(),
)
.into()
}
});
let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
let impl_ty_substs = tcx.mk_substs(&substs);
let container_id = impl_ty.container_id(tcx);
let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
let impl_ty_value = tcx.type_of(impl_ty.def_id).subst_identity();
let param_env = tcx.param_env(impl_ty.def_id);
smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
// Extend the impl's identity substs with late-bound GAT vars
let normalize_impl_ty_substs = ty::InternalSubsts::identity_for_item(tcx, container_id)
.extend_to(tcx, impl_ty.def_id, |param, _| match param.kind {
GenericParamDefKind::Type { .. } => {
let kind = ty::BoundTyKind::Param(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Ty(kind);
bound_vars.push(bound_var);
tcx.mk_bound(
ty::INNERMOST,
ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
GenericParamDefKind::Lifetime => {
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Region(kind);
bound_vars.push(bound_var);
tcx.mk_re_late_bound(
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
tcx.mk_const(
ty::ConstKind::Bound(
ty::INNERMOST,
ty::BoundVar::from_usize(bound_vars.len() - 1),
),
tcx.type_of(param.def_id)
.no_bound_vars()
.expect("const parameter types cannot be generic"),
)
.into()
}
});
// When checking something like
//
// trait X { type Y: PartialEq<<Self as X>::Y> }
@ -1971,9 +1962,13 @@ pub(super) fn check_type_bounds<'tcx>(
// we want <T as X>::Y to normalize to S. This is valid because we are
// checking the default value specifically here. Add this equality to the
// ParamEnv for normalization specifically.
let normalize_impl_ty = tcx.type_of(impl_ty.def_id).subst(tcx, normalize_impl_ty_substs);
let rebased_substs =
normalize_impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
let normalize_param_env = {
let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
match impl_ty_value.kind() {
match normalize_impl_ty.kind() {
ty::Alias(ty::Projection, proj)
if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
{
@ -1987,7 +1982,7 @@ pub(super) fn check_type_bounds<'tcx>(
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
term: impl_ty_value.into(),
term: normalize_impl_ty.into(),
},
bound_vars,
)
@ -2068,8 +2063,7 @@ pub(super) fn check_type_bounds<'tcx>(
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
let outlives_environment =
OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
infcx.err_ctxt().check_region_obligations_and_report_errors(
impl_ty.def_id.expect_local(),

View file

@ -114,8 +114,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
return;
}
let outlives_environment =
OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
let _ = infcx
.err_ctxt()
@ -675,7 +674,6 @@ fn resolve_regions_with_wf_tys<'tcx>(
let infcx = tcx.infer_ctxt().build();
let outlives_environment = OutlivesEnvironment::with_bounds(
param_env,
Some(&infcx),
infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
);
let region_bound_pairs = outlives_environment.region_bound_pairs();

View file

@ -179,7 +179,7 @@ fn get_impl_substs(
}
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
let _ =
infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {

View file

@ -238,15 +238,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Note that there are two tests to check that this remains true
// (`regions-reassign-{match,let}-bound-pointer.rs`).
//
// 2. Things go horribly wrong if we use subtype. The reason for
// THIS is a fairly subtle case involving bound regions. See the
// `givens` field in `region_constraints`, as well as the test
// 2. An outdated issue related to the old HIR borrowck. See the test
// `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
// for details. Short version is that we must sometimes detect
// relationships between specific region variables and regions
// bound in a closure signature, and that detection gets thrown
// off when we substitute fresh region variables here to enable
// subtyping.
}
/// Compute the new expected type and default binding mode from the old ones

View file

@ -640,11 +640,9 @@ pub fn make_query_region_constraints<'tcx>(
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
region_constraints: &RegionConstraintData<'tcx>,
) -> QueryRegionConstraints<'tcx> {
let RegionConstraintData { constraints, verifys, givens, member_constraints } =
region_constraints;
let RegionConstraintData { constraints, verifys, member_constraints } = region_constraints;
assert!(verifys.is_empty());
assert!(givens.is_empty());
debug!(?constraints);

View file

@ -43,18 +43,16 @@ pub struct TypeFreshener<'a, 'tcx> {
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
keep_static: bool,
}
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'tcx>) -> TypeFreshener<'a, 'tcx> {
TypeFreshener {
infcx,
ty_freshen_count: 0,
const_freshen_count: 0,
ty_freshen_map: Default::default(),
const_freshen_map: Default::default(),
keep_static,
}
}
@ -121,18 +119,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
| ty::ReFree(_)
| ty::ReVar(_)
| ty::RePlaceholder(..)
| ty::ReStatic
| ty::ReError(_)
| ty::ReErased => {
// replace all free regions with 'erased
self.interner().lifetimes.re_erased
}
ty::ReStatic => {
if self.keep_static {
r
} else {
self.interner().lifetimes.re_erased
}
}
| ty::ReErased => self.interner().lifetimes.re_erased,
}
}

View file

@ -13,7 +13,7 @@ use rustc_data_structures::graph::implementation::{
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
};
use rustc_data_structures::intern::Interned;
use rustc_index::vec::{Idx, IndexVec};
use rustc_index::vec::IndexVec;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::PlaceholderRegion;
use rustc_middle::ty::{self, Ty, TyCtxt};
@ -132,7 +132,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
let graph = self.construct_graph();
self.expand_givens(&graph);
self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
@ -164,38 +163,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
// Givens are a kind of horrible hack to account for
// constraints like 'c <= '0 that are known to hold due to
// closure signatures (see the comment above on the `givens`
// field). They should go away. But until they do, the role
// of this fn is to account for the transitive nature:
//
// Given 'c <= '0
// and '0 <= '1
// then 'c <= '1
let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
for (r, vid) in seeds {
// While all things transitively reachable in the graph
// from the variable (`'0` in the example above).
let seed_index = NodeIndex(vid.index() as usize);
for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
let succ_index = succ_index.0;
// The first N nodes correspond to the region
// variables. Other nodes correspond to constant
// regions.
if succ_index < self.num_vars() {
let succ_vid = RegionVid::new(succ_index);
// Add `'c <= '1`.
self.data.givens.insert((r, succ_vid));
}
}
}
}
/// Gets the LUb of a given region and the empty region
fn lub_empty(&self, a_region: Region<'tcx>) -> Result<Region<'tcx>, PlaceholderRegion> {
match *a_region {
@ -362,18 +329,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
) -> bool {
debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
match *a_region {
// Check if this relationship is implied by a given.
ty::ReEarlyBound(_) | ty::ReFree(_) => {
if self.data.givens.contains(&(a_region, b_vid)) {
debug!("given");
return false;
}
}
_ => {}
}
match *b_data {
VarValue::Empty(empty_ui) => {
let lub = match self.lub_empty(a_region) {

View file

@ -713,12 +713,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
freshen::TypeFreshener::new(self, false)
}
/// Like `freshener`, but does not replace `'static` regions.
pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
freshen::TypeFreshener::new(self, true)
freshen::TypeFreshener::new(self)
}
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
@ -874,10 +869,6 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
}
pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
}
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
where
T: at::ToTrace<'tcx>,

View file

@ -1,9 +1,9 @@
use crate::infer::free_regions::FreeRegionMap;
use crate::infer::{GenericKind, InferCtxt};
use crate::infer::GenericKind;
use crate::traits::query::OutlivesBound;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
use rustc_middle::ty::{self, Region};
use super::explicit_outlives_bounds;
@ -75,7 +75,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
region_bound_pairs: Default::default(),
};
builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
builder.add_outlives_bounds(explicit_outlives_bounds(param_env));
builder
}
@ -89,11 +89,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
/// Create a new `OutlivesEnvironment` with extra outlives bounds.
pub fn with_bounds(
param_env: ty::ParamEnv<'tcx>,
infcx: Option<&InferCtxt<'tcx>>,
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
) -> Self {
let mut builder = Self::builder(param_env);
builder.add_outlives_bounds(infcx, extra_bounds);
builder.add_outlives_bounds(extra_bounds);
builder.build()
}
@ -120,12 +119,7 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
}
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
///
/// The `infcx` parameter is optional; if the implied bounds may
/// contain inference variables, it must be supplied, in which
/// case we will register "givens" on the inference context. (See
/// `RegionConstraintData`.)
fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I)
fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
where
I: IntoIterator<Item = OutlivesBound<'tcx>>,
{
@ -142,27 +136,17 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
}
OutlivesBound::RegionSubRegion(r_a, r_b) => {
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
infcx
.expect("no infcx provided but region vars found")
.add_given(r_a, vid_b);
} else {
// In principle, we could record (and take
// advantage of) every relationship here, but
// we are also free not to -- it simply means
// strictly less that we can successfully type
// check. Right now we only look for things
// relationships between free regions. (It may
// also be that we should revise our inference
// system to be more general and to make use
// of *every* relationship that arises here,
// but presently we do not.)
if r_a.is_free_or_static() && r_b.is_free() {
self.region_relation.add(r_a, r_b)
}
}
}
OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
(
ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
) => self.region_relation.add(r_a, r_b),
(ty::ReError(_), _) | (_, ty::ReError(_)) => {}
// FIXME(#109628): We shouldn't have existential variables in implied bounds.
// Panic here once the linked issue is resolved!
(ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
_ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
},
}
}
}

View file

@ -424,9 +424,6 @@ impl<'tcx> MiniGraph<'tcx> {
&AddConstraint(Constraint::RegSubReg(a, b)) => {
each_edge(a, b);
}
&AddGiven(a, b) => {
each_edge(a, tcx.mk_re_var(b));
}
&AddVerify(i) => span_bug!(
verifys[i].origin.span(),
"we never add verifications while doing higher-ranked things",

View file

@ -7,7 +7,7 @@ use super::{
InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
@ -104,26 +104,6 @@ pub struct RegionConstraintData<'tcx> {
/// An example is a `A <= B` where neither `A` nor `B` are
/// inference variables.
pub verifys: Vec<Verify<'tcx>>,
/// A "given" is a relationship that is known to hold. In
/// particular, we often know from closure fn signatures that a
/// particular free region must be a subregion of a region
/// variable:
///
/// foo.iter().filter(<'a> |x: &'a &'b T| ...)
///
/// In situations like this, `'b` is in fact a region variable
/// introduced by the call to `iter()`, and `'a` is a bound region
/// on the closure (as indicated by the `<'a>` prefix). If we are
/// naive, we wind up inferring that `'b` must be `'static`,
/// because we require that it be greater than `'a` and we do not
/// know what `'a` is precisely.
///
/// This hashmap is used to avoid that naive scenario. Basically
/// we record the fact that `'a <= 'b` is implied by the fn
/// signature, and then ignore the constraint when solving
/// equations. This is a bit of a hack but seems to work.
pub givens: FxIndexSet<(Region<'tcx>, ty::RegionVid)>,
}
/// Represents a constraint that influences the inference process.
@ -297,9 +277,6 @@ pub(crate) enum UndoLog<'tcx> {
/// We added the given `verify`.
AddVerify(usize),
/// We added the given `given`.
AddGiven(Region<'tcx>, ty::RegionVid),
/// We added a GLB/LUB "combination variable".
AddCombination(CombineMapType, TwoRegions<'tcx>),
}
@ -348,9 +325,6 @@ impl<'tcx> RegionConstraintStorage<'tcx> {
self.data.verifys.pop();
assert_eq!(self.data.verifys.len(), index);
}
AddGiven(sub, sup) => {
self.data.givens.remove(&(sub, sup));
}
AddCombination(Glb, ref regions) => {
self.glbs.remove(regions);
}
@ -492,15 +466,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
self.undo_log.push(AddVerify(index));
}
pub(super) fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
// cannot add givens once regions are resolved
if self.data.givens.insert((sub, sup)) {
debug!("add_given({:?} <= {:?})", sub, sup);
self.undo_log.push(AddGiven(sub, sup));
}
}
pub(super) fn make_eqregion(
&mut self,
origin: SubregionOrigin<'tcx>,
@ -804,11 +769,8 @@ impl<'tcx> RegionConstraintData<'tcx> {
/// Returns `true` if this region constraint data contains no constraints, and `false`
/// otherwise.
pub fn is_empty(&self) -> bool {
let RegionConstraintData { constraints, member_constraints, verifys, givens } = self;
constraints.is_empty()
&& member_constraints.is_empty()
&& verifys.is_empty()
&& givens.is_empty()
let RegionConstraintData { constraints, member_constraints, verifys } = self;
constraints.is_empty() && member_constraints.is_empty() && verifys.is_empty()
}
}

View file

@ -8,8 +8,8 @@ edition = "2021"
[dependencies]
libloading = "0.7.1"
tracing = "0.1"
rustc-rayon-core = { version = "0.4.0", optional = true }
rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc-rayon = { version = "0.5.0", optional = true }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
@ -52,4 +52,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" }
[features]
llvm = ['rustc_codegen_llvm']
rustc_use_parallel_compiler = ['rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler']
rustc_use_parallel_compiler = ['rustc-rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler']

View file

@ -183,7 +183,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
.try_collect_active_jobs()
.expect("active jobs shouldn't be locked in deadlock handler")
});
let registry = rustc_rayon_core::Registry::current();
let registry = rayon_core::Registry::current();
thread::spawn(move || deadlock(query_map, &registry));
});
if let Some(size) = get_stack_size() {

View file

@ -26,8 +26,8 @@ rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_query_system = { path = "../rustc_query_system" }
rustc-rayon-core = { version = "0.4.0", optional = true }
rustc-rayon = { version = "0.4.0", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc-rayon = { version = "0.5.0", optional = true }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }

View file

@ -4,6 +4,8 @@ use crate::dep_graph::TaskDepsRef;
use crate::ty::query;
use rustc_data_structures::sync::{self, Lock};
use rustc_errors::Diagnostic;
#[cfg(not(parallel_compiler))]
use std::cell::Cell;
use std::mem;
use std::ptr;
use thin_vec::ThinVec;
@ -47,52 +49,15 @@ impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
}
}
// Import the thread-local variable from Rayon, which is preserved for Rayon jobs.
#[cfg(parallel_compiler)]
mod tlv {
use rustc_rayon_core as rayon_core;
use std::ptr;
/// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
/// This is used to get the pointer to the current `ImplicitCtxt`.
#[inline]
pub(super) fn get_tlv() -> *const () {
ptr::from_exposed_addr(rayon_core::tlv::get())
}
/// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
/// to `value` during the call to `f`. It is restored to its previous value after.
/// This is used to set the pointer to the new `ImplicitCtxt`.
#[inline]
pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
rayon_core::tlv::with(value.expose_addr(), f)
}
}
use rayon_core::tlv::TLV;
// Otherwise define our own
#[cfg(not(parallel_compiler))]
mod tlv {
use std::cell::Cell;
use std::ptr;
thread_local! {
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
}
/// Gets the pointer to the current `ImplicitCtxt`.
#[inline]
pub(super) fn get_tlv() -> *const () {
TLV.with(|tlv| tlv.get())
}
/// Sets TLV to `value` during the call to `f`.
/// It is restored to its previous value after.
/// This is used to set the pointer to the new `ImplicitCtxt`.
#[inline]
pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
let old = TLV.replace(value);
let _reset = rustc_data_structures::OnDrop(move || TLV.set(old));
f()
}
thread_local! {
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
}
#[inline]
@ -111,7 +76,11 @@ pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) ->
where
F: FnOnce() -> R,
{
tlv::with_tlv(erase(context), f)
TLV.with(|tlv| {
let old = tlv.replace(erase(context));
let _reset = rustc_data_structures::OnDrop(move || tlv.set(old));
f()
})
}
/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
@ -120,7 +89,7 @@ pub fn with_context_opt<F, R>(f: F) -> R
where
F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
{
let context = tlv::get_tlv();
let context = TLV.get();
if context.is_null() {
f(None)
} else {

View file

@ -1327,27 +1327,40 @@ fn create_mono_items_for_default_impls<'tcx>(
return;
}
let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
return;
};
// Lifetimes never affect trait selection, so we are allowed to eagerly
// instantiate an instance of an impl method if the impl (and method,
// which we check below) is only parameterized over lifetime. In that case,
// we use the ReErased, which has no lifetime information associated with
// it, to validate whether or not the impl is legal to instantiate at all.
let only_region_params = |param: &ty::GenericParamDef, _: &_| match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
unreachable!(
"`own_requires_monomorphization` check means that \
we should have no type/const params"
)
}
};
let impl_substs = InternalSubsts::for_item(tcx, item.owner_id.to_def_id(), only_region_params);
let trait_ref = trait_ref.subst(tcx, impl_substs);
// Unlike 'lazy' monomorphization that begins by collecting items transitively
// called by `main` or other global items, when eagerly monomorphizing impl
// items, we never actually check that the predicates of this impl are satisfied
// in a empty reveal-all param env (i.e. with no assumptions).
//
// Even though this impl has no substitutions, because we don't consider higher-
// ranked predicates such as `for<'a> &'a mut [u8]: Copy` to be trivially false,
// we must now check that the impl has no impossible-to-satisfy predicates.
if tcx.subst_and_check_impossible_predicates((
item.owner_id.to_def_id(),
&InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()),
)) {
// Even though this impl has no type or const substitutions, because we don't
// consider higher-ranked predicates such as `for<'a> &'a mut [u8]: Copy` to
// be trivially false. We must now check that the impl has no impossible-to-satisfy
// predicates.
if tcx.subst_and_check_impossible_predicates((item.owner_id.to_def_id(), impl_substs)) {
return;
}
let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
return;
};
let trait_ref = trait_ref.subst_identity();
let param_env = ty::ParamEnv::reveal_all();
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
@ -1360,12 +1373,9 @@ fn create_mono_items_for_default_impls<'tcx>(
continue;
}
let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
trait_ref.substs[param.index as usize]
}
});
// As mentioned above, the method is legal to eagerly instantiate if it
// only has lifetime substitutions. This is validated by
let substs = trait_ref.substs.extend_to(tcx, method.def_id, only_region_params);
let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, substs);
let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);

View file

@ -16,7 +16,7 @@ rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_query_system = { path = "../rustc_query_system" }
rustc-rayon-core = { version = "0.4.0", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }

View file

@ -15,7 +15,7 @@ rustc_feature = { path = "../rustc_feature" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc-rayon-core = { version = "0.4.0", optional = true }
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }

View file

@ -18,11 +18,11 @@ use std::num::NonZeroU64;
#[cfg(parallel_compiler)]
use {
parking_lot::{Condvar, Mutex},
rayon_core,
rustc_data_structures::fx::FxHashSet,
rustc_data_structures::sync::Lock,
rustc_data_structures::sync::Lrc,
rustc_data_structures::{jobserver, OnDrop},
rustc_rayon_core as rayon_core,
rustc_span::DUMMY_SP,
std::iter,
std::process,

View file

@ -4,7 +4,7 @@ version = "0.0.0"
edition = "2021"
[dependencies]
indexmap = "1.9.1"
indexmap = "1.9.3"
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"

View file

@ -18,4 +18,4 @@ tracing = "0.1"
sha1 = "0.10.0"
sha2 = "0.10.1"
md5 = { package = "md-5", version = "0.10.0" }
indexmap = { version = "1.9.1" }
indexmap = { version = "1.9.3" }

View file

@ -402,7 +402,6 @@ fn resolve_negative_obligation<'tcx>(
let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
Some(&infcx),
infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
);

View file

@ -111,7 +111,6 @@ pub fn type_allowed_to_implement_copy<'tcx>(
// Check regions assuming the self type of the impl is WF
let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
Some(&infcx),
infcx.implied_bounds_tys(
param_env,
parent_cause.body_id,

View file

@ -3,7 +3,8 @@ use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
use crate::traits::query::NoSolution;
use crate::traits::{ObligationCause, ObligationCtxt};
use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::ty::{self, ParamEnv, Ty};
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
use rustc_span::def_id::LocalDefId;
pub use rustc_middle::traits::query::OutlivesBound;
@ -52,6 +53,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
body_id: LocalDefId,
ty: Ty<'tcx>,
) -> Vec<OutlivesBound<'tcx>> {
let ty = self.resolve_vars_if_possible(ty);
let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
assert!(!ty.needs_infer());
let span = self.tcx.def_span(body_id);
let result = param_env
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
@ -106,10 +111,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
tys: FxIndexSet<Ty<'tcx>>,
) -> Bounds<'a, 'tcx> {
tys.into_iter()
.map(move |ty| {
let ty = self.resolve_vars_if_possible(ty);
self.implied_outlives_bounds(param_env, body_id, ty)
})
.map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
.flatten()
}
}

View file

@ -211,7 +211,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
freshener: infcx.freshener_keep_static(),
freshener: infcx.freshener(),
intercrate_ambiguity_causes: None,
query_mode: TraitQueryMode::Standard,
}
@ -770,14 +770,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => {
// A global type with no late-bound regions can only
// contain the "'static" lifetime (any other lifetime
// would either be late-bound or local), so it is guaranteed
// to outlive any other lifetime
if pred.0.is_global() && !pred.0.has_late_bound_vars() {
Ok(EvaluatedToOk)
} else {
// A global type with no free lifetimes or generic parameters
// outlives anything.
if pred.0.has_free_regions()
|| pred.0.has_late_bound_regions()
|| pred.0.has_non_region_infer()
|| pred.0.has_non_region_infer()
{
Ok(EvaluatedToOkModuloRegions)
} else {
Ok(EvaluatedToOk)
}
}
@ -1825,6 +1827,12 @@ enum DropVictim {
No,
}
impl DropVictim {
fn drop_if(should_drop: bool) -> DropVictim {
if should_drop { DropVictim::Yes } else { DropVictim::No }
}
}
/// ## Winnowing
///
/// Winnowing is the process of attempting to resolve ambiguity by
@ -1890,11 +1898,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// or the current one if tied (they should both evaluate to the same answer). This is
// probably best characterized as a "hack", since we might prefer to just do our
// best to *not* create essentially duplicate candidates in the first place.
if other.bound_vars().len() <= victim.bound_vars().len() {
DropVictim::Yes
} else {
DropVictim::No
}
DropVictim::drop_if(other.bound_vars().len() <= victim.bound_vars().len())
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
&& other.skip_binder().polarity == victim.skip_binder().polarity
@ -1924,17 +1928,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ObjectCandidate(_)
| ProjectionCandidate(..),
) => {
if is_global(other_cand) {
DropVictim::No
} else {
// We have a where clause so don't go around looking
// for impls. Arbitrarily give param candidates priority
// over projection and object candidates.
//
// Global bounds from the where clause should be ignored
// here (see issue #50825).
DropVictim::Yes
}
// We have a where clause so don't go around looking
// for impls. Arbitrarily give param candidates priority
// over projection and object candidates.
//
// Global bounds from the where clause should be ignored
// here (see issue #50825).
DropVictim::drop_if(!is_global(other_cand))
}
(ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
// Prefer these to a global where-clause bound
@ -1956,18 +1956,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
if is_global(victim_cand) && other.evaluation.must_apply_modulo_regions() {
DropVictim::Yes
} else {
DropVictim::No
}
DropVictim::drop_if(
is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(),
)
}
(ProjectionCandidate(i, _), ProjectionCandidate(j, _))
| (ObjectCandidate(i), ObjectCandidate(j)) => {
// Arbitrarily pick the lower numbered candidate for backwards
// compatibility reasons. Don't let this affect inference.
if i < j && !needs_infer { DropVictim::Yes } else { DropVictim::No }
DropVictim::drop_if(i < j && !needs_infer)
}
(ObjectCandidate(_), ProjectionCandidate(..))
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
@ -2018,55 +2016,65 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
}
if other.evaluation.must_apply_considering_regions() {
match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
// Subtle: If the predicate we are evaluating has inference
// variables, do *not* allow discarding candidates due to
// marker trait impls.
//
// Without this restriction, we could end up accidentally
// constraining inference variables based on an arbitrarily
// chosen trait impl.
//
// Imagine we have the following code:
//
// ```rust
// #[marker] trait MyTrait {}
// impl MyTrait for u8 {}
// impl MyTrait for bool {}
// ```
//
// And we are evaluating the predicate `<_#0t as MyTrait>`.
//
// During selection, we will end up with one candidate for each
// impl of `MyTrait`. If we were to discard one impl in favor
// of the other, we would be left with one candidate, causing
// us to "successfully" select the predicate, unifying
// _#0t with (for example) `u8`.
//
// However, we have no reason to believe that this unification
// is correct - we've essentially just picked an arbitrary
// *possibility* for _#0t, and required that this be the *only*
// possibility.
//
// Eventually, we will either:
// 1) Unify all inference variables in the predicate through
// some other means (e.g. type-checking of a function). We will
// then be in a position to drop marker trait candidates
// without constraining inference variables (since there are
// none left to constrain)
// 2) Be left with some unconstrained inference variables. We
// will then correctly report an inference error, since the
// existence of multiple marker trait impls tells us nothing
// about which one should actually apply.
if needs_infer { DropVictim::No } else { DropVictim::Yes }
}
Some(_) => DropVictim::Yes,
None => DropVictim::No,
match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
// For #33140 the impl headers must be exactly equal, the trait must not have
// any associated items and there are no where-clauses.
//
// We can just arbitrarily drop one of the impls.
Some(ty::ImplOverlapKind::Issue33140) => {
assert_eq!(other.evaluation, victim.evaluation);
DropVictim::Yes
}
} else {
DropVictim::No
// For candidates which already reference errors it doesn't really
// matter what we do 🤷
Some(ty::ImplOverlapKind::Permitted { marker: false }) => {
DropVictim::drop_if(other.evaluation.must_apply_considering_regions())
}
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
// Subtle: If the predicate we are evaluating has inference
// variables, do *not* allow discarding candidates due to
// marker trait impls.
//
// Without this restriction, we could end up accidentally
// constraining inference variables based on an arbitrarily
// chosen trait impl.
//
// Imagine we have the following code:
//
// ```rust
// #[marker] trait MyTrait {}
// impl MyTrait for u8 {}
// impl MyTrait for bool {}
// ```
//
// And we are evaluating the predicate `<_#0t as MyTrait>`.
//
// During selection, we will end up with one candidate for each
// impl of `MyTrait`. If we were to discard one impl in favor
// of the other, we would be left with one candidate, causing
// us to "successfully" select the predicate, unifying
// _#0t with (for example) `u8`.
//
// However, we have no reason to believe that this unification
// is correct - we've essentially just picked an arbitrary
// *possibility* for _#0t, and required that this be the *only*
// possibility.
//
// Eventually, we will either:
// 1) Unify all inference variables in the predicate through
// some other means (e.g. type-checking of a function). We will
// then be in a position to drop marker trait candidates
// without constraining inference variables (since there are
// none left to constrain)
// 2) Be left with some unconstrained inference variables. We
// will then correctly report an inference error, since the
// existence of multiple marker trait impls tells us nothing
// about which one should actually apply.
DropVictim::drop_if(
!needs_infer && other.evaluation.must_apply_considering_regions(),
)
}
None => DropVictim::No,
}
}