diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index ead75dcd798..5a89fd89941 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -385,13 +385,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { option_regions: _, } => { let hidden_ty = self.resolve_vars_if_possible(&hidden_ty); - opaque_types::report_unexpected_hidden_region( + opaque_types::unexpected_hidden_region_diagnostic( self.tcx, Some(region_scope_tree), opaque_type_def_id, hidden_ty, pick_region, - ); + ).emit(); } } } diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 656b9271115..1bc5ce473f5 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -9,6 +9,7 @@ use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind}; use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt}; use crate::util::nodemap::DefIdMap; +use errors::DiagnosticBuilder; use rustc_data_structures::fx::FxHashMap; use std::rc::Rc; @@ -499,13 +500,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } -pub fn report_unexpected_hidden_region( +pub fn unexpected_hidden_region_diagnostic( tcx: TyCtxt<'tcx>, region_scope_tree: Option<®ion::ScopeTree>, opaque_type_def_id: DefId, hidden_ty: Ty<'tcx>, hidden_region: ty::Region<'tcx>, -) { +) -> DiagnosticBuilder<'tcx> { let span = tcx.def_span(opaque_type_def_id); let mut err = struct_span_err!( tcx.sess, @@ -573,7 +574,7 @@ pub fn report_unexpected_hidden_region( } } - err.emit(); + err } // Visitor that requires that (almost) all regions in the type visited outlive @@ -724,13 +725,13 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { None => { if !self.map_missing_regions_to_empty && !self.tainted_by_errors { if let Some(hidden_ty) = self.hidden_ty.take() { - report_unexpected_hidden_region( + unexpected_hidden_region_diagnostic( self.tcx, None, self.opaque_type_def_id, hidden_ty, r, - ); + ).emit(); } } self.tcx.lifetimes.re_empty diff --git a/src/librustc_mir/borrow_check/nll/pick_constraints.rs b/src/librustc_mir/borrow_check/nll/pick_constraints.rs index b594a15b6d8..dff0801f2eb 100644 --- a/src/librustc_mir/borrow_check/nll/pick_constraints.rs +++ b/src/librustc_mir/borrow_check/nll/pick_constraints.rs @@ -71,10 +71,12 @@ impl<'tcx> PickConstraintSet<'tcx, ty::RegionVid> { p_c: &PickConstraint<'tcx>, mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid, ) { + debug!("push_constraint(p_c={:?})", p_c); let pick_region_vid: ty::RegionVid = to_region_vid(p_c.pick_region); let next_constraint = self.first_constraints.get(&pick_region_vid).cloned(); let start_index = self.option_regions.len(); let end_index = start_index + p_c.option_regions.len(); + debug!("push_constraint: pick_region_vid={:?}", pick_region_vid); let constraint_index = self.constraints.push(NllPickConstraint { next_constraint, pick_region_vid, @@ -136,6 +138,12 @@ impl<'tcx, R> PickConstraintSet<'tcx, R> where R: Copy + Hash + Eq, { + crate fn all_indices( + &self, + ) -> impl Iterator { + self.constraints.indices() + } + /// Iterate down the constraint indices associated with a given /// peek-region. You can then use `option_regions` and other /// methods to access data. diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index adee5bda425..ad58e4a47eb 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1,20 +1,23 @@ use super::universal_regions::UniversalRegions; use crate::borrow_check::nll::constraints::graph::NormalConstraintGraph; -use crate::borrow_check::nll::constraints::{ConstraintSccIndex, OutlivesConstraintSet, OutlivesConstraint}; +use crate::borrow_check::nll::constraints::{ + ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet, +}; use crate::borrow_check::nll::pick_constraints::PickConstraintSet; use crate::borrow_check::nll::region_infer::values::{ - PlaceholderIndices, RegionElement, ToElementIndex + PlaceholderIndices, RegionElement, ToElementIndex, }; -use crate::borrow_check::Upvar; use crate::borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use crate::borrow_check::nll::type_check::Locations; +use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryOutlivesConstraint; +use rustc::infer::opaque_types; use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin}; use rustc::mir::{ - ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, - ConstraintCategory, Local, Location, Body, + Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, + ConstraintCategory, Local, Location, }; use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common::{self, ErrorReported}; @@ -61,6 +64,9 @@ pub struct RegionInferenceContext<'tcx> { /// compute the values of each region. constraint_sccs: Rc>, + /// The "pick R0 from [R1..Rn]" constraints, indexed by SCC. + pick_constraints: Rc>, + /// Map closure bounds to a `Span` that should be used for error reporting. closure_bounds_mapping: FxHashMap>, @@ -188,7 +194,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { universal_region_relations: Rc>, _body: &Body<'tcx>, outlives_constraints: OutlivesConstraintSet, - pick_constraints: PickConstraintSet<'tcx, RegionVid>, + pick_constraints_in: PickConstraintSet<'tcx, RegionVid>, closure_bounds_mapping: FxHashMap< Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, @@ -220,9 +226,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions); - let _pick_constraints_scc = pick_constraints.into_mapped( // TODO - |r| constraint_sccs.scc(r), - ); + let pick_constraints = Rc::new(pick_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); let mut result = Self { definitions, @@ -230,6 +234,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraints, constraint_graph, constraint_sccs, + pick_constraints, closure_bounds_mapping, scc_universes, scc_representatives, @@ -347,9 +352,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!( "init_free_and_bound_regions: placeholder {:?} is \ not compatible with universe {:?} of its SCC {:?}", - placeholder, - scc_universe, - scc, + placeholder, scc_universe, scc, ); self.add_incompatible_universe(scc); } @@ -434,11 +437,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // to store those. Otherwise, we'll pass in `None` to the // functions below, which will trigger them to report errors // eagerly. - let mut outlives_requirements = if infcx.tcx.is_closure(mir_def_id) { - Some(vec![]) - } else { - None - }; + let mut outlives_requirements = + if infcx.tcx.is_closure(mir_def_id) { Some(vec![]) } else { None }; self.check_type_tests( infcx, @@ -457,16 +457,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer, ); + self.check_pick_constraints(infcx, mir_def_id, errors_buffer); + let outlives_requirements = outlives_requirements.unwrap_or(vec![]); if outlives_requirements.is_empty() { None } else { let num_external_vids = self.universal_regions.num_global_and_external_regions(); - Some(ClosureRegionRequirements { - num_external_vids, - outlives_requirements, - }) + Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }) } } @@ -496,6 +495,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + /// Computes the value of the SCC `scc_a` if it has not already + /// been computed. The `visited` parameter is a bitset #[inline] fn propagate_constraint_sccs_if_new( &mut self, @@ -507,6 +508,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + /// Computes the value of the SCC `scc_a`, which has not yet been + /// computed. This works by first computing all successors of the + /// SCC (if they haven't been computed already) and then unioning + /// together their elements. fn propagate_constraint_sccs_new( &mut self, scc_a: ConstraintSccIndex, @@ -516,10 +521,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Walk each SCC `B` such that `A: B`... for &scc_b in constraint_sccs.successors(scc_a) { - debug!( - "propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", - scc_a, scc_b - ); + debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b); // ...compute the value of `B`... self.propagate_constraint_sccs_if_new(scc_b, visited); @@ -537,6 +539,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + // Now take pick constraints into account + let pick_constraints = self.pick_constraints.clone(); + for p_c_i in pick_constraints.indices(scc_a) { + self.apply_pick_constraint(scc_a, pick_constraints.option_regions(p_c_i)); + } + debug!( "propagate_constraint_sccs: scc_a = {:?} has value {:?}", scc_a, @@ -544,6 +552,114 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); } + /// Invoked for each `pick R0 from [R1..Rn]` constraint. + /// + /// `scc` is the SCC containing R0, and `option_regions` are the + /// `R1..Rn` regions -- they are always known to be universal + /// regions (and if that's not true, we just don't attempt to + /// enforce the constraint). + /// + /// The current value of `scc` at the time the method is invoked + /// is considered a *lower bound*. If possible, we will modify + /// the constraint to set it equal to one of the option regions. + /// If we make any changes, returns true, else false. + fn apply_pick_constraint( + &mut self, + scc: ConstraintSccIndex, + option_regions: &[ty::RegionVid], + ) -> bool { + debug!("apply_pick_constraint(scc={:?}, option_regions={:#?})", scc, option_regions,); + + if let Some(uh_oh) = + option_regions.iter().find(|&&r| !self.universal_regions.is_universal_region(r)) + { + debug!("apply_pick_constraint: option region `{:?}` is not a universal region", uh_oh); + return false; + } + + // Create a mutable vector of the options. We'll try to winnow + // them down. + let mut option_regions: Vec = option_regions.to_vec(); + + // The 'pick-region' in a pick-constraint is part of the + // hidden type, which must be in the root universe. Therefore, + // it cannot have any placeholders in its value. + assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT); + debug_assert!( + self.scc_values.placeholders_contained_in(scc).next().is_none(), + "scc {:?} in a pick-constraint has placeholder value: {:?}", + scc, + self.scc_values.region_value_str(scc), + ); + + // The existing value for `scc` is a lower-bound. This will + // consist of some set {P} + {LB} of points {P} and + // lower-bound free regions {LB}. As each option region O is a + // free region, it will outlive the points. But we can only + // consider the option O if O: LB. + option_regions.retain(|&o_r| { + self.scc_values + .universal_regions_outlived_by(scc) + .all(|lb| self.universal_region_relations.outlives(o_r, lb)) + }); + + // Now find all the *upper bounds* -- that is, each UB is a free + // region that must outlive pick region R0 (`UB: R0`). Therefore, + // we need only keep an option O if `UB: O`. + // + // TODO -- need to implement the reverse graph construction for this + // + // let mut upper_bounds = ...; + // option_regions.retain(|&o_r| { + // upper_bounds + // .all(|ub| self.universal_region_relations.outlives( + // ub, + // o_r, + // }) + // }); + + // If we ruled everything out, we're done. + if option_regions.is_empty() { + return false; + } + + // Otherwise, we need to find the minimum option, if any, and take that. + debug!("apply_pick_constraint: option_regions remaining are {:#?}", option_regions); + let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option { + let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2); + let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1); + if r1_outlives_r2 && r2_outlives_r1 { + Some(r1.min(r2)) + } else if r1_outlives_r2 { + Some(r2) + } else if r2_outlives_r1 { + Some(r1) + } else { + None + } + }; + let mut best_option = option_regions[0]; + for &other_option in &option_regions[1..] { + debug!( + "apply_pick_constraint: best_option={:?} other_option={:?}", + best_option, other_option, + ); + match min(best_option, other_option) { + Some(m) => best_option = m, + None => { + debug!( + "apply_pick_constraint: {:?} and {:?} are incomparable --> no best choice", + best_option, other_option, + ); + return false; + } + } + } + + debug!("apply_pick_constraint: best_choice={:?}", best_option); + self.scc_values.add_element(scc, best_option) + } + /// Returns `true` if all the elements in the value of `scc_b` are nameable /// in `scc_a`. Used during constraint propagation, and only once /// the value of `scc_b` has been computed. @@ -560,9 +676,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Otherwise, we have to iterate over the universe elements in // B's value, and check whether all of them are nameable // from universe_a - self.scc_values - .placeholders_contained_in(scc_b) - .all(|p| universe_a.can_name(p.universe)) + self.scc_values.placeholders_contained_in(scc_b).all(|p| universe_a.can_name(p.universe)) } /// Extend `scc` so that it can outlive some placeholder region @@ -737,12 +851,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> bool { let tcx = infcx.tcx; - let TypeTest { - generic_kind, - lower_bound, - locations, - verify_bound: _, - } = type_test; + let TypeTest { generic_kind, lower_bound, locations, verify_bound: _ } = type_test; let generic_ty = generic_kind.to_ty(tcx); let subject = match self.try_promote_type_test_subject(infcx, generic_ty) { @@ -892,11 +1001,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// except that it converts further takes the non-local upper /// bound of `'y`, so that the final result is non-local. fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!( - "non_local_universal_upper_bound(r={:?}={})", - r, - self.region_value_str(r) - ); + debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); let lub = self.universal_upper_bound(r); @@ -904,10 +1009,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // creator. let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub); - debug!( - "non_local_universal_upper_bound: non_local_lub={:?}", - non_local_lub - ); + debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub); non_local_lub } @@ -927,11 +1029,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!( - "universal_upper_bound(r={:?}={})", - r, - self.region_value_str(r) - ); + debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); // Find the smallest universal region that contains all other // universal regions within `region`. @@ -956,10 +1054,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { lower_bound: RegionVid, verify_bound: &VerifyBound<'tcx>, ) -> bool { - debug!( - "eval_verify_bound(lower_bound={:?}, verify_bound={:?})", - lower_bound, verify_bound - ); + debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound); match verify_bound { VerifyBound::IfEq(test_ty, verify_bound1) => { @@ -968,7 +1063,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { VerifyBound::OutlivedBy(r) => { let r_vid = self.to_region_vid(r); - self.eval_outlives(body, r_vid, lower_bound) + self.eval_outlives(r_vid, lower_bound) } VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| { @@ -1041,23 +1136,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } - // Evaluate whether `sup_region: sub_region @ point`. - fn eval_outlives( - &self, - _body: &Body<'tcx>, - sup_region: RegionVid, - sub_region: RegionVid, - ) -> bool { + // Evaluate whether `sup_region == sub_region`. + fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool { + self.eval_outlives(r1, r2) && self.eval_outlives(r2, r1) + } + + // Evaluate whether `sup_region: sub_region`. + fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { debug!("eval_outlives({:?}: {:?})", sup_region, sub_region); - debug!( - "eval_outlives: sup_region's value = {:?}", - self.region_value_str(sup_region), - ); - debug!( - "eval_outlives: sub_region's value = {:?}", - self.region_value_str(sub_region), - ); + debug!("eval_outlives: sup_region's value = {:?}", self.region_value_str(sup_region),); + debug!("eval_outlives: sub_region's value = {:?}", self.region_value_str(sub_region),); let sub_region_scc = self.constraint_sccs.scc(sub_region); let sup_region_scc = self.constraint_sccs.scc(sup_region); @@ -1068,9 +1157,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // now). Therefore, the sup-region outlives the sub-region if, // for each universal region R1 in the sub-region, there // exists some region R2 in the sup-region that outlives R1. - let universal_outlives = self.scc_values - .universal_regions_outlived_by(sub_region_scc) - .all(|r1| { + let universal_outlives = + self.scc_values.universal_regions_outlived_by(sub_region_scc).all(|r1| { self.scc_values .universal_regions_outlived_by(sup_region_scc) .any(|r2| self.universal_region_relations.outlives(r2, r1)) @@ -1088,8 +1176,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { return true; } - self.scc_values - .contains_points(sup_region_scc, sub_region_scc) + self.scc_values.contains_points(sup_region_scc, sub_region_scc) } /// Once regions have been propagated, this method is used to see @@ -1171,12 +1258,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Because this free region must be in the ROOT universe, we // know it cannot contain any bound universes. assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT); - debug_assert!( - self.scc_values - .placeholders_contained_in(longer_fr_scc) - .next() - .is_none() - ); + debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none()); // Only check all of the relations for the main representative of each // SCC, otherwise just check that we outlive said representative. This @@ -1230,9 +1312,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer: &mut Vec, ) -> Option { // If it is known that `fr: o`, carry on. - if self.universal_region_relations - .outlives(longer_fr, shorter_fr) - { + if self.universal_region_relations.outlives(longer_fr, shorter_fr) { return None; } @@ -1246,9 +1326,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // We'll call it `fr-` -- it's ever so slightly smaller than // `longer_fr`. - if let Some(fr_minus) = self - .universal_region_relations - .non_local_lower_bound(longer_fr) + if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) { debug!("check_universal_region: fr_minus={:?}", fr_minus); @@ -1258,12 +1336,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Grow `shorter_fr` until we find some non-local regions. (We // always will.) We'll call them `shorter_fr+` -- they're ever // so slightly larger than `shorter_fr`. - let shorter_fr_plus = self.universal_region_relations - .non_local_upper_bounds(&shorter_fr); - debug!( - "check_universal_region: shorter_fr_plus={:?}", - shorter_fr_plus - ); + let shorter_fr_plus = + self.universal_region_relations.non_local_upper_bounds(&shorter_fr); + debug!("check_universal_region: shorter_fr_plus={:?}", shorter_fr_plus); for &&fr in &shorter_fr_plus { // Push the constraint `fr-: shorter_fr+` propagated_outlives_requirements.push(ClosureOutlivesRequirement { @@ -1295,28 +1370,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { longer_fr: RegionVid, placeholder: ty::PlaceholderRegion, ) { - debug!( - "check_bound_universal_region(fr={:?}, placeholder={:?})", - longer_fr, placeholder, - ); + debug!("check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr, placeholder,); let longer_fr_scc = self.constraint_sccs.scc(longer_fr); - debug!( - "check_bound_universal_region: longer_fr_scc={:?}", - longer_fr_scc, - ); + debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,); // If we have some bound universal region `'a`, then the only // elements it can contain is itself -- we don't know anything // else about it! let error_element = match { - self.scc_values - .elements_contained_in(longer_fr_scc) - .find(|element| match element { - RegionElement::Location(_) => true, - RegionElement::RootUniversalRegion(_) => true, - RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1, - }) + self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element { + RegionElement::Location(_) => true, + RegionElement::RootUniversalRegion(_) => true, + RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1, + }) } { Some(v) => v, None => return, @@ -1327,7 +1394,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { let error_region = match error_element { RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l), RegionElement::RootUniversalRegion(r) => r, - RegionElement::PlaceholderRegion(error_placeholder) => self.definitions + RegionElement::PlaceholderRegion(error_placeholder) => self + .definitions .iter_enumerated() .filter_map(|(r, definition)| match definition.origin { NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r), @@ -1345,12 +1413,44 @@ impl<'tcx> RegionInferenceContext<'tcx> { // the AST-based checker uses a more conservative check, // so to even see this error, one must pass in a special // flag. - let mut diag = infcx - .tcx - .sess - .struct_span_err(span, "higher-ranked subtype error"); + let mut diag = infcx.tcx.sess.struct_span_err(span, "higher-ranked subtype error"); diag.emit(); } + + fn check_pick_constraints( + &self, + infcx: &InferCtxt<'_, 'tcx>, + mir_def_id: DefId, + errors_buffer: &mut Vec, // TODO + ) { + let pick_constraints = self.pick_constraints.clone(); + for p_c_i in pick_constraints.all_indices() { + debug!("check_pick_constraint(p_c_i={:?})", p_c_i); + let p_c = &pick_constraints[p_c_i]; + let pick_region_vid = p_c.pick_region_vid; + debug!("check_pick_constraint: pick_region_vid={:?} with value {}", pick_region_vid, self.region_value_str(pick_region_vid)); + let option_regions = pick_constraints.option_regions(p_c_i); + debug!("check_pick_constraint: option_regions={:?}", option_regions); + + // did the pick-region wind up equal to any of the option regions? + if let Some(o) = option_regions.iter().find(|&&o_r| self.eval_equal(o_r, p_c.pick_region_vid)) { + debug!("check_pick_constraint: evaluated as equal to {:?}", o); + continue; + } + + // if not, report an error + let region_scope_tree = &infcx.tcx.region_scope_tree(mir_def_id); + let pick_region = infcx.tcx.mk_region(ty::ReVar(pick_region_vid)); // XXX + opaque_types::unexpected_hidden_region_diagnostic( + infcx.tcx, + Some(region_scope_tree), + p_c.opaque_type_def_id, + p_c.hidden_ty, + pick_region, + ) + .buffer(errors_buffer); + } + } } impl<'tcx> RegionDefinition<'tcx> { @@ -1364,11 +1464,7 @@ impl<'tcx> RegionDefinition<'tcx> { _ => NLLRegionVariableOrigin::Existential, }; - Self { - origin, - universe, - external_name: None, - } + Self { origin, universe, external_name: None } } } @@ -1471,10 +1567,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx if let ty::ReClosureBound(vid) = r { closure_mapping[*vid] } else { - bug!( - "subst_closure_mapping: encountered non-closure bound free region {:?}", - r - ) + bug!("subst_closure_mapping: encountered non-closure bound free region {:?}", r) } }) } diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index c3bd4f6edf4..e7ae9de3c2e 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -51,6 +51,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { + debug!("convert_all(query_constraints={:#?})", query_constraints); + let QueryRegionConstraints { outlives, pick_constraints } = query_constraints; // Annoying: to invoke `self.to_region_vid`, we need access to