From 89d955f81bd803f3eef7db921449f5ed5fbb0adc Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Wed, 3 May 2023 22:38:03 -0400 Subject: [PATCH 01/16] Initial attempt at deduplicating region constraints --- .../src/solve/eval_ctxt/canonical.rs | 5 +- .../dedup_solver/constraint_walker.rs | 134 +++++ .../eval_ctxt/canonical/dedup_solver/mod.rs | 193 ++++++ .../canonical/dedup_solver/solver.rs | 561 ++++++++++++++++++ out.txt | 402 +++++++++++++ .../higher-rank-trait-bounds/issue-95230.rs | 6 +- tests/ui/traits/new-solver/dedup-vars.rs | 28 + 7 files changed, 1324 insertions(+), 5 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs create mode 100644 compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs create mode 100644 compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs create mode 100644 out.txt create mode 100644 tests/ui/traits/new-solver/dedup-vars.rs diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index fdb209fbff871..8039e2de4b473 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -25,6 +25,8 @@ use rustc_span::DUMMY_SP; use std::iter; use std::ops::Deref; +mod dedup_solver; + impl<'tcx> EvalCtxt<'_, 'tcx> { /// Canonicalizes the goal remembering the original values /// for each bound variable. @@ -92,12 +94,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } }; - let canonical = Canonicalizer::canonicalize( + let mut canonical = Canonicalizer::canonicalize( self.infcx, CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, &mut Default::default(), response, ); + dedup_solver::Deduper::dedup(self.infcx.tcx, &mut canonical); Ok(canonical) } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs new file mode 100644 index 0000000000000..d8ac0e0e29d88 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs @@ -0,0 +1,134 @@ +use crate::infer::region_constraints::MemberConstraint; +use rustc_middle::ty; +use ty::subst::{GenericArg, GenericArgKind}; +use ty::{Const, OutlivesPredicate, Placeholder, Region, Ty, TyCtxt}; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use std::rc::Rc; + +pub type Outlives<'tcx> = OutlivesPredicate, Region<'tcx>>; + +pub struct ConstraintWalker<'tcx, 'a> { + tcx: TyCtxt<'tcx>, + fetch_var: &'a mut dyn FnMut(usize) -> usize, + pub vars: Vec, +} +impl<'tcx, 'a> ConstraintWalker<'tcx, 'a> { + pub fn new(tcx: TyCtxt<'tcx>, fetch_var: &'a mut dyn FnMut(usize) -> usize) -> Self { + Self { tcx, fetch_var: fetch_var, vars: Vec::new() } + } + pub fn reset(&mut self) { + self.vars.clear(); + } + pub fn add_var(&mut self, var: usize) -> usize { + self.vars.push(var); + return (self.fetch_var)(var); + } + + // The walk functions recursively erases all dedupable vars in an input (replacing them with 0s), + // and returns the dedupable vars in order + + pub fn walk_outlives(&mut self, input: &Outlives<'tcx>) -> Outlives<'tcx> { + ty::OutlivesPredicate( + self.walk_generic_arg(input.0.clone()), + self.walk_region(input.1.clone()), + ) + } + pub fn walk_members(&mut self, input: &MemberConstraint<'tcx>) -> MemberConstraint<'tcx> { + MemberConstraint { + key: ty::OpaqueTypeKey { + def_id: input.key.def_id, + substs: self.walk_substs_ref(input.key.substs), + }, + definition_span: input.definition_span, + hidden_ty: self.walk_ty(input.hidden_ty), + member_region: self.walk_region(input.member_region), + choice_regions: Rc::new( + input.choice_regions.iter().map(|x| self.walk_region(*x)).collect::>(), + ), + } + } + fn walk_generic_arg(&mut self, input: GenericArg<'tcx>) -> GenericArg<'tcx> { + match input.unpack() { + GenericArgKind::Lifetime(region) => GenericArg::<'tcx>::from(self.walk_region(region)), + GenericArgKind::Const(const_var) => { + GenericArg::<'tcx>::from(self.walk_const(const_var)) + } + _ => input, + } + } + fn walk_region(&mut self, input: Region<'tcx>) -> Region<'tcx> { + let rewritten = match input.kind() { + // TODO: Are these all of the variants that can have variables? + ty::ReLateBound(db_indx, bound_region) => { + ty::ReLateBound(db_indx, self.walk_bound_region(bound_region)) + } + ty::ReVar(region_id) => { + ty::ReVar(ty::RegionVid::from_usize(self.add_var(region_id.index()))) + } + ty::RePlaceholder(region) => ty::RePlaceholder(Placeholder { + universe: region.universe, + bound: self.walk_bound_region(region.bound), + }), + _ => return input, + }; + self.tcx.mk_region_from_kind(rewritten) + } + fn walk_ty(&mut self, input: Ty<'tcx>) -> Ty<'tcx> { + let rewritten = match input.kind() { + // TODO: Quite a few are missing + ty::Adt(adt_def, substs) => ty::Adt(*adt_def, self.walk_substs_ref(substs)), + ty::Array(elem_ty, count) => ty::Array(self.walk_ty(*elem_ty), self.walk_const(*count)), + ty::Slice(elem_ty) => ty::Slice(self.walk_ty(*elem_ty)), + ty::RawPtr(ptr) => { + ty::RawPtr(ty::TypeAndMut { ty: self.walk_ty(ptr.ty), mutbl: ptr.mutbl }) + } + ty::Ref(ref_region, ref_ty, ref_mutbl) => { + ty::Ref(self.walk_region(*ref_region), self.walk_ty(*ref_ty), *ref_mutbl) + } + ty::FnDef(def_id, substs) => ty::FnDef(*def_id, self.walk_substs_ref(substs)), + ty::Tuple(elems) => ty::Tuple( + self.tcx + .mk_type_list(&elems.into_iter().map(|x| self.walk_ty(x)).collect::>()), + ), + ty::Bound(indx, bound_ty) => ty::Bound(*indx, self.walk_bound_ty(*bound_ty)), + ty::Placeholder(placeholder) => ty::Placeholder(Placeholder { + universe: placeholder.universe, + bound: self.walk_bound_ty(placeholder.bound), + }), + _ => return input, + }; + self.tcx.mk_ty_from_kind(rewritten) + } + fn walk_const(&mut self, input: Const<'tcx>) -> Const<'tcx> { + let rewritten_ty = self.walk_ty(input.ty()); + match input.kind() { + ty::ConstKind::Param(param) => self.tcx.mk_const( + ty::ParamConst { + index: self.add_var(param.index as usize) as u32, + name: param.name, + }, + rewritten_ty, + ), + _ => input, + } + } + fn walk_bound_region(&mut self, input: ty::BoundRegion) -> ty::BoundRegion { + ty::BoundRegion { + var: ty::BoundVar::from_usize(self.add_var(input.var.index())), + kind: input.kind, + } + } + fn walk_bound_ty(&mut self, input: ty::BoundTy) -> ty::BoundTy { + ty::BoundTy { + var: ty::BoundVar::from_usize(self.add_var(input.var.index())), + kind: input.kind, + } + } + fn walk_substs_ref( + &mut self, + input: &'tcx ty::List>, + ) -> &'tcx ty::List> { + self.tcx.mk_substs(&input.into_iter().map(|x| self.walk_generic_arg(x)).collect::>()) + } +} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs new file mode 100644 index 0000000000000..9fde1d85995e0 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs @@ -0,0 +1,193 @@ +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unreachable_code)] +#![allow(unused_imports)] +use crate::infer::canonical::{Canonical, CanonicalVarInfos}; +use crate::infer::region_constraints::MemberConstraint; +use crate::solve::{Response, ExternalConstraintsData}; +use rustc_middle::ty::{TyCtxt, UniverseIndex}; + +use std::ops::Deref; +use std::hash::Hash; +use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxIndexMap, FxIndexSet}; + +mod solver; +mod constraint_walker; +use constraint_walker::{ConstraintWalker, Outlives}; + +pub struct Deduper<'tcx> { + tcx: TyCtxt<'tcx>, + rule_vars: Vec>, + rule_cats: FxIndexMap, Vec>, + /// Maps a constraint index (the index inside constraint_vars) back to its index in outlives + indx_to_outlives: FxHashMap, + /// Maps a constraint index (the index inside constraint_vars) back to its index in member_constraints + indx_to_members: FxHashMap, +} +#[derive(Debug, PartialEq, Eq, Hash)] +enum ConstraintType<'tcx> { + Outlives(Outlives<'tcx>), + Member(MemberConstraint<'tcx>), +} + +impl<'tcx> Deduper<'tcx> { + pub fn dedup(tcx: TyCtxt<'tcx>, input: &mut Canonical<'tcx, Response<'tcx>>) { + let mut constraints = input.value.external_constraints.deref().clone(); + let mut deduper = Self { + tcx, + rule_vars: Vec::new(), + rule_cats: FxIndexMap::default(), + indx_to_outlives: FxHashMap::default(), + indx_to_members: FxHashMap::default(), + }; + deduper.dedup_internal(&mut constraints, &mut input.variables, &mut input.max_universe); + input.value.external_constraints = tcx.mk_external_constraints(constraints); + } + fn dedup_internal( + &mut self, + constraints: &mut ExternalConstraintsData<'tcx>, + variables: &mut CanonicalVarInfos<'tcx>, + max_universe: &mut UniverseIndex + ) { + dedup_exact_eq(&mut constraints.region_constraints.outlives); + dedup_exact_eq(&mut constraints.region_constraints.member_constraints); + + let dedupable_vars: FxIndexSet = variables + .iter() + .enumerate() + .filter(|(_, var)| var.universe() > UniverseIndex::ROOT) + .map(|(indx, _)| indx) + .collect(); + + self.extract_constraint_data(&dedupable_vars, constraints, variables); + + let rule_vars = std::mem::take(&mut self.rule_vars); + let rule_cats = std::mem::take(&mut self.rule_cats).into_values().collect::>(); + let unremovable_vars: FxIndexSet = (0..variables.len()) + .filter(|x| !dedupable_vars.contains(x)) + .collect(); + + let solve_result = solver::DedupSolver::dedup(rule_vars, rule_cats, unremovable_vars); + self.remove_duplicate_constraints(&solve_result.removed_constraints, constraints); + self.compress_variables(&solve_result.removed_vars, constraints, variables, max_universe); + } + fn extract_constraint_data( + &mut self, + dedupable_vars: &FxIndexSet, + constraints: &mut ExternalConstraintsData<'tcx>, + variables: &mut CanonicalVarInfos<'tcx> + ) { + let num_vars = variables.len(); + let mut dummy_var_rewriter = |var| num_vars; + /* + let mut dummy_var_rewriter = |var| { + if dedupable_vars.contains(&var) { + return num_vars; + } + var + }; + */ + for (indx, outlives) in constraints.region_constraints.outlives.iter().enumerate() { + let mut extractor = ConstraintWalker::new(self.tcx, &mut dummy_var_rewriter); + let erased = ConstraintType::Outlives(extractor.walk_outlives(&outlives.0)); + let vars = std::mem::take(&mut extractor.vars); + if vars.is_empty() { continue; } + self.process_constraint_data(indx, erased, vars); + } + for (indx, member) in constraints.region_constraints.member_constraints.iter().enumerate() { + let mut extractor = ConstraintWalker::new(self.tcx, &mut dummy_var_rewriter); + let erased = ConstraintType::Member(extractor.walk_members(member)); + let vars = std::mem::take(&mut extractor.vars); + if vars.is_empty() { continue; } + self.process_constraint_data(indx, erased, vars); + } + } + fn process_constraint_data( + &mut self, + input_indx: usize, + erased: ConstraintType<'tcx>, + vars: Vec + ) { + self.rule_vars.push(vars); + let constraint_indx = self.rule_vars.len() - 1; + match &erased { + ConstraintType::Outlives(_) => &mut self.indx_to_outlives, + ConstraintType::Member(_) => &mut self.indx_to_members, + }.insert(constraint_indx, input_indx); + self.rule_cats.entry(erased).or_insert_with(Vec::new).push(constraint_indx); + } + fn remove_duplicate_constraints(&mut self, to_remove: &FxIndexSet, constraints: &mut ExternalConstraintsData<'tcx>) { + let mut remove_outlives: FxIndexSet = to_remove.iter().filter_map(|x| self.indx_to_outlives.get(x)).cloned().collect(); + let mut remove_members: FxIndexSet = to_remove.iter().filter_map(|x| self.indx_to_members.get(x)).cloned().collect(); + remove_outlives.sort(); + remove_members.sort(); + + for indx in remove_outlives.into_iter().rev() { + constraints.region_constraints.outlives.swap_remove(indx); + } + for indx in remove_members.into_iter().rev() { + constraints.region_constraints.member_constraints.swap_remove(indx); + } + } + fn compress_variables( + &mut self, + removed_vars: &FxIndexSet, + constraints: &mut ExternalConstraintsData<'tcx>, + variables: &mut CanonicalVarInfos<'tcx>, + max_universe: &mut UniverseIndex + ) { + let mut vars = variables.as_slice().to_vec(); + let mut universes_available: FxIndexSet = vars.iter().map(|x| x.universe()).collect(); + universes_available.sort(); + + let mut compressed_vars: FxHashMap = FxHashMap::default(); + let mut universes_used: FxIndexSet = FxIndexSet::default(); + + let mut num_removed = 0; + let mut var_indx = 0; + while var_indx < vars.len() { + let original_var_indx = var_indx + num_removed; + if removed_vars.contains(&original_var_indx) { + num_removed += 1; + vars.remove(var_indx); + continue; + } + compressed_vars.insert(original_var_indx, var_indx); + universes_used.insert(vars[var_indx].universe()); + var_indx += 1; + } + universes_used.sort(); + + for var in vars.iter_mut() { + *var = var.with_updated_universe( + *universes_available.get_index( + universes_used.get_index_of(&var.universe()).unwrap() + ).unwrap() + ); + } + + let mut var_rewriter = |var| compressed_vars.get(&var).cloned().unwrap_or(var); + for outlives in constraints.region_constraints.outlives.iter_mut() { + let mut walker = ConstraintWalker::new(self.tcx, &mut var_rewriter); + outlives.0 = walker.walk_outlives(&outlives.0); + } + for member in constraints.region_constraints.member_constraints.iter_mut() { + let mut walker = ConstraintWalker::new(self.tcx, &mut var_rewriter); + *member = walker.walk_members(member); + } + + *variables = self.tcx.mk_canonical_var_infos(&vars); + *max_universe = UniverseIndex::from(universes_used.len().saturating_sub(1)); + } +} + +fn dedup_exact_eq(input: &mut Vec) { + let mut indx = 0; + while indx < input.len() { + if input.iter().skip(indx+1).any(|x| x == &input[indx]) { + input.swap_remove(indx); + continue; + } + indx += 1; + } +} \ No newline at end of file diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs new file mode 100644 index 0000000000000..305243b925d11 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -0,0 +1,561 @@ +// Quick terminology mapping: +// * "rule" => region constraint ("rule" is just shorter) +// * "category"/"cat" => group of constraints with similar structure, i.e. +// constraints can only be merged if they're in the +// same category +// * "mapping" => mapping from one set of variables to another. Mappings MUST +// be many-to-one. Obviously, they can't be one-to-many, and +// a one-to-one mapping isn't really productive, because +// we're not eliminating any variables that way +// +// This algorithm, in its present state, *is* exponential time. This exponential time +// case happens iff we have potential mappings that overlap, thus requiring them +// to be combined. For example, if we have a category A that contains constraints involving +// variables [1, 2, 3] and [11, 12, 4], and a category B that contains constraints involving +// variables [1, 2, 100] and [11, 12, 101], then the mapping in category A from the first +// constraint to the second constraint is valid if and only if the mapping from the first +// constraint to the second constraint in category B is valid (i.e. they depend on each other). +// In this trivial case, it's obvious that they're both valid, but more complicated cases +// can create a graph of dependencies (potentially with cycles), creating exponential behavior. +// +// In general, I don't think the exponential case should be happening *that* often, and if it does, +// the dependencies graph shouldn't be very deep, so it shouldn't be terrible. However, I'm not very +// knowledgable on the types of region constraints that can be generated, so maybe this assertion is false. +// There's some heuristics that I can use to speed the exponential part up, or maybe just cap the search depth. + +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use std::cell::RefCell; +use std::collections::BTreeMap; + +#[derive(Debug)] +pub struct DedupSolver { + /// The variables present in each rule - the inner vec contains the variables, in the order + /// that they appear in the rule + rule_vars: Vec>, + /// The categories that rules can be partitioned into - the inner vec contains all the rules + /// that are in the same category + rule_cats: Vec>, + unremovable_vars: FxIndexSet, + + /// The below are internal variables used in the solving process: + + /// All the mappings that can possibly be taken + mappings: FxIndexMap, + /// Rules that have already been removed by deduplication + removed_rules: RefCell>, + /// All of the currently applied var mappings, summed together + applied_mappings: RefCell, +} +#[derive(Debug)] +pub struct DedupResult { + pub removed_constraints: FxIndexSet, + pub removed_vars: FxIndexSet, +} +#[derive(Clone, Hash, PartialEq, Eq, Debug)] +struct Mapping(BTreeMap); +#[derive(Debug, Clone, PartialEq, Eq)] +struct MappingInfo { + dependencies: FxIndexMap>, + rule_mappings: FxIndexMap, +} +#[derive(Debug, PartialEq, Eq)] +enum MapEvalErr { + Conflicts, + Unremovable, +} + +impl DedupSolver { + pub fn dedup( + constraint_vars: Vec>, + constraint_categories: Vec>, + unremovable_vars: FxIndexSet, + ) -> DedupResult { + let mut deduper = Self { + rule_vars: constraint_vars, + rule_cats: constraint_categories, + unremovable_vars, + + mappings: FxIndexMap::default(), + removed_rules: RefCell::new(FxIndexSet::default()), + applied_mappings: RefCell::new(Mapping::map_rules(&[], &[])), + }; + deduper.refine_categories(); + deduper.compute_mappings(); + deduper.resolve_dependencies(); + + let mut removed_vars = FxIndexSet::default(); + for (from, to) in deduper.applied_mappings.borrow().0.iter() { + if *from == *to { + continue; + } + removed_vars.insert(*from); + } + DedupResult { + removed_constraints: deduper.removed_rules.into_inner(), + removed_vars, + } + } + fn refine_categories(&mut self) { + // Refine categories based on shape + for cat_indx in 0..self.rule_cats.len() { + let mut shape_categories: FxIndexMap, usize> = FxIndexMap::default(); + let mut rule_indx = 0; + while rule_indx < self.rule_cats[cat_indx].len() { + let rule = self.rule_cats[cat_indx][rule_indx]; + let shape = Self::canonicalize_rule_shape(&mut self.rule_vars[rule]); + let is_first_entry = shape_categories.is_empty(); + let new_cat = *shape_categories.entry(shape).or_insert_with(|| { + if is_first_entry { + cat_indx + } else { + self.rule_cats.push(Vec::new()); + self.rule_cats.len() - 1 + } + }); + if new_cat == cat_indx { + rule_indx += 1; + continue; + } + self.rule_cats[cat_indx].swap_remove(rule_indx); + self.rule_cats[new_cat].push(rule); + } + } + // Refine categories based on indices of variables + for cat_indx in 0..self.rule_cats.len() { + // A vec of tuples representing index categories. + // First element of tuple is a mapping from a variable to the index it occurs in + // Second element of tuple is the category + let mut index_categories: Vec<(FxIndexMap, usize)> = Vec::new(); + let mut rule_indx = 0; + while rule_indx < self.rule_cats[cat_indx].len() { + let rule = self.rule_cats[cat_indx][rule_indx]; + let rule_vars = &self.rule_vars[rule]; + let rule_var_indices: FxIndexMap = + rule_vars.iter().enumerate().map(|(indx, x)| (*x, indx)).collect(); + + let mut found_cat = None; + for (cat_vars, new_cat_indx) in index_categories.iter_mut() { + let is_cat_member = rule_vars + .iter() + .enumerate() + .all(|(indx, x)| *cat_vars.get(x).unwrap_or(&indx) == indx); + if !is_cat_member { + continue; + } + found_cat = Some(*new_cat_indx); + cat_vars.extend(&rule_var_indices); + break; + } + let new_cat = found_cat.unwrap_or_else(|| { + if index_categories.is_empty() { + cat_indx + } else { + self.rule_cats.push(Vec::new()); + let new_cat = self.rule_cats.len() - 1; + index_categories.push((rule_var_indices, new_cat)); + new_cat + } + }); + if new_cat == cat_indx { + rule_indx += 1; + continue; + } + self.rule_cats[cat_indx].swap_remove(rule_indx); + self.rule_cats[new_cat].push(rule); + } + } + } + /// Returns the "shape" of a rule - related to the idea of de bruijn indices + /// For example, a rule involving the vars [1, 1, 2, 3] has a shape of [0, 0, 1, 2], + /// and a rule involving vars [3, 4] has a shape of [0, 1] + /// It takes a mutable reference to the vars because it also removes duplicates from + /// the input vector after computing the shape + /// Clearly, two constraints can be mapped onto each other only if they have the + /// same shape + fn canonicalize_rule_shape(vars: &mut Vec) -> Vec { + let mut shape = Vec::new(); + let mut num_vars = 0; + let mut indx = 0; + while indx < vars.len() { + if let Some(val) = shape.iter().find(|y| vars[**y] == vars[indx]) { + shape.push(*val); + vars.remove(indx); + } else { + shape.push(num_vars); + num_vars += 1; + indx += 1; + } + } + shape + } + + /// Computes the set of all possible mappings + /// If a mapping has no dependencies, then it's eagerly taken, to increase performance + /// Deduplication can be done greedily because if two rules can be merged, then they're + /// equivalent in every way, including in relations to other rules + fn compute_mappings(&mut self) { + let mut invalid_maps: FxIndexSet = FxIndexSet::default(); + for cat in self.rule_cats.iter() { + for (n, rule_1) in + cat.iter().enumerate().filter(|x| !self.removed_rules.borrow().contains(x.1)) + { + for rule_2 in + cat.iter().skip(n + 1).filter(|x| !self.removed_rules.borrow().contains(*x)) + { + let forward = + Mapping::map_rules(&self.rule_vars[*rule_1], &self.rule_vars[*rule_2]); + if invalid_maps.contains(&forward) || self.mappings.contains_key(&forward) { + continue; + } + let reverse = + Mapping::map_rules(&self.rule_vars[*rule_2], &self.rule_vars[*rule_1]); + if invalid_maps.contains(&reverse) || self.mappings.contains_key(&reverse) { + continue; + } + + let (eval_forward, eval_reverse) = + (self.eval_mapping(&forward), self.eval_mapping(&reverse)); + if eval_forward == Err(MapEvalErr::Conflicts) + || eval_reverse == Err(MapEvalErr::Conflicts) + { + invalid_maps.insert(forward); + invalid_maps.insert(reverse); + continue; + } + if let Ok(eval_forward) = eval_forward { + if !self.try_apply_mapping(&forward, &eval_forward, false) { + self.mappings.insert(forward, eval_forward); + } + } + if let Ok(eval_reverse) = eval_reverse { + if !self.try_apply_mapping(&reverse, &eval_reverse, false) { + self.mappings.insert(reverse, eval_reverse); + } + } + } + } + } + self.resolve_dependencies_to_mapping(); + } + /// Currently, dependencies are in the form FxIndexMap, + /// where A is a rule that must be mapped by another mapping. We must + /// populate the EmptyFxIndexSet with a set of mappings that can map A without + /// conflicting with the current mapping + fn resolve_dependencies_to_mapping(&mut self) { + self.mappings.retain(|mapping, mapping_info| { + if self.applied_mappings.borrow().conflicts_with(mapping) { + return false; + } + mapping_info + .dependencies + .retain(|dependency, _| !self.removed_rules.borrow().contains(dependency)); + true + }); + // A map from a constraint to the mappings that will eliminate it + let mut constraint_mappings: FxIndexMap> = FxIndexMap::default(); + for (indx, (_, mapping_info)) in self.mappings.iter().enumerate() { + for (from_rule, _) in mapping_info.rule_mappings.iter() { + constraint_mappings + .entry(*from_rule) + .or_insert_with(FxIndexSet::default) + .insert(indx); + } + } + for indx in 0..self.mappings.len() { + let mapping = self.get_mapping(indx); + let input_dependencies = &self.get_mapping_info(indx).dependencies; + let mut dependencies = Vec::new(); + for (dependency, _) in input_dependencies.iter() { + let mut resolve_options = FxIndexSet::default(); + if let Some(resolve_mappings) = constraint_mappings.get(dependency) { + resolve_options.extend( + resolve_mappings + .iter() + .filter(|x| !mapping.conflicts_with(&self.get_mapping(**x))) + .cloned(), + ) + } + // Don't duplicate dependency groups + if dependencies.contains(&resolve_options) { + continue; + } + dependencies.push(resolve_options); + } + // After this point, the actual rules that a dependency maps + // stops mattering - all that matters is that the dependency *exists* + self.mappings.get_index_mut(indx).unwrap().1.dependencies = + dependencies.into_iter().enumerate().collect(); + } + } + /// Evaluates the mapping. Can return None if the mapping is invalid (i.e. it maps + /// some constraints onto a constraint that doesn't exist, or conflicts with the + /// mappings that were already greedily applied). Otherwise, returns MappingInfo. + /// MappingInfo can contain dependencies - these occur if a mapping *partially* maps + /// a constraint onto another, so the mapping isn't immediately invalid, but we do need + /// another mapping to complete that partial map for it to actually be valid + fn eval_mapping(&self, mapping: &Mapping) -> Result { + let maps_unremovable_var = + mapping.0.iter().any(|(from, to)| self.unremovable_vars.contains(from) && from != to); + + let mut info = MappingInfo::new(); + for cat in self.rule_cats.iter() { + for rule_1 in cat { + let vars_1 = &self.rule_vars[*rule_1]; + if !mapping.affects_rule(vars_1) { + continue; + } + let mut found_non_conflicting = false; + for rule_2 in cat.iter() { + let vars_2 = &self.rule_vars[*rule_2]; + let trial_mapping = Mapping::map_rules(vars_1, vars_2); + if mapping.conflicts_with(&trial_mapping) { + continue; + } + found_non_conflicting = true; + // Only maps a subset of variables in rule_1 + if !mapping.maps_fully(vars_1, vars_2) { + info.dependencies.insert(*rule_1, FxIndexSet::default()); + continue; + } + if *rule_1 != *rule_2 { + info.rule_mappings.insert(*rule_1, *rule_2); + } + } + if !found_non_conflicting { + return Err(MapEvalErr::Conflicts); + } + } + } + for fully_mapped in info.rule_mappings.keys() { + info.dependencies.remove(fully_mapped); + } + if maps_unremovable_var { + return Err(MapEvalErr::Unremovable); + } + Ok(info) + } + + fn resolve_dependencies(&mut self) { + let mut used_mappings = FxIndexSet::default(); + for indx in 0..self.mappings.len() { + if used_mappings.contains(&indx) { + continue; + } + if self.applied_mappings.borrow().conflicts_with(self.get_mapping(indx)) { + continue; + } + let applied_mappings = self.applied_mappings.borrow().clone(); + let mut starting_set = FxIndexSet::default(); + starting_set.insert(indx); + if let Some(applied_mappings) = + self.dfs_search(used_mappings.clone(), applied_mappings, starting_set) + { + for mapping in applied_mappings { + if used_mappings.contains(&mapping) { + continue; + } + let application_result = self.try_apply_mapping( + self.get_mapping(mapping), + self.get_mapping_info(mapping), + true, + ); + assert!(application_result); + used_mappings.insert(mapping); + } + } + } + } + // There's quite a few heuristics that will probably yield *significant* speedups + // I'll look into that later, if the rest of this approach is sound + fn dfs_search( + &self, + mut used_mappings: FxIndexSet, + mut applied_mappings: Mapping, + from: FxIndexSet, + ) -> Option> { + for mapping_indx in from.iter() { + let (mapping, _) = self.mappings.get_index(*mapping_indx).unwrap(); + if applied_mappings.conflicts_with(mapping) { + return None; + } + applied_mappings.0.extend(&mapping.0); + } + if from.iter().all(|x| used_mappings.contains(x)) { + return Some(used_mappings); + } + used_mappings.extend(from.iter()); + + let choices: Vec<&FxIndexSet> = + from.iter().flat_map(|x| self.get_mapping_info(*x).dependencies.values()).collect(); + if choices.is_empty() { + return Some(used_mappings); + } + let mut choice_indices = vec![0; choices.len()]; + while *choice_indices.last().unwrap() < choices.last().unwrap().len() { + let choice: FxIndexSet = choice_indices + .iter() + .zip(&choices) + .map(|(x, y)| *y.get_index(*x).unwrap()) + .collect(); + let search_result = + self.dfs_search(used_mappings.clone(), applied_mappings.clone(), choice); + if search_result.is_some() { + return search_result; + } + + for (val, limit) in choice_indices.iter_mut().zip(choices.iter().map(|x| x.len())) { + *val += 1; + if *val >= limit { + *val = 0; + continue; + } + break; + } + } + None + } + + fn try_apply_mapping( + &self, + mapping: &Mapping, + info: &MappingInfo, + allow_dependencies: bool, + ) -> bool { + if !allow_dependencies && !info.dependencies.is_empty() { + return false; + } + if self.applied_mappings.borrow().conflicts_with(mapping) { + return false; + } + self.removed_rules.borrow_mut().extend(info.rule_mappings.keys()); + self.applied_mappings.borrow_mut().0.extend(&mapping.0); + true + } + fn get_mapping(&self, index: usize) -> &Mapping { + &self.mappings.get_index(index).unwrap().0 + } + fn get_mapping_info(&self, index: usize) -> &MappingInfo { + &self.mappings.get_index(index).unwrap().1 + } +} + +impl Mapping { + fn map_rules(from: &[usize], to: &[usize]) -> Self { + Self(from.iter().zip(to).map(|(x, y)| (*x, *y)).collect()) + } + fn maps_var(&self, rule: usize) -> Option { + self.0.get(&rule).map(|x| *x) + } + fn affects_rule(&self, rule: &[usize]) -> bool { + rule.iter().any(|x| self.maps_var(*x).unwrap_or(*x) != *x) + } + fn maps_fully(&self, from: &[usize], to: &[usize]) -> bool { + if from.len() != to.len() { + return false; + } + from.iter().zip(to).all(|(x, y)| self.maps_var(*x).unwrap_or(*x) == *y) + } + fn conflicts_with(&self, other: &Self) -> bool { + for (from_a, to_a) in self.0.iter() { + for (from_b, to_b) in other.0.iter() { + let map_conflicts = from_a == from_b && to_a != to_b; + let not_productive = + to_b == from_a && from_a != to_a || to_a == from_b && from_b != to_b; + if map_conflicts || not_productive { + return true; + } + } + } + false + } +} +impl MappingInfo { + fn new() -> Self { + Self { dependencies: FxIndexMap::default(), rule_mappings: FxIndexMap::default() } + } +} + +/* +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_noop() { + let deduped = DedupSolver::dedup( + vec![vec![1], vec![1, 1], vec![2], vec![3]], + vec![vec![0, 1], vec![2], vec![3]], + FxIndexSet::default(), + ); + assert!(deduped.is_empty()); + } + #[test] + fn test_simple() { + let deduped = DedupSolver::dedup( + vec![vec![1], vec![2], vec![3]], + vec![vec![0, 1], vec![2]], + FxIndexSet::default(), + ); + assert!([FxIndexSet::from([0]), FxIndexSet::from([1])].contains(&deduped)); + } + #[test] + fn test_dependencies() { + let deduped = DedupSolver::dedup( + vec![ + vec![1, 2, 13], + vec![4, 5, 16], + vec![1, 2, 23], + vec![4, 5, 26], + vec![1, 2], + vec![4, 5], + ], + vec![vec![0, 1], vec![2, 3], vec![4, 5]], + FxIndexSet::default(), + ); + assert!([FxIndexSet::from([0, 2, 4]), FxIndexSet::from([1, 3, 5])].contains(&deduped)); + } + #[test] + fn test_dependencies_unresolvable() { + let deduped = DedupSolver::dedup( + vec![ + vec![1, 2, 13], + vec![4, 5, 16], + vec![1, 2, 23], + vec![4, 6, 26], + vec![1, 2], + vec![4, 5], + ], + vec![vec![0, 1], vec![2, 3], vec![4, 5]], + FxIndexSet::default(), + ); + assert!(deduped.is_empty()); + } + #[test] + fn test_gh_issues_example() { + let deduped = DedupSolver::dedup( + vec![vec![1], vec![2], vec![3]], + vec![vec![0, 1, 2]], + FxIndexSet::default(), + ); + assert!([FxIndexSet::from([0, 1]), FxIndexSet::from([0, 2]), FxIndexSet::from([1, 2])] + .contains(&deduped)); + } + #[test] + fn test_unremovable() { + let deduped = DedupSolver::dedup( + vec![ + vec![0, 1], + vec![0, 2], + vec![1, 0], + vec![2, 0], + vec![3, 1], + vec![3, 2], + vec![1, 3], + vec![2, 3], + ], + vec![vec![0, 1, 2, 3, 4, 5, 6, 7]], + FxIndexSet::from([0, 1, 2]), + ); + assert!(deduped == FxIndexSet::from([4, 5, 6, 7])); + } +} +*/ diff --git a/out.txt b/out.txt new file mode 100644 index 0000000000000..a4c64cdf31a62 --- /dev/null +++ b/out.txt @@ -0,0 +1,402 @@ +Building stage0 library artifacts (x86_64-unknown-linux-gnu) +Building compiler artifacts (stage0 -> stage1, x86_64-unknown-linux-gnu) +Assembling stage1 compiler +Building stage1 library artifacts (x86_64-unknown-linux-gnu) +Building stage0 tool compiletest (x86_64-unknown-linux-gnu) +Check compiletest suite=ui mode=ui (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) + +running 1 tests +F + +failures: + +---- [ui] tests/ui/traits/new-solver/dedup-vars.rs stdout ---- + +error: Error: expected failure status (Some(1)) but received status Some(101). +status: exit status: 101 +command: "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc" "/home/ndrewxie/rust/tests/ui/traits/new-solver/dedup-vars.rs" "-Zthreads=1" "--sysroot" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/stage1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Zdeduplicate-diagnostics=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/test/ui/traits/new-solver/dedup-vars" "-A" "unused" "-Crpath" "-Cdebuginfo=0" "-Lnative=/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/test/ui/traits/new-solver/dedup-vars/auxiliary" "-Ztrait-solver=next" +--- stdout ------------------------------- +BEFORE: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + Bar, + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], +} +AFTER: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + Bar, + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], +} +BEFORE: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + Bar, + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], +} +AFTER: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + Bar, + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], +} +BEFORE: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + Bar, + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U1, + variables: [ + CanonicalVarInfo { + kind: PlaceholderRegion( + Placeholder { + universe: U1, + bound: BoundRegion { + var: 0, + kind: BrNamed(DefId(0:5 ~ dedup_vars[ed74]::Bar::'a), 'a), + }, + }, + ), + }, + ], +} +AFTER: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + Bar, + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: PlaceholderRegion( + Placeholder { + universe: U0, + bound: BoundRegion { + var: 0, + kind: BrNamed(DefId(0:5 ~ dedup_vars[ed74]::Bar::'a), 'a), + }, + }, + ), + }, + ], +} +BEFORE: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [], +} +AFTER: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [], +} +------------------------------------------ +--- stderr ------------------------------- +thread 'rustc' panicked at 'index out of bounds: the len is 0 but the index is 0', compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs:255:21 +stack backtrace: + 0: 0x7fe9f9570c37 - std::backtrace_rs::backtrace::trace_unsynchronized::h352d783f8836f973 + 1: 0x7fe9f956701b - ::fmt::h68e861c138d09dfc + 2: 0x7fe9f95e4159 - core::fmt::write::hc9837b4a6b405547 + 3: 0x7fe9f9534451 - std::io::Write::write_fmt::hb24223809381b675 + 4: 0x7fe9f9566e8d - std::sys_common::backtrace::print::h4375715fac3c73a0 + 5: 0x7fe9f954b877 - std::panicking::default_hook::{{closure}}::h1cd100ebfe0cbede + 6: 0x7fe9f954b61a - std::panicking::default_hook::hb341913f9cf3b16c + 7: 0x7fe9f9ef2c3f - rustc_driver_impl[3012c1cd686720e8]::DEFAULT_HOOK::{closure#0}::{closure#0} + 8: 0x7fe9f954bdf2 - std::panicking::rust_panic_with_hook::h7b51e523793dcd2c + 9: 0x7fe9f953dfe3 - std::panicking::begin_panic_handler::{{closure}}::h4eff0803b93bf7f1 + 10: 0x7fe9f953df16 - std::sys_common::backtrace::__rust_end_short_backtrace::hc754a8eb77b3845c + 11: 0x7fe9f954b972 - rust_begin_unwind + 12: 0x7fe9f95333e3 - core::panicking::panic_fmt::h766f9bd0d9567fe0 + 13: 0x7fe9f9533552 - core::panicking::panic_bounds_check::he75c4b878228025a + 14: 0x7fe9fc1f8b56 - <&mut ::compute_query_response_substitution::{closure#0} as core[4df9b0e25e0d2810]::ops::function::FnOnce<((usize, rustc_middle[5074ee5b4c22835b]::infer::canonical::CanonicalVarInfo),)>>::call_once + 15: 0x7fe9fc10cd95 - >>::collect_and_apply::>>, ::compute_query_response_substitution::{closure#0}>, ::mk_substs_from_iter>>, ::compute_query_response_substitution::{closure#0}>, rustc_middle[5074ee5b4c22835b]::ty::subst::GenericArg>::{closure#0}> + 16: 0x7fe9fc1177c3 - ::mk_substs_from_iter::>>, ::compute_query_response_substitution::{closure#0}>, rustc_middle[5074ee5b4c22835b]::ty::subst::GenericArg> + 17: 0x7fe9fc11d6e1 - ::evaluate_goal + 18: 0x7fe9fbfec45e - ::repeat_while_none::::try_evaluate_added_goals::{closure#0}, ::try_evaluate_added_goals::{closure#1}> + 19: 0x7fe9fc121e72 - ::try_evaluate_added_goals + 20: 0x7fe9fc121406 - ::evaluate_added_goals_and_make_canonical_response + 21: 0x7fe9fc11f2c7 - ::compute_goal + 22: 0x7fe9fc17fdef - ::repeat_while_none::, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#0}, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#1}> + 23: 0x7fe9fc20143f - >::with_anon_task::::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>> + 24: 0x7fe9fc180080 - ::with_new_goal::<::evaluate_canonical_goal::{closure#0}::{closure#0}> + 25: 0x7fe9fc11d1a8 - ::evaluate_goal + 26: 0x7fe9fbfec45e - ::repeat_while_none::::try_evaluate_added_goals::{closure#0}, ::try_evaluate_added_goals::{closure#1}> + 27: 0x7fe9fc121e72 - ::try_evaluate_added_goals + 28: 0x7fe9fc121406 - ::evaluate_added_goals_and_make_canonical_response + 29: 0x7fe9fc11e435 - ::compute_goal + 30: 0x7fe9fc17fdef - ::repeat_while_none::, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#0}, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#1}> + 31: 0x7fe9fc20143f - >::with_anon_task::::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>> + 32: 0x7fe9fc180080 - ::with_new_goal::<::evaluate_canonical_goal::{closure#0}::{closure#0}> + 33: 0x7fe9fc11d1a8 - ::evaluate_goal + 34: 0x7fe9fc1507fb - ::evaluate_root_goal + 35: 0x7fe9fc194536 - ::select_where_possible + 36: 0x7fe9fc1f66f8 - ::select_all_or_error + 37: 0x7fe9fc048c64 - ::select_all_or_error + 38: 0x7fe9fa63faf5 - rustc_hir_analysis[2d38e76667e9459]::check::wfcheck::enter_wf_checking_ctxt:: + 39: 0x7fe9fa57448a - rustc_hir_analysis[2d38e76667e9459]::check::wfcheck::check_type_defn + 40: 0x7fe9fa570bb1 - rustc_hir_analysis[2d38e76667e9459]::check::wfcheck::check_well_formed + 41: 0x7fe9fb729dbd - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 0usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 0usize]>> + 42: 0x7fe9fb7f9b03 - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: + 43: 0x7fe9fb56d050 - rustc_query_impl[d83653c600d19515]::get_query::check_well_formed + 44: 0x7fe9fa6575fe - ::par_trait_items::{closure#0}>::{closure#0}::{closure#0}> as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once + 45: 0x7fe9fa5f87c9 - std[e0afd7ea5d3fe186]::panicking::try::<(), core[4df9b0e25e0d2810]::panic::unwind_safe::AssertUnwindSafe::par_items::{closure#0}>::{closure#0}::{closure#0}>> + 46: 0x7fe9fa5960e4 - rustc_data_structures[96c7fbd8d6df213a]::sync::par_for_each_in::<&[rustc_hir[a03203a1750d3af4]::hir::ItemId], ::par_items::{closure#0}> + 47: 0x7fe9fa6776f8 - ::par_items:: + 48: 0x7fe9fa5758de - rustc_hir_analysis[2d38e76667e9459]::check::wfcheck::check_mod_type_wf + 49: 0x7fe9fb729d1d - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 0usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 0usize]>> + 50: 0x7fe9fb7f937d - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: + 51: 0x7fe9fb54ecc0 - rustc_query_impl[d83653c600d19515]::get_query::check_mod_type_wf + 52: 0x7fe9fa65771e - ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}> as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once + 53: 0x7fe9fa5f87f9 - std[e0afd7ea5d3fe186]::panicking::try::<(), core[4df9b0e25e0d2810]::panic::unwind_safe::AssertUnwindSafe::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}>> + 54: 0x7fe9fa5961b4 - rustc_data_structures[96c7fbd8d6df213a]::sync::par_for_each_in::<&[rustc_hir[a03203a1750d3af4]::hir_id::OwnerId], ::par_for_each_module::{closure#0}> + 55: 0x7fe9fa64363e - ::track_errors:: + 56: 0x7fe9fa651b33 - rustc_hir_analysis[2d38e76667e9459]::check_crate + 57: 0x7fe9f9fa9371 - rustc_interface[7e80568d2ceb88d0]::passes::analysis + 58: 0x7fe9fb732834 - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 1usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 1usize]>> + 59: 0x7fe9fb850c57 - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: + 60: 0x7fe9fb532c9a - rustc_query_impl[d83653c600d19515]::get_query::analysis + 61: 0x7fe9f9f5999e - >>::with::::enter>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 62: 0x7fe9f9f46bd8 - ::enter::> + 63: 0x7fe9f9f70754 - ::enter::, rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 64: 0x7fe9f9efd629 - rustc_span[bc72e8cf61038315]::set_source_map::, rustc_interface[7e80568d2ceb88d0]::interface::run_compiler, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}::{closure#0}> + 65: 0x7fe9f9efe2bf - >::set::, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 66: 0x7fe9f9f63010 - std[e0afd7ea5d3fe186]::sys_common::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 67: 0x7fe9f9f79c04 - ::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}> as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once + 68: 0x7fe9f9f53374 - std[e0afd7ea5d3fe186]::panicking::try::, core[4df9b0e25e0d2810]::panic::unwind_safe::AssertUnwindSafe<::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}>> + 69: 0x7fe9f9f621a9 - std[e0afd7ea5d3fe186]::panic::catch_unwind::::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}>, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 70: 0x7fe9f9f7c5e2 - <::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1} as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} + 71: 0x7fe9f95849da - as core::ops::function::FnOnce>::call_once::h481e59266d00f875 + 72: 0x7fe9f958ac0a - std::sys::unix::thread::Thread::new::thread_start::h7e46e4f9732e143e + 73: 0x7fe9f008aea7 - start_thread + 74: 0x7fe9f93dfa2f - clone + 75: 0x0 - + +error: the compiler unexpectedly panicked. this is a bug. + +note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md + +note: rustc 1.71.0-dev running on x86_64-unknown-linux-gnu + +note: compiler flags: -Z threads=1 -C codegen-units=1 -Z ui-testing -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z deduplicate-diagnostics=no -C strip=debuginfo -C prefer-dynamic -C rpath -C debuginfo=0 -Z trait-solver=next + +query stack during panic: +#0 [check_well_formed] checking that `Bar` is well-formed +#1 [check_mod_type_wf] checking that types are well-formed in top-level module +#2 [analysis] running analysis passes on this crate +end of query stack +------------------------------------------ + + + +failures: + [ui] tests/ui/traits/new-solver/dedup-vars.rs + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 14891 filtered out; finished in 52.18ms + +Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.rs b/tests/ui/higher-rank-trait-bounds/issue-95230.rs index 769b6a9253769..dd0dcc0a2d183 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-95230.rs +++ b/tests/ui/higher-rank-trait-bounds/issue-95230.rs @@ -1,7 +1,5 @@ -// revisions: old new -//[new] compile-flags: -Ztrait-solver=next -//[old] check-pass -//[new] known-bug: #109764 +// compile-flags: -Ztrait-solver=next +// check-pass pub struct Bar diff --git a/tests/ui/traits/new-solver/dedup-vars.rs b/tests/ui/traits/new-solver/dedup-vars.rs new file mode 100644 index 0000000000000..8d3bf7fa9aab6 --- /dev/null +++ b/tests/ui/traits/new-solver/dedup-vars.rs @@ -0,0 +1,28 @@ +// check-pass +// compile-flags: -Ztrait-solver=next + +struct Foo +where + Foo:, + (): 'static; + +pub struct Bar +where + for<'a> &'a mut Self:; + +unsafe impl Send for Unique { } + +pub struct Unique { + pointer: *const T, +} + +pub struct Node { + vals: V, + edges: Unique>, +} + +fn is_send() {} + +fn main() { + is_send::>(); +} From 074b9b0e495f8090f65403f0d097455f65b1dd4f Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Wed, 3 May 2023 22:41:59 -0400 Subject: [PATCH 02/16] Added a few comments --- .../eval_ctxt/canonical/dedup_solver/constraint_walker.rs | 7 +++++-- .../src/solve/eval_ctxt/canonical/dedup_solver/mod.rs | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs index d8ac0e0e29d88..177af41ea5771 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs @@ -8,6 +8,8 @@ use std::rc::Rc; pub type Outlives<'tcx> = OutlivesPredicate, Region<'tcx>>; +/// Walks over constraints and fetches variables present in the constraint, in order +/// Also has the ability to re-write the variables there pub struct ConstraintWalker<'tcx, 'a> { tcx: TyCtxt<'tcx>, fetch_var: &'a mut dyn FnMut(usize) -> usize, @@ -25,8 +27,9 @@ impl<'tcx, 'a> ConstraintWalker<'tcx, 'a> { return (self.fetch_var)(var); } - // The walk functions recursively erases all dedupable vars in an input (replacing them with 0s), - // and returns the dedupable vars in order + // The walk functions recursively walk over an Enum, extracting the variables present inside (in order) + // Then, a substitution for each variable is computed using the fetch_var closure stored as a property + // If we don't want to re-write variables, we can just use |x| x as the fetch_var closure pub fn walk_outlives(&mut self, input: &Outlives<'tcx>) -> Outlives<'tcx> { ty::OutlivesPredicate( diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs index 9fde1d85995e0..c35d0d8f6b5eb 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs @@ -71,6 +71,8 @@ impl<'tcx> Deduper<'tcx> { self.remove_duplicate_constraints(&solve_result.removed_constraints, constraints); self.compress_variables(&solve_result.removed_vars, constraints, variables, max_universe); } + // Extracts data about each constraint, i.e. the variables present, as well as the constraint + // categories fn extract_constraint_data( &mut self, dedupable_vars: &FxIndexSet, @@ -78,6 +80,10 @@ impl<'tcx> Deduper<'tcx> { variables: &mut CanonicalVarInfos<'tcx> ) { let num_vars = variables.len(); + // dummy_var_rewriter is the fetch_var function that will be given to ConstraintWalker + // it re-writes all variables with a dummy value (num_vars - guaranteed to NOT be a var index), + // allowing us to compare constraints based solely on their structure, not on the variables present + // Used to compute constraint categories let mut dummy_var_rewriter = |var| num_vars; /* let mut dummy_var_rewriter = |var| { From 96f35a74bb2852cdaab83ae3308e436d48782192 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Wed, 3 May 2023 22:44:48 -0400 Subject: [PATCH 03/16] Added a few comments (3) --- out.txt | 402 -------------------------------------------------------- 1 file changed, 402 deletions(-) delete mode 100644 out.txt diff --git a/out.txt b/out.txt deleted file mode 100644 index a4c64cdf31a62..0000000000000 --- a/out.txt +++ /dev/null @@ -1,402 +0,0 @@ -Building stage0 library artifacts (x86_64-unknown-linux-gnu) -Building compiler artifacts (stage0 -> stage1, x86_64-unknown-linux-gnu) -Assembling stage1 compiler -Building stage1 library artifacts (x86_64-unknown-linux-gnu) -Building stage0 tool compiletest (x86_64-unknown-linux-gnu) -Check compiletest suite=ui mode=ui (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) - -running 1 tests -F - -failures: - ----- [ui] tests/ui/traits/new-solver/dedup-vars.rs stdout ---- - -error: Error: expected failure status (Some(1)) but received status Some(101). -status: exit status: 101 -command: "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc" "/home/ndrewxie/rust/tests/ui/traits/new-solver/dedup-vars.rs" "-Zthreads=1" "--sysroot" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/stage1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Zdeduplicate-diagnostics=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/test/ui/traits/new-solver/dedup-vars" "-A" "unused" "-Crpath" "-Cdebuginfo=0" "-Lnative=/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/test/ui/traits/new-solver/dedup-vars/auxiliary" "-Ztrait-solver=next" ---- stdout ------------------------------- -BEFORE: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - Bar, - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], -} -AFTER: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - Bar, - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], -} -BEFORE: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - Bar, - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], -} -AFTER: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - Bar, - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], -} -BEFORE: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - Bar, - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U1, - variables: [ - CanonicalVarInfo { - kind: PlaceholderRegion( - Placeholder { - universe: U1, - bound: BoundRegion { - var: 0, - kind: BrNamed(DefId(0:5 ~ dedup_vars[ed74]::Bar::'a), 'a), - }, - }, - ), - }, - ], -} -AFTER: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - Bar, - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: PlaceholderRegion( - Placeholder { - universe: U0, - bound: BoundRegion { - var: 0, - kind: BrNamed(DefId(0:5 ~ dedup_vars[ed74]::Bar::'a), 'a), - }, - }, - ), - }, - ], -} -BEFORE: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [], -} -AFTER: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [], -} ------------------------------------------- ---- stderr ------------------------------- -thread 'rustc' panicked at 'index out of bounds: the len is 0 but the index is 0', compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs:255:21 -stack backtrace: - 0: 0x7fe9f9570c37 - std::backtrace_rs::backtrace::trace_unsynchronized::h352d783f8836f973 - 1: 0x7fe9f956701b - ::fmt::h68e861c138d09dfc - 2: 0x7fe9f95e4159 - core::fmt::write::hc9837b4a6b405547 - 3: 0x7fe9f9534451 - std::io::Write::write_fmt::hb24223809381b675 - 4: 0x7fe9f9566e8d - std::sys_common::backtrace::print::h4375715fac3c73a0 - 5: 0x7fe9f954b877 - std::panicking::default_hook::{{closure}}::h1cd100ebfe0cbede - 6: 0x7fe9f954b61a - std::panicking::default_hook::hb341913f9cf3b16c - 7: 0x7fe9f9ef2c3f - rustc_driver_impl[3012c1cd686720e8]::DEFAULT_HOOK::{closure#0}::{closure#0} - 8: 0x7fe9f954bdf2 - std::panicking::rust_panic_with_hook::h7b51e523793dcd2c - 9: 0x7fe9f953dfe3 - std::panicking::begin_panic_handler::{{closure}}::h4eff0803b93bf7f1 - 10: 0x7fe9f953df16 - std::sys_common::backtrace::__rust_end_short_backtrace::hc754a8eb77b3845c - 11: 0x7fe9f954b972 - rust_begin_unwind - 12: 0x7fe9f95333e3 - core::panicking::panic_fmt::h766f9bd0d9567fe0 - 13: 0x7fe9f9533552 - core::panicking::panic_bounds_check::he75c4b878228025a - 14: 0x7fe9fc1f8b56 - <&mut ::compute_query_response_substitution::{closure#0} as core[4df9b0e25e0d2810]::ops::function::FnOnce<((usize, rustc_middle[5074ee5b4c22835b]::infer::canonical::CanonicalVarInfo),)>>::call_once - 15: 0x7fe9fc10cd95 - >>::collect_and_apply::>>, ::compute_query_response_substitution::{closure#0}>, ::mk_substs_from_iter>>, ::compute_query_response_substitution::{closure#0}>, rustc_middle[5074ee5b4c22835b]::ty::subst::GenericArg>::{closure#0}> - 16: 0x7fe9fc1177c3 - ::mk_substs_from_iter::>>, ::compute_query_response_substitution::{closure#0}>, rustc_middle[5074ee5b4c22835b]::ty::subst::GenericArg> - 17: 0x7fe9fc11d6e1 - ::evaluate_goal - 18: 0x7fe9fbfec45e - ::repeat_while_none::::try_evaluate_added_goals::{closure#0}, ::try_evaluate_added_goals::{closure#1}> - 19: 0x7fe9fc121e72 - ::try_evaluate_added_goals - 20: 0x7fe9fc121406 - ::evaluate_added_goals_and_make_canonical_response - 21: 0x7fe9fc11f2c7 - ::compute_goal - 22: 0x7fe9fc17fdef - ::repeat_while_none::, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#0}, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#1}> - 23: 0x7fe9fc20143f - >::with_anon_task::::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>> - 24: 0x7fe9fc180080 - ::with_new_goal::<::evaluate_canonical_goal::{closure#0}::{closure#0}> - 25: 0x7fe9fc11d1a8 - ::evaluate_goal - 26: 0x7fe9fbfec45e - ::repeat_while_none::::try_evaluate_added_goals::{closure#0}, ::try_evaluate_added_goals::{closure#1}> - 27: 0x7fe9fc121e72 - ::try_evaluate_added_goals - 28: 0x7fe9fc121406 - ::evaluate_added_goals_and_make_canonical_response - 29: 0x7fe9fc11e435 - ::compute_goal - 30: 0x7fe9fc17fdef - ::repeat_while_none::, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#0}, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#1}> - 31: 0x7fe9fc20143f - >::with_anon_task::::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>> - 32: 0x7fe9fc180080 - ::with_new_goal::<::evaluate_canonical_goal::{closure#0}::{closure#0}> - 33: 0x7fe9fc11d1a8 - ::evaluate_goal - 34: 0x7fe9fc1507fb - ::evaluate_root_goal - 35: 0x7fe9fc194536 - ::select_where_possible - 36: 0x7fe9fc1f66f8 - ::select_all_or_error - 37: 0x7fe9fc048c64 - ::select_all_or_error - 38: 0x7fe9fa63faf5 - rustc_hir_analysis[2d38e76667e9459]::check::wfcheck::enter_wf_checking_ctxt:: - 39: 0x7fe9fa57448a - rustc_hir_analysis[2d38e76667e9459]::check::wfcheck::check_type_defn - 40: 0x7fe9fa570bb1 - rustc_hir_analysis[2d38e76667e9459]::check::wfcheck::check_well_formed - 41: 0x7fe9fb729dbd - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 0usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 0usize]>> - 42: 0x7fe9fb7f9b03 - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: - 43: 0x7fe9fb56d050 - rustc_query_impl[d83653c600d19515]::get_query::check_well_formed - 44: 0x7fe9fa6575fe - ::par_trait_items::{closure#0}>::{closure#0}::{closure#0}> as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once - 45: 0x7fe9fa5f87c9 - std[e0afd7ea5d3fe186]::panicking::try::<(), core[4df9b0e25e0d2810]::panic::unwind_safe::AssertUnwindSafe::par_items::{closure#0}>::{closure#0}::{closure#0}>> - 46: 0x7fe9fa5960e4 - rustc_data_structures[96c7fbd8d6df213a]::sync::par_for_each_in::<&[rustc_hir[a03203a1750d3af4]::hir::ItemId], ::par_items::{closure#0}> - 47: 0x7fe9fa6776f8 - ::par_items:: - 48: 0x7fe9fa5758de - rustc_hir_analysis[2d38e76667e9459]::check::wfcheck::check_mod_type_wf - 49: 0x7fe9fb729d1d - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 0usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 0usize]>> - 50: 0x7fe9fb7f937d - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: - 51: 0x7fe9fb54ecc0 - rustc_query_impl[d83653c600d19515]::get_query::check_mod_type_wf - 52: 0x7fe9fa65771e - ::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}> as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once - 53: 0x7fe9fa5f87f9 - std[e0afd7ea5d3fe186]::panicking::try::<(), core[4df9b0e25e0d2810]::panic::unwind_safe::AssertUnwindSafe::par_for_each_module::{closure#0}>::{closure#0}::{closure#0}>> - 54: 0x7fe9fa5961b4 - rustc_data_structures[96c7fbd8d6df213a]::sync::par_for_each_in::<&[rustc_hir[a03203a1750d3af4]::hir_id::OwnerId], ::par_for_each_module::{closure#0}> - 55: 0x7fe9fa64363e - ::track_errors:: - 56: 0x7fe9fa651b33 - rustc_hir_analysis[2d38e76667e9459]::check_crate - 57: 0x7fe9f9fa9371 - rustc_interface[7e80568d2ceb88d0]::passes::analysis - 58: 0x7fe9fb732834 - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 1usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 1usize]>> - 59: 0x7fe9fb850c57 - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: - 60: 0x7fe9fb532c9a - rustc_query_impl[d83653c600d19515]::get_query::analysis - 61: 0x7fe9f9f5999e - >>::with::::enter>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 62: 0x7fe9f9f46bd8 - ::enter::> - 63: 0x7fe9f9f70754 - ::enter::, rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 64: 0x7fe9f9efd629 - rustc_span[bc72e8cf61038315]::set_source_map::, rustc_interface[7e80568d2ceb88d0]::interface::run_compiler, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}::{closure#0}> - 65: 0x7fe9f9efe2bf - >::set::, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 66: 0x7fe9f9f63010 - std[e0afd7ea5d3fe186]::sys_common::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 67: 0x7fe9f9f79c04 - ::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}> as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once - 68: 0x7fe9f9f53374 - std[e0afd7ea5d3fe186]::panicking::try::, core[4df9b0e25e0d2810]::panic::unwind_safe::AssertUnwindSafe<::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}>> - 69: 0x7fe9f9f621a9 - std[e0afd7ea5d3fe186]::panic::catch_unwind::::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}>, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 70: 0x7fe9f9f7c5e2 - <::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1} as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} - 71: 0x7fe9f95849da - as core::ops::function::FnOnce>::call_once::h481e59266d00f875 - 72: 0x7fe9f958ac0a - std::sys::unix::thread::Thread::new::thread_start::h7e46e4f9732e143e - 73: 0x7fe9f008aea7 - start_thread - 74: 0x7fe9f93dfa2f - clone - 75: 0x0 - - -error: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc 1.71.0-dev running on x86_64-unknown-linux-gnu - -note: compiler flags: -Z threads=1 -C codegen-units=1 -Z ui-testing -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z deduplicate-diagnostics=no -C strip=debuginfo -C prefer-dynamic -C rpath -C debuginfo=0 -Z trait-solver=next - -query stack during panic: -#0 [check_well_formed] checking that `Bar` is well-formed -#1 [check_mod_type_wf] checking that types are well-formed in top-level module -#2 [analysis] running analysis passes on this crate -end of query stack ------------------------------------------- - - - -failures: - [ui] tests/ui/traits/new-solver/dedup-vars.rs - -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 14891 filtered out; finished in 52.18ms - -Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu From dce80d40daa122710d3bd258aa132ea0da1acf9a Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Wed, 3 May 2023 23:58:38 -0400 Subject: [PATCH 04/16] Fixed Rc/Arc issue and tidy errors --- .../dedup_solver/constraint_walker.rs | 4 +- .../eval_ctxt/canonical/dedup_solver/mod.rs | 81 ++++++++++------- .../canonical/dedup_solver/solver.rs | 90 +------------------ 3 files changed, 51 insertions(+), 124 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs index 177af41ea5771..980b053580412 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs @@ -62,7 +62,7 @@ impl<'tcx, 'a> ConstraintWalker<'tcx, 'a> { } fn walk_region(&mut self, input: Region<'tcx>) -> Region<'tcx> { let rewritten = match input.kind() { - // TODO: Are these all of the variants that can have variables? + // FIXME: Are these all of the variants that can have variables? ty::ReLateBound(db_indx, bound_region) => { ty::ReLateBound(db_indx, self.walk_bound_region(bound_region)) } @@ -79,7 +79,7 @@ impl<'tcx, 'a> ConstraintWalker<'tcx, 'a> { } fn walk_ty(&mut self, input: Ty<'tcx>) -> Ty<'tcx> { let rewritten = match input.kind() { - // TODO: Quite a few are missing + // FIXME: Quite a few are missing ty::Adt(adt_def, substs) => ty::Adt(*adt_def, self.walk_substs_ref(substs)), ty::Array(elem_ty, count) => ty::Array(self.walk_ty(*elem_ty), self.walk_const(*count)), ty::Slice(elem_ty) => ty::Slice(self.walk_ty(*elem_ty)), diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs index c35d0d8f6b5eb..5ff6a7997cb90 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs @@ -4,15 +4,15 @@ #![allow(unused_imports)] use crate::infer::canonical::{Canonical, CanonicalVarInfos}; use crate::infer::region_constraints::MemberConstraint; -use crate::solve::{Response, ExternalConstraintsData}; +use crate::solve::{ExternalConstraintsData, Response}; use rustc_middle::ty::{TyCtxt, UniverseIndex}; -use std::ops::Deref; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use std::hash::Hash; -use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxIndexMap, FxIndexSet}; +use std::ops::Deref; -mod solver; mod constraint_walker; +mod solver; use constraint_walker::{ConstraintWalker, Outlives}; pub struct Deduper<'tcx> { @@ -32,6 +32,7 @@ enum ConstraintType<'tcx> { impl<'tcx> Deduper<'tcx> { pub fn dedup(tcx: TyCtxt<'tcx>, input: &mut Canonical<'tcx, Response<'tcx>>) { + println!("INPUT: {:#?}", input); let mut constraints = input.value.external_constraints.deref().clone(); let mut deduper = Self { tcx, @@ -42,16 +43,17 @@ impl<'tcx> Deduper<'tcx> { }; deduper.dedup_internal(&mut constraints, &mut input.variables, &mut input.max_universe); input.value.external_constraints = tcx.mk_external_constraints(constraints); + println!("OUTPUT: {:#?}", input); } fn dedup_internal( - &mut self, - constraints: &mut ExternalConstraintsData<'tcx>, + &mut self, + constraints: &mut ExternalConstraintsData<'tcx>, variables: &mut CanonicalVarInfos<'tcx>, - max_universe: &mut UniverseIndex - ) { + max_universe: &mut UniverseIndex, + ) { dedup_exact_eq(&mut constraints.region_constraints.outlives); dedup_exact_eq(&mut constraints.region_constraints.member_constraints); - + let dedupable_vars: FxIndexSet = variables .iter() .enumerate() @@ -63,10 +65,9 @@ impl<'tcx> Deduper<'tcx> { let rule_vars = std::mem::take(&mut self.rule_vars); let rule_cats = std::mem::take(&mut self.rule_cats).into_values().collect::>(); - let unremovable_vars: FxIndexSet = (0..variables.len()) - .filter(|x| !dedupable_vars.contains(x)) - .collect(); - + let unremovable_vars: FxIndexSet = + (0..variables.len()).filter(|x| !dedupable_vars.contains(x)).collect(); + let solve_result = solver::DedupSolver::dedup(rule_vars, rule_cats, unremovable_vars); self.remove_duplicate_constraints(&solve_result.removed_constraints, constraints); self.compress_variables(&solve_result.removed_vars, constraints, variables, max_universe); @@ -74,10 +75,10 @@ impl<'tcx> Deduper<'tcx> { // Extracts data about each constraint, i.e. the variables present, as well as the constraint // categories fn extract_constraint_data( - &mut self, - dedupable_vars: &FxIndexSet, + &mut self, + dedupable_vars: &FxIndexSet, constraints: &mut ExternalConstraintsData<'tcx>, - variables: &mut CanonicalVarInfos<'tcx> + variables: &mut CanonicalVarInfos<'tcx>, ) { let num_vars = variables.len(); // dummy_var_rewriter is the fetch_var function that will be given to ConstraintWalker @@ -97,34 +98,45 @@ impl<'tcx> Deduper<'tcx> { let mut extractor = ConstraintWalker::new(self.tcx, &mut dummy_var_rewriter); let erased = ConstraintType::Outlives(extractor.walk_outlives(&outlives.0)); let vars = std::mem::take(&mut extractor.vars); - if vars.is_empty() { continue; } + if vars.is_empty() { + continue; + } self.process_constraint_data(indx, erased, vars); } for (indx, member) in constraints.region_constraints.member_constraints.iter().enumerate() { let mut extractor = ConstraintWalker::new(self.tcx, &mut dummy_var_rewriter); let erased = ConstraintType::Member(extractor.walk_members(member)); let vars = std::mem::take(&mut extractor.vars); - if vars.is_empty() { continue; } + if vars.is_empty() { + continue; + } self.process_constraint_data(indx, erased, vars); } } fn process_constraint_data( - &mut self, + &mut self, input_indx: usize, - erased: ConstraintType<'tcx>, - vars: Vec + erased: ConstraintType<'tcx>, + vars: Vec, ) { self.rule_vars.push(vars); let constraint_indx = self.rule_vars.len() - 1; match &erased { ConstraintType::Outlives(_) => &mut self.indx_to_outlives, ConstraintType::Member(_) => &mut self.indx_to_members, - }.insert(constraint_indx, input_indx); + } + .insert(constraint_indx, input_indx); self.rule_cats.entry(erased).or_insert_with(Vec::new).push(constraint_indx); } - fn remove_duplicate_constraints(&mut self, to_remove: &FxIndexSet, constraints: &mut ExternalConstraintsData<'tcx>) { - let mut remove_outlives: FxIndexSet = to_remove.iter().filter_map(|x| self.indx_to_outlives.get(x)).cloned().collect(); - let mut remove_members: FxIndexSet = to_remove.iter().filter_map(|x| self.indx_to_members.get(x)).cloned().collect(); + fn remove_duplicate_constraints( + &mut self, + to_remove: &FxIndexSet, + constraints: &mut ExternalConstraintsData<'tcx>, + ) { + let mut remove_outlives: FxIndexSet = + to_remove.iter().filter_map(|x| self.indx_to_outlives.get(x)).cloned().collect(); + let mut remove_members: FxIndexSet = + to_remove.iter().filter_map(|x| self.indx_to_members.get(x)).cloned().collect(); remove_outlives.sort(); remove_members.sort(); @@ -136,14 +148,15 @@ impl<'tcx> Deduper<'tcx> { } } fn compress_variables( - &mut self, - removed_vars: &FxIndexSet, + &mut self, + removed_vars: &FxIndexSet, constraints: &mut ExternalConstraintsData<'tcx>, variables: &mut CanonicalVarInfos<'tcx>, - max_universe: &mut UniverseIndex + max_universe: &mut UniverseIndex, ) { let mut vars = variables.as_slice().to_vec(); - let mut universes_available: FxIndexSet = vars.iter().map(|x| x.universe()).collect(); + let mut universes_available: FxIndexSet = + vars.iter().map(|x| x.universe()).collect(); universes_available.sort(); let mut compressed_vars: FxHashMap = FxHashMap::default(); @@ -166,9 +179,9 @@ impl<'tcx> Deduper<'tcx> { for var in vars.iter_mut() { *var = var.with_updated_universe( - *universes_available.get_index( - universes_used.get_index_of(&var.universe()).unwrap() - ).unwrap() + *universes_available + .get_index(universes_used.get_index_of(&var.universe()).unwrap()) + .unwrap(), ); } @@ -190,10 +203,10 @@ impl<'tcx> Deduper<'tcx> { fn dedup_exact_eq(input: &mut Vec) { let mut indx = 0; while indx < input.len() { - if input.iter().skip(indx+1).any(|x| x == &input[indx]) { + if input.iter().skip(indx + 1).any(|x| x == &input[indx]) { input.swap_remove(indx); continue; } indx += 1; } -} \ No newline at end of file +} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs index 305243b925d11..928db24464b93 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -90,10 +90,7 @@ impl DedupSolver { } removed_vars.insert(*from); } - DedupResult { - removed_constraints: deduper.removed_rules.into_inner(), - removed_vars, - } + DedupResult { removed_constraints: deduper.removed_rules.into_inner(), removed_vars } } fn refine_categories(&mut self) { // Refine categories based on shape @@ -475,87 +472,4 @@ impl MappingInfo { } } -/* -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_noop() { - let deduped = DedupSolver::dedup( - vec![vec![1], vec![1, 1], vec![2], vec![3]], - vec![vec![0, 1], vec![2], vec![3]], - FxIndexSet::default(), - ); - assert!(deduped.is_empty()); - } - #[test] - fn test_simple() { - let deduped = DedupSolver::dedup( - vec![vec![1], vec![2], vec![3]], - vec![vec![0, 1], vec![2]], - FxIndexSet::default(), - ); - assert!([FxIndexSet::from([0]), FxIndexSet::from([1])].contains(&deduped)); - } - #[test] - fn test_dependencies() { - let deduped = DedupSolver::dedup( - vec![ - vec![1, 2, 13], - vec![4, 5, 16], - vec![1, 2, 23], - vec![4, 5, 26], - vec![1, 2], - vec![4, 5], - ], - vec![vec![0, 1], vec![2, 3], vec![4, 5]], - FxIndexSet::default(), - ); - assert!([FxIndexSet::from([0, 2, 4]), FxIndexSet::from([1, 3, 5])].contains(&deduped)); - } - #[test] - fn test_dependencies_unresolvable() { - let deduped = DedupSolver::dedup( - vec![ - vec![1, 2, 13], - vec![4, 5, 16], - vec![1, 2, 23], - vec![4, 6, 26], - vec![1, 2], - vec![4, 5], - ], - vec![vec![0, 1], vec![2, 3], vec![4, 5]], - FxIndexSet::default(), - ); - assert!(deduped.is_empty()); - } - #[test] - fn test_gh_issues_example() { - let deduped = DedupSolver::dedup( - vec![vec![1], vec![2], vec![3]], - vec![vec![0, 1, 2]], - FxIndexSet::default(), - ); - assert!([FxIndexSet::from([0, 1]), FxIndexSet::from([0, 2]), FxIndexSet::from([1, 2])] - .contains(&deduped)); - } - #[test] - fn test_unremovable() { - let deduped = DedupSolver::dedup( - vec![ - vec![0, 1], - vec![0, 2], - vec![1, 0], - vec![2, 0], - vec![3, 1], - vec![3, 2], - vec![1, 3], - vec![2, 3], - ], - vec![vec![0, 1, 2, 3, 4, 5, 6, 7]], - FxIndexSet::from([0, 1, 2]), - ); - assert!(deduped == FxIndexSet::from([4, 5, 6, 7])); - } -} -*/ +// FIXME: Tests that test the solver on its own have been deleted cuz tidy check won't stop yelling at me - add back later From 3ac13f5cbdd2c4910cc381841d587133278d46dd Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Thu, 4 May 2023 00:10:42 -0400 Subject: [PATCH 05/16] Fiddling around with git... Fixed Rc/Arc issue with Lrc, unstaged src/tools/cargo (hopefully) --- .../eval_ctxt/canonical/dedup_solver/constraint_walker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs index 980b053580412..d953b5b3b026f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs @@ -4,7 +4,7 @@ use ty::subst::{GenericArg, GenericArgKind}; use ty::{Const, OutlivesPredicate, Placeholder, Region, Ty, TyCtxt}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; -use std::rc::Rc; +use rustc_data_structures::sync::Lrc; pub type Outlives<'tcx> = OutlivesPredicate, Region<'tcx>>; @@ -46,7 +46,7 @@ impl<'tcx, 'a> ConstraintWalker<'tcx, 'a> { definition_span: input.definition_span, hidden_ty: self.walk_ty(input.hidden_ty), member_region: self.walk_region(input.member_region), - choice_regions: Rc::new( + choice_regions: Lrc::new( input.choice_regions.iter().map(|x| self.walk_region(*x)).collect::>(), ), } From a4e4973a95bfd9bad7f7ec45da992f330757b00f Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Thu, 4 May 2023 00:39:32 -0400 Subject: [PATCH 06/16] Removed debug printlns (whoops) --- .../src/solve/eval_ctxt/canonical/dedup_solver/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs index 5ff6a7997cb90..db24e614079a1 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs @@ -32,7 +32,6 @@ enum ConstraintType<'tcx> { impl<'tcx> Deduper<'tcx> { pub fn dedup(tcx: TyCtxt<'tcx>, input: &mut Canonical<'tcx, Response<'tcx>>) { - println!("INPUT: {:#?}", input); let mut constraints = input.value.external_constraints.deref().clone(); let mut deduper = Self { tcx, @@ -43,7 +42,6 @@ impl<'tcx> Deduper<'tcx> { }; deduper.dedup_internal(&mut constraints, &mut input.variables, &mut input.max_universe); input.value.external_constraints = tcx.mk_external_constraints(constraints); - println!("OUTPUT: {:#?}", input); } fn dedup_internal( &mut self, From 6de1233d00600099a576e2d690bb9416ec0a923a Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Fri, 5 May 2023 16:23:31 -0400 Subject: [PATCH 07/16] fixup! Added a few comments --- .../dedup_solver/constraint_walker.rs | 4 - .../eval_ctxt/canonical/dedup_solver/mod.rs | 109 +++---- .../canonical/dedup_solver/solver.rs | 294 +++++++++--------- 3 files changed, 194 insertions(+), 213 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs index d953b5b3b026f..88ab3f7668176 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs @@ -3,7 +3,6 @@ use rustc_middle::ty; use ty::subst::{GenericArg, GenericArgKind}; use ty::{Const, OutlivesPredicate, Placeholder, Region, Ty, TyCtxt}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::Lrc; pub type Outlives<'tcx> = OutlivesPredicate, Region<'tcx>>; @@ -19,9 +18,6 @@ impl<'tcx, 'a> ConstraintWalker<'tcx, 'a> { pub fn new(tcx: TyCtxt<'tcx>, fetch_var: &'a mut dyn FnMut(usize) -> usize) -> Self { Self { tcx, fetch_var: fetch_var, vars: Vec::new() } } - pub fn reset(&mut self) { - self.vars.clear(); - } pub fn add_var(&mut self, var: usize) -> usize { self.vars.push(var); return (self.fetch_var)(var); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs index db24e614079a1..474a9e92c0c16 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs @@ -1,28 +1,26 @@ -#![allow(dead_code)] -#![allow(unused_variables)] -#![allow(unreachable_code)] -#![allow(unused_imports)] use crate::infer::canonical::{Canonical, CanonicalVarInfos}; use crate::infer::region_constraints::MemberConstraint; use crate::solve::{ExternalConstraintsData, Response}; use rustc_middle::ty::{TyCtxt, UniverseIndex}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_index::{Idx, IndexVec}; use std::hash::Hash; use std::ops::Deref; mod constraint_walker; mod solver; use constraint_walker::{ConstraintWalker, Outlives}; +use solver::{ConstraintIndex, DedupSolver, VarIndex}; pub struct Deduper<'tcx> { tcx: TyCtxt<'tcx>, - rule_vars: Vec>, - rule_cats: FxIndexMap, Vec>, + constraint_vars: IndexVec>, + constraint_cliques: FxIndexMap, Vec>, /// Maps a constraint index (the index inside constraint_vars) back to its index in outlives - indx_to_outlives: FxHashMap, + indx_to_outlives: FxHashMap, /// Maps a constraint index (the index inside constraint_vars) back to its index in member_constraints - indx_to_members: FxHashMap, + indx_to_members: FxHashMap, } #[derive(Debug, PartialEq, Eq, Hash)] enum ConstraintType<'tcx> { @@ -35,8 +33,8 @@ impl<'tcx> Deduper<'tcx> { let mut constraints = input.value.external_constraints.deref().clone(); let mut deduper = Self { tcx, - rule_vars: Vec::new(), - rule_cats: FxIndexMap::default(), + constraint_vars: IndexVec::new(), + constraint_cliques: FxIndexMap::default(), indx_to_outlives: FxHashMap::default(), indx_to_members: FxHashMap::default(), }; @@ -49,24 +47,35 @@ impl<'tcx> Deduper<'tcx> { variables: &mut CanonicalVarInfos<'tcx>, max_universe: &mut UniverseIndex, ) { - dedup_exact_eq(&mut constraints.region_constraints.outlives); - dedup_exact_eq(&mut constraints.region_constraints.member_constraints); + constraints.region_constraints.outlives = + FxIndexSet::<_>::from_iter(constraints.region_constraints.outlives.clone().into_iter()) + .into_iter() + .collect(); + constraints.region_constraints.member_constraints = FxIndexSet::<_>::from_iter( + constraints.region_constraints.member_constraints.clone().into_iter(), + ) + .into_iter() + .collect(); - let dedupable_vars: FxIndexSet = variables + let dedupable_vars: FxIndexSet = variables .iter() .enumerate() .filter(|(_, var)| var.universe() > UniverseIndex::ROOT) - .map(|(indx, _)| indx) + .map(|(indx, _)| VarIndex::new(indx)) .collect(); - self.extract_constraint_data(&dedupable_vars, constraints, variables); + self.extract_constraint_data(constraints, variables); - let rule_vars = std::mem::take(&mut self.rule_vars); - let rule_cats = std::mem::take(&mut self.rule_cats).into_values().collect::>(); - let unremovable_vars: FxIndexSet = - (0..variables.len()).filter(|x| !dedupable_vars.contains(x)).collect(); + let constraint_vars = std::mem::take(&mut self.constraint_vars); + let constraint_cliques = + std::mem::take(&mut self.constraint_cliques).into_values().collect::>(); + let unremovable_vars: FxIndexSet<_> = (0..variables.len()) + .map(VarIndex::new) + .filter(|x| !dedupable_vars.contains(x)) + .collect(); - let solve_result = solver::DedupSolver::dedup(rule_vars, rule_cats, unremovable_vars); + let solve_result = + DedupSolver::dedup(constraint_vars, constraint_cliques, unremovable_vars); self.remove_duplicate_constraints(&solve_result.removed_constraints, constraints); self.compress_variables(&solve_result.removed_vars, constraints, variables, max_universe); } @@ -74,7 +83,6 @@ impl<'tcx> Deduper<'tcx> { // categories fn extract_constraint_data( &mut self, - dedupable_vars: &FxIndexSet, constraints: &mut ExternalConstraintsData<'tcx>, variables: &mut CanonicalVarInfos<'tcx>, ) { @@ -83,19 +91,12 @@ impl<'tcx> Deduper<'tcx> { // it re-writes all variables with a dummy value (num_vars - guaranteed to NOT be a var index), // allowing us to compare constraints based solely on their structure, not on the variables present // Used to compute constraint categories - let mut dummy_var_rewriter = |var| num_vars; - /* - let mut dummy_var_rewriter = |var| { - if dedupable_vars.contains(&var) { - return num_vars; - } - var - }; - */ + let mut dummy_var_rewriter = |_| num_vars; + for (indx, outlives) in constraints.region_constraints.outlives.iter().enumerate() { let mut extractor = ConstraintWalker::new(self.tcx, &mut dummy_var_rewriter); let erased = ConstraintType::Outlives(extractor.walk_outlives(&outlives.0)); - let vars = std::mem::take(&mut extractor.vars); + let vars: Vec<_> = extractor.vars.iter().map(|x| VarIndex::new(*x)).collect(); if vars.is_empty() { continue; } @@ -104,7 +105,7 @@ impl<'tcx> Deduper<'tcx> { for (indx, member) in constraints.region_constraints.member_constraints.iter().enumerate() { let mut extractor = ConstraintWalker::new(self.tcx, &mut dummy_var_rewriter); let erased = ConstraintType::Member(extractor.walk_members(member)); - let vars = std::mem::take(&mut extractor.vars); + let vars: Vec<_> = extractor.vars.iter().map(|x| VarIndex::new(*x)).collect(); if vars.is_empty() { continue; } @@ -115,20 +116,20 @@ impl<'tcx> Deduper<'tcx> { &mut self, input_indx: usize, erased: ConstraintType<'tcx>, - vars: Vec, + vars: Vec, ) { - self.rule_vars.push(vars); - let constraint_indx = self.rule_vars.len() - 1; + let constraint_indx = self.constraint_vars.next_index(); + self.constraint_vars.push(vars); match &erased { ConstraintType::Outlives(_) => &mut self.indx_to_outlives, ConstraintType::Member(_) => &mut self.indx_to_members, } .insert(constraint_indx, input_indx); - self.rule_cats.entry(erased).or_insert_with(Vec::new).push(constraint_indx); + self.constraint_cliques.entry(erased).or_insert_with(Vec::new).push(constraint_indx); } fn remove_duplicate_constraints( &mut self, - to_remove: &FxIndexSet, + to_remove: &FxIndexSet, constraints: &mut ExternalConstraintsData<'tcx>, ) { let mut remove_outlives: FxIndexSet = @@ -147,7 +148,7 @@ impl<'tcx> Deduper<'tcx> { } fn compress_variables( &mut self, - removed_vars: &FxIndexSet, + removed_vars: &FxIndexSet, constraints: &mut ExternalConstraintsData<'tcx>, variables: &mut CanonicalVarInfos<'tcx>, max_universe: &mut UniverseIndex, @@ -157,21 +158,21 @@ impl<'tcx> Deduper<'tcx> { vars.iter().map(|x| x.universe()).collect(); universes_available.sort(); - let mut compressed_vars: FxHashMap = FxHashMap::default(); + let mut compressed_vars: FxHashMap = FxHashMap::default(); let mut universes_used: FxIndexSet = FxIndexSet::default(); let mut num_removed = 0; - let mut var_indx = 0; - while var_indx < vars.len() { - let original_var_indx = var_indx + num_removed; + let mut var_indx = VarIndex::new(0); + while var_indx.index() < vars.len() { + let original_var_indx = var_indx.plus(num_removed); if removed_vars.contains(&original_var_indx) { num_removed += 1; - vars.remove(var_indx); + vars.remove(var_indx.index()); continue; } - compressed_vars.insert(original_var_indx, var_indx); - universes_used.insert(vars[var_indx].universe()); - var_indx += 1; + compressed_vars.insert(original_var_indx, var_indx.index()); + universes_used.insert(vars[var_indx.index()].universe()); + var_indx.increment_by(1); } universes_used.sort(); @@ -183,7 +184,8 @@ impl<'tcx> Deduper<'tcx> { ); } - let mut var_rewriter = |var| compressed_vars.get(&var).cloned().unwrap_or(var); + let mut var_rewriter = + |var| compressed_vars.get(&VarIndex::from(var)).cloned().unwrap_or(var); for outlives in constraints.region_constraints.outlives.iter_mut() { let mut walker = ConstraintWalker::new(self.tcx, &mut var_rewriter); outlives.0 = walker.walk_outlives(&outlives.0); @@ -197,14 +199,3 @@ impl<'tcx> Deduper<'tcx> { *max_universe = UniverseIndex::from(universes_used.len().saturating_sub(1)); } } - -fn dedup_exact_eq(input: &mut Vec) { - let mut indx = 0; - while indx < input.len() { - if input.iter().skip(indx + 1).any(|x| x == &input[indx]) { - input.swap_remove(indx); - continue; - } - indx += 1; - } -} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs index 928db24464b93..c01bc2fefbd73 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -1,62 +1,47 @@ -// Quick terminology mapping: -// * "rule" => region constraint ("rule" is just shorter) -// * "category"/"cat" => group of constraints with similar structure, i.e. -// constraints can only be merged if they're in the -// same category -// * "mapping" => mapping from one set of variables to another. Mappings MUST -// be many-to-one. Obviously, they can't be one-to-many, and -// a one-to-one mapping isn't really productive, because -// we're not eliminating any variables that way -// -// This algorithm, in its present state, *is* exponential time. This exponential time -// case happens iff we have potential mappings that overlap, thus requiring them -// to be combined. For example, if we have a category A that contains constraints involving -// variables [1, 2, 3] and [11, 12, 4], and a category B that contains constraints involving -// variables [1, 2, 100] and [11, 12, 101], then the mapping in category A from the first -// constraint to the second constraint is valid if and only if the mapping from the first -// constraint to the second constraint in category B is valid (i.e. they depend on each other). -// In this trivial case, it's obvious that they're both valid, but more complicated cases -// can create a graph of dependencies (potentially with cycles), creating exponential behavior. -// -// In general, I don't think the exponential case should be happening *that* often, and if it does, -// the dependencies graph shouldn't be very deep, so it shouldn't be terrible. However, I'm not very -// knowledgable on the types of region constraints that can be generated, so maybe this assertion is false. -// There's some heuristics that I can use to speed the exponential part up, or maybe just cap the search depth. - use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_index::{Idx, IndexVec}; use std::cell::RefCell; use std::collections::BTreeMap; +rustc_index::newtype_index! { pub struct VarIndex {} } +rustc_index::newtype_index! { pub struct ConstraintIndex {} } +rustc_index::newtype_index! { + /// Identifies a clique in the dedup graph by an index + /// Two constraints can potentially be merged if and only if they belong to the same clique + pub struct CliqueIndex {} +} +rustc_index::newtype_index! { pub struct MappingIndex {} } + #[derive(Debug)] pub struct DedupSolver { - /// The variables present in each rule - the inner vec contains the variables, in the order - /// that they appear in the rule - rule_vars: Vec>, - /// The categories that rules can be partitioned into - the inner vec contains all the rules + /// The variables present in each constraint - the inner vec contains the variables, in the order + /// that they appear in the constraint + constraint_vars: IndexVec>, + /// The categories that constraints can be partitioned into - the inner vec contains all the constraints /// that are in the same category - rule_cats: Vec>, - unremovable_vars: FxIndexSet, + constraint_cliques: IndexVec>, + unremovable_vars: FxIndexSet, /// The below are internal variables used in the solving process: /// All the mappings that can possibly be taken mappings: FxIndexMap, - /// Rules that have already been removed by deduplication - removed_rules: RefCell>, + /// Constraints that have already been removed by deduplication + removed_constraints: RefCell>, /// All of the currently applied var mappings, summed together applied_mappings: RefCell, } #[derive(Debug)] pub struct DedupResult { - pub removed_constraints: FxIndexSet, - pub removed_vars: FxIndexSet, + pub removed_constraints: FxIndexSet, + pub removed_vars: FxIndexSet, } #[derive(Clone, Hash, PartialEq, Eq, Debug)] -struct Mapping(BTreeMap); +struct Mapping(BTreeMap); #[derive(Debug, Clone, PartialEq, Eq)] struct MappingInfo { - dependencies: FxIndexMap>, - rule_mappings: FxIndexMap, + dependencies: FxIndexMap>, + constraint_mappings: FxIndexMap, } #[derive(Debug, PartialEq, Eq)] enum MapEvalErr { @@ -66,20 +51,20 @@ enum MapEvalErr { impl DedupSolver { pub fn dedup( - constraint_vars: Vec>, - constraint_categories: Vec>, - unremovable_vars: FxIndexSet, + constraint_vars: IndexVec>, + constraint_cliques: IndexVec>, + unremovable_vars: FxIndexSet, ) -> DedupResult { let mut deduper = Self { - rule_vars: constraint_vars, - rule_cats: constraint_categories, + constraint_vars, + constraint_cliques, unremovable_vars, mappings: FxIndexMap::default(), - removed_rules: RefCell::new(FxIndexSet::default()), - applied_mappings: RefCell::new(Mapping::map_rules(&[], &[])), + removed_constraints: RefCell::new(FxIndexSet::default()), + applied_mappings: RefCell::new(Mapping::map_constraints(&[], &[])), }; - deduper.refine_categories(); + deduper.refine_cliques(); deduper.compute_mappings(); deduper.resolve_dependencies(); @@ -90,86 +75,86 @@ impl DedupSolver { } removed_vars.insert(*from); } - DedupResult { removed_constraints: deduper.removed_rules.into_inner(), removed_vars } + DedupResult { removed_constraints: deduper.removed_constraints.into_inner(), removed_vars } } - fn refine_categories(&mut self) { + fn refine_cliques(&mut self) { // Refine categories based on shape - for cat_indx in 0..self.rule_cats.len() { - let mut shape_categories: FxIndexMap, usize> = FxIndexMap::default(); - let mut rule_indx = 0; - while rule_indx < self.rule_cats[cat_indx].len() { - let rule = self.rule_cats[cat_indx][rule_indx]; - let shape = Self::canonicalize_rule_shape(&mut self.rule_vars[rule]); - let is_first_entry = shape_categories.is_empty(); - let new_cat = *shape_categories.entry(shape).or_insert_with(|| { + for clique_indx in (0..self.constraint_cliques.len()).map(CliqueIndex::new) { + let mut shape_cliques: FxIndexMap, CliqueIndex> = FxIndexMap::default(); + let mut constraint_indx = 0; + while constraint_indx < self.constraint_cliques[clique_indx].len() { + let constraint = self.constraint_cliques[clique_indx][constraint_indx]; + let shape = + Self::canonicalize_constraint_shape(&mut self.constraint_vars[constraint]); + let is_first_entry = shape_cliques.is_empty(); + let new_clique = *shape_cliques.entry(shape).or_insert_with(|| { if is_first_entry { - cat_indx + clique_indx } else { - self.rule_cats.push(Vec::new()); - self.rule_cats.len() - 1 + self.constraint_cliques.push(Vec::new()); + CliqueIndex::new(self.constraint_cliques.len() - 1) } }); - if new_cat == cat_indx { - rule_indx += 1; + if new_clique == clique_indx { + constraint_indx += 1; continue; } - self.rule_cats[cat_indx].swap_remove(rule_indx); - self.rule_cats[new_cat].push(rule); + self.constraint_cliques[clique_indx].swap_remove(constraint_indx); + self.constraint_cliques[new_clique].push(constraint); } } // Refine categories based on indices of variables - for cat_indx in 0..self.rule_cats.len() { - // A vec of tuples representing index categories. - // First element of tuple is a mapping from a variable to the index it occurs in - // Second element of tuple is the category - let mut index_categories: Vec<(FxIndexMap, usize)> = Vec::new(); - let mut rule_indx = 0; - while rule_indx < self.rule_cats[cat_indx].len() { - let rule = self.rule_cats[cat_indx][rule_indx]; - let rule_vars = &self.rule_vars[rule]; - let rule_var_indices: FxIndexMap = - rule_vars.iter().enumerate().map(|(indx, x)| (*x, indx)).collect(); + for clique_indx in (0..self.constraint_cliques.len()).map(CliqueIndex::new) { + // First element of tuple (the FxIndexMap) maps a variable to + // the index it occurs in + let mut index_cliques: Vec<(FxIndexMap, CliqueIndex)> = Vec::new(); + let mut constraint_indx = 0; + while constraint_indx < self.constraint_cliques[clique_indx].len() { + let constraint = self.constraint_cliques[clique_indx][constraint_indx]; + let constraint_vars = &self.constraint_vars[constraint]; + let constraint_var_indices: FxIndexMap = + constraint_vars.iter().enumerate().map(|(indx, x)| (*x, indx)).collect(); - let mut found_cat = None; - for (cat_vars, new_cat_indx) in index_categories.iter_mut() { - let is_cat_member = rule_vars + let mut found_clique = None; + for (clique_vars, new_clique_indx) in index_cliques.iter_mut() { + let is_clique_member = constraint_vars .iter() .enumerate() - .all(|(indx, x)| *cat_vars.get(x).unwrap_or(&indx) == indx); - if !is_cat_member { + .all(|(indx, x)| *clique_vars.get(x).unwrap_or(&indx) == indx); + if !is_clique_member { continue; } - found_cat = Some(*new_cat_indx); - cat_vars.extend(&rule_var_indices); + found_clique = Some(*new_clique_indx); + clique_vars.extend(&constraint_var_indices); break; } - let new_cat = found_cat.unwrap_or_else(|| { - if index_categories.is_empty() { - cat_indx + let new_clique = found_clique.unwrap_or_else(|| { + if index_cliques.is_empty() { + clique_indx } else { - self.rule_cats.push(Vec::new()); - let new_cat = self.rule_cats.len() - 1; - index_categories.push((rule_var_indices, new_cat)); - new_cat + let new_clique = self.constraint_cliques.next_index(); + self.constraint_cliques.push(Vec::new()); + index_cliques.push((constraint_var_indices, new_clique)); + new_clique } }); - if new_cat == cat_indx { - rule_indx += 1; + if new_clique == clique_indx { + constraint_indx += 1; continue; } - self.rule_cats[cat_indx].swap_remove(rule_indx); - self.rule_cats[new_cat].push(rule); + self.constraint_cliques[clique_indx].swap_remove(constraint_indx); + self.constraint_cliques[new_clique].push(constraint); } } } - /// Returns the "shape" of a rule - related to the idea of de bruijn indices - /// For example, a rule involving the vars [1, 1, 2, 3] has a shape of [0, 0, 1, 2], - /// and a rule involving vars [3, 4] has a shape of [0, 1] + /// Returns the "shape" of a constraint - related to the idea of de bruijn indices + /// For example, a constraint involving the vars [1, 1, 2, 3] has a shape of [0, 0, 1, 2], + /// and a constraint involving vars [3, 4] has a shape of [0, 1] /// It takes a mutable reference to the vars because it also removes duplicates from /// the input vector after computing the shape /// Clearly, two constraints can be mapped onto each other only if they have the /// same shape - fn canonicalize_rule_shape(vars: &mut Vec) -> Vec { + fn canonicalize_constraint_shape(vars: &mut Vec) -> Vec { let mut shape = Vec::new(); let mut num_vars = 0; let mut indx = 0; @@ -188,24 +173,32 @@ impl DedupSolver { /// Computes the set of all possible mappings /// If a mapping has no dependencies, then it's eagerly taken, to increase performance - /// Deduplication can be done greedily because if two rules can be merged, then they're - /// equivalent in every way, including in relations to other rules + /// Deduplication can be done greedily because if two constraints can be merged, then they're + /// equivalent in every way, including in relations to other constraints fn compute_mappings(&mut self) { let mut invalid_maps: FxIndexSet = FxIndexSet::default(); - for cat in self.rule_cats.iter() { - for (n, rule_1) in - cat.iter().enumerate().filter(|x| !self.removed_rules.borrow().contains(x.1)) + for clique in self.constraint_cliques.iter() { + for (n, constraint_1) in clique + .iter() + .enumerate() + .filter(|x| !self.removed_constraints.borrow().contains(x.1)) { - for rule_2 in - cat.iter().skip(n + 1).filter(|x| !self.removed_rules.borrow().contains(*x)) + for constraint_2 in clique + .iter() + .skip(n + 1) + .filter(|x| !self.removed_constraints.borrow().contains(*x)) { - let forward = - Mapping::map_rules(&self.rule_vars[*rule_1], &self.rule_vars[*rule_2]); + let forward = Mapping::map_constraints( + &self.constraint_vars[*constraint_1], + &self.constraint_vars[*constraint_2], + ); if invalid_maps.contains(&forward) || self.mappings.contains_key(&forward) { continue; } - let reverse = - Mapping::map_rules(&self.rule_vars[*rule_2], &self.rule_vars[*rule_1]); + let reverse = Mapping::map_constraints( + &self.constraint_vars[*constraint_2], + &self.constraint_vars[*constraint_1], + ); if invalid_maps.contains(&reverse) || self.mappings.contains_key(&reverse) { continue; } @@ -235,7 +228,7 @@ impl DedupSolver { self.resolve_dependencies_to_mapping(); } /// Currently, dependencies are in the form FxIndexMap, - /// where A is a rule that must be mapped by another mapping. We must + /// where A is a constraint that must be mapped by another mapping. We must /// populate the EmptyFxIndexSet with a set of mappings that can map A without /// conflicting with the current mapping fn resolve_dependencies_to_mapping(&mut self) { @@ -245,23 +238,24 @@ impl DedupSolver { } mapping_info .dependencies - .retain(|dependency, _| !self.removed_rules.borrow().contains(dependency)); + .retain(|dependency, _| !self.removed_constraints.borrow().contains(dependency)); true }); // A map from a constraint to the mappings that will eliminate it - let mut constraint_mappings: FxIndexMap> = FxIndexMap::default(); + let mut constraint_mappings: FxIndexMap> = + FxIndexMap::default(); for (indx, (_, mapping_info)) in self.mappings.iter().enumerate() { - for (from_rule, _) in mapping_info.rule_mappings.iter() { + for (from_constraint, _) in mapping_info.constraint_mappings.iter() { constraint_mappings - .entry(*from_rule) + .entry(*from_constraint) .or_insert_with(FxIndexSet::default) - .insert(indx); + .insert(MappingIndex::new(indx)); } } - for indx in 0..self.mappings.len() { + for indx in (0..self.mappings.len()).map(MappingIndex::new) { let mapping = self.get_mapping(indx); let input_dependencies = &self.get_mapping_info(indx).dependencies; - let mut dependencies = Vec::new(); + let mut dependencies = IndexVec::new(); for (dependency, _) in input_dependencies.iter() { let mut resolve_options = FxIndexSet::default(); if let Some(resolve_mappings) = constraint_mappings.get(dependency) { @@ -273,15 +267,15 @@ impl DedupSolver { ) } // Don't duplicate dependency groups - if dependencies.contains(&resolve_options) { + if dependencies.iter().any(|x| x == &resolve_options) { continue; } dependencies.push(resolve_options); } - // After this point, the actual rules that a dependency maps + // After this point, the actual constraints that a dependency maps // stops mattering - all that matters is that the dependency *exists* - self.mappings.get_index_mut(indx).unwrap().1.dependencies = - dependencies.into_iter().enumerate().collect(); + self.mappings.get_index_mut(indx.index()).unwrap().1.dependencies = + dependencies.into_iter_enumerated().collect(); } } /// Evaluates the mapping. Can return None if the mapping is invalid (i.e. it maps @@ -295,27 +289,27 @@ impl DedupSolver { mapping.0.iter().any(|(from, to)| self.unremovable_vars.contains(from) && from != to); let mut info = MappingInfo::new(); - for cat in self.rule_cats.iter() { - for rule_1 in cat { - let vars_1 = &self.rule_vars[*rule_1]; - if !mapping.affects_rule(vars_1) { + for clique in self.constraint_cliques.iter() { + for constraint_1 in clique { + let vars_1 = &self.constraint_vars[*constraint_1]; + if !mapping.affects_constraint(vars_1) { continue; } let mut found_non_conflicting = false; - for rule_2 in cat.iter() { - let vars_2 = &self.rule_vars[*rule_2]; - let trial_mapping = Mapping::map_rules(vars_1, vars_2); + for constraint_2 in clique.iter() { + let vars_2 = &self.constraint_vars[*constraint_2]; + let trial_mapping = Mapping::map_constraints(vars_1, vars_2); if mapping.conflicts_with(&trial_mapping) { continue; } found_non_conflicting = true; - // Only maps a subset of variables in rule_1 + // Only maps a subset of variables in constraint_1 if !mapping.maps_fully(vars_1, vars_2) { - info.dependencies.insert(*rule_1, FxIndexSet::default()); + info.dependencies.insert(*constraint_1, FxIndexSet::default()); continue; } - if *rule_1 != *rule_2 { - info.rule_mappings.insert(*rule_1, *rule_2); + if *constraint_1 != *constraint_2 { + info.constraint_mappings.insert(*constraint_1, *constraint_2); } } if !found_non_conflicting { @@ -323,7 +317,7 @@ impl DedupSolver { } } } - for fully_mapped in info.rule_mappings.keys() { + for fully_mapped in info.constraint_mappings.keys() { info.dependencies.remove(fully_mapped); } if maps_unremovable_var { @@ -334,7 +328,7 @@ impl DedupSolver { fn resolve_dependencies(&mut self) { let mut used_mappings = FxIndexSet::default(); - for indx in 0..self.mappings.len() { + for indx in (0..self.mappings.len()).map(MappingIndex::new) { if used_mappings.contains(&indx) { continue; } @@ -366,12 +360,12 @@ impl DedupSolver { // I'll look into that later, if the rest of this approach is sound fn dfs_search( &self, - mut used_mappings: FxIndexSet, + mut used_mappings: FxIndexSet, mut applied_mappings: Mapping, - from: FxIndexSet, - ) -> Option> { + from: FxIndexSet, + ) -> Option> { for mapping_indx in from.iter() { - let (mapping, _) = self.mappings.get_index(*mapping_indx).unwrap(); + let (mapping, _) = self.mappings.get_index(mapping_indx.index()).unwrap(); if applied_mappings.conflicts_with(mapping) { return None; } @@ -382,14 +376,14 @@ impl DedupSolver { } used_mappings.extend(from.iter()); - let choices: Vec<&FxIndexSet> = + let choices: Vec<&FxIndexSet> = from.iter().flat_map(|x| self.get_mapping_info(*x).dependencies.values()).collect(); if choices.is_empty() { return Some(used_mappings); } let mut choice_indices = vec![0; choices.len()]; while *choice_indices.last().unwrap() < choices.last().unwrap().len() { - let choice: FxIndexSet = choice_indices + let choice: FxIndexSet = choice_indices .iter() .zip(&choices) .map(|(x, y)| *y.get_index(*x).unwrap()) @@ -424,29 +418,29 @@ impl DedupSolver { if self.applied_mappings.borrow().conflicts_with(mapping) { return false; } - self.removed_rules.borrow_mut().extend(info.rule_mappings.keys()); + self.removed_constraints.borrow_mut().extend(info.constraint_mappings.keys()); self.applied_mappings.borrow_mut().0.extend(&mapping.0); true } - fn get_mapping(&self, index: usize) -> &Mapping { - &self.mappings.get_index(index).unwrap().0 + fn get_mapping(&self, index: MappingIndex) -> &Mapping { + &self.mappings.get_index(index.index()).unwrap().0 } - fn get_mapping_info(&self, index: usize) -> &MappingInfo { - &self.mappings.get_index(index).unwrap().1 + fn get_mapping_info(&self, index: MappingIndex) -> &MappingInfo { + &self.mappings.get_index(index.index()).unwrap().1 } } impl Mapping { - fn map_rules(from: &[usize], to: &[usize]) -> Self { + fn map_constraints(from: &[VarIndex], to: &[VarIndex]) -> Self { Self(from.iter().zip(to).map(|(x, y)| (*x, *y)).collect()) } - fn maps_var(&self, rule: usize) -> Option { - self.0.get(&rule).map(|x| *x) + fn maps_var(&self, constraint: VarIndex) -> Option { + self.0.get(&constraint).map(|x| *x) } - fn affects_rule(&self, rule: &[usize]) -> bool { - rule.iter().any(|x| self.maps_var(*x).unwrap_or(*x) != *x) + fn affects_constraint(&self, constraint: &[VarIndex]) -> bool { + constraint.iter().any(|x| self.maps_var(*x).unwrap_or(*x) != *x) } - fn maps_fully(&self, from: &[usize], to: &[usize]) -> bool { + fn maps_fully(&self, from: &[VarIndex], to: &[VarIndex]) -> bool { if from.len() != to.len() { return false; } @@ -468,7 +462,7 @@ impl Mapping { } impl MappingInfo { fn new() -> Self { - Self { dependencies: FxIndexMap::default(), rule_mappings: FxIndexMap::default() } + Self { dependencies: FxIndexMap::default(), constraint_mappings: FxIndexMap::default() } } } From 3a3e40c71dbfbe2532ad350fa2847c2f68176a9c Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Thu, 11 May 2023 13:27:30 -0400 Subject: [PATCH 08/16] Moved deduplication to compute_external_query_constraints instead of canonicalization, reworked constraint_walker to use TypeFolder/TypeFoldable --- .../src/solve/eval_ctxt/canonical.rs | 6 +- .../solve/eval_ctxt/canonical/dedup_solver.rs | 125 ++++++++++ .../dedup_solver/constraint_walker.rs | 221 +++++++++--------- .../eval_ctxt/canonical/dedup_solver/mod.rs | 201 ---------------- .../canonical/dedup_solver/solver.rs | 5 +- .../canonical/dedup_solver/solver/tests.rs | 103 ++++++++ 6 files changed, 343 insertions(+), 318 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs delete mode 100644 compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs create mode 100644 compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 8039e2de4b473..e33a07f5bcbff 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -94,13 +94,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } }; - let mut canonical = Canonicalizer::canonicalize( + let canonical = Canonicalizer::canonicalize( self.infcx, CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, &mut Default::default(), response, ); - dedup_solver::Deduper::dedup(self.infcx.tcx, &mut canonical); Ok(canonical) } @@ -143,7 +142,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // Cannot use `take_registered_region_obligations` as we may compute the response // inside of a `probe` whenever we have multiple choices inside of the solver. let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); - let region_constraints = self.infcx.with_region_constraints(|region_constraints| { + let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { make_query_region_constraints( self.tcx(), region_obligations @@ -152,6 +151,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { region_constraints, ) }); + dedup_solver::Deduper::dedup(self.infcx, self.max_input_universe, &mut region_constraints); let mut opaque_types = self.infcx.clone_opaque_types_for_query_response(); // Only return opaque type keys for newly-defined opaques diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs new file mode 100644 index 0000000000000..f93c3c1e3cc75 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs @@ -0,0 +1,125 @@ +use crate::infer::canonical::QueryRegionConstraints; +use crate::infer::region_constraints::MemberConstraint; +use rustc_infer::infer::InferCtxt; +use rustc_middle::ty; +use ty::{subst::GenericArg, Region, UniverseIndex}; + +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_index::IndexVec; +use std::hash::Hash; + +mod constraint_walker; +mod solver; +use constraint_walker::{DedupWalker, DedupableIndexer}; +use solver::{ConstraintIndex, DedupSolver, VarIndex}; + +pub struct Deduper<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + max_nameable_universe: UniverseIndex, + + var_indexer: DedupableIndexer<'tcx>, + constraint_vars: IndexVec>, + /// Constraints that are identical except for the value of their variables are grouped into the same clique + constraint_cliques: FxIndexMap, Vec>, + /// Maps a constraint index (the index inside constraint_vars) back to its index in outlives + indx_to_outlives: FxHashMap, + /// Maps a constraint index (the index inside constraint_vars) back to its index in member_constraints + indx_to_members: FxHashMap, +} +#[derive(Debug, PartialEq, Eq, Hash)] +enum ConstraintType<'tcx> { + Outlives(Outlives<'tcx>), + Member(MemberConstraint<'tcx>), +} +pub type Outlives<'tcx> = ty::OutlivesPredicate, Region<'tcx>>; + +impl<'a, 'tcx> Deduper<'a, 'tcx> { + pub fn dedup( + infcx: &'a InferCtxt<'tcx>, + max_nameable_universe: UniverseIndex, + constraints: &mut QueryRegionConstraints<'tcx>, + ) { + let mut deduper = Self { + infcx, + max_nameable_universe, + + var_indexer: DedupableIndexer::new(), + constraint_vars: IndexVec::default(), + constraint_cliques: FxIndexMap::default(), + indx_to_outlives: FxHashMap::default(), + indx_to_members: FxHashMap::default(), + }; + deduper.dedup_internal(constraints); + } + fn dedup_internal(&mut self, constraints: &mut QueryRegionConstraints<'tcx>) { + fn dedup_exact(input: &mut Vec) { + *input = FxIndexSet::::from_iter(input.clone()).into_iter().collect(); + } + dedup_exact(&mut constraints.outlives); + dedup_exact(&mut constraints.member_constraints); + + self.lower_constraints_into_solver(constraints); + let constraint_vars = std::mem::take(&mut self.constraint_vars); + let constraint_cliques = + std::mem::take(&mut self.constraint_cliques).into_iter().map(|x| x.1).collect(); + let unremovable_vars = + self.var_indexer.unremovable_vars.iter().map(|x| VarIndex::from(*x)).collect(); + let removed = DedupSolver::dedup(constraint_vars, constraint_cliques, unremovable_vars) + .removed_constraints; + + let mut removed_outlives = + removed.iter().filter_map(|x| self.indx_to_outlives.get(x)).collect::>(); + let mut removed_members = + removed.iter().filter_map(|x| self.indx_to_members.get(x)).collect::>(); + removed_outlives.sort(); + removed_members.sort(); + + for removed_outlive in removed_outlives.into_iter().rev() { + constraints.outlives.swap_remove(*removed_outlive); + } + for removed_member in removed_members.into_iter().rev() { + constraints.member_constraints.swap_remove(*removed_member); + } + } + fn lower_constraints_into_solver(&mut self, constraints: &QueryRegionConstraints<'tcx>) { + for (outlives_indx, outlives) in constraints.outlives.iter().enumerate() { + let (erased, vars) = DedupWalker::erase_dedupables( + self.infcx, + &mut self.var_indexer, + self.max_nameable_universe, + outlives.0.clone(), + ); + self.insert_constraint(vars, ConstraintType::Outlives(erased), outlives_indx); + } + for (member_indx, member) in constraints.member_constraints.iter().enumerate() { + let (erased, vars) = DedupWalker::erase_dedupables( + self.infcx, + &mut self.var_indexer, + self.max_nameable_universe, + member.clone(), + ); + self.insert_constraint(vars, ConstraintType::Member(erased), member_indx); + } + } + fn insert_constraint( + &mut self, + vars: Vec, + erased: ConstraintType<'tcx>, + original_indx: usize, + ) { + if vars.is_empty() { + return; + } + let constraint_indx = self.constraint_vars.next_index(); + match erased { + ConstraintType::Outlives(_) => { + self.indx_to_outlives.insert(constraint_indx, original_indx) + } + ConstraintType::Member(_) => { + self.indx_to_members.insert(constraint_indx, original_indx) + } + }; + self.constraint_vars.push(vars.into_iter().map(VarIndex::from).collect()); + self.constraint_cliques.entry(erased).or_insert_with(Vec::new).push(constraint_indx); + } +} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs index 88ab3f7668176..cb42fe1dbb5ef 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs @@ -1,133 +1,130 @@ -use crate::infer::region_constraints::MemberConstraint; +use rustc_data_structures::fx::FxIndexSet; +use rustc_infer::infer::InferCtxt; use rustc_middle::ty; -use ty::subst::{GenericArg, GenericArgKind}; -use ty::{Const, OutlivesPredicate, Placeholder, Region, Ty, TyCtxt}; +use rustc_middle::ty::{Const, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_data_structures::sync::Lrc; +pub struct DedupWalker<'me, 'tcx> { + infcx: &'me InferCtxt<'tcx>, + var_indexer: &'me mut DedupableIndexer<'tcx>, + max_nameable_universe: ty::UniverseIndex, -pub type Outlives<'tcx> = OutlivesPredicate, Region<'tcx>>; + vars_present: Vec, +} +pub struct DedupableIndexer<'tcx> { + vars: FxIndexSet>, + pub unremovable_vars: FxIndexSet, +} +#[derive(Hash, PartialEq, Eq)] +enum DedupVar<'tcx> { + Region(Region<'tcx>), + Ty(Ty<'tcx>), + Const(Const<'tcx>), +} -/// Walks over constraints and fetches variables present in the constraint, in order -/// Also has the ability to re-write the variables there -pub struct ConstraintWalker<'tcx, 'a> { - tcx: TyCtxt<'tcx>, - fetch_var: &'a mut dyn FnMut(usize) -> usize, - pub vars: Vec, +impl<'me, 'tcx> DedupWalker<'me, 'tcx> { + pub fn erase_dedupables>>( + infcx: &'me InferCtxt<'tcx>, + var_indexer: &'me mut DedupableIndexer<'tcx>, + max_nameable_universe: ty::UniverseIndex, + value: T, + ) -> (T, Vec) { + let mut dedup_walker = + Self { infcx, var_indexer, max_nameable_universe, vars_present: Vec::new() }; + let folded = value.fold_with(&mut dedup_walker); + (folded, dedup_walker.vars_present) + } } -impl<'tcx, 'a> ConstraintWalker<'tcx, 'a> { - pub fn new(tcx: TyCtxt<'tcx>, fetch_var: &'a mut dyn FnMut(usize) -> usize) -> Self { - Self { tcx, fetch_var: fetch_var, vars: Vec::new() } +impl<'tcx> DedupableIndexer<'tcx> { + pub fn new() -> Self { + Self { vars: FxIndexSet::default(), unremovable_vars: FxIndexSet::default() } } - pub fn add_var(&mut self, var: usize) -> usize { - self.vars.push(var); - return (self.fetch_var)(var); + fn lookup(&mut self, var: DedupVar<'tcx>) -> usize { + self.vars.get_index_of(&var).unwrap_or_else(|| self.vars.insert_full(var).0) } + fn add_unremovable_var(&mut self, var: usize) { + self.unremovable_vars.insert(var); + } +} - // The walk functions recursively walk over an Enum, extracting the variables present inside (in order) - // Then, a substitution for each variable is computed using the fetch_var closure stored as a property - // If we don't want to re-write variables, we can just use |x| x as the fetch_var closure +impl<'tcx> TypeFolder> for DedupWalker<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } - pub fn walk_outlives(&mut self, input: &Outlives<'tcx>) -> Outlives<'tcx> { - ty::OutlivesPredicate( - self.walk_generic_arg(input.0.clone()), - self.walk_region(input.1.clone()), - ) + fn fold_binder>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { + t.super_fold_with(self) } - pub fn walk_members(&mut self, input: &MemberConstraint<'tcx>) -> MemberConstraint<'tcx> { - MemberConstraint { - key: ty::OpaqueTypeKey { - def_id: input.key.def_id, - substs: self.walk_substs_ref(input.key.substs), - }, - definition_span: input.definition_span, - hidden_ty: self.walk_ty(input.hidden_ty), - member_region: self.walk_region(input.member_region), - choice_regions: Lrc::new( - input.choice_regions.iter().map(|x| self.walk_region(*x)).collect::>(), - ), + + fn fold_region(&mut self, region: Region<'tcx>) -> Region<'tcx> { + let universe = match *region { + ty::ReVar(..) | ty::RePlaceholder(..) => self.infcx.universe_of_region(region), + _ => return region, + }; + let var_id = self.var_indexer.lookup(DedupVar::Region(region)); + self.vars_present.push(var_id); + if self.max_nameable_universe.can_name(universe) { + self.var_indexer.add_unremovable_var(var_id); } + // dummy value + self.interner().mk_re_placeholder(ty::Placeholder { + universe: ty::UniverseIndex::from(self.max_nameable_universe.index() + 1), + bound: ty::BoundRegion { + var: ty::BoundVar::from_usize(0), + kind: ty::BoundRegionKind::BrEnv, + }, + }) } - fn walk_generic_arg(&mut self, input: GenericArg<'tcx>) -> GenericArg<'tcx> { - match input.unpack() { - GenericArgKind::Lifetime(region) => GenericArg::<'tcx>::from(self.walk_region(region)), - GenericArgKind::Const(const_var) => { - GenericArg::<'tcx>::from(self.walk_const(const_var)) + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + let universe = match *ty.kind() { + ty::Placeholder(p) => p.universe, + ty::Infer(ty::InferTy::TyVar(vid)) => { + if let Err(uni) = self.infcx.probe_ty_var(vid) { + uni + } else { + return ty; + } } - _ => input, + _ => return ty, + }; + let var_id = self.var_indexer.lookup(DedupVar::Ty(ty)); + self.vars_present.push(var_id); + if self.max_nameable_universe.can_name(universe) { + self.var_indexer.add_unremovable_var(var_id); } + // dummy value + self.interner().mk_ty_from_kind(ty::Placeholder(ty::Placeholder { + universe: ty::UniverseIndex::from(self.max_nameable_universe.index() + 1), + bound: ty::BoundTy { var: ty::BoundVar::from_usize(0), kind: ty::BoundTyKind::Anon }, + })) } - fn walk_region(&mut self, input: Region<'tcx>) -> Region<'tcx> { - let rewritten = match input.kind() { - // FIXME: Are these all of the variants that can have variables? - ty::ReLateBound(db_indx, bound_region) => { - ty::ReLateBound(db_indx, self.walk_bound_region(bound_region)) - } - ty::ReVar(region_id) => { - ty::ReVar(ty::RegionVid::from_usize(self.add_var(region_id.index()))) + + fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> { + let new_ty = self.fold_ty(ct.ty()); + let universe = match ct.kind() { + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + if let Err(uni) = self.infcx.probe_const_var(vid) { Some(uni) } else { None } } - ty::RePlaceholder(region) => ty::RePlaceholder(Placeholder { - universe: region.universe, - bound: self.walk_bound_region(region.bound), - }), - _ => return input, + ty::ConstKind::Placeholder(p) => Some(p.universe), + _ => None, }; - self.tcx.mk_region_from_kind(rewritten) - } - fn walk_ty(&mut self, input: Ty<'tcx>) -> Ty<'tcx> { - let rewritten = match input.kind() { - // FIXME: Quite a few are missing - ty::Adt(adt_def, substs) => ty::Adt(*adt_def, self.walk_substs_ref(substs)), - ty::Array(elem_ty, count) => ty::Array(self.walk_ty(*elem_ty), self.walk_const(*count)), - ty::Slice(elem_ty) => ty::Slice(self.walk_ty(*elem_ty)), - ty::RawPtr(ptr) => { - ty::RawPtr(ty::TypeAndMut { ty: self.walk_ty(ptr.ty), mutbl: ptr.mutbl }) + let new_const_kind = if let Some(uni) = universe { + let var_id = self.var_indexer.lookup(DedupVar::Const(ct)); + self.vars_present.push(var_id); + if self.max_nameable_universe.can_name(uni) { + self.var_indexer.add_unremovable_var(var_id); } - ty::Ref(ref_region, ref_ty, ref_mutbl) => { - ty::Ref(self.walk_region(*ref_region), self.walk_ty(*ref_ty), *ref_mutbl) - } - ty::FnDef(def_id, substs) => ty::FnDef(*def_id, self.walk_substs_ref(substs)), - ty::Tuple(elems) => ty::Tuple( - self.tcx - .mk_type_list(&elems.into_iter().map(|x| self.walk_ty(x)).collect::>()), - ), - ty::Bound(indx, bound_ty) => ty::Bound(*indx, self.walk_bound_ty(*bound_ty)), - ty::Placeholder(placeholder) => ty::Placeholder(Placeholder { - universe: placeholder.universe, - bound: self.walk_bound_ty(placeholder.bound), - }), - _ => return input, + // dummy value + ty::ConstKind::Placeholder(ty::Placeholder { + universe: ty::UniverseIndex::from(self.max_nameable_universe.index() + 1), + bound: ty::BoundVar::from_usize(0), + }) + } else { + ct.kind() }; - self.tcx.mk_ty_from_kind(rewritten) - } - fn walk_const(&mut self, input: Const<'tcx>) -> Const<'tcx> { - let rewritten_ty = self.walk_ty(input.ty()); - match input.kind() { - ty::ConstKind::Param(param) => self.tcx.mk_const( - ty::ParamConst { - index: self.add_var(param.index as usize) as u32, - name: param.name, - }, - rewritten_ty, - ), - _ => input, - } - } - fn walk_bound_region(&mut self, input: ty::BoundRegion) -> ty::BoundRegion { - ty::BoundRegion { - var: ty::BoundVar::from_usize(self.add_var(input.var.index())), - kind: input.kind, - } - } - fn walk_bound_ty(&mut self, input: ty::BoundTy) -> ty::BoundTy { - ty::BoundTy { - var: ty::BoundVar::from_usize(self.add_var(input.var.index())), - kind: input.kind, - } - } - fn walk_substs_ref( - &mut self, - input: &'tcx ty::List>, - ) -> &'tcx ty::List> { - self.tcx.mk_substs(&input.into_iter().map(|x| self.walk_generic_arg(x)).collect::>()) + self.infcx.tcx.mk_const(new_const_kind, new_ty) } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs deleted file mode 100644 index 474a9e92c0c16..0000000000000 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/mod.rs +++ /dev/null @@ -1,201 +0,0 @@ -use crate::infer::canonical::{Canonical, CanonicalVarInfos}; -use crate::infer::region_constraints::MemberConstraint; -use crate::solve::{ExternalConstraintsData, Response}; -use rustc_middle::ty::{TyCtxt, UniverseIndex}; - -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; -use rustc_index::{Idx, IndexVec}; -use std::hash::Hash; -use std::ops::Deref; - -mod constraint_walker; -mod solver; -use constraint_walker::{ConstraintWalker, Outlives}; -use solver::{ConstraintIndex, DedupSolver, VarIndex}; - -pub struct Deduper<'tcx> { - tcx: TyCtxt<'tcx>, - constraint_vars: IndexVec>, - constraint_cliques: FxIndexMap, Vec>, - /// Maps a constraint index (the index inside constraint_vars) back to its index in outlives - indx_to_outlives: FxHashMap, - /// Maps a constraint index (the index inside constraint_vars) back to its index in member_constraints - indx_to_members: FxHashMap, -} -#[derive(Debug, PartialEq, Eq, Hash)] -enum ConstraintType<'tcx> { - Outlives(Outlives<'tcx>), - Member(MemberConstraint<'tcx>), -} - -impl<'tcx> Deduper<'tcx> { - pub fn dedup(tcx: TyCtxt<'tcx>, input: &mut Canonical<'tcx, Response<'tcx>>) { - let mut constraints = input.value.external_constraints.deref().clone(); - let mut deduper = Self { - tcx, - constraint_vars: IndexVec::new(), - constraint_cliques: FxIndexMap::default(), - indx_to_outlives: FxHashMap::default(), - indx_to_members: FxHashMap::default(), - }; - deduper.dedup_internal(&mut constraints, &mut input.variables, &mut input.max_universe); - input.value.external_constraints = tcx.mk_external_constraints(constraints); - } - fn dedup_internal( - &mut self, - constraints: &mut ExternalConstraintsData<'tcx>, - variables: &mut CanonicalVarInfos<'tcx>, - max_universe: &mut UniverseIndex, - ) { - constraints.region_constraints.outlives = - FxIndexSet::<_>::from_iter(constraints.region_constraints.outlives.clone().into_iter()) - .into_iter() - .collect(); - constraints.region_constraints.member_constraints = FxIndexSet::<_>::from_iter( - constraints.region_constraints.member_constraints.clone().into_iter(), - ) - .into_iter() - .collect(); - - let dedupable_vars: FxIndexSet = variables - .iter() - .enumerate() - .filter(|(_, var)| var.universe() > UniverseIndex::ROOT) - .map(|(indx, _)| VarIndex::new(indx)) - .collect(); - - self.extract_constraint_data(constraints, variables); - - let constraint_vars = std::mem::take(&mut self.constraint_vars); - let constraint_cliques = - std::mem::take(&mut self.constraint_cliques).into_values().collect::>(); - let unremovable_vars: FxIndexSet<_> = (0..variables.len()) - .map(VarIndex::new) - .filter(|x| !dedupable_vars.contains(x)) - .collect(); - - let solve_result = - DedupSolver::dedup(constraint_vars, constraint_cliques, unremovable_vars); - self.remove_duplicate_constraints(&solve_result.removed_constraints, constraints); - self.compress_variables(&solve_result.removed_vars, constraints, variables, max_universe); - } - // Extracts data about each constraint, i.e. the variables present, as well as the constraint - // categories - fn extract_constraint_data( - &mut self, - constraints: &mut ExternalConstraintsData<'tcx>, - variables: &mut CanonicalVarInfos<'tcx>, - ) { - let num_vars = variables.len(); - // dummy_var_rewriter is the fetch_var function that will be given to ConstraintWalker - // it re-writes all variables with a dummy value (num_vars - guaranteed to NOT be a var index), - // allowing us to compare constraints based solely on their structure, not on the variables present - // Used to compute constraint categories - let mut dummy_var_rewriter = |_| num_vars; - - for (indx, outlives) in constraints.region_constraints.outlives.iter().enumerate() { - let mut extractor = ConstraintWalker::new(self.tcx, &mut dummy_var_rewriter); - let erased = ConstraintType::Outlives(extractor.walk_outlives(&outlives.0)); - let vars: Vec<_> = extractor.vars.iter().map(|x| VarIndex::new(*x)).collect(); - if vars.is_empty() { - continue; - } - self.process_constraint_data(indx, erased, vars); - } - for (indx, member) in constraints.region_constraints.member_constraints.iter().enumerate() { - let mut extractor = ConstraintWalker::new(self.tcx, &mut dummy_var_rewriter); - let erased = ConstraintType::Member(extractor.walk_members(member)); - let vars: Vec<_> = extractor.vars.iter().map(|x| VarIndex::new(*x)).collect(); - if vars.is_empty() { - continue; - } - self.process_constraint_data(indx, erased, vars); - } - } - fn process_constraint_data( - &mut self, - input_indx: usize, - erased: ConstraintType<'tcx>, - vars: Vec, - ) { - let constraint_indx = self.constraint_vars.next_index(); - self.constraint_vars.push(vars); - match &erased { - ConstraintType::Outlives(_) => &mut self.indx_to_outlives, - ConstraintType::Member(_) => &mut self.indx_to_members, - } - .insert(constraint_indx, input_indx); - self.constraint_cliques.entry(erased).or_insert_with(Vec::new).push(constraint_indx); - } - fn remove_duplicate_constraints( - &mut self, - to_remove: &FxIndexSet, - constraints: &mut ExternalConstraintsData<'tcx>, - ) { - let mut remove_outlives: FxIndexSet = - to_remove.iter().filter_map(|x| self.indx_to_outlives.get(x)).cloned().collect(); - let mut remove_members: FxIndexSet = - to_remove.iter().filter_map(|x| self.indx_to_members.get(x)).cloned().collect(); - remove_outlives.sort(); - remove_members.sort(); - - for indx in remove_outlives.into_iter().rev() { - constraints.region_constraints.outlives.swap_remove(indx); - } - for indx in remove_members.into_iter().rev() { - constraints.region_constraints.member_constraints.swap_remove(indx); - } - } - fn compress_variables( - &mut self, - removed_vars: &FxIndexSet, - constraints: &mut ExternalConstraintsData<'tcx>, - variables: &mut CanonicalVarInfos<'tcx>, - max_universe: &mut UniverseIndex, - ) { - let mut vars = variables.as_slice().to_vec(); - let mut universes_available: FxIndexSet = - vars.iter().map(|x| x.universe()).collect(); - universes_available.sort(); - - let mut compressed_vars: FxHashMap = FxHashMap::default(); - let mut universes_used: FxIndexSet = FxIndexSet::default(); - - let mut num_removed = 0; - let mut var_indx = VarIndex::new(0); - while var_indx.index() < vars.len() { - let original_var_indx = var_indx.plus(num_removed); - if removed_vars.contains(&original_var_indx) { - num_removed += 1; - vars.remove(var_indx.index()); - continue; - } - compressed_vars.insert(original_var_indx, var_indx.index()); - universes_used.insert(vars[var_indx.index()].universe()); - var_indx.increment_by(1); - } - universes_used.sort(); - - for var in vars.iter_mut() { - *var = var.with_updated_universe( - *universes_available - .get_index(universes_used.get_index_of(&var.universe()).unwrap()) - .unwrap(), - ); - } - - let mut var_rewriter = - |var| compressed_vars.get(&VarIndex::from(var)).cloned().unwrap_or(var); - for outlives in constraints.region_constraints.outlives.iter_mut() { - let mut walker = ConstraintWalker::new(self.tcx, &mut var_rewriter); - outlives.0 = walker.walk_outlives(&outlives.0); - } - for member in constraints.region_constraints.member_constraints.iter_mut() { - let mut walker = ConstraintWalker::new(self.tcx, &mut var_rewriter); - *member = walker.walk_members(member); - } - - *variables = self.tcx.mk_canonical_var_infos(&vars); - *max_universe = UniverseIndex::from(universes_used.len().saturating_sub(1)); - } -} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs index c01bc2fefbd73..808faea2a8e9f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -3,6 +3,9 @@ use rustc_index::{Idx, IndexVec}; use std::cell::RefCell; use std::collections::BTreeMap; +#[cfg(test)] +mod tests; + rustc_index::newtype_index! { pub struct VarIndex {} } rustc_index::newtype_index! { pub struct ConstraintIndex {} } rustc_index::newtype_index! { @@ -465,5 +468,3 @@ impl MappingInfo { Self { dependencies: FxIndexMap::default(), constraint_mappings: FxIndexMap::default() } } } - -// FIXME: Tests that test the solver on its own have been deleted cuz tidy check won't stop yelling at me - add back later diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs new file mode 100644 index 0000000000000..c34e7527ec3bf --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs @@ -0,0 +1,103 @@ +use super::*; + +fn constraint_vars(input: Vec>) -> IndexVec> { + input + .into_iter() + .map(|constraint| constraint.into_iter().map(|x| VarIndex::new(x)).collect()) + .collect() +} +fn constraint_cliques(input: Vec>) -> IndexVec> { + input + .into_iter() + .map(|clique| clique.into_iter().map(|x| ConstraintIndex::new(x)).collect()) + .collect() +} +fn constraint_set(input: [usize; N]) -> FxIndexSet { + FxIndexSet::from_iter(input.into_iter().map(|x| ConstraintIndex::new(x))) +} + +#[test] +fn test_noop() { + let deduped = DedupSolver::dedup( + constraint_vars(vec![vec![1], vec![1, 1], vec![2], vec![3]]), + constraint_cliques(vec![vec![0, 1], vec![2], vec![3]]), + FxIndexSet::default(), + ); + assert!(deduped.removed_constraints.is_empty()); +} +#[test] +fn test_simple() { + let deduped = DedupSolver::dedup( + constraint_vars(vec![vec![1], vec![2], vec![3]]), + constraint_cliques(vec![vec![0, 1], vec![2]]), + FxIndexSet::default(), + ); + assert!([constraint_set([0]), constraint_set([1])].contains(&deduped.removed_constraints)); +} +#[test] +fn test_dependencies() { + let deduped = DedupSolver::dedup( + constraint_vars(vec![ + vec![1, 2, 13], + vec![4, 5, 16], + vec![1, 2, 23], + vec![4, 5, 26], + vec![1, 2], + vec![4, 5], + ]), + constraint_cliques(vec![vec![0, 1], vec![2, 3], vec![4, 5]]), + FxIndexSet::default(), + ); + assert!( + [constraint_set([0, 2, 4]), constraint_set([1, 3, 5])] + .contains(&deduped.removed_constraints) + ); +} +#[test] +fn test_unremovable_var() { + fn try_dedup(unremovable_vars: FxIndexSet) -> FxIndexSet { + DedupSolver::dedup( + constraint_vars(vec![ + vec![1, 2, 13], + vec![4, 5, 16], + vec![1, 2, 23], + vec![4, 5, 26], + vec![1, 2], + vec![4, 5], + ]), + constraint_cliques(vec![vec![0, 1], vec![2, 3], vec![4, 5]]), + unremovable_vars, + ) + .removed_constraints + } + assert_eq!(try_dedup(FxIndexSet::from_iter([VarIndex::new(13)])), constraint_set([1, 3, 5])); + assert_eq!(try_dedup(FxIndexSet::from_iter([VarIndex::new(16)])), constraint_set([0, 2, 4])); +} +#[test] +fn test_dependencies_unresolvable() { + let deduped = DedupSolver::dedup( + constraint_vars(vec![ + vec![1, 2, 13], + vec![4, 5, 16], + vec![1, 2, 23], + vec![4, 6, 26], + vec![1, 2], + vec![4, 5], + ]), + constraint_cliques(vec![vec![0, 1], vec![2, 3], vec![4, 5]]), + FxIndexSet::default(), + ); + assert!(deduped.removed_constraints.is_empty()); +} +#[test] +fn test_gh_issues_example() { + let deduped = DedupSolver::dedup( + constraint_vars(vec![vec![1], vec![2], vec![3]]), + constraint_cliques(vec![vec![0, 1, 2]]), + FxIndexSet::default(), + ); + assert!( + [constraint_set([0, 1]), constraint_set([0, 2]), constraint_set([1, 2])] + .contains(&deduped.removed_constraints) + ); +} From 4e10821918c44469f4e393a30b395a5886970216 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Sun, 14 May 2023 03:23:52 -0400 Subject: [PATCH 09/16] Added more comments + slight cleanup to code --- .../solve/eval_ctxt/canonical/dedup_solver.rs | 5 + .../dedup_solver/constraint_walker.rs | 20 +- .../canonical/dedup_solver/solver.rs | 188 ++++++++++-------- .../canonical/dedup_solver/solver/tests.rs | 51 +++-- 4 files changed, 156 insertions(+), 108 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs index f93c3c1e3cc75..c0aba692898c2 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs @@ -1,3 +1,8 @@ +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(dead_code)] +#![allow(unreachable_code)] + use crate::infer::canonical::QueryRegionConstraints; use crate::infer::region_constraints::MemberConstraint; use rustc_infer::infer::InferCtxt; diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs index cb42fe1dbb5ef..2e74bda4df4db 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs @@ -1,7 +1,9 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_infer::infer::InferCtxt; use rustc_middle::ty; -use rustc_middle::ty::{Const, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{ + Const, GenericArg, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, +}; pub struct DedupWalker<'me, 'tcx> { infcx: &'me InferCtxt<'tcx>, @@ -11,15 +13,9 @@ pub struct DedupWalker<'me, 'tcx> { vars_present: Vec, } pub struct DedupableIndexer<'tcx> { - vars: FxIndexSet>, + vars: FxIndexSet>, pub unremovable_vars: FxIndexSet, } -#[derive(Hash, PartialEq, Eq)] -enum DedupVar<'tcx> { - Region(Region<'tcx>), - Ty(Ty<'tcx>), - Const(Const<'tcx>), -} impl<'me, 'tcx> DedupWalker<'me, 'tcx> { pub fn erase_dedupables>>( @@ -38,7 +34,7 @@ impl<'tcx> DedupableIndexer<'tcx> { pub fn new() -> Self { Self { vars: FxIndexSet::default(), unremovable_vars: FxIndexSet::default() } } - fn lookup(&mut self, var: DedupVar<'tcx>) -> usize { + fn lookup(&mut self, var: GenericArg<'tcx>) -> usize { self.vars.get_index_of(&var).unwrap_or_else(|| self.vars.insert_full(var).0) } fn add_unremovable_var(&mut self, var: usize) { @@ -63,7 +59,7 @@ impl<'tcx> TypeFolder> for DedupWalker<'_, 'tcx> { ty::ReVar(..) | ty::RePlaceholder(..) => self.infcx.universe_of_region(region), _ => return region, }; - let var_id = self.var_indexer.lookup(DedupVar::Region(region)); + let var_id = self.var_indexer.lookup(GenericArg::from(region)); self.vars_present.push(var_id); if self.max_nameable_universe.can_name(universe) { self.var_indexer.add_unremovable_var(var_id); @@ -90,7 +86,7 @@ impl<'tcx> TypeFolder> for DedupWalker<'_, 'tcx> { } _ => return ty, }; - let var_id = self.var_indexer.lookup(DedupVar::Ty(ty)); + let var_id = self.var_indexer.lookup(GenericArg::from(ty)); self.vars_present.push(var_id); if self.max_nameable_universe.can_name(universe) { self.var_indexer.add_unremovable_var(var_id); @@ -112,7 +108,7 @@ impl<'tcx> TypeFolder> for DedupWalker<'_, 'tcx> { _ => None, }; let new_const_kind = if let Some(uni) = universe { - let var_id = self.var_indexer.lookup(DedupVar::Const(ct)); + let var_id = self.var_indexer.lookup(GenericArg::from(ct)); self.vars_present.push(var_id); if self.max_nameable_universe.can_name(uni) { self.var_indexer.add_unremovable_var(var_id); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs index 808faea2a8e9f..aab7ce1b04f0e 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -18,11 +18,16 @@ rustc_index::newtype_index! { pub struct MappingIndex {} } #[derive(Debug)] pub struct DedupSolver { /// The variables present in each constraint - the inner vec contains the variables, in the order - /// that they appear in the constraint + /// that they appear in the constraint. See solver/tests.rs for examples on how constraints are lowered to this format constraint_vars: IndexVec>, - /// The categories that constraints can be partitioned into - the inner vec contains all the constraints - /// that are in the same category + /// The cliques that constraints are partitioned into. These are determined as follows: imagine a graph where + /// each constraint is a vertex, and an edge exists between a pair of constraints if there is a many-to-one mapping of + /// variables that perfectly maps one constraint onto the other. The constraint cliques are just cliques within this graph. + /// By nature of this problem, it is impossible for a constraint to be in two cliques constraint_cliques: IndexVec>, + /// A set of variables we cannot remove, i.e. they belong to a universe that the caller can name. We keep track of these + /// to determine if there's a variable that we **can** remove that behaves like one of these, where in that case we just + /// remove the unremovable var and keep the removable ones unremovable_vars: FxIndexSet, /// The below are internal variables used in the solving process: @@ -37,14 +42,13 @@ pub struct DedupSolver { #[derive(Debug)] pub struct DedupResult { pub removed_constraints: FxIndexSet, - pub removed_vars: FxIndexSet, } #[derive(Clone, Hash, PartialEq, Eq, Debug)] struct Mapping(BTreeMap); #[derive(Debug, Clone, PartialEq, Eq)] struct MappingInfo { dependencies: FxIndexMap>, - constraint_mappings: FxIndexMap, + eliminated_constraints: FxIndexSet, } #[derive(Debug, PartialEq, Eq)] enum MapEvalErr { @@ -71,14 +75,7 @@ impl DedupSolver { deduper.compute_mappings(); deduper.resolve_dependencies(); - let mut removed_vars = FxIndexSet::default(); - for (from, to) in deduper.applied_mappings.borrow().0.iter() { - if *from == *to { - continue; - } - removed_vars.insert(*from); - } - DedupResult { removed_constraints: deduper.removed_constraints.into_inner(), removed_vars } + DedupResult { removed_constraints: deduper.removed_constraints.into_inner() } } fn refine_cliques(&mut self) { // Refine categories based on shape @@ -150,7 +147,8 @@ impl DedupSolver { } } } - /// Returns the "shape" of a constraint - related to the idea of de bruijn indices + /// Returns the "shape" of a constraint, which captures information about the location(s) and + /// multiplicity of variables in the constraint, irrespective of the actual variable indices /// For example, a constraint involving the vars [1, 1, 2, 3] has a shape of [0, 0, 1, 2], /// and a constraint involving vars [3, 4] has a shape of [0, 1] /// It takes a mutable reference to the vars because it also removes duplicates from @@ -176,6 +174,7 @@ impl DedupSolver { /// Computes the set of all possible mappings /// If a mapping has no dependencies, then it's eagerly taken, to increase performance + /// If a mapping has dependencies, then it's added to `self.mappings` /// Deduplication can be done greedily because if two constraints can be merged, then they're /// equivalent in every way, including in relations to other constraints fn compute_mappings(&mut self) { @@ -191,6 +190,7 @@ impl DedupSolver { .skip(n + 1) .filter(|x| !self.removed_constraints.borrow().contains(*x)) { + // Maps constraint_1 to constraint_2 let forward = Mapping::map_constraints( &self.constraint_vars[*constraint_1], &self.constraint_vars[*constraint_2], @@ -198,6 +198,7 @@ impl DedupSolver { if invalid_maps.contains(&forward) || self.mappings.contains_key(&forward) { continue; } + // Maps constraint_2 to constraint_1 let reverse = Mapping::map_constraints( &self.constraint_vars[*constraint_2], &self.constraint_vars[*constraint_1], @@ -206,6 +207,13 @@ impl DedupSolver { continue; } + // if constraint_1 and constraint_2 can be merged, this relation should be + // bidirectional, i.e. we can merge 1 into 2 or 2 into 1 + // For example, if a clique contains constraints [1, 2] and [11, 12] and another + // clique contains constraint [1], then we **cannot** merge vars 1 and 11 - the + // reverse direction (merging 11 into 1) works (if we map 11 to 1 and 12 to 2), + // but the forward direction (merging 1 into 11) doesn't work, as this would + // map the constraint [1] into [11], which is a constraint that doesn't exist let (eval_forward, eval_reverse) = (self.eval_mapping(&forward), self.eval_mapping(&reverse)); if eval_forward == Err(MapEvalErr::Conflicts) @@ -230,27 +238,76 @@ impl DedupSolver { } self.resolve_dependencies_to_mapping(); } - /// Currently, dependencies are in the form FxIndexMap, - /// where A is a constraint that must be mapped by another mapping. We must - /// populate the EmptyFxIndexSet with a set of mappings that can map A without + /// Evaluates the mapping. Can return None if the mapping is invalid (i.e. it maps + /// some constraints onto a constraint that doesn't exist, or conflicts with the + /// mappings that were already greedily applied). Otherwise, returns MappingInfo. + /// MappingInfo can contain dependencies - these occur if a mapping *partially* maps + /// a constraint onto another, so the mapping isn't immediately invalid, but we do need + /// another mapping to complete that partial map for it to actually be valid + fn eval_mapping(&self, mapping: &Mapping) -> Result { + let maps_unremovable_var = + mapping.0.iter().any(|(from, to)| self.unremovable_vars.contains(from) && from != to); + + let mut info = MappingInfo::new(); + for clique in self.constraint_cliques.iter() { + for constraint_1 in clique { + let vars_1 = &self.constraint_vars[*constraint_1]; + if !mapping.affects_constraint(vars_1) { + continue; + } + let mut found_non_conflicting = false; + for constraint_2 in clique.iter() { + let vars_2 = &self.constraint_vars[*constraint_2]; + let trial_mapping = Mapping::map_constraints(vars_1, vars_2); + if mapping.conflicts_with(&trial_mapping) { + continue; + } + found_non_conflicting = true; + // Only maps a subset of variables in constraint_1 + if !mapping.contains_fully(&trial_mapping) { + // The input mapping can be applied only if there's another mapping that + // maps every variable in constraint_1 (and doesn't conflict with the input mapping) + info.dependencies.insert(*constraint_1, FxIndexSet::default()); + continue; + } + if *constraint_1 != *constraint_2 { + info.eliminated_constraints.insert(*constraint_1); + } + } + if !found_non_conflicting { + return Err(MapEvalErr::Conflicts); + } + } + } + if maps_unremovable_var { + return Err(MapEvalErr::Unremovable); + } + Ok(info) + } + /// Currently, dependencies are in the form FxIndexMap, + /// where ConstraintIndex is the constraint we must *also* map in order to apply this mapping. + /// We must populate the Empty FxIndexSet with a set of mappings that can map the constraint without /// conflicting with the current mapping fn resolve_dependencies_to_mapping(&mut self) { self.mappings.retain(|mapping, mapping_info| { + // Remove mappings that conflict with already-applied mappings if self.applied_mappings.borrow().conflicts_with(mapping) { return false; } + // If a constraint has already been removed by a pre-existing mapping, this current + // mapping's dependency on this constraint has been resolved mapping_info .dependencies .retain(|dependency, _| !self.removed_constraints.borrow().contains(dependency)); true }); - // A map from a constraint to the mappings that will eliminate it + // A map from a constraint to the mappings that will eliminate it (i.e. map it fully) let mut constraint_mappings: FxIndexMap> = FxIndexMap::default(); for (indx, (_, mapping_info)) in self.mappings.iter().enumerate() { - for (from_constraint, _) in mapping_info.constraint_mappings.iter() { + for eliminated_constraint in mapping_info.eliminated_constraints.iter() { constraint_mappings - .entry(*from_constraint) + .entry(*eliminated_constraint) .or_insert_with(FxIndexSet::default) .insert(MappingIndex::new(indx)); } @@ -260,6 +317,7 @@ impl DedupSolver { let input_dependencies = &self.get_mapping_info(indx).dependencies; let mut dependencies = IndexVec::new(); for (dependency, _) in input_dependencies.iter() { + // The set of mappings that can resolve this dependency let mut resolve_options = FxIndexSet::default(); if let Some(resolve_mappings) = constraint_mappings.get(dependency) { resolve_options.extend( @@ -281,54 +339,9 @@ impl DedupSolver { dependencies.into_iter_enumerated().collect(); } } - /// Evaluates the mapping. Can return None if the mapping is invalid (i.e. it maps - /// some constraints onto a constraint that doesn't exist, or conflicts with the - /// mappings that were already greedily applied). Otherwise, returns MappingInfo. - /// MappingInfo can contain dependencies - these occur if a mapping *partially* maps - /// a constraint onto another, so the mapping isn't immediately invalid, but we do need - /// another mapping to complete that partial map for it to actually be valid - fn eval_mapping(&self, mapping: &Mapping) -> Result { - let maps_unremovable_var = - mapping.0.iter().any(|(from, to)| self.unremovable_vars.contains(from) && from != to); - - let mut info = MappingInfo::new(); - for clique in self.constraint_cliques.iter() { - for constraint_1 in clique { - let vars_1 = &self.constraint_vars[*constraint_1]; - if !mapping.affects_constraint(vars_1) { - continue; - } - let mut found_non_conflicting = false; - for constraint_2 in clique.iter() { - let vars_2 = &self.constraint_vars[*constraint_2]; - let trial_mapping = Mapping::map_constraints(vars_1, vars_2); - if mapping.conflicts_with(&trial_mapping) { - continue; - } - found_non_conflicting = true; - // Only maps a subset of variables in constraint_1 - if !mapping.maps_fully(vars_1, vars_2) { - info.dependencies.insert(*constraint_1, FxIndexSet::default()); - continue; - } - if *constraint_1 != *constraint_2 { - info.constraint_mappings.insert(*constraint_1, *constraint_2); - } - } - if !found_non_conflicting { - return Err(MapEvalErr::Conflicts); - } - } - } - for fully_mapped in info.constraint_mappings.keys() { - info.dependencies.remove(fully_mapped); - } - if maps_unremovable_var { - return Err(MapEvalErr::Unremovable); - } - Ok(info) - } + /// Resolves dependencies on mappings - i.e. we find a set of mappings that mutually satisfy each other's + /// dependencies, and don't conflict fn resolve_dependencies(&mut self) { let mut used_mappings = FxIndexSet::default(); for indx in (0..self.mappings.len()).map(MappingIndex::new) { @@ -359,8 +372,12 @@ impl DedupSolver { } } } - // There's quite a few heuristics that will probably yield *significant* speedups - // I'll look into that later, if the rest of this approach is sound + /// Performs a depth-first search on the dependencies graph of mappings. Each call to this functino + /// takes in 3 arguments - the mappings that are already presumed to be part of the set of mappings + /// that should be applied together, these mappings aggregated into a single mapping, and a `from` set, + /// i.e. a set of mappings that we just added, and thus might have unresolved dependencies + /// There's quite a few heuristics that will probably yield *significant* speedups + /// I'll look into that later, if the rest of this approach is sound fn dfs_search( &self, mut used_mappings: FxIndexSet, @@ -379,16 +396,22 @@ impl DedupSolver { } used_mappings.extend(from.iter()); - let choices: Vec<&FxIndexSet> = + // For each unresolved dependency, we have a set of Mappings that can resolve it + let unresolved_dependencies: Vec<&FxIndexSet> = from.iter().flat_map(|x| self.get_mapping_info(*x).dependencies.values()).collect(); - if choices.is_empty() { + if unresolved_dependencies.is_empty() { return Some(used_mappings); } - let mut choice_indices = vec![0; choices.len()]; - while *choice_indices.last().unwrap() < choices.last().unwrap().len() { - let choice: FxIndexSet = choice_indices + // For each unresolved dependency, we have an index denoting the index in the FxIndexSet that + // we will try applying next + // Essentially, we just sweep through all the combinations exhaustively, e.g. if we have 3 + // unresolved dependencies, each with 3 options, we would go "[0, 0, 0]", "[1, 0, 0]", "[2, 0, 0]", + // "[0, 1, 0]", "[1, 1, 0]", "[2, 1, 0]", so on and so forth until we find one that succeeds + let mut trial_indices = vec![0; unresolved_dependencies.len()]; + while *trial_indices.last().unwrap() < unresolved_dependencies.last().unwrap().len() { + let choice: FxIndexSet = trial_indices .iter() - .zip(&choices) + .zip(&unresolved_dependencies) .map(|(x, y)| *y.get_index(*x).unwrap()) .collect(); let search_result = @@ -397,7 +420,9 @@ impl DedupSolver { return search_result; } - for (val, limit) in choice_indices.iter_mut().zip(choices.iter().map(|x| x.len())) { + for (val, limit) in + trial_indices.iter_mut().zip(unresolved_dependencies.iter().map(|x| x.len())) + { *val += 1; if *val >= limit { *val = 0; @@ -421,7 +446,7 @@ impl DedupSolver { if self.applied_mappings.borrow().conflicts_with(mapping) { return false; } - self.removed_constraints.borrow_mut().extend(info.constraint_mappings.keys()); + self.removed_constraints.borrow_mut().extend(info.eliminated_constraints.iter()); self.applied_mappings.borrow_mut().0.extend(&mapping.0); true } @@ -443,11 +468,8 @@ impl Mapping { fn affects_constraint(&self, constraint: &[VarIndex]) -> bool { constraint.iter().any(|x| self.maps_var(*x).unwrap_or(*x) != *x) } - fn maps_fully(&self, from: &[VarIndex], to: &[VarIndex]) -> bool { - if from.len() != to.len() { - return false; - } - from.iter().zip(to).all(|(x, y)| self.maps_var(*x).unwrap_or(*x) == *y) + fn contains_fully(&self, other: &Self) -> bool { + other.0.iter().all(|(from, to)| self.maps_var(*from) == Some(*to)) } fn conflicts_with(&self, other: &Self) -> bool { for (from_a, to_a) in self.0.iter() { @@ -465,6 +487,6 @@ impl Mapping { } impl MappingInfo { fn new() -> Self { - Self { dependencies: FxIndexMap::default(), constraint_mappings: FxIndexMap::default() } + Self { dependencies: FxIndexMap::default(), eliminated_constraints: FxIndexSet::default() } } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs index c34e7527ec3bf..96ab53d35a3a5 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs @@ -16,17 +16,45 @@ fn constraint_set(input: [usize; N]) -> FxIndexSet) -> FxIndexSet { + // Same constraints as `test_dependencies`, but just imagine that all the vars in + // unremovable_vars are vars the caller can name, and therefore can't be removed DedupSolver::dedup( constraint_vars(vec![ vec![1, 2, 13], @@ -89,15 +126,3 @@ fn test_dependencies_unresolvable() { ); assert!(deduped.removed_constraints.is_empty()); } -#[test] -fn test_gh_issues_example() { - let deduped = DedupSolver::dedup( - constraint_vars(vec![vec![1], vec![2], vec![3]]), - constraint_cliques(vec![vec![0, 1, 2]]), - FxIndexSet::default(), - ); - assert!( - [constraint_set([0, 1]), constraint_set([0, 2]), constraint_set([1, 2])] - .contains(&deduped.removed_constraints) - ); -} From 3d28fdae53e1ae61fb81de086b7e68b472314ae1 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Sun, 14 May 2023 03:28:55 -0400 Subject: [PATCH 10/16] Removed some ignore warning markers added during debugging --- .../src/solve/eval_ctxt/canonical/dedup_solver.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs index c0aba692898c2..f93c3c1e3cc75 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs @@ -1,8 +1,3 @@ -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] -#![allow(unreachable_code)] - use crate::infer::canonical::QueryRegionConstraints; use crate::infer::region_constraints::MemberConstraint; use rustc_infer::infer::InferCtxt; From 73dbf78d7386232e4845f9c3be359d690022b300 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Mon, 15 May 2023 00:38:52 -0400 Subject: [PATCH 11/16] Minor simplifications+optimizations for core dedup solver, added a few more comments --- .../canonical/dedup_solver/solver.rs | 183 +++++++++++------- .../canonical/dedup_solver/solver/tests.rs | 3 + 2 files changed, 112 insertions(+), 74 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs index aab7ce1b04f0e..295403a4c0e3a 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_index::{Idx, IndexVec}; use std::cell::RefCell; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; #[cfg(test)] mod tests; @@ -47,8 +47,18 @@ pub struct DedupResult { struct Mapping(BTreeMap); #[derive(Debug, Clone, PartialEq, Eq)] struct MappingInfo { - dependencies: FxIndexMap>, + /// The constraints that a mapping will eliminate. For example, if we have the constraints + /// [1, 2] (with ConstraintIndex of 0) and [3, 4], the mapping 1:3,2:4 will eliminate constraint 0 eliminated_constraints: FxIndexSet, + /// A mapping has dependencies if it only maps a subset of the variables in a constraint, and therefore + /// depends on another mapping to complete the full mapping. For example, if we have the constraints + /// [1, 2] (index 1), [11, 12] (index 2), [2, 3] (index 3), and [12, 13] (index 4), the mapping + /// that merges the 1st constraint into the 2nd (mapping vars 1 to 11, 2 to 12) will also "partially" + /// map the 3rd constraint (because the mapping maps var 2, which the 3rd constraint contains). + /// This will partially map the 3rd constraint into [12, 3], which isn't a pre-existing constraint - HOWEVER, + /// if we also apply the mapping var2->var12,var3->var13, then it maps the constraint to [12, 13] which *is* + /// a preexisting constraint. Therefore, the two constraints depend on each other + dependencies: FxIndexMap>, } #[derive(Debug, PartialEq, Eq)] enum MapEvalErr { @@ -69,7 +79,7 @@ impl DedupSolver { mappings: FxIndexMap::default(), removed_constraints: RefCell::new(FxIndexSet::default()), - applied_mappings: RefCell::new(Mapping::map_constraints(&[], &[])), + applied_mappings: RefCell::new(Mapping::from(&[], &[])), }; deduper.refine_cliques(); deduper.compute_mappings(); @@ -77,8 +87,15 @@ impl DedupSolver { DedupResult { removed_constraints: deduper.removed_constraints.into_inner() } } + /// The input cliques are provided just on a basis of the structure of the constraints, i.e. + /// "are they the same if we ignore variables unnameable from the caller". However, just because + /// this is the case doesn't mean that two constraints can be merged - for example, the constraint + /// involving vars [1, 3] can't be merged with a constraint involving vars [2, 2]. + /// This function refines the cliques such that if we create a graph with constraints as vertices + /// and edges if they can be merged, constraint_cliques now represents the **true** cliques of the + /// graph, i.e. any two constrains in the same clique can now create a valid mapping fn refine_cliques(&mut self) { - // Refine categories based on shape + // Refine categories based on shape - see canonicalize_constraint_shape for more info for clique_indx in (0..self.constraint_cliques.len()).map(CliqueIndex::new) { let mut shape_cliques: FxIndexMap, CliqueIndex> = FxIndexMap::default(); let mut constraint_indx = 0; @@ -103,7 +120,17 @@ impl DedupSolver { self.constraint_cliques[new_clique].push(constraint); } } - // Refine categories based on indices of variables + // Refine categories based on indices of variables. This is based on the observation that + // if a variable V is present in a constraint C1 at some set of indices I, then a constraint + // C2 can be merged with C1 only if one of the following cases are satisfied: + // a. V is present in constraint C2 at the **same** set of indices I, where in that case + // the variable mapping that merges these two constraints would just map V onto V + // b. V is not present in constraint C2 at all, in which case some other variable would + // be mapped onto V + // If none of these above cases are true, that means we have a situation where we map V + // to another variable U, and a variable W would be mapped onto V - in this case, we're just + // shuffling variables around without actually eliminating any, which is unproductive and + // hence an "invalid mapping" for clique_indx in (0..self.constraint_cliques.len()).map(CliqueIndex::new) { // First element of tuple (the FxIndexMap) maps a variable to // the index it occurs in @@ -178,7 +205,6 @@ impl DedupSolver { /// Deduplication can be done greedily because if two constraints can be merged, then they're /// equivalent in every way, including in relations to other constraints fn compute_mappings(&mut self) { - let mut invalid_maps: FxIndexSet = FxIndexSet::default(); for clique in self.constraint_cliques.iter() { for (n, constraint_1) in clique .iter() @@ -191,19 +217,17 @@ impl DedupSolver { .filter(|x| !self.removed_constraints.borrow().contains(*x)) { // Maps constraint_1 to constraint_2 - let forward = Mapping::map_constraints( + let forward = Mapping::from( &self.constraint_vars[*constraint_1], &self.constraint_vars[*constraint_2], ); - if invalid_maps.contains(&forward) || self.mappings.contains_key(&forward) { - continue; - } // Maps constraint_2 to constraint_1 - let reverse = Mapping::map_constraints( + let reverse = Mapping::from( &self.constraint_vars[*constraint_2], &self.constraint_vars[*constraint_1], ); - if invalid_maps.contains(&reverse) || self.mappings.contains_key(&reverse) { + if self.mappings.contains_key(&forward) || self.mappings.contains_key(&reverse) + { continue; } @@ -219,17 +243,15 @@ impl DedupSolver { if eval_forward == Err(MapEvalErr::Conflicts) || eval_reverse == Err(MapEvalErr::Conflicts) { - invalid_maps.insert(forward); - invalid_maps.insert(reverse); continue; } if let Ok(eval_forward) = eval_forward { - if !self.try_apply_mapping(&forward, &eval_forward, false) { + if self.try_apply_mapping(&forward, &eval_forward, false) == Err(true) { self.mappings.insert(forward, eval_forward); } } if let Ok(eval_reverse) = eval_reverse { - if !self.try_apply_mapping(&reverse, &eval_reverse, false) { + if self.try_apply_mapping(&reverse, &eval_reverse, false) == Err(true) { self.mappings.insert(reverse, eval_reverse); } } @@ -258,7 +280,7 @@ impl DedupSolver { let mut found_non_conflicting = false; for constraint_2 in clique.iter() { let vars_2 = &self.constraint_vars[*constraint_2]; - let trial_mapping = Mapping::map_constraints(vars_1, vars_2); + let trial_mapping = Mapping::from(vars_1, vars_2); if mapping.conflicts_with(&trial_mapping) { continue; } @@ -267,7 +289,7 @@ impl DedupSolver { if !mapping.contains_fully(&trial_mapping) { // The input mapping can be applied only if there's another mapping that // maps every variable in constraint_1 (and doesn't conflict with the input mapping) - info.dependencies.insert(*constraint_1, FxIndexSet::default()); + info.dependencies.insert(*constraint_1, BTreeSet::default()); continue; } if *constraint_1 != *constraint_2 { @@ -302,46 +324,41 @@ impl DedupSolver { true }); // A map from a constraint to the mappings that will eliminate it (i.e. map it fully) - let mut constraint_mappings: FxIndexMap> = + let mut constraint_mappings: FxIndexMap> = FxIndexMap::default(); for (indx, (_, mapping_info)) in self.mappings.iter().enumerate() { for eliminated_constraint in mapping_info.eliminated_constraints.iter() { constraint_mappings .entry(*eliminated_constraint) - .or_insert_with(FxIndexSet::default) + .or_insert_with(BTreeSet::default) .insert(MappingIndex::new(indx)); } } for indx in (0..self.mappings.len()).map(MappingIndex::new) { let mapping = self.get_mapping(indx); let input_dependencies = &self.get_mapping_info(indx).dependencies; - let mut dependencies = IndexVec::new(); + let mut dependencies = FxIndexSet::default(); for (dependency, _) in input_dependencies.iter() { // The set of mappings that can resolve this dependency - let mut resolve_options = FxIndexSet::default(); - if let Some(resolve_mappings) = constraint_mappings.get(dependency) { - resolve_options.extend( - resolve_mappings - .iter() - .filter(|x| !mapping.conflicts_with(&self.get_mapping(**x))) - .cloned(), - ) - } - // Don't duplicate dependency groups - if dependencies.iter().any(|x| x == &resolve_options) { - continue; - } - dependencies.push(resolve_options); + let mut resolve_options = + constraint_mappings.get(dependency).cloned().unwrap_or_else(BTreeSet::new); + resolve_options.retain(|x| !mapping.conflicts_with(&self.get_mapping(*x))); + dependencies.insert(resolve_options); } // After this point, the actual constraints that a dependency maps // stops mattering - all that matters is that the dependency *exists* - self.mappings.get_index_mut(indx.index()).unwrap().1.dependencies = - dependencies.into_iter_enumerated().collect(); + let old_dependencies = + &mut self.mappings.get_index_mut(indx.index()).unwrap().1.dependencies; + *old_dependencies = dependencies + .into_iter() + .enumerate() + .map(|(indx, x)| (ConstraintIndex::from(indx), x)) + .collect(); } } - /// Resolves dependencies on mappings - i.e. we find a set of mappings that mutually satisfy each other's - /// dependencies, and don't conflict + /// Resolves dependencies on mappings - i.e. we find sets of mappings that mutually satisfy each other's + /// dependencies, and don't conflict, then apply these mappings fn resolve_dependencies(&mut self) { let mut used_mappings = FxIndexSet::default(); for indx in (0..self.mappings.len()).map(MappingIndex::new) { @@ -366,24 +383,25 @@ impl DedupSolver { self.get_mapping_info(mapping), true, ); - assert!(application_result); + assert!(application_result.is_ok()); used_mappings.insert(mapping); } } } } - /// Performs a depth-first search on the dependencies graph of mappings. Each call to this functino - /// takes in 3 arguments - the mappings that are already presumed to be part of the set of mappings - /// that should be applied together, these mappings aggregated into a single mapping, and a `from` set, - /// i.e. a set of mappings that we just added, and thus might have unresolved dependencies - /// There's quite a few heuristics that will probably yield *significant* speedups - /// I'll look into that later, if the rest of this approach is sound + /// Finds a set of mappings that mutually satisfy each other's dependencies without conflicting with each + /// other, or the mappings that have already been applied. It does this through depth first search - + /// it takes a FxIndexSet of the mappings that have already been presumed to be part of the mapping set as well + /// as a FxIndexSet of mappings that we are trying to add to this set (`from`). These mappings still may have + /// dependencies that might be unresolved, so dfs_search attempts to resolve these dependencies, recursively calling + /// itself if necessary. If `from` has no unresolved dependencies, then a set of mappings is found, and we return fn dfs_search( &self, mut used_mappings: FxIndexSet, mut applied_mappings: Mapping, - from: FxIndexSet, + mut from: FxIndexSet, ) -> Option> { + // Apply the mappings that we're trying to apply (in `from`), aborting if there's any conflicts for mapping_indx in from.iter() { let (mapping, _) = self.mappings.get_index(mapping_indx.index()).unwrap(); if applied_mappings.conflicts_with(mapping) { @@ -391,41 +409,55 @@ impl DedupSolver { } applied_mappings.0.extend(&mapping.0); } - if from.iter().all(|x| used_mappings.contains(x)) { + // If we already applied a mapping, we now remove it from `from`, as its dependencies have + // been resolved and therefore we don't need to worry about it + from.retain(|x| !used_mappings.contains(x)); + if from.is_empty() { return Some(used_mappings); } used_mappings.extend(from.iter()); - // For each unresolved dependency, we have a set of Mappings that can resolve it - let unresolved_dependencies: Vec<&FxIndexSet> = - from.iter().flat_map(|x| self.get_mapping_info(*x).dependencies.values()).collect(); - if unresolved_dependencies.is_empty() { - return Some(used_mappings); + // For each unresolved dependency, we have a list of Mappings that can resolve it + let mut unresolved_dependencies: FxIndexSet> = FxIndexSet::default(); + for from_mapping in from.iter() { + let resolve_options = self.get_mapping_info(*from_mapping).dependencies.values(); + let resolve_options = resolve_options.map(|x| { + Vec::from_iter( + x.iter() + .cloned() + // Throw out mappings that conflict with the current `used_mappings` we're + // trying to satisfy the dependencies of + .filter(|x| !self.get_mapping(*x).conflicts_with(&applied_mappings)), + ) + }); + unresolved_dependencies.extend(resolve_options); + } + if unresolved_dependencies.iter().any(|x| x.is_empty()) { + return None; } - // For each unresolved dependency, we have an index denoting the index in the FxIndexSet that - // we will try applying next - // Essentially, we just sweep through all the combinations exhaustively, e.g. if we have 3 - // unresolved dependencies, each with 3 options, we would go "[0, 0, 0]", "[1, 0, 0]", "[2, 0, 0]", - // "[0, 1, 0]", "[1, 1, 0]", "[2, 1, 0]", so on and so forth until we find one that succeeds + // For each unresolved dependency, we have a list of Mappings that can resolve it. The idea is that + // we need to pick one mapping from each list to create the set of mappings we're going to try adding + // to the set of mappings, and right now, it's done incredibly naively - for each list of mappings, + // we store the value that denotes the index of the mapping in that list that we're going to try + // adding next. We start out with a vec of all zeroes, i.e. we try taking the first element of each + // list, and we sweep the indices in order, e.g. going [0, 0, 0], [1, 0, 0], [2, 0, 0], [3, 0, 0], + // [0, 1, 0], [1, 1, 0], [2, 1, 0], [3, 1, 0], [0, 2, 0], so on and so forth let mut trial_indices = vec![0; unresolved_dependencies.len()]; while *trial_indices.last().unwrap() < unresolved_dependencies.last().unwrap().len() { - let choice: FxIndexSet = trial_indices - .iter() - .zip(&unresolved_dependencies) - .map(|(x, y)| *y.get_index(*x).unwrap()) - .collect(); + // The set of mappings that were chosen to be added next + let choice: FxIndexSet = + trial_indices.iter().zip(&unresolved_dependencies).map(|(x, y)| y[*x]).collect(); let search_result = self.dfs_search(used_mappings.clone(), applied_mappings.clone(), choice); if search_result.is_some() { return search_result; } - for (val, limit) in - trial_indices.iter_mut().zip(unresolved_dependencies.iter().map(|x| x.len())) - { - *val += 1; - if *val >= limit { - *val = 0; + // Advance the indices to the next possibility + for (indx, options) in trial_indices.iter_mut().zip(&unresolved_dependencies) { + *indx += 1; + if *indx >= options.len() { + *indx = 0; continue; } break; @@ -434,21 +466,24 @@ impl DedupSolver { None } + /// Tries to apply a mapping, returning Ok(()) if the application was a success, Err(true) if the + /// application failed but only because of unresolved dependencies, and Err(false) if the application + /// fails because of conflicts fn try_apply_mapping( &self, mapping: &Mapping, info: &MappingInfo, allow_dependencies: bool, - ) -> bool { + ) -> Result<(), bool> { if !allow_dependencies && !info.dependencies.is_empty() { - return false; + return Err(true); } if self.applied_mappings.borrow().conflicts_with(mapping) { - return false; + return Err(false); } self.removed_constraints.borrow_mut().extend(info.eliminated_constraints.iter()); self.applied_mappings.borrow_mut().0.extend(&mapping.0); - true + Ok(()) } fn get_mapping(&self, index: MappingIndex) -> &Mapping { &self.mappings.get_index(index.index()).unwrap().0 @@ -459,7 +494,7 @@ impl DedupSolver { } impl Mapping { - fn map_constraints(from: &[VarIndex], to: &[VarIndex]) -> Self { + fn from(from: &[VarIndex], to: &[VarIndex]) -> Self { Self(from.iter().zip(to).map(|(x, y)| (*x, *y)).collect()) } fn maps_var(&self, constraint: VarIndex) -> Option { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs index 96ab53d35a3a5..388a6353c5988 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs @@ -1,17 +1,20 @@ use super::*; +// Quick type conversion function to make tests more compact - nothing important to see here fn constraint_vars(input: Vec>) -> IndexVec> { input .into_iter() .map(|constraint| constraint.into_iter().map(|x| VarIndex::new(x)).collect()) .collect() } +// Quick type conversion function to make tests more compact - nothing important to see here fn constraint_cliques(input: Vec>) -> IndexVec> { input .into_iter() .map(|clique| clique.into_iter().map(|x| ConstraintIndex::new(x)).collect()) .collect() } +// Quick type conversion function to make tests more compact - nothing important to see here fn constraint_set(input: [usize; N]) -> FxIndexSet { FxIndexSet::from_iter(input.into_iter().map(|x| ConstraintIndex::new(x))) } From 021310a789356247dd2515e0712ec7f31f2ffa8d Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Mon, 22 May 2023 12:41:14 -0400 Subject: [PATCH 12/16] Removed some (likely premature) optimizations to improve code clarity --- .../canonical/dedup_solver/solver.rs | 195 +++++------------- .../canonical/dedup_solver/solver/tests.rs | 9 + 2 files changed, 62 insertions(+), 142 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs index 295403a4c0e3a..a1acb2fbf1115 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -20,10 +20,8 @@ pub struct DedupSolver { /// The variables present in each constraint - the inner vec contains the variables, in the order /// that they appear in the constraint. See solver/tests.rs for examples on how constraints are lowered to this format constraint_vars: IndexVec>, - /// The cliques that constraints are partitioned into. These are determined as follows: imagine a graph where - /// each constraint is a vertex, and an edge exists between a pair of constraints if there is a many-to-one mapping of - /// variables that perfectly maps one constraint onto the other. The constraint cliques are just cliques within this graph. - /// By nature of this problem, it is impossible for a constraint to be in two cliques + /// The cliques that constraints are partitioned into. Constraints can only be merged if they belong to the same clique, + /// and it's impossible for a constraint to be in more than one clique constraint_cliques: IndexVec>, /// A set of variables we cannot remove, i.e. they belong to a universe that the caller can name. We keep track of these /// to determine if there's a variable that we **can** remove that behaves like one of these, where in that case we just @@ -61,7 +59,8 @@ struct MappingInfo { dependencies: FxIndexMap>, } #[derive(Debug, PartialEq, Eq)] -enum MapEvalErr { +enum MapEval { + Ok(MappingInfo), Conflicts, Unremovable, } @@ -79,125 +78,13 @@ impl DedupSolver { mappings: FxIndexMap::default(), removed_constraints: RefCell::new(FxIndexSet::default()), - applied_mappings: RefCell::new(Mapping::from(&[], &[])), + applied_mappings: RefCell::new(Mapping::from(&[], &[]).unwrap()), }; - deduper.refine_cliques(); deduper.compute_mappings(); deduper.resolve_dependencies(); DedupResult { removed_constraints: deduper.removed_constraints.into_inner() } } - /// The input cliques are provided just on a basis of the structure of the constraints, i.e. - /// "are they the same if we ignore variables unnameable from the caller". However, just because - /// this is the case doesn't mean that two constraints can be merged - for example, the constraint - /// involving vars [1, 3] can't be merged with a constraint involving vars [2, 2]. - /// This function refines the cliques such that if we create a graph with constraints as vertices - /// and edges if they can be merged, constraint_cliques now represents the **true** cliques of the - /// graph, i.e. any two constrains in the same clique can now create a valid mapping - fn refine_cliques(&mut self) { - // Refine categories based on shape - see canonicalize_constraint_shape for more info - for clique_indx in (0..self.constraint_cliques.len()).map(CliqueIndex::new) { - let mut shape_cliques: FxIndexMap, CliqueIndex> = FxIndexMap::default(); - let mut constraint_indx = 0; - while constraint_indx < self.constraint_cliques[clique_indx].len() { - let constraint = self.constraint_cliques[clique_indx][constraint_indx]; - let shape = - Self::canonicalize_constraint_shape(&mut self.constraint_vars[constraint]); - let is_first_entry = shape_cliques.is_empty(); - let new_clique = *shape_cliques.entry(shape).or_insert_with(|| { - if is_first_entry { - clique_indx - } else { - self.constraint_cliques.push(Vec::new()); - CliqueIndex::new(self.constraint_cliques.len() - 1) - } - }); - if new_clique == clique_indx { - constraint_indx += 1; - continue; - } - self.constraint_cliques[clique_indx].swap_remove(constraint_indx); - self.constraint_cliques[new_clique].push(constraint); - } - } - // Refine categories based on indices of variables. This is based on the observation that - // if a variable V is present in a constraint C1 at some set of indices I, then a constraint - // C2 can be merged with C1 only if one of the following cases are satisfied: - // a. V is present in constraint C2 at the **same** set of indices I, where in that case - // the variable mapping that merges these two constraints would just map V onto V - // b. V is not present in constraint C2 at all, in which case some other variable would - // be mapped onto V - // If none of these above cases are true, that means we have a situation where we map V - // to another variable U, and a variable W would be mapped onto V - in this case, we're just - // shuffling variables around without actually eliminating any, which is unproductive and - // hence an "invalid mapping" - for clique_indx in (0..self.constraint_cliques.len()).map(CliqueIndex::new) { - // First element of tuple (the FxIndexMap) maps a variable to - // the index it occurs in - let mut index_cliques: Vec<(FxIndexMap, CliqueIndex)> = Vec::new(); - let mut constraint_indx = 0; - while constraint_indx < self.constraint_cliques[clique_indx].len() { - let constraint = self.constraint_cliques[clique_indx][constraint_indx]; - let constraint_vars = &self.constraint_vars[constraint]; - let constraint_var_indices: FxIndexMap = - constraint_vars.iter().enumerate().map(|(indx, x)| (*x, indx)).collect(); - - let mut found_clique = None; - for (clique_vars, new_clique_indx) in index_cliques.iter_mut() { - let is_clique_member = constraint_vars - .iter() - .enumerate() - .all(|(indx, x)| *clique_vars.get(x).unwrap_or(&indx) == indx); - if !is_clique_member { - continue; - } - found_clique = Some(*new_clique_indx); - clique_vars.extend(&constraint_var_indices); - break; - } - let new_clique = found_clique.unwrap_or_else(|| { - if index_cliques.is_empty() { - clique_indx - } else { - let new_clique = self.constraint_cliques.next_index(); - self.constraint_cliques.push(Vec::new()); - index_cliques.push((constraint_var_indices, new_clique)); - new_clique - } - }); - if new_clique == clique_indx { - constraint_indx += 1; - continue; - } - self.constraint_cliques[clique_indx].swap_remove(constraint_indx); - self.constraint_cliques[new_clique].push(constraint); - } - } - } - /// Returns the "shape" of a constraint, which captures information about the location(s) and - /// multiplicity of variables in the constraint, irrespective of the actual variable indices - /// For example, a constraint involving the vars [1, 1, 2, 3] has a shape of [0, 0, 1, 2], - /// and a constraint involving vars [3, 4] has a shape of [0, 1] - /// It takes a mutable reference to the vars because it also removes duplicates from - /// the input vector after computing the shape - /// Clearly, two constraints can be mapped onto each other only if they have the - /// same shape - fn canonicalize_constraint_shape(vars: &mut Vec) -> Vec { - let mut shape = Vec::new(); - let mut num_vars = 0; - let mut indx = 0; - while indx < vars.len() { - if let Some(val) = shape.iter().find(|y| vars[**y] == vars[indx]) { - shape.push(*val); - vars.remove(indx); - } else { - shape.push(num_vars); - num_vars += 1; - indx += 1; - } - } - shape - } /// Computes the set of all possible mappings /// If a mapping has no dependencies, then it's eagerly taken, to increase performance @@ -211,27 +98,22 @@ impl DedupSolver { .enumerate() .filter(|x| !self.removed_constraints.borrow().contains(x.1)) { + let constraint_1_vars = &self.constraint_vars[*constraint_1]; for constraint_2 in clique .iter() .skip(n + 1) .filter(|x| !self.removed_constraints.borrow().contains(*x)) { + let constraint_2_vars = &self.constraint_vars[*constraint_2]; // Maps constraint_1 to constraint_2 - let forward = Mapping::from( - &self.constraint_vars[*constraint_1], - &self.constraint_vars[*constraint_2], - ); + let forward = Mapping::from(constraint_1_vars, constraint_2_vars); // Maps constraint_2 to constraint_1 - let reverse = Mapping::from( - &self.constraint_vars[*constraint_2], - &self.constraint_vars[*constraint_1], - ); - if self.mappings.contains_key(&forward) || self.mappings.contains_key(&reverse) - { + let reverse = Mapping::from(constraint_2_vars, constraint_1_vars); + let (Ok(forward), Ok(reverse)) = (forward, reverse) else { continue; - } + }; - // if constraint_1 and constraint_2 can be merged, this relation should be + // If constraint_1 and constraint_2 can be merged, this relation should be // bidirectional, i.e. we can merge 1 into 2 or 2 into 1 // For example, if a clique contains constraints [1, 2] and [11, 12] and another // clique contains constraint [1], then we **cannot** merge vars 1 and 11 - the @@ -240,17 +122,15 @@ impl DedupSolver { // map the constraint [1] into [11], which is a constraint that doesn't exist let (eval_forward, eval_reverse) = (self.eval_mapping(&forward), self.eval_mapping(&reverse)); - if eval_forward == Err(MapEvalErr::Conflicts) - || eval_reverse == Err(MapEvalErr::Conflicts) - { + if eval_forward == MapEval::Conflicts || eval_reverse == MapEval::Conflicts { continue; } - if let Ok(eval_forward) = eval_forward { + if let MapEval::Ok(eval_forward) = eval_forward { if self.try_apply_mapping(&forward, &eval_forward, false) == Err(true) { self.mappings.insert(forward, eval_forward); } } - if let Ok(eval_reverse) = eval_reverse { + if let MapEval::Ok(eval_reverse) = eval_reverse { if self.try_apply_mapping(&reverse, &eval_reverse, false) == Err(true) { self.mappings.insert(reverse, eval_reverse); } @@ -266,7 +146,7 @@ impl DedupSolver { /// MappingInfo can contain dependencies - these occur if a mapping *partially* maps /// a constraint onto another, so the mapping isn't immediately invalid, but we do need /// another mapping to complete that partial map for it to actually be valid - fn eval_mapping(&self, mapping: &Mapping) -> Result { + fn eval_mapping(&self, mapping: &Mapping) -> MapEval { let maps_unremovable_var = mapping.0.iter().any(|(from, to)| self.unremovable_vars.contains(from) && from != to); @@ -280,7 +160,9 @@ impl DedupSolver { let mut found_non_conflicting = false; for constraint_2 in clique.iter() { let vars_2 = &self.constraint_vars[*constraint_2]; - let trial_mapping = Mapping::from(vars_1, vars_2); + let Ok(trial_mapping) = Mapping::from(vars_1, vars_2) else { + continue; + }; if mapping.conflicts_with(&trial_mapping) { continue; } @@ -297,14 +179,14 @@ impl DedupSolver { } } if !found_non_conflicting { - return Err(MapEvalErr::Conflicts); + return MapEval::Conflicts; } } } if maps_unremovable_var { - return Err(MapEvalErr::Unremovable); + return MapEval::Unremovable; } - Ok(info) + MapEval::Ok(info) } /// Currently, dependencies are in the form FxIndexMap, /// where ConstraintIndex is the constraint we must *also* map in order to apply this mapping. @@ -494,22 +376,51 @@ impl DedupSolver { } impl Mapping { - fn from(from: &[VarIndex], to: &[VarIndex]) -> Self { - Self(from.iter().zip(to).map(|(x, y)| (*x, *y)).collect()) + /// Creates a mapping between two constraints. If the resulting mapping is invalid, + /// an Err is returned + fn from(from: &[VarIndex], to: &[VarIndex]) -> Result { + if from.len() != to.len() { + return Err(()); + } + let mut mapping_set = BTreeMap::new(); + for (from_var, to_var) in from.iter().zip(to) { + if let Some(previous_map) = mapping_set.get(from_var) { + if previous_map != to_var { + return Err(()); + } + continue; + } + mapping_set.insert(*from_var, *to_var); + } + // We impose a constraint that a variable cannot be both a key and a value of + // a mapping, as that would mean [1, 2] can be mapped onto [2, 1] - however, + // these are fundamentally different constraints that can't be merged. + // The only exception is if a var maps to itself - that's fine, as all it's saying + // is that we want to fix a variable and don't map it + if mapping_set.values().any(|x| mapping_set.get(x).unwrap_or(x) != x) { + return Err(()); + } + Ok(Self(mapping_set)) } fn maps_var(&self, constraint: VarIndex) -> Option { self.0.get(&constraint).map(|x| *x) } + /// Returns whether the mapping will change the given constraint if applied fn affects_constraint(&self, constraint: &[VarIndex]) -> bool { constraint.iter().any(|x| self.maps_var(*x).unwrap_or(*x) != *x) } + /// Returns whether a mapping is a superset of another mapping fn contains_fully(&self, other: &Self) -> bool { other.0.iter().all(|(from, to)| self.maps_var(*from) == Some(*to)) } + /// Returns whether a mapping conflicts with another mapping, i.e. they can't be applied together fn conflicts_with(&self, other: &Self) -> bool { for (from_a, to_a) in self.0.iter() { for (from_b, to_b) in other.0.iter() { + // Maps the same key to different values - conflicts! let map_conflicts = from_a == from_b && to_a != to_b; + // Map A maps var v to w, but map B maps w to v. Applying both maps together doesn't + // remove any variables, but just shuffles them around, so we call this a conflict let not_productive = to_b == from_a && from_a != to_a || to_a == from_b && from_b != to_b; if map_conflicts || not_productive { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs index 388a6353c5988..ef02e8f2d56b2 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs @@ -66,6 +66,15 @@ fn test_simple() { assert!([constraint_set([0]), constraint_set([1])].contains(&deduped.removed_constraints)); } #[test] +fn test_simple_2() { + let deduped = DedupSolver::dedup( + constraint_vars(vec![vec![0, 1], vec![2, 1], vec![1, 0], vec![1, 2]]), + constraint_cliques(vec![vec![0, 1, 2, 3]]), + FxIndexSet::from_iter([VarIndex::new(0), VarIndex::new(1)]), + ); + assert_eq!(deduped.removed_constraints, constraint_set([1, 3])); +} +#[test] fn test_dependencies() { // Example of constraint that produces this lowering: // (&'?1 Foo, &'?2 Foo): &'?13 From 7c55e5628f8f49ef0d2eaca34be780619482cf22 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Sun, 28 May 2023 16:30:16 -0400 Subject: [PATCH 13/16] Removed unsound notion of unremovable_vars, prioritized removal of newer constraints over older --- .../solve/eval_ctxt/canonical/dedup_solver.rs | 8 +- .../dedup_solver/constraint_walker.rs | 48 +- .../canonical/dedup_solver/solver.rs | 64 +- .../canonical/dedup_solver/solver/tests.rs | 71 +- out.txt | 1535 +++++++++++++++++ .../{dedup-vars.rs => dedup-placeholders.rs} | 1 - 6 files changed, 1620 insertions(+), 107 deletions(-) create mode 100644 out.txt rename tests/ui/traits/new-solver/{dedup-vars.rs => dedup-placeholders.rs} (99%) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs index f93c3c1e3cc75..b356ceb3a8ea8 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver.rs @@ -62,9 +62,11 @@ impl<'a, 'tcx> Deduper<'a, 'tcx> { let constraint_vars = std::mem::take(&mut self.constraint_vars); let constraint_cliques = std::mem::take(&mut self.constraint_cliques).into_iter().map(|x| x.1).collect(); - let unremovable_vars = - self.var_indexer.unremovable_vars.iter().map(|x| VarIndex::from(*x)).collect(); - let removed = DedupSolver::dedup(constraint_vars, constraint_cliques, unremovable_vars) + let var_universes = std::mem::take(&mut self.var_indexer.var_universes) + .into_iter() + .map(|(var, uni)| (VarIndex::from(var), uni.index())) + .collect(); + let removed = DedupSolver::dedup(constraint_vars, constraint_cliques, var_universes) .removed_constraints; let mut removed_outlives = diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs index 2e74bda4df4db..7c4b4692f4870 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_infer::infer::InferCtxt; use rustc_middle::ty; use rustc_middle::ty::{ @@ -14,7 +14,7 @@ pub struct DedupWalker<'me, 'tcx> { } pub struct DedupableIndexer<'tcx> { vars: FxIndexSet>, - pub unremovable_vars: FxIndexSet, + pub var_universes: FxIndexMap, } impl<'me, 'tcx> DedupWalker<'me, 'tcx> { @@ -32,13 +32,12 @@ impl<'me, 'tcx> DedupWalker<'me, 'tcx> { } impl<'tcx> DedupableIndexer<'tcx> { pub fn new() -> Self { - Self { vars: FxIndexSet::default(), unremovable_vars: FxIndexSet::default() } + Self { vars: FxIndexSet::default(), var_universes: FxIndexMap::default() } } - fn lookup(&mut self, var: GenericArg<'tcx>) -> usize { - self.vars.get_index_of(&var).unwrap_or_else(|| self.vars.insert_full(var).0) - } - fn add_unremovable_var(&mut self, var: usize) { - self.unremovable_vars.insert(var); + fn lookup(&mut self, var: GenericArg<'tcx>, universe: ty::UniverseIndex) -> usize { + let var_indx = self.vars.get_index_of(&var).unwrap_or_else(|| self.vars.insert_full(var).0); + self.var_universes.insert(var_indx, universe); + var_indx } } @@ -59,11 +58,11 @@ impl<'tcx> TypeFolder> for DedupWalker<'_, 'tcx> { ty::ReVar(..) | ty::RePlaceholder(..) => self.infcx.universe_of_region(region), _ => return region, }; - let var_id = self.var_indexer.lookup(GenericArg::from(region)); - self.vars_present.push(var_id); if self.max_nameable_universe.can_name(universe) { - self.var_indexer.add_unremovable_var(var_id); + return region; } + let var_id = self.var_indexer.lookup(GenericArg::from(region), universe); + self.vars_present.push(var_id); // dummy value self.interner().mk_re_placeholder(ty::Placeholder { universe: ty::UniverseIndex::from(self.max_nameable_universe.index() + 1), @@ -77,6 +76,7 @@ impl<'tcx> TypeFolder> for DedupWalker<'_, 'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let universe = match *ty.kind() { ty::Placeholder(p) => p.universe, + /* ty::Infer(ty::InferTy::TyVar(vid)) => { if let Err(uni) = self.infcx.probe_ty_var(vid) { uni @@ -84,13 +84,14 @@ impl<'tcx> TypeFolder> for DedupWalker<'_, 'tcx> { return ty; } } + */ _ => return ty, }; - let var_id = self.var_indexer.lookup(GenericArg::from(ty)); - self.vars_present.push(var_id); if self.max_nameable_universe.can_name(universe) { - self.var_indexer.add_unremovable_var(var_id); + return ty; } + let var_id = self.var_indexer.lookup(GenericArg::from(ty), universe); + self.vars_present.push(var_id); // dummy value self.interner().mk_ty_from_kind(ty::Placeholder(ty::Placeholder { universe: ty::UniverseIndex::from(self.max_nameable_universe.index() + 1), @@ -101,23 +102,26 @@ impl<'tcx> TypeFolder> for DedupWalker<'_, 'tcx> { fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> { let new_ty = self.fold_ty(ct.ty()); let universe = match ct.kind() { + /* ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { if let Err(uni) = self.infcx.probe_const_var(vid) { Some(uni) } else { None } } + */ ty::ConstKind::Placeholder(p) => Some(p.universe), _ => None, }; let new_const_kind = if let Some(uni) = universe { - let var_id = self.var_indexer.lookup(GenericArg::from(ct)); - self.vars_present.push(var_id); if self.max_nameable_universe.can_name(uni) { - self.var_indexer.add_unremovable_var(var_id); + ct.kind() + } else { + let var_id = self.var_indexer.lookup(GenericArg::from(ct), uni); + self.vars_present.push(var_id); + // dummy value + ty::ConstKind::Placeholder(ty::Placeholder { + universe: ty::UniverseIndex::from(self.max_nameable_universe.index() + 1), + bound: ty::BoundVar::from_usize(0), + }) } - // dummy value - ty::ConstKind::Placeholder(ty::Placeholder { - universe: ty::UniverseIndex::from(self.max_nameable_universe.index() + 1), - bound: ty::BoundVar::from_usize(0), - }) } else { ct.kind() }; diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs index a1acb2fbf1115..69b69bdff8adb 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_index::{Idx, IndexVec}; use std::cell::RefCell; use std::collections::{BTreeMap, BTreeSet}; @@ -23,10 +23,9 @@ pub struct DedupSolver { /// The cliques that constraints are partitioned into. Constraints can only be merged if they belong to the same clique, /// and it's impossible for a constraint to be in more than one clique constraint_cliques: IndexVec>, - /// A set of variables we cannot remove, i.e. they belong to a universe that the caller can name. We keep track of these - /// to determine if there's a variable that we **can** remove that behaves like one of these, where in that case we just - /// remove the unremovable var and keep the removable ones - unremovable_vars: FxIndexSet, + /// The universes each var resides in. This is used because deduping prioritizes the removal of constraints + /// that involve the highest universe indices + var_universes: FxHashMap, /// The below are internal variables used in the solving process: @@ -58,23 +57,17 @@ struct MappingInfo { /// a preexisting constraint. Therefore, the two constraints depend on each other dependencies: FxIndexMap>, } -#[derive(Debug, PartialEq, Eq)] -enum MapEval { - Ok(MappingInfo), - Conflicts, - Unremovable, -} impl DedupSolver { pub fn dedup( constraint_vars: IndexVec>, constraint_cliques: IndexVec>, - unremovable_vars: FxIndexSet, + var_universes: FxHashMap, ) -> DedupResult { let mut deduper = Self { constraint_vars, constraint_cliques, - unremovable_vars, + var_universes, mappings: FxIndexMap::default(), removed_constraints: RefCell::new(FxIndexSet::default()), @@ -122,18 +115,20 @@ impl DedupSolver { // map the constraint [1] into [11], which is a constraint that doesn't exist let (eval_forward, eval_reverse) = (self.eval_mapping(&forward), self.eval_mapping(&reverse)); - if eval_forward == MapEval::Conflicts || eval_reverse == MapEval::Conflicts { + let (Ok(eval_forward), Ok(eval_reverse)) = (eval_forward, eval_reverse) else { continue; - } - if let MapEval::Ok(eval_forward) = eval_forward { - if self.try_apply_mapping(&forward, &eval_forward, false) == Err(true) { - self.mappings.insert(forward, eval_forward); - } - } - if let MapEval::Ok(eval_reverse) = eval_reverse { - if self.try_apply_mapping(&reverse, &eval_reverse, false) == Err(true) { - self.mappings.insert(reverse, eval_reverse); - } + }; + + let max_forward_universe = forward.max_removed_universe(&self.var_universes); + let max_reverse_universe = reverse.max_removed_universe(&self.var_universes); + let (chosen_mapping, chosen_eval) = + if max_forward_universe >= max_reverse_universe { + (forward, eval_forward) + } else { + (reverse, eval_reverse) + }; + if self.try_apply_mapping(&chosen_mapping, &chosen_eval, false) == Err(true) { + self.mappings.insert(chosen_mapping, chosen_eval); } } } @@ -146,10 +141,7 @@ impl DedupSolver { /// MappingInfo can contain dependencies - these occur if a mapping *partially* maps /// a constraint onto another, so the mapping isn't immediately invalid, but we do need /// another mapping to complete that partial map for it to actually be valid - fn eval_mapping(&self, mapping: &Mapping) -> MapEval { - let maps_unremovable_var = - mapping.0.iter().any(|(from, to)| self.unremovable_vars.contains(from) && from != to); - + fn eval_mapping(&self, mapping: &Mapping) -> Result { let mut info = MappingInfo::new(); for clique in self.constraint_cliques.iter() { for constraint_1 in clique { @@ -179,14 +171,11 @@ impl DedupSolver { } } if !found_non_conflicting { - return MapEval::Conflicts; + return Err(()); } } } - if maps_unremovable_var { - return MapEval::Unremovable; - } - MapEval::Ok(info) + Ok(info) } /// Currently, dependencies are in the form FxIndexMap, /// where ConstraintIndex is the constraint we must *also* map in order to apply this mapping. @@ -294,9 +283,6 @@ impl DedupSolver { // If we already applied a mapping, we now remove it from `from`, as its dependencies have // been resolved and therefore we don't need to worry about it from.retain(|x| !used_mappings.contains(x)); - if from.is_empty() { - return Some(used_mappings); - } used_mappings.extend(from.iter()); // For each unresolved dependency, we have a list of Mappings that can resolve it @@ -314,6 +300,9 @@ impl DedupSolver { }); unresolved_dependencies.extend(resolve_options); } + if unresolved_dependencies.is_empty() { + return Some(used_mappings); + } if unresolved_dependencies.iter().any(|x| x.is_empty()) { return None; } @@ -430,6 +419,9 @@ impl Mapping { } false } + fn max_removed_universe(&self, var_universes: &FxHashMap) -> usize { + self.0.keys().map(|x| *var_universes.get(x).unwrap()).max().unwrap_or(0) + } } impl MappingInfo { fn new() -> Self { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs index ef02e8f2d56b2..fdf1b9cf668cc 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver/tests.rs @@ -29,12 +29,9 @@ fn test_gh_issues_example() { let deduped = DedupSolver::dedup( constraint_vars(vec![vec![1], vec![2], vec![3]]), constraint_cliques(vec![vec![0, 1, 2]]), - FxIndexSet::default(), - ); - assert!( - [constraint_set([0, 1]), constraint_set([0, 2]), constraint_set([1, 2])] - .contains(&deduped.removed_constraints) + FxHashMap::from_iter([(VarIndex::new(1), 1), (VarIndex::new(2), 2), (VarIndex::new(3), 3)]), ); + assert_eq!(constraint_set([1, 2]), deduped.removed_constraints); } #[test] fn test_noop() { @@ -47,7 +44,7 @@ fn test_noop() { let deduped = DedupSolver::dedup( constraint_vars(vec![vec![1], vec![1, 1], vec![2], vec![3]]), constraint_cliques(vec![vec![0], vec![1], vec![2], vec![3]]), - FxIndexSet::default(), + FxHashMap::from_iter([(VarIndex::new(1), 1), (VarIndex::new(2), 2), (VarIndex::new(3), 3)]), ); assert!(deduped.removed_constraints.is_empty()); } @@ -61,18 +58,9 @@ fn test_simple() { let deduped = DedupSolver::dedup( constraint_vars(vec![vec![1], vec![2], vec![3]]), constraint_cliques(vec![vec![0, 1], vec![2]]), - FxIndexSet::default(), - ); - assert!([constraint_set([0]), constraint_set([1])].contains(&deduped.removed_constraints)); -} -#[test] -fn test_simple_2() { - let deduped = DedupSolver::dedup( - constraint_vars(vec![vec![0, 1], vec![2, 1], vec![1, 0], vec![1, 2]]), - constraint_cliques(vec![vec![0, 1, 2, 3]]), - FxIndexSet::from_iter([VarIndex::new(0), VarIndex::new(1)]), + FxHashMap::from_iter([(VarIndex::new(1), 1), (VarIndex::new(2), 2), (VarIndex::new(3), 3)]), ); - assert_eq!(deduped.removed_constraints, constraint_set([1, 3])); + assert_eq!(constraint_set([1]), deduped.removed_constraints); } #[test] fn test_dependencies() { @@ -93,34 +81,18 @@ fn test_dependencies() { vec![4, 5], ]), constraint_cliques(vec![vec![0, 1], vec![2, 3], vec![4, 5]]), - FxIndexSet::default(), - ); - assert!( - [constraint_set([0, 2, 4]), constraint_set([1, 3, 5])] - .contains(&deduped.removed_constraints) + FxHashMap::from_iter([ + (VarIndex::new(1), 1), + (VarIndex::new(2), 2), + (VarIndex::new(4), 3), + (VarIndex::new(5), 4), + (VarIndex::new(13), 5), + (VarIndex::new(16), 6), + (VarIndex::new(23), 7), + (VarIndex::new(26), 8), + ]), ); -} -#[test] -fn test_unremovable_var() { - fn try_dedup(unremovable_vars: FxIndexSet) -> FxIndexSet { - // Same constraints as `test_dependencies`, but just imagine that all the vars in - // unremovable_vars are vars the caller can name, and therefore can't be removed - DedupSolver::dedup( - constraint_vars(vec![ - vec![1, 2, 13], - vec![4, 5, 16], - vec![1, 2, 23], - vec![4, 5, 26], - vec![1, 2], - vec![4, 5], - ]), - constraint_cliques(vec![vec![0, 1], vec![2, 3], vec![4, 5]]), - unremovable_vars, - ) - .removed_constraints - } - assert_eq!(try_dedup(FxIndexSet::from_iter([VarIndex::new(13)])), constraint_set([1, 3, 5])); - assert_eq!(try_dedup(FxIndexSet::from_iter([VarIndex::new(16)])), constraint_set([0, 2, 4])); + assert_eq!(constraint_set([1, 3, 5]), deduped.removed_constraints); } #[test] fn test_dependencies_unresolvable() { @@ -134,7 +106,16 @@ fn test_dependencies_unresolvable() { vec![4, 5], ]), constraint_cliques(vec![vec![0, 1], vec![2, 3], vec![4, 5]]), - FxIndexSet::default(), + FxHashMap::from_iter([ + (VarIndex::new(1), 1), + (VarIndex::new(2), 2), + (VarIndex::new(4), 3), + (VarIndex::new(5), 4), + (VarIndex::new(13), 5), + (VarIndex::new(16), 6), + (VarIndex::new(23), 7), + (VarIndex::new(26), 8), + ]), ); assert!(deduped.removed_constraints.is_empty()); } diff --git a/out.txt b/out.txt new file mode 100644 index 0000000000000..f7a8f45399b18 --- /dev/null +++ b/out.txt @@ -0,0 +1,1535 @@ +Building stage0 library artifacts (x86_64-unknown-linux-gnu) +Building compiler artifacts (stage0 -> stage1, x86_64-unknown-linux-gnu) +Assembling stage1 compiler +Building stage1 library artifacts (x86_64-unknown-linux-gnu) +Building stage0 tool compiletest (x86_64-unknown-linux-gnu) +Check compiletest suite=ui mode=ui (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) + +running 1 tests +F + +failures: + +---- [ui] tests/ui/traits/new-solver/dedup-placeholders.rs stdout ---- + +error: test compilation failed although it shouldn't! +status: exit status: 101 +command: "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc" "/home/ndrewxie/rust/tests/ui/traits/new-solver/dedup-placeholders.rs" "-Zthreads=1" "--sysroot" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/stage1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Zdeduplicate-diagnostics=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/test/ui/traits/new-solver/dedup-placeholders" "-A" "unused" "-Crpath" "-Cdebuginfo=0" "-Lnative=/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/test/ui/traits/new-solver/dedup-placeholders/auxiliary" "-Ztrait-solver=next" +--- stdout ------------------------------- +Computing goal Goal { + predicate: Binder(TraitPredicate( as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Consider impl candidate +Computing goal Goal { + predicate: Binder(TraitPredicate(, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Assembling with goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Auto trait candidate Goal { + predicate: TraitPredicate(, polarity:Positive), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +Disqualify auto trait self ty: !0 +Consider implied clause +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: ParamEnv( + 0, + ), + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ^0, + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: PlaceholderTy( + Placeholder { + universe: U0, + bound: BoundTy { + var: 0, + kind: Anon, + }, + }, + ), + }, + ], + }, + }, +] +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Assembling with goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Auto trait candidate Goal { + predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +Disqualify auto trait self ty: Unique +CANDIDATES: [ + Candidate { + source: Impl( + DefId(0:3 ~ dedup_placeholders[a62d]::{impl#0}), + ), + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ^0, + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: PlaceholderTy( + Placeholder { + universe: U0, + bound: BoundTy { + var: 0, + kind: Anon, + }, + }, + ), + }, + ], + }, + }, +] +Computing goal Goal { + predicate: Binder(WellFormed(Unique), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::wf +Adding wellformed Goal { predicate: Unique, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Wellformed yields subgoals [] +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Computing goal Goal { + predicate: Binder(WellFormed(!0), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::wf +Adding wellformed Goal { predicate: !0, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Wellformed yields subgoals [] +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Computing goal Goal { + predicate: Binder(WellFormed(*const !0), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::wf +Adding wellformed Goal { predicate: *const !0, param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Wellformed yields subgoals [] +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Computing goal Goal { + predicate: Binder(WellFormed(!0), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::wf +Adding wellformed Goal { predicate: !0, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Wellformed yields subgoals [] +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Computing goal Goal { + predicate: Binder(WellFormed(Unique>), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::wf +Adding wellformed Goal { predicate: Unique>, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Wellformed yields subgoals [Goal { predicate: Binder(TraitPredicate(, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } }] +Computing goal Goal { + predicate: Binder(TraitPredicate(, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Consider implied clause +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: ParamEnv( + 0, + ), + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ^0, + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: PlaceholderTy( + Placeholder { + universe: U0, + bound: BoundTy { + var: 0, + kind: Anon, + }, + }, + ), + }, + ], + }, + }, +] +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Computing goal Goal { + predicate: Binder(WellFormed(()), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::wf +Adding wellformed Goal { predicate: (), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Wellformed yields subgoals [] +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Computing goal Goal { + predicate: Binder(TraitPredicate(, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Consider implied clause +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: ParamEnv( + 1, + ), + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ^0, + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: PlaceholderTy( + Placeholder { + universe: U0, + bound: BoundTy { + var: 0, + kind: Anon, + }, + }, + ), + }, + ], + }, + }, +] +Computing goal Goal { + predicate: Binder(WellFormed(!0), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::wf +Adding wellformed Goal { predicate: !0, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Wellformed yields subgoals [] +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Computing goal Goal { + predicate: Binder(TraitPredicate(, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Assembling with goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Auto trait candidate Goal { + predicate: TraitPredicate(, polarity:Positive), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +Disqualify auto trait self ty: !0 +Consider implied clause +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: ParamEnv( + 0, + ), + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ^0, + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: PlaceholderTy( + Placeholder { + universe: U0, + bound: BoundTy { + var: 0, + kind: Anon, + }, + }, + ), + }, + ], + }, + }, +] +Computing goal Goal { + predicate: Binder(WellFormed(()), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::wf +Adding wellformed Goal { predicate: (), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Wellformed yields subgoals [] +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Computing goal Goal { + predicate: Binder(TraitPredicate(<() as std::marker::Sized>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [ + Binder(TraitPredicate(, polarity:Positive), []), + Binder(TraitPredicate(, polarity:Positive), []), + ], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(<() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(<() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } +Adding [] +probe_and_evaluate_goal_for_constituent_tys +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: BuiltinImpl, + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ^0, + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: PlaceholderTy( + Placeholder { + universe: U0, + bound: BoundTy { + var: 0, + kind: Anon, + }, + }, + ), + }, + ], + }, + }, +] +Computing goal Goal { + predicate: Binder(TraitPredicate(<() as std::marker::Sized>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(<() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(<() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Adding [] +probe_and_evaluate_goal_for_constituent_tys +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: BuiltinImpl, + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [], + }, + }, +] +Computing goal Goal { + predicate: Binder(WellFormed(Node<&()>), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::wf +Adding wellformed Goal { predicate: Node<&()>, param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Wellformed yields subgoals [Goal { predicate: Binder(TraitPredicate(<&() as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, Goal { predicate: Binder(OutlivesPredicate((), '?0), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }] +Computing goal Goal { + predicate: Binder(TraitPredicate(<&() as std::marker::Sized>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(<&() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(<&() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Adding [] +probe_and_evaluate_goal_for_constituent_tys +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: BuiltinImpl, + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], + }, + }, +] +Computing goal Goal { + predicate: Binder(OutlivesPredicate((), '?0), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::typeoutlives +Adding ty outlives Goal { predicate: OutlivesPredicate((), '?0), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +INPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + (), + '?0, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + (), + '?0, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +INPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + (), + '?0, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + (), + '?0, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Computing goal Goal { + predicate: Binder(TraitPredicate( as std::marker::Sized>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate( as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate( as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Adding [] +probe_and_evaluate_goal_for_constituent_tys +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: BuiltinImpl, + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], + }, + }, +] +Computing goal Goal { + predicate: Binder(TraitPredicate( as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Assembling with goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Auto trait candidate Goal { + predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +Disqualify auto trait self ty: Node<&()> +Adding [ + Goal { + predicate: Binder(TraitPredicate(<&() as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, + }, + Goal { + predicate: Binder(TraitPredicate(> as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, + }, +] +probe_and_evaluate_goal_for_constituent_tys +Computing goal Goal { + predicate: Binder(TraitPredicate(<&() as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(<&() as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(<&() as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Consider impl candidate +Computing goal Goal { + predicate: Binder(TraitPredicate(<() as std::marker::Sync>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(<() as std::marker::Sync>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(<() as std::marker::Sync>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Assembling with goal Goal { predicate: TraitPredicate(<() as std::marker::Sync>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Auto trait candidate Goal { + predicate: TraitPredicate(<() as std::marker::Sync>, polarity:Positive), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +Disqualify auto trait self ty: () +Adding [] +probe_and_evaluate_goal_for_constituent_tys +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: BuiltinImpl, + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [], + }, + }, +] +INPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + '?1, + '?0, + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + '?0, + '?1, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + '?1, + '?0, + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + '?0, + '?1, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Assembling with goal Goal { predicate: TraitPredicate(<&() as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Auto trait candidate Goal { + predicate: TraitPredicate(<&() as std::marker::Send>, polarity:Positive), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +Disqualify auto trait self ty: &() +CANDIDATES: [ + Candidate { + source: Impl( + DefId(2:2677 ~ core[c742]::marker::{impl#2}), + ), + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], + }, + }, +] +Computing goal Goal { + predicate: Binder(TraitPredicate(> as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Consider impl candidate +INPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Assembling with goal Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Auto trait candidate Goal { + predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +Disqualify auto trait self ty: Unique> +CANDIDATES: [ + Candidate { + source: Impl( + DefId(0:3 ~ dedup_placeholders[a62d]::{impl#0}), + ), + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], + }, + }, +] +INPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + '?1, + '?0, + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + '?0, + '?1, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + '?1, + '?0, + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + '?0, + '?1, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +CANDIDATES: [ + Candidate { + source: BuiltinImpl, + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], + }, + }, +] +Computing goal Goal { + predicate: Binder(TraitPredicate( as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Assembling with goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Auto trait candidate Goal { + predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +Disqualify auto trait self ty: Node<&()> +Adding [ + Goal { + predicate: Binder(TraitPredicate(<&() as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, + }, + Goal { + predicate: Binder(TraitPredicate(> as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, + }, +] +probe_and_evaluate_goal_for_constituent_tys +Computing goal Goal { + predicate: Binder(TraitPredicate(> as std::marker::Send>, polarity:Positive), []), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +clause::trait +Computing trait goal Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Computing candidates for Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Consider impl candidate +INPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + '?1, + '?0, + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + '?0, + '?1, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +OUTPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + '?1, + '?0, + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + '?0, + '?1, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +Exiting eval_added_goals - NOT an overflow +Assembling with goal Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } +Auto trait candidate Goal { + predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), + param_env: ParamEnv { + caller_bounds: [], + reveal: UserFacing, + constness: NotConst, + }, +} +Disqualify auto trait self ty: Unique> +CANDIDATES: [ + Candidate { + source: Impl( + DefId(0:3 ~ dedup_placeholders[a62d]::{impl#0}), + ), + result: Canonical { + value: Response { + certainty: Yes, + var_values: CanonicalVarValues { + var_values: [ + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ], + }, + external_constraints: ExternalConstraints( + Interned( + ExternalConstraintsData { + region_constraints: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), + ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), + ), + BoringNoLocation, + ), + ], + member_constraints: [], + }, + opaque_types: [], + }, + PrivateZst, + ), + ), + }, + max_universe: U0, + variables: [ + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + CanonicalVarInfo { + kind: Region( + U0, + ), + }, + ], + }, + }, +] +INPUT: QueryRegionConstraints { + outlives: [ + ( + OutlivesPredicate( + '?1, + '?0, + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + '?2, + '?0, + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + '?0, + '?1, + ), + BoringNoLocation, + ), + ( + OutlivesPredicate( + '?0, + '?2, + ), + BoringNoLocation, + ), + ], + member_constraints: [], +} +------------------------------------------ +--- stderr ------------------------------- +thread 'rustc' panicked at 'HERE'S THE STACK', compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs:59:53 +stack backtrace: + 0: 0x7f0400691b37 - std::backtrace_rs::backtrace::trace_unsynchronized::h352d783f8836f973 + 1: 0x7f0400687fab - ::fmt::h68e861c138d09dfc + 2: 0x7f0400704da9 - core::fmt::write::hc9837b4a6b405547 + 3: 0x7f0400655401 - std::io::Write::write_fmt::hb24223809381b675 + 4: 0x7f0400687e1d - std::sys_common::backtrace::print::h4375715fac3c73a0 + 5: 0x7f040066c6f7 - std::panicking::default_hook::{{closure}}::h1cd100ebfe0cbede + 6: 0x7f040066c49a - std::panicking::default_hook::hb341913f9cf3b16c + 7: 0x7f040101409f - rustc_driver_impl[3012c1cd686720e8]::DEFAULT_HOOK::{closure#0}::{closure#0} + 8: 0x7f040066cc72 - std::panicking::rust_panic_with_hook::h7b51e523793dcd2c + 9: 0x7f040065ef32 - std::panicking::begin_panic_handler::{{closure}}::h4eff0803b93bf7f1 + 10: 0x7f040065eea6 - std::sys_common::backtrace::__rust_end_short_backtrace::hc754a8eb77b3845c + 11: 0x7f040066c7f2 - rust_begin_unwind + 12: 0x7f04006543e3 - core::panicking::panic_fmt::h766f9bd0d9567fe0 + 13: 0x7f04031024de - >::fold_region + 14: 0x7f040321a4a8 - >::try_fold_with:: + 15: 0x7f04031939b3 - as rustc_type_ir[ec05b60311a3d35]::fold::TypeFoldable>::fold_with:: + 16: 0x7f04032a370e - ::erase_dedupables::> + 17: 0x7f04032a60d6 - ::dedup + 18: 0x7f040322e3ea - ::evaluate_added_goals_and_make_canonical_response + 19: 0x7f04032465fa - ::probe::, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>, ::probe, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>, ::probe_and_evaluate_goal_for_constituent_tys::{closure#0}>::{closure#0}> + 20: 0x7f04030f623f - ::probe_and_evaluate_goal_for_constituent_tys:: + 21: 0x7f0403149fa0 - ::consider_auto_trait_candidate + 22: 0x7f04030ef1e2 - ::assemble_and_evaluate_candidates:: + 23: 0x7f040322f9f9 - ::compute_trait_goal + 24: 0x7f040322ae0a - ::compute_goal + 25: 0x7f040328e72f - ::repeat_while_none::, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#0}, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#1}> + 26: 0x7f040330c86f - >::with_anon_task::::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>> + 27: 0x7f040328e9c0 - ::with_new_goal::<::evaluate_canonical_goal::{closure#0}::{closure#0}> + 28: 0x7f04032297b8 - ::evaluate_goal + 29: 0x7f040325df5b - ::evaluate_root_goal + 30: 0x7f04032a2f86 - ::select_where_possible + 31: 0x7f040146a22b - ::select_obligations_where_possible::<::lookup_op_method::{closure#2}> + 32: 0x7f04013de626 - ::check_argument_types + 33: 0x7f04013bbb55 - ::confirm_builtin_call + 34: 0x7f04013baec2 - ::check_call + 35: 0x7f040141ad55 - ::check_expr_kind + 36: 0x7f04013cc618 - ::check_expr_with_expectation_and_args + 37: 0x7f0401419b01 - ::check_expr_with_expectation + 38: 0x7f04013e563d - ::check_stmt + 39: 0x7f040146a93d - ::with_breakable_ctxt::<::check_block_with_expected::{closure#0}, ()> + 40: 0x7f04013e582e - ::check_block_with_expected + 41: 0x7f040141a784 - ::check_expr_kind + 42: 0x7f04013cc618 - ::check_expr_with_expectation_and_args + 43: 0x7f0401419b01 - ::check_expr_with_expectation + 44: 0x7f04013cde27 - ::check_return_expr + 45: 0x7f040149c666 - rustc_hir_typeck[6337532b6125a2ea]::check::check_fn + 46: 0x7f04015bb721 - rustc_hir_typeck[6337532b6125a2ea]::typeck_with_fallback:: + 47: 0x7f040283edcd - >>::with::::{closure#2}::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 8usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 8usize]>> + 48: 0x7f040295b9aa - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: + 49: 0x7f0402661ab4 - rustc_query_impl[d83653c600d19515]::get_query::typeck + 50: 0x7f040152d03c - rustc_middle[5074ee5b4c22835b]::ty::query::query_get_at::>> + 51: 0x7f040152d5b9 - rustc_hir_typeck[6337532b6125a2ea]::used_trait_imports + 52: 0x7f0402837acd - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 8usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 8usize]>> + 53: 0x7f040291352a - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: + 54: 0x7f0402662574 - rustc_query_impl[d83653c600d19515]::get_query::used_trait_imports + 55: 0x7f040177a595 - rustc_hir_analysis[2d38e76667e9459]::check_unused::check_crate + 56: 0x7f040176c426 - rustc_hir_analysis[2d38e76667e9459]::check_crate + 57: 0x7f04010ca581 - rustc_interface[7e80568d2ceb88d0]::passes::analysis + 58: 0x7f040283efc4 - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 1usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 1usize]>> + 59: 0x7f040295d147 - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: + 60: 0x7f0402644aba - rustc_query_impl[d83653c600d19515]::get_query::analysis + 61: 0x7f040107abfe - >>::with::::enter>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 62: 0x7f0401067f88 - ::enter::> + 63: 0x7f0401091994 - ::enter::, rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 64: 0x7f040101eac9 - rustc_span[bc72e8cf61038315]::set_source_map::, rustc_interface[7e80568d2ceb88d0]::interface::run_compiler, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}::{closure#0}> + 65: 0x7f040101f75f - >::set::, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 66: 0x7f0401084250 - std[e0afd7ea5d3fe186]::sys_common::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 67: 0x7f040109ae44 - ::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}> as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once + 68: 0x7f04010745e4 - std[e0afd7ea5d3fe186]::panicking::try::, core[4df9b0e25e0d2810]::panic::unwind_safe::AssertUnwindSafe<::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}>> + 69: 0x7f04010833e9 - std[e0afd7ea5d3fe186]::panic::catch_unwind::::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}>, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> + 70: 0x7f040109d822 - <::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1} as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} + 71: 0x7f04006a561a - as core::ops::function::FnOnce>::call_once::h481e59266d00f875 + 72: 0x7f04006ab7fa - std::sys::unix::thread::Thread::new::thread_start::h7e46e4f9732e143e + 73: 0x7f03f721cea7 - start_thread + 74: 0x7f0400502a2f - clone + 75: 0x0 - + +error: the compiler unexpectedly panicked. this is a bug. + +note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md + +note: rustc 1.71.0-dev running on x86_64-unknown-linux-gnu + +note: compiler flags: -Z threads=1 -C codegen-units=1 -Z ui-testing -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z deduplicate-diagnostics=no -C strip=debuginfo -C prefer-dynamic -C rpath -C debuginfo=0 -Z trait-solver=next + +query stack during panic: +#0 [typeck] type-checking `main` +#1 [used_trait_imports] finding used_trait_imports `main` +#2 [analysis] running analysis passes on this crate +end of query stack +------------------------------------------ + + + +failures: + [ui] tests/ui/traits/new-solver/dedup-placeholders.rs + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 14899 filtered out; finished in 53.67ms + +Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu diff --git a/tests/ui/traits/new-solver/dedup-vars.rs b/tests/ui/traits/new-solver/dedup-placeholders.rs similarity index 99% rename from tests/ui/traits/new-solver/dedup-vars.rs rename to tests/ui/traits/new-solver/dedup-placeholders.rs index 8d3bf7fa9aab6..bce0324094015 100644 --- a/tests/ui/traits/new-solver/dedup-vars.rs +++ b/tests/ui/traits/new-solver/dedup-placeholders.rs @@ -1,6 +1,5 @@ // check-pass // compile-flags: -Ztrait-solver=next - struct Foo where Foo:, From 61d08a6a2fdbdab1ed151ce8e6fec4fb838e59c0 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Sun, 28 May 2023 16:31:43 -0400 Subject: [PATCH 14/16] Removed unsound notion of unremovable_vars, prioritized removal of newer constraints over older (2) --- out.txt | 1535 ------------------------------------------------------- 1 file changed, 1535 deletions(-) delete mode 100644 out.txt diff --git a/out.txt b/out.txt deleted file mode 100644 index f7a8f45399b18..0000000000000 --- a/out.txt +++ /dev/null @@ -1,1535 +0,0 @@ -Building stage0 library artifacts (x86_64-unknown-linux-gnu) -Building compiler artifacts (stage0 -> stage1, x86_64-unknown-linux-gnu) -Assembling stage1 compiler -Building stage1 library artifacts (x86_64-unknown-linux-gnu) -Building stage0 tool compiletest (x86_64-unknown-linux-gnu) -Check compiletest suite=ui mode=ui (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) - -running 1 tests -F - -failures: - ----- [ui] tests/ui/traits/new-solver/dedup-placeholders.rs stdout ---- - -error: test compilation failed although it shouldn't! -status: exit status: 101 -command: "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc" "/home/ndrewxie/rust/tests/ui/traits/new-solver/dedup-placeholders.rs" "-Zthreads=1" "--sysroot" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/stage1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Zdeduplicate-diagnostics=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/test/ui/traits/new-solver/dedup-placeholders" "-A" "unused" "-Crpath" "-Cdebuginfo=0" "-Lnative=/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/home/ndrewxie/rust/build/x86_64-unknown-linux-gnu/test/ui/traits/new-solver/dedup-placeholders/auxiliary" "-Ztrait-solver=next" ---- stdout ------------------------------- -Computing goal Goal { - predicate: Binder(TraitPredicate( as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Consider impl candidate -Computing goal Goal { - predicate: Binder(TraitPredicate(, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Assembling with goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Auto trait candidate Goal { - predicate: TraitPredicate(, polarity:Positive), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -Disqualify auto trait self ty: !0 -Consider implied clause -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: ParamEnv( - 0, - ), - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ^0, - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: PlaceholderTy( - Placeholder { - universe: U0, - bound: BoundTy { - var: 0, - kind: Anon, - }, - }, - ), - }, - ], - }, - }, -] -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Assembling with goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Auto trait candidate Goal { - predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -Disqualify auto trait self ty: Unique -CANDIDATES: [ - Candidate { - source: Impl( - DefId(0:3 ~ dedup_placeholders[a62d]::{impl#0}), - ), - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ^0, - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: PlaceholderTy( - Placeholder { - universe: U0, - bound: BoundTy { - var: 0, - kind: Anon, - }, - }, - ), - }, - ], - }, - }, -] -Computing goal Goal { - predicate: Binder(WellFormed(Unique), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::wf -Adding wellformed Goal { predicate: Unique, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Wellformed yields subgoals [] -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Computing goal Goal { - predicate: Binder(WellFormed(!0), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::wf -Adding wellformed Goal { predicate: !0, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Wellformed yields subgoals [] -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Computing goal Goal { - predicate: Binder(WellFormed(*const !0), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::wf -Adding wellformed Goal { predicate: *const !0, param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Wellformed yields subgoals [] -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Computing goal Goal { - predicate: Binder(WellFormed(!0), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::wf -Adding wellformed Goal { predicate: !0, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Wellformed yields subgoals [] -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Computing goal Goal { - predicate: Binder(WellFormed(Unique>), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::wf -Adding wellformed Goal { predicate: Unique>, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Wellformed yields subgoals [Goal { predicate: Binder(TraitPredicate(, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } }] -Computing goal Goal { - predicate: Binder(TraitPredicate(, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Consider implied clause -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: ParamEnv( - 0, - ), - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ^0, - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: PlaceholderTy( - Placeholder { - universe: U0, - bound: BoundTy { - var: 0, - kind: Anon, - }, - }, - ), - }, - ], - }, - }, -] -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Computing goal Goal { - predicate: Binder(WellFormed(()), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::wf -Adding wellformed Goal { predicate: (), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Wellformed yields subgoals [] -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Computing goal Goal { - predicate: Binder(TraitPredicate(, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Consider implied clause -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: ParamEnv( - 1, - ), - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ^0, - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: PlaceholderTy( - Placeholder { - universe: U0, - bound: BoundTy { - var: 0, - kind: Anon, - }, - }, - ), - }, - ], - }, - }, -] -Computing goal Goal { - predicate: Binder(WellFormed(!0), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::wf -Adding wellformed Goal { predicate: !0, param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Wellformed yields subgoals [] -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Computing goal Goal { - predicate: Binder(TraitPredicate(, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Assembling with goal Goal { predicate: TraitPredicate(, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Auto trait candidate Goal { - predicate: TraitPredicate(, polarity:Positive), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -Disqualify auto trait self ty: !0 -Consider implied clause -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: ParamEnv( - 0, - ), - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ^0, - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: PlaceholderTy( - Placeholder { - universe: U0, - bound: BoundTy { - var: 0, - kind: Anon, - }, - }, - ), - }, - ], - }, - }, -] -Computing goal Goal { - predicate: Binder(WellFormed(()), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::wf -Adding wellformed Goal { predicate: (), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Wellformed yields subgoals [] -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Computing goal Goal { - predicate: Binder(TraitPredicate(<() as std::marker::Sized>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [ - Binder(TraitPredicate(, polarity:Positive), []), - Binder(TraitPredicate(, polarity:Positive), []), - ], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(<() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(<() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [Binder(TraitPredicate(, polarity:Positive), []), Binder(TraitPredicate(, polarity:Positive), [])], reveal: UserFacing, constness: NotConst } } -Adding [] -probe_and_evaluate_goal_for_constituent_tys -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: BuiltinImpl, - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ^0, - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: PlaceholderTy( - Placeholder { - universe: U0, - bound: BoundTy { - var: 0, - kind: Anon, - }, - }, - ), - }, - ], - }, - }, -] -Computing goal Goal { - predicate: Binder(TraitPredicate(<() as std::marker::Sized>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(<() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(<() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Adding [] -probe_and_evaluate_goal_for_constituent_tys -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: BuiltinImpl, - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [], - }, - }, -] -Computing goal Goal { - predicate: Binder(WellFormed(Node<&()>), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::wf -Adding wellformed Goal { predicate: Node<&()>, param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Wellformed yields subgoals [Goal { predicate: Binder(TraitPredicate(<&() as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, Goal { predicate: Binder(OutlivesPredicate((), '?0), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }] -Computing goal Goal { - predicate: Binder(TraitPredicate(<&() as std::marker::Sized>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(<&() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(<&() as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Adding [] -probe_and_evaluate_goal_for_constituent_tys -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: BuiltinImpl, - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], - }, - }, -] -Computing goal Goal { - predicate: Binder(OutlivesPredicate((), '?0), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::typeoutlives -Adding ty outlives Goal { predicate: OutlivesPredicate((), '?0), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -INPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - (), - '?0, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - (), - '?0, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -INPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - (), - '?0, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - (), - '?0, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Computing goal Goal { - predicate: Binder(TraitPredicate( as std::marker::Sized>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate( as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate( as std::marker::Sized>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Adding [] -probe_and_evaluate_goal_for_constituent_tys -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: BuiltinImpl, - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], - }, - }, -] -Computing goal Goal { - predicate: Binder(TraitPredicate( as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Assembling with goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Auto trait candidate Goal { - predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -Disqualify auto trait self ty: Node<&()> -Adding [ - Goal { - predicate: Binder(TraitPredicate(<&() as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, - }, - Goal { - predicate: Binder(TraitPredicate(> as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, - }, -] -probe_and_evaluate_goal_for_constituent_tys -Computing goal Goal { - predicate: Binder(TraitPredicate(<&() as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(<&() as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(<&() as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Consider impl candidate -Computing goal Goal { - predicate: Binder(TraitPredicate(<() as std::marker::Sync>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(<() as std::marker::Sync>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(<() as std::marker::Sync>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Assembling with goal Goal { predicate: TraitPredicate(<() as std::marker::Sync>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Auto trait candidate Goal { - predicate: TraitPredicate(<() as std::marker::Sync>, polarity:Positive), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -Disqualify auto trait self ty: () -Adding [] -probe_and_evaluate_goal_for_constituent_tys -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: BuiltinImpl, - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [], - }, - }, -] -INPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - '?1, - '?0, - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - '?0, - '?1, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - '?1, - '?0, - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - '?0, - '?1, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Assembling with goal Goal { predicate: TraitPredicate(<&() as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Auto trait candidate Goal { - predicate: TraitPredicate(<&() as std::marker::Send>, polarity:Positive), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -Disqualify auto trait self ty: &() -CANDIDATES: [ - Candidate { - source: Impl( - DefId(2:2677 ~ core[c742]::marker::{impl#2}), - ), - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], - }, - }, -] -Computing goal Goal { - predicate: Binder(TraitPredicate(> as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Consider impl candidate -INPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Assembling with goal Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Auto trait candidate Goal { - predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -Disqualify auto trait self ty: Unique> -CANDIDATES: [ - Candidate { - source: Impl( - DefId(0:3 ~ dedup_placeholders[a62d]::{impl#0}), - ), - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], - }, - }, -] -INPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - '?1, - '?0, - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - '?0, - '?1, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - '?1, - '?0, - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - '?0, - '?1, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -CANDIDATES: [ - Candidate { - source: BuiltinImpl, - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], - }, - }, -] -Computing goal Goal { - predicate: Binder(TraitPredicate( as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Assembling with goal Goal { predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Auto trait candidate Goal { - predicate: TraitPredicate( as std::marker::Send>, polarity:Positive), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -Disqualify auto trait self ty: Node<&()> -Adding [ - Goal { - predicate: Binder(TraitPredicate(<&() as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, - }, - Goal { - predicate: Binder(TraitPredicate(> as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, - }, -] -probe_and_evaluate_goal_for_constituent_tys -Computing goal Goal { - predicate: Binder(TraitPredicate(> as std::marker::Send>, polarity:Positive), []), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -clause::trait -Computing trait goal Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Computing candidates for Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Consider impl candidate -INPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - '?1, - '?0, - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - '?0, - '?1, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -OUTPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - '?1, - '?0, - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - '?0, - '?1, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} -Exiting eval_added_goals - NOT an overflow -Assembling with goal Goal { predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } } -Auto trait candidate Goal { - predicate: TraitPredicate(> as std::marker::Send>, polarity:Positive), - param_env: ParamEnv { - caller_bounds: [], - reveal: UserFacing, - constness: NotConst, - }, -} -Disqualify auto trait self ty: Unique> -CANDIDATES: [ - Candidate { - source: Impl( - DefId(0:3 ~ dedup_placeholders[a62d]::{impl#0}), - ), - result: Canonical { - value: Response { - certainty: Yes, - var_values: CanonicalVarValues { - var_values: [ - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ], - }, - external_constraints: ExternalConstraints( - Interned( - ExternalConstraintsData { - region_constraints: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }), - ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }), - ), - BoringNoLocation, - ), - ], - member_constraints: [], - }, - opaque_types: [], - }, - PrivateZst, - ), - ), - }, - max_universe: U0, - variables: [ - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - CanonicalVarInfo { - kind: Region( - U0, - ), - }, - ], - }, - }, -] -INPUT: QueryRegionConstraints { - outlives: [ - ( - OutlivesPredicate( - '?1, - '?0, - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - '?2, - '?0, - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - '?0, - '?1, - ), - BoringNoLocation, - ), - ( - OutlivesPredicate( - '?0, - '?2, - ), - BoringNoLocation, - ), - ], - member_constraints: [], -} ------------------------------------------- ---- stderr ------------------------------- -thread 'rustc' panicked at 'HERE'S THE STACK', compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/constraint_walker.rs:59:53 -stack backtrace: - 0: 0x7f0400691b37 - std::backtrace_rs::backtrace::trace_unsynchronized::h352d783f8836f973 - 1: 0x7f0400687fab - ::fmt::h68e861c138d09dfc - 2: 0x7f0400704da9 - core::fmt::write::hc9837b4a6b405547 - 3: 0x7f0400655401 - std::io::Write::write_fmt::hb24223809381b675 - 4: 0x7f0400687e1d - std::sys_common::backtrace::print::h4375715fac3c73a0 - 5: 0x7f040066c6f7 - std::panicking::default_hook::{{closure}}::h1cd100ebfe0cbede - 6: 0x7f040066c49a - std::panicking::default_hook::hb341913f9cf3b16c - 7: 0x7f040101409f - rustc_driver_impl[3012c1cd686720e8]::DEFAULT_HOOK::{closure#0}::{closure#0} - 8: 0x7f040066cc72 - std::panicking::rust_panic_with_hook::h7b51e523793dcd2c - 9: 0x7f040065ef32 - std::panicking::begin_panic_handler::{{closure}}::h4eff0803b93bf7f1 - 10: 0x7f040065eea6 - std::sys_common::backtrace::__rust_end_short_backtrace::hc754a8eb77b3845c - 11: 0x7f040066c7f2 - rust_begin_unwind - 12: 0x7f04006543e3 - core::panicking::panic_fmt::h766f9bd0d9567fe0 - 13: 0x7f04031024de - >::fold_region - 14: 0x7f040321a4a8 - >::try_fold_with:: - 15: 0x7f04031939b3 - as rustc_type_ir[ec05b60311a3d35]::fold::TypeFoldable>::fold_with:: - 16: 0x7f04032a370e - ::erase_dedupables::> - 17: 0x7f04032a60d6 - ::dedup - 18: 0x7f040322e3ea - ::evaluate_added_goals_and_make_canonical_response - 19: 0x7f04032465fa - ::probe::, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>, ::probe, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>, ::probe_and_evaluate_goal_for_constituent_tys::{closure#0}>::{closure#0}> - 20: 0x7f04030f623f - ::probe_and_evaluate_goal_for_constituent_tys:: - 21: 0x7f0403149fa0 - ::consider_auto_trait_candidate - 22: 0x7f04030ef1e2 - ::assemble_and_evaluate_candidates:: - 23: 0x7f040322f9f9 - ::compute_trait_goal - 24: 0x7f040322ae0a - ::compute_goal - 25: 0x7f040328e72f - ::repeat_while_none::, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#0}, ::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}::{closure#1}> - 26: 0x7f040330c86f - >::with_anon_task::::with_new_goal<::evaluate_canonical_goal::{closure#0}::{closure#0}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result, rustc_middle[5074ee5b4c22835b]::traits::query::NoSolution>> - 27: 0x7f040328e9c0 - ::with_new_goal::<::evaluate_canonical_goal::{closure#0}::{closure#0}> - 28: 0x7f04032297b8 - ::evaluate_goal - 29: 0x7f040325df5b - ::evaluate_root_goal - 30: 0x7f04032a2f86 - ::select_where_possible - 31: 0x7f040146a22b - ::select_obligations_where_possible::<::lookup_op_method::{closure#2}> - 32: 0x7f04013de626 - ::check_argument_types - 33: 0x7f04013bbb55 - ::confirm_builtin_call - 34: 0x7f04013baec2 - ::check_call - 35: 0x7f040141ad55 - ::check_expr_kind - 36: 0x7f04013cc618 - ::check_expr_with_expectation_and_args - 37: 0x7f0401419b01 - ::check_expr_with_expectation - 38: 0x7f04013e563d - ::check_stmt - 39: 0x7f040146a93d - ::with_breakable_ctxt::<::check_block_with_expected::{closure#0}, ()> - 40: 0x7f04013e582e - ::check_block_with_expected - 41: 0x7f040141a784 - ::check_expr_kind - 42: 0x7f04013cc618 - ::check_expr_with_expectation_and_args - 43: 0x7f0401419b01 - ::check_expr_with_expectation - 44: 0x7f04013cde27 - ::check_return_expr - 45: 0x7f040149c666 - rustc_hir_typeck[6337532b6125a2ea]::check::check_fn - 46: 0x7f04015bb721 - rustc_hir_typeck[6337532b6125a2ea]::typeck_with_fallback:: - 47: 0x7f040283edcd - >>::with::::{closure#2}::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 8usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 8usize]>> - 48: 0x7f040295b9aa - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: - 49: 0x7f0402661ab4 - rustc_query_impl[d83653c600d19515]::get_query::typeck - 50: 0x7f040152d03c - rustc_middle[5074ee5b4c22835b]::ty::query::query_get_at::>> - 51: 0x7f040152d5b9 - rustc_hir_typeck[6337532b6125a2ea]::used_trait_imports - 52: 0x7f0402837acd - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 8usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 8usize]>> - 53: 0x7f040291352a - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: - 54: 0x7f0402662574 - rustc_query_impl[d83653c600d19515]::get_query::used_trait_imports - 55: 0x7f040177a595 - rustc_hir_analysis[2d38e76667e9459]::check_unused::check_crate - 56: 0x7f040176c426 - rustc_hir_analysis[2d38e76667e9459]::check_crate - 57: 0x7f04010ca581 - rustc_interface[7e80568d2ceb88d0]::passes::analysis - 58: 0x7f040283efc4 - >>::with::::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 1usize]>>::{closure#0}, rustc_middle[5074ee5b4c22835b]::query::erase::Erased<[u8; 1usize]>> - 59: 0x7f040295d147 - rustc_query_system[2c39904fb33629ae]::query::plumbing::try_execute_query:: - 60: 0x7f0402644aba - rustc_query_impl[d83653c600d19515]::get_query::analysis - 61: 0x7f040107abfe - >>::with::::enter>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 62: 0x7f0401067f88 - ::enter::> - 63: 0x7f0401091994 - ::enter::, rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 64: 0x7f040101eac9 - rustc_span[bc72e8cf61038315]::set_source_map::, rustc_interface[7e80568d2ceb88d0]::interface::run_compiler, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}::{closure#0}> - 65: 0x7f040101f75f - >::set::, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 66: 0x7f0401084250 - std[e0afd7ea5d3fe186]::sys_common::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 67: 0x7f040109ae44 - ::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}> as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once - 68: 0x7f04010745e4 - std[e0afd7ea5d3fe186]::panicking::try::, core[4df9b0e25e0d2810]::panic::unwind_safe::AssertUnwindSafe<::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}>> - 69: 0x7f04010833e9 - std[e0afd7ea5d3fe186]::panic::catch_unwind::::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1}::{closure#0}>, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>> - 70: 0x7f040109d822 - <::spawn_unchecked_, rustc_driver_impl[3012c1cd686720e8]::run_compiler::{closure#1}>::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[4df9b0e25e0d2810]::result::Result<(), rustc_span[bc72e8cf61038315]::ErrorGuaranteed>>::{closure#1} as core[4df9b0e25e0d2810]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} - 71: 0x7f04006a561a - as core::ops::function::FnOnce>::call_once::h481e59266d00f875 - 72: 0x7f04006ab7fa - std::sys::unix::thread::Thread::new::thread_start::h7e46e4f9732e143e - 73: 0x7f03f721cea7 - start_thread - 74: 0x7f0400502a2f - clone - 75: 0x0 - - -error: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc 1.71.0-dev running on x86_64-unknown-linux-gnu - -note: compiler flags: -Z threads=1 -C codegen-units=1 -Z ui-testing -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z deduplicate-diagnostics=no -C strip=debuginfo -C prefer-dynamic -C rpath -C debuginfo=0 -Z trait-solver=next - -query stack during panic: -#0 [typeck] type-checking `main` -#1 [used_trait_imports] finding used_trait_imports `main` -#2 [analysis] running analysis passes on this crate -end of query stack ------------------------------------------- - - - -failures: - [ui] tests/ui/traits/new-solver/dedup-placeholders.rs - -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 14899 filtered out; finished in 53.67ms - -Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu From 711986b49cd75ac7520f7d38702a6260363e8660 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Sun, 28 May 2023 23:20:25 -0400 Subject: [PATCH 15/16] Hopefully simplified solver impl a bit --- .../canonical/dedup_solver/solver.rs | 282 +++++++++++------- 1 file changed, 170 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs index 69b69bdff8adb..8cd5075f90337 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -1,7 +1,9 @@ +const MAX_DFS_DEPTH: usize = 6; // lol + use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_index::{Idx, IndexVec}; use std::cell::RefCell; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; #[cfg(test)] mod tests; @@ -30,7 +32,7 @@ pub struct DedupSolver { /// The below are internal variables used in the solving process: /// All the mappings that can possibly be taken - mappings: FxIndexMap, + mappings: FxIndexMap, /// Constraints that have already been removed by deduplication removed_constraints: RefCell>, /// All of the currently applied var mappings, summed together @@ -43,10 +45,11 @@ pub struct DedupResult { #[derive(Clone, Hash, PartialEq, Eq, Debug)] struct Mapping(BTreeMap); #[derive(Debug, Clone, PartialEq, Eq)] -struct MappingInfo { - /// The constraints that a mapping will eliminate. For example, if we have the constraints - /// [1, 2] (with ConstraintIndex of 0) and [3, 4], the mapping 1:3,2:4 will eliminate constraint 0 - eliminated_constraints: FxIndexSet, +enum MappingEval { + /// If a mapping can be applied just as-is, the mapping eval result is of variant `Removes`, which + /// contains the set of constraints that the mapping will remove. The meaning of "as-is" is explained + /// in the doc for the next variant + Removes(FxIndexSet), /// A mapping has dependencies if it only maps a subset of the variables in a constraint, and therefore /// depends on another mapping to complete the full mapping. For example, if we have the constraints /// [1, 2] (index 1), [11, 12] (index 2), [2, 3] (index 3), and [12, 13] (index 4), the mapping @@ -54,8 +57,15 @@ struct MappingInfo { /// map the 3rd constraint (because the mapping maps var 2, which the 3rd constraint contains). /// This will partially map the 3rd constraint into [12, 3], which isn't a pre-existing constraint - HOWEVER, /// if we also apply the mapping var2->var12,var3->var13, then it maps the constraint to [12, 13] which *is* - /// a preexisting constraint. Therefore, the two constraints depend on each other - dependencies: FxIndexMap>, + /// a preexisting constraint. Therefore, the "mappabiilty" of the two constraints depends on that of the other. + /// `DependsOn` is a set of vecs because a constraint can depend on multiple other cnostraints being mapped - each + /// constraint that has to be mapped gets its own Vec that stores the list of Mappings that will satisfy the dependency + DependsOn(FxIndexSet>), + /// A temporary, intermediate variant used to calculate the actual contents of the `DependsOn` variant + InterimDependencies { + removes: FxIndexSet, + depends_on: FxIndexSet, + }, } impl DedupSolver { @@ -127,22 +137,25 @@ impl DedupSolver { } else { (reverse, eval_reverse) }; - if self.try_apply_mapping(&chosen_mapping, &chosen_eval, false) == Err(true) { + + // If there's dependencies, we add it to mappings and will think about it later + if matches!(&chosen_eval, MappingEval::InterimDependencies { .. }) { self.mappings.insert(chosen_mapping, chosen_eval); + continue; } + // Otherwise apply + let _ = self.try_apply_mapping(&chosen_mapping, &chosen_eval); } } } - self.resolve_dependencies_to_mapping(); + self.mappings.retain(|mapping, _| !self.applied_mappings.borrow().conflicts_with(mapping)); + self.resolve_interim_dependencies(); } - /// Evaluates the mapping. Can return None if the mapping is invalid (i.e. it maps + /// Evaluates the mapping. Can return Err if the mapping is invalid (i.e. it maps /// some constraints onto a constraint that doesn't exist, or conflicts with the - /// mappings that were already greedily applied). Otherwise, returns MappingInfo. - /// MappingInfo can contain dependencies - these occur if a mapping *partially* maps - /// a constraint onto another, so the mapping isn't immediately invalid, but we do need - /// another mapping to complete that partial map for it to actually be valid - fn eval_mapping(&self, mapping: &Mapping) -> Result { - let mut info = MappingInfo::new(); + /// mappings that were already greedily applied). Otherwise, returns a MappingEval + fn eval_mapping(&self, mapping: &Mapping) -> Result { + let mut eval = MappingEval::new(); for clique in self.constraint_cliques.iter() { for constraint_1 in clique { let vars_1 = &self.constraint_vars[*constraint_1]; @@ -163,11 +176,11 @@ impl DedupSolver { if !mapping.contains_fully(&trial_mapping) { // The input mapping can be applied only if there's another mapping that // maps every variable in constraint_1 (and doesn't conflict with the input mapping) - info.dependencies.insert(*constraint_1, BTreeSet::default()); + eval.add_constraint_dependency(*constraint_1); continue; } if *constraint_1 != *constraint_2 { - info.eliminated_constraints.insert(*constraint_1); + eval.add_constraint_removal(*constraint_1); } } if !found_non_conflicting { @@ -175,56 +188,40 @@ impl DedupSolver { } } } - Ok(info) + Ok(eval) } - /// Currently, dependencies are in the form FxIndexMap, - /// where ConstraintIndex is the constraint we must *also* map in order to apply this mapping. - /// We must populate the Empty FxIndexSet with a set of mappings that can map the constraint without - /// conflicting with the current mapping - fn resolve_dependencies_to_mapping(&mut self) { - self.mappings.retain(|mapping, mapping_info| { + /// Currently, all dependencies are InterimDependencies(dep_set), where dep_set is the set of constraints + /// that the mapping depends on. This function will convert those InterimDependencies into DependsOns, + /// which contain information about which mappings can satisfy the dependencies + fn resolve_interim_dependencies(&mut self) { + self.mappings.retain(|mapping, mapping_eval| { // Remove mappings that conflict with already-applied mappings if self.applied_mappings.borrow().conflicts_with(mapping) { return false; } // If a constraint has already been removed by a pre-existing mapping, this current // mapping's dependency on this constraint has been resolved - mapping_info - .dependencies - .retain(|dependency, _| !self.removed_constraints.borrow().contains(dependency)); + if let MappingEval::InterimDependencies { depends_on, .. } = mapping_eval { + depends_on.retain(|x| !self.removed_constraints.borrow().contains(x)); + } true }); // A map from a constraint to the mappings that will eliminate it (i.e. map it fully) - let mut constraint_mappings: FxIndexMap> = + let mut constraint_mappings: FxIndexMap> = FxIndexMap::default(); - for (indx, (_, mapping_info)) in self.mappings.iter().enumerate() { - for eliminated_constraint in mapping_info.eliminated_constraints.iter() { + for (mapping_index, (_, mapping_info)) in self.mappings.iter().enumerate() { + let Some(removes_constraints) = mapping_info.removes_constraints() else { + continue; + }; + for eliminated_constraint in removes_constraints { constraint_mappings .entry(*eliminated_constraint) - .or_insert_with(BTreeSet::default) - .insert(MappingIndex::new(indx)); + .or_insert_with(Vec::new) + .push(MappingIndex::new(mapping_index)); } } - for indx in (0..self.mappings.len()).map(MappingIndex::new) { - let mapping = self.get_mapping(indx); - let input_dependencies = &self.get_mapping_info(indx).dependencies; - let mut dependencies = FxIndexSet::default(); - for (dependency, _) in input_dependencies.iter() { - // The set of mappings that can resolve this dependency - let mut resolve_options = - constraint_mappings.get(dependency).cloned().unwrap_or_else(BTreeSet::new); - resolve_options.retain(|x| !mapping.conflicts_with(&self.get_mapping(*x))); - dependencies.insert(resolve_options); - } - // After this point, the actual constraints that a dependency maps - // stops mattering - all that matters is that the dependency *exists* - let old_dependencies = - &mut self.mappings.get_index_mut(indx.index()).unwrap().1.dependencies; - *old_dependencies = dependencies - .into_iter() - .enumerate() - .map(|(indx, x)| (ConstraintIndex::from(indx), x)) - .collect(); + for (_, mapping_eval) in self.mappings.iter_mut() { + mapping_eval.resolve_from_interim(&constraint_mappings); } } @@ -233,35 +230,35 @@ impl DedupSolver { fn resolve_dependencies(&mut self) { let mut used_mappings = FxIndexSet::default(); for indx in (0..self.mappings.len()).map(MappingIndex::new) { - if used_mappings.contains(&indx) { - continue; - } - if self.applied_mappings.borrow().conflicts_with(self.get_mapping(indx)) { + if used_mappings.contains(&indx) + || self.applied_mappings.borrow().conflicts_with(self.get_mapping(indx)) + { continue; } + let applied_mappings = self.applied_mappings.borrow().clone(); - let mut starting_set = FxIndexSet::default(); - starting_set.insert(indx); - if let Some(applied_mappings) = - self.dfs_search(used_mappings.clone(), applied_mappings, starting_set) - { + let starting_set = FxIndexSet::from_iter([indx]); + if let Some(applied_mappings) = self.dfs_search( + used_mappings.clone(), + applied_mappings, + starting_set, + MAX_DFS_DEPTH, + ) { + let mut summed_mapping = self.applied_mappings.borrow().clone(); for mapping in applied_mappings { - if used_mappings.contains(&mapping) { - continue; - } - let application_result = self.try_apply_mapping( - self.get_mapping(mapping), - self.get_mapping_info(mapping), - true, - ); - assert!(application_result.is_ok()); + summed_mapping.join_mappings(&self.get_mapping(mapping)); used_mappings.insert(mapping); } + let summed_eval = self.eval_mapping(&summed_mapping); + assert!(summed_eval.is_ok()); + let application_result = + self.try_apply_mapping(&summed_mapping, &summed_eval.unwrap()); + assert!(application_result.is_ok()); } } } /// Finds a set of mappings that mutually satisfy each other's dependencies without conflicting with each - /// other, or the mappings that have already been applied. It does this through depth first search - + /// other or the mappings that have already been applied. It does this through depth first search - /// it takes a FxIndexSet of the mappings that have already been presumed to be part of the mapping set as well /// as a FxIndexSet of mappings that we are trying to add to this set (`from`). These mappings still may have /// dependencies that might be unresolved, so dfs_search attempts to resolve these dependencies, recursively calling @@ -271,38 +268,42 @@ impl DedupSolver { mut used_mappings: FxIndexSet, mut applied_mappings: Mapping, mut from: FxIndexSet, + remaining_depth: usize, ) -> Option> { + if remaining_depth == 0 { + return None; + } + + // If we already applied a mapping, we now remove it from `from`, as its dependencies have + // been resolved and therefore we don't need to worry about it + from.retain(|x| !used_mappings.contains(x)); + used_mappings.extend(from.iter()); + // Apply the mappings that we're trying to apply (in `from`), aborting if there's any conflicts for mapping_indx in from.iter() { let (mapping, _) = self.mappings.get_index(mapping_indx.index()).unwrap(); if applied_mappings.conflicts_with(mapping) { return None; } - applied_mappings.0.extend(&mapping.0); + applied_mappings.join_mappings(&mapping); } - // If we already applied a mapping, we now remove it from `from`, as its dependencies have - // been resolved and therefore we don't need to worry about it - from.retain(|x| !used_mappings.contains(x)); - used_mappings.extend(from.iter()); // For each unresolved dependency, we have a list of Mappings that can resolve it - let mut unresolved_dependencies: FxIndexSet> = FxIndexSet::default(); - for from_mapping in from.iter() { - let resolve_options = self.get_mapping_info(*from_mapping).dependencies.values(); - let resolve_options = resolve_options.map(|x| { - Vec::from_iter( - x.iter() - .cloned() - // Throw out mappings that conflict with the current `used_mappings` we're - // trying to satisfy the dependencies of - .filter(|x| !self.get_mapping(*x).conflicts_with(&applied_mappings)), - ) - }); - unresolved_dependencies.extend(resolve_options); - } + let unresolved_dependencies: FxIndexSet> = FxIndexSet::from_iter( + from.iter() + .flat_map(|x| self.get_mapping_info(*x).get_mapping_dependencies().unwrap()) + .map(|mapping_choices| { + let mut new_choices = mapping_choices.clone(); + new_choices.retain(|x| !self.get_mapping(*x).conflicts_with(&applied_mappings)); + new_choices + }), + ); + + // Wooo, no dependencies left to resolve! if unresolved_dependencies.is_empty() { return Some(used_mappings); } + // At least one dependency has no viable resolution options (the Vec is empty) - failed if unresolved_dependencies.iter().any(|x| x.is_empty()) { return None; } @@ -318,8 +319,12 @@ impl DedupSolver { // The set of mappings that were chosen to be added next let choice: FxIndexSet = trial_indices.iter().zip(&unresolved_dependencies).map(|(x, y)| y[*x]).collect(); - let search_result = - self.dfs_search(used_mappings.clone(), applied_mappings.clone(), choice); + let search_result = self.dfs_search( + used_mappings.clone(), + applied_mappings.clone(), + choice, + remaining_depth - 1, + ); if search_result.is_some() { return search_result; } @@ -337,29 +342,22 @@ impl DedupSolver { None } - /// Tries to apply a mapping, returning Ok(()) if the application was a success, Err(true) if the - /// application failed but only because of unresolved dependencies, and Err(false) if the application - /// fails because of conflicts - fn try_apply_mapping( - &self, - mapping: &Mapping, - info: &MappingInfo, - allow_dependencies: bool, - ) -> Result<(), bool> { - if !allow_dependencies && !info.dependencies.is_empty() { - return Err(true); - } + /// Tries to apply a mapping, returning Ok if it works, otherwise Err + fn try_apply_mapping(&self, mapping: &Mapping, info: &MappingEval) -> Result<(), ()> { + let MappingEval::Removes(removes) = info else { + return Err(()); + }; if self.applied_mappings.borrow().conflicts_with(mapping) { - return Err(false); + return Err(()); } - self.removed_constraints.borrow_mut().extend(info.eliminated_constraints.iter()); - self.applied_mappings.borrow_mut().0.extend(&mapping.0); + self.removed_constraints.borrow_mut().extend(removes.clone()); + self.applied_mappings.borrow_mut().join_mappings(&mapping); Ok(()) } fn get_mapping(&self, index: MappingIndex) -> &Mapping { &self.mappings.get_index(index.index()).unwrap().0 } - fn get_mapping_info(&self, index: MappingIndex) -> &MappingInfo { + fn get_mapping_info(&self, index: MappingIndex) -> &MappingEval { &self.mappings.get_index(index.index()).unwrap().1 } } @@ -422,9 +420,69 @@ impl Mapping { fn max_removed_universe(&self, var_universes: &FxHashMap) -> usize { self.0.keys().map(|x| *var_universes.get(x).unwrap()).max().unwrap_or(0) } + fn join_mappings(&mut self, other: &Self) { + assert!(!self.conflicts_with(other)); + self.0.extend(&other.0); + } } -impl MappingInfo { +impl MappingEval { fn new() -> Self { - Self { dependencies: FxIndexMap::default(), eliminated_constraints: FxIndexSet::default() } + Self::Removes(FxIndexSet::default()) + } + fn add_constraint_removal(&mut self, constraint: ConstraintIndex) { + match self { + Self::Removes(removes) => { + removes.insert(constraint); + } + Self::InterimDependencies { removes, .. } => { + removes.insert(constraint); + } + _ => {} + } + } + fn add_constraint_dependency(&mut self, constraint: ConstraintIndex) { + if let Self::InterimDependencies { depends_on, .. } = self { + depends_on.insert(constraint); + return; + } + if let Self::Removes(removes) = self.clone() { + *self = Self::InterimDependencies { + removes: removes, + depends_on: FxIndexSet::from_iter([constraint]), + }; + } + } + fn removes_constraints<'a>(&'a self) -> Option<&'a FxIndexSet> { + match self { + Self::Removes(removes) => Some(removes), + Self::InterimDependencies { removes, .. } => Some(removes), + _ => None, + } + } + fn resolve_from_interim( + &mut self, + constraint_mappings: &FxIndexMap>, + ) { + match self.clone() { + Self::InterimDependencies { depends_on, .. } => { + let resolution_set = depends_on + .into_iter() + .map(|x| { + let mut maps = + constraint_mappings.get(&x).cloned().unwrap_or_else(Vec::new); + maps.sort(); + maps + }) + .collect::>(); + *self = Self::DependsOn(resolution_set); + } + _ => {} + } + } + fn get_mapping_dependencies<'a>(&'a self) -> Option<&'a FxIndexSet>> { + match self { + Self::DependsOn(set) => Some(set), + _ => None, + } } } From 67fbe17e064329a886479ddb34676c2c4099f261 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Sun, 28 May 2023 23:21:17 -0400 Subject: [PATCH 16/16] Hopefully simplified solver impl a bit (2) --- .../src/solve/eval_ctxt/canonical/dedup_solver/solver.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs index 8cd5075f90337..c8b2b21a8429a 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical/dedup_solver/solver.rs @@ -129,6 +129,8 @@ impl DedupSolver { continue; }; + // Prioritize the removal of constraints referencing higher universes, because + // those are newer constraints (right?) let max_forward_universe = forward.max_removed_universe(&self.var_universes); let max_reverse_universe = reverse.max_removed_universe(&self.var_universes); let (chosen_mapping, chosen_eval) =