From 3bca170bc7543da8ddb1b550a824ad0f4cbaf395 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 06:54:31 +0300 Subject: [PATCH 1/8] introduce, but do not use, `free_region_relation` computation This duplicates, effectively, existing code in the universal regions computation. --- src/librustc_mir/borrow_check/nll/mod.rs | 2 + .../borrow_check/nll/region_infer/mod.rs | 4 +- .../nll/type_check/free_region_relations.rs | 225 ++++++++++++++++++ .../borrow_check/nll/type_check/mod.rs | 14 +- src/librustc_mir/lib.rs | 2 + 5 files changed, 243 insertions(+), 4 deletions(-) create mode 100644 src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 63d5de4f2e525..c236fbc4f7213 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -104,6 +104,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( None }; + let universal_regions = Rc::new(universal_regions); + let elements = &Rc::new(RegionValueElements::new(mir)); // Run the MIR type-checker. 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 19ff6d9a7e34c..9785a544a4dca 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -206,15 +206,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// of constraints produced by the MIR type check. pub(crate) fn new( var_infos: VarInfos, - universal_regions: UniversalRegions<'tcx>, + universal_regions: Rc>, _mir: &Mir<'tcx>, outlives_constraints: ConstraintSet, type_tests: Vec>, liveness_constraints: LivenessValues, elements: &Rc, ) -> Self { - let universal_regions = Rc::new(universal_regions); - // Create a RegionDefinition for each inference variable. let definitions: IndexVec<_, _> = var_infos .into_iter() diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs new file mode 100644 index 0000000000000..3cf3ae1d166e8 --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -0,0 +1,225 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use borrow_check::location::LocationTable; +use borrow_check::nll::facts::AllFacts; +use borrow_check::nll::universal_regions::UniversalRegions; +use borrow_check::nll::type_check::constraint_conversion; +use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints}; +use rustc::hir::def_id::DefId; +use rustc::infer::region_constraints::GenericKind; +use rustc::infer::InferCtxt; +use rustc::traits::query::outlives_bounds::{self, OutlivesBound}; +use rustc::traits::query::type_op::{self, TypeOp}; +use rustc::ty::{self, RegionVid, Ty}; +use rustc_data_structures::transitive_relation::TransitiveRelation; +use std::rc::Rc; +use syntax::ast; + +#[derive(Debug)] +crate struct UniversalRegionRelations<'tcx> { + universal_regions: Rc>, + + /// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to + /// be true. These encode relationships like `T: 'a` that are + /// added via implicit bounds. + /// + /// Each region here is guaranteed to be a key in the `indices` + /// map. We use the "original" regions (i.e., the keys from the + /// map, and not the values) because the code in + /// `process_registered_region_obligations` has some special-cased + /// logic expecting to see (e.g.) `ReStatic`, and if we supplied + /// our special inference variable there, we would mess that up. + crate region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, + + /// Stores the outlives relations that are known to hold from the + /// implied bounds, in-scope where clauses, and that sort of + /// thing. + outlives: TransitiveRelation, + + /// This is the `<=` relation; that is, if `a: b`, then `b <= a`, + /// and we store that here. This is useful when figuring out how + /// to express some local region in terms of external regions our + /// caller will understand. + inverse_outlives: TransitiveRelation, +} + +impl UniversalRegionRelations<'tcx> { + crate fn create( + infcx: &InferCtxt<'_, '_, 'tcx>, + mir_def_id: DefId, + param_env: ty::ParamEnv<'tcx>, + location_table: &LocationTable, + implicit_region_bound: Option>, + universal_regions: &Rc>, + constraints: &mut MirTypeckRegionConstraints<'tcx>, + all_facts: &mut Option, + ) -> Self { + let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap(); + UniversalRegionRelationsBuilder { + infcx, + mir_def_id, + mir_node_id, + param_env, + implicit_region_bound, + constraints, + location_table, + all_facts, + universal_regions: universal_regions.clone(), + relations: UniversalRegionRelations { + universal_regions: universal_regions.clone(), + region_bound_pairs: Vec::new(), + outlives: TransitiveRelation::new(), + inverse_outlives: TransitiveRelation::new(), + }, + }.create() + } + + /// Records in the `outlives_relation` (and + /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the + /// builder below. + fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { + debug!( + "relate_universal_regions: fr_a={:?} outlives fr_b={:?}", + fr_a, fr_b + ); + self.outlives.add(fr_a, fr_b); + self.inverse_outlives.add(fr_b, fr_a); + } +} + +struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> { + infcx: &'this InferCtxt<'this, 'gcx, 'tcx>, + mir_def_id: DefId, + mir_node_id: ast::NodeId, + param_env: ty::ParamEnv<'tcx>, + location_table: &'this LocationTable, + universal_regions: Rc>, + relations: UniversalRegionRelations<'tcx>, + implicit_region_bound: Option>, + constraints: &'this mut MirTypeckRegionConstraints<'tcx>, + all_facts: &'this mut Option, +} + +impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { + crate fn create(mut self) -> UniversalRegionRelations<'tcx> { + let unnormalized_input_output_tys = self + .universal_regions + .unnormalized_input_tys + .iter() + .cloned() + .chain(Some(self.universal_regions.unnormalized_output_ty)); + + // For each of the input/output types: + // - Normalize the type. This will create some region + // constraints, which we buffer up because we are + // not ready to process them yet. + // - Then compute the implied bounds. This will adjust + // the `relations.region_bound_pairs` and so forth. + // - After this is done, we'll process the constraints, once + // the `relations` is built. + let constraint_sets: Vec<_> = unnormalized_input_output_tys + .flat_map(|ty| { + debug!("build: input_or_output={:?}", ty); + let (ty, constraints) = self + .param_env + .and(type_op::normalize::Normalize::new(ty)) + .fully_perform(self.infcx) + .unwrap_or_else(|_| bug!("failed to normalize {:?}", ty)); + self.add_implied_bounds(ty); + constraints + }) + .collect(); + + // Insert the facts we know from the predicates. Why? Why not. + let param_env = self.param_env; + self.add_outlives_bounds(outlives_bounds::explicit_outlives_bounds(param_env)); + + // Finally: + // - outlives is reflexive, so `'r: 'r` for every region `'r` + // - `'static: 'r` for every region `'r` + // - `'r: 'fn_body` for every (other) universally quantified + // region `'r`, all of which are provided by our caller + let fr_static = self.universal_regions.fr_static; + let fr_fn_body = self.universal_regions.fr_fn_body; + for fr in self.universal_regions.universal_regions() { + debug!( + "build: relating free region {:?} to itself and to 'static", + fr + ); + self.relations.relate_universal_regions(fr, fr); + self.relations.relate_universal_regions(fr_static, fr); + self.relations.relate_universal_regions(fr, fr_fn_body); + } + + for data in constraint_sets { + constraint_conversion::ConstraintConversion::new( + self.infcx.tcx, + &self.universal_regions, + &self.location_table, + &self.relations.region_bound_pairs, + self.implicit_region_bound, + self.param_env, + Locations::All, + &mut self.constraints.outlives_constraints, + &mut self.constraints.type_tests, + &mut self.all_facts, + ).convert_all(&data); + } + + self.relations + } + + /// Update the type of a single local, which should represent + /// either the return type of the MIR or one of its arguments. At + /// the same time, compute and add any implied bounds that come + /// from this local. + fn add_implied_bounds(&mut self, ty: Ty<'tcx>) { + debug!("add_implied_bounds(ty={:?})", ty); + let span = self.infcx.tcx.def_span(self.mir_def_id); + let bounds = self + .infcx + .implied_outlives_bounds(self.param_env, self.mir_node_id, ty, span); + self.add_outlives_bounds(bounds); + } + + /// Registers the `OutlivesBound` items from `outlives_bounds` in + /// the outlives relation as well as the region-bound pairs + /// listing. + fn add_outlives_bounds(&mut self, outlives_bounds: I) + where + I: IntoIterator>, + { + for outlives_bound in outlives_bounds { + debug!("add_outlives_bounds(bound={:?})", outlives_bound); + + match outlives_bound { + OutlivesBound::RegionSubRegion(r1, r2) => { + // The bound says that `r1 <= r2`; we store `r2: r1`. + let r1 = self.universal_regions.to_region_vid(r1); + let r2 = self.universal_regions.to_region_vid(r2); + self.relations.relate_universal_regions(r2, r1); + } + + OutlivesBound::RegionSubParam(r_a, param_b) => { + self.relations + .region_bound_pairs + .push((r_a, GenericKind::Param(param_b))); + } + + OutlivesBound::RegionSubProjection(r_a, projection_b) => { + self.relations + .region_bound_pairs + .push((r_a, GenericKind::Projection(projection_b))); + } + } + } + } +} diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index b67de34593f80..be14819b64895 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -71,6 +71,7 @@ macro_rules! span_mirbug_and_err { } mod constraint_conversion; +mod free_region_relations; mod input_output; mod liveness; mod relate_tys; @@ -110,7 +111,7 @@ pub(crate) fn type_check<'gcx, 'tcx>( param_env: ty::ParamEnv<'gcx>, mir: &Mir<'tcx>, mir_def_id: DefId, - universal_regions: &UniversalRegions<'tcx>, + universal_regions: &Rc>, location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, liveness: &LivenessResults, @@ -127,6 +128,17 @@ pub(crate) fn type_check<'gcx, 'tcx>( type_tests: Vec::default(), }; + let _urr = free_region_relations::UniversalRegionRelations::create( + infcx, + mir_def_id, + param_env, + location_table, + Some(implicit_region_bound), + universal_regions, + &mut constraints, + all_facts, + ); + { let mut borrowck_context = BorrowCheckContext { universal_regions, diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 54730ecd75fbd..3f32d307409ed 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,6 +14,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ +#![feature(infer_outlives_requirements)] +#![feature(in_band_lifetimes)] #![feature(slice_patterns)] #![feature(slice_sort_by_cached_key)] #![feature(from_ref)] From d1e67fcacdcc41ac1666fda816fb874a6d12a370 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 14:30:22 +0300 Subject: [PATCH 2/8] remove universal-region-relation computation from universal_regions --- src/librustc_mir/borrow_check/nll/mod.rs | 3 +- .../borrow_check/nll/region_infer/dump_mir.rs | 2 +- .../borrow_check/nll/region_infer/mod.rs | 21 +- .../nll/type_check/free_region_relations.rs | 118 ++++++++- .../nll/type_check/input_output.rs | 4 +- .../borrow_check/nll/type_check/mod.rs | 116 +++++---- .../borrow_check/nll/universal_regions.rs | 242 +----------------- 7 files changed, 206 insertions(+), 300 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index c236fbc4f7213..973568a67f030 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -111,7 +111,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( // Run the MIR type-checker. let liveness_map = NllLivenessMap::compute(&mir); let liveness = LivenessResults::compute(mir, &liveness_map); - let constraint_sets = type_check::type_check( + let (constraint_sets, universal_region_relations) = type_check::type_check( infcx, param_env, mir, @@ -155,6 +155,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( let mut regioncx = RegionInferenceContext::new( var_origins, universal_regions, + universal_region_relations, mir, outlives_constraints, type_tests, diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs index 88b34c767324c..d3b4f0a0447a1 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs @@ -33,7 +33,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .universal_regions .region_classification(region) .unwrap(); - let outlived_by = self.universal_regions.regions_outlived_by(region); + let outlived_by = self.universal_region_relations.regions_outlived_by(region); writeln!( out, "| {r:rw$} | {c:cw$} | {ob}", 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 9785a544a4dca..6281b5dd4b64c 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -15,6 +15,7 @@ use borrow_check::nll::constraints::{ }; use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex}; use borrow_check::nll::type_check::Locations; +use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::region_constraints::{GenericKind, VarInfos}; @@ -80,8 +81,12 @@ pub struct RegionInferenceContext<'tcx> { type_tests: Vec>, /// Information about the universally quantified regions in scope - /// on this function and their (known) relations to one another. + /// on this function. universal_regions: Rc>, + + /// Information about how the universally quantified regions in + /// scope on this function relate to one another. + universal_region_relations: Rc>, } struct RegionDefinition<'tcx> { @@ -207,6 +212,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn new( var_infos: VarInfos, universal_regions: Rc>, + universal_region_relations: Rc>, _mir: &Mir<'tcx>, outlives_constraints: ConstraintSet, type_tests: Vec>, @@ -249,6 +255,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { scc_values, type_tests, universal_regions, + universal_region_relations, }; result.init_free_and_bound_regions(); @@ -766,7 +773,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Grow further to get smallest universal region known to // creator. - let non_local_lub = self.universal_regions.non_local_upper_bound(lub); + let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub); debug!( "non_local_universal_upper_bound: non_local_lub={:?}", @@ -802,7 +809,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut lub = self.universal_regions.fr_fn_body; let r_scc = self.constraint_sccs.scc(r); for ur in self.scc_values.universal_regions_outlived_by(r_scc) { - lub = self.universal_regions.postdom_upper_bound(lub, ur); + lub = self.universal_region_relations.postdom_upper_bound(lub, ur); } debug!("universal_upper_bound: r={:?} lub={:?}", r, lub); @@ -870,7 +877,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .all(|r1| { self.scc_values .universal_regions_outlived_by(sup_region_scc) - .any(|r2| self.universal_regions.outlives(r2, r1)) + .any(|r2| self.universal_region_relations.outlives(r2, r1)) }); if !universal_outlives { @@ -975,7 +982,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // (because `fr` includes `end(o)`). for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) { // If it is known that `fr: o`, carry on. - if self.universal_regions.outlives(longer_fr, shorter_fr) { + if self.universal_region_relations.outlives(longer_fr, shorter_fr) { continue; } @@ -989,14 +996,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `fr` until we find a non-local region (if we do). // We'll call that `fr-` -- it's ever so slightly smaller than `fr`. - if let Some(fr_minus) = self.universal_regions.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); // Grow `shorter_fr` until we find a non-local // region. (We always will.) We'll call that // `shorter_fr+` -- it's ever so slightly larger than // `fr`. - let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr); + let shorter_fr_plus = self.universal_region_relations.non_local_upper_bound(shorter_fr); debug!( "check_universal_region: shorter_fr_plus={:?}", shorter_fr_plus diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index 3cf3ae1d166e8..d2850f8f32443 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -9,11 +9,13 @@ // except according to those terms. use borrow_check::location::LocationTable; +use borrow_check::nll::ToRegionVid; use borrow_check::nll::facts::AllFacts; -use borrow_check::nll::universal_regions::UniversalRegions; use borrow_check::nll::type_check::constraint_conversion; use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints}; +use borrow_check::nll::universal_regions::UniversalRegions; use rustc::hir::def_id::DefId; +use rustc::infer::outlives::free_region_map::FreeRegionRelations; use rustc::infer::region_constraints::GenericKind; use rustc::infer::InferCtxt; use rustc::traits::query::outlives_bounds::{self, OutlivesBound}; @@ -93,6 +95,107 @@ impl UniversalRegionRelations<'tcx> { self.outlives.add(fr_a, fr_b); self.inverse_outlives.add(fr_b, fr_a); } + + /// Given two universal regions, returns the postdominating + /// upper-bound (effectively the least upper bound). + /// + /// (See `TransitiveRelation::postdom_upper_bound` for details on + /// the postdominating upper bound in general.) + crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { + assert!(self.universal_regions.is_universal_region(fr1)); + assert!(self.universal_regions.is_universal_region(fr2)); + *self + .inverse_outlives + .postdom_upper_bound(&fr1, &fr2) + .unwrap_or(&self.universal_regions.fr_static) + } + + /// Finds an "upper bound" for `fr` that is not local. In other + /// words, returns the smallest (*) known region `fr1` that (a) + /// outlives `fr` and (b) is not local. This cannot fail, because + /// we will always find `'static` at worst. + /// + /// (*) If there are multiple competing choices, we pick the "postdominating" + /// one. See `TransitiveRelation::postdom_upper_bound` for details. + crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { + debug!("non_local_upper_bound(fr={:?})", fr); + self.non_local_bound(&self.inverse_outlives, fr) + .unwrap_or(self.universal_regions.fr_static) + } + + /// Finds a "lower bound" for `fr` that is not local. In other + /// words, returns the largest (*) known region `fr1` that (a) is + /// outlived by `fr` and (b) is not local. This cannot fail, + /// because we will always find `'static` at worst. + /// + /// (*) If there are multiple competing choices, we pick the "postdominating" + /// one. See `TransitiveRelation::postdom_upper_bound` for details. + crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option { + debug!("non_local_lower_bound(fr={:?})", fr); + self.non_local_bound(&self.outlives, fr) + } + + /// Helper for `non_local_upper_bound` and + /// `non_local_lower_bound`. Repeatedly invokes `postdom_parent` + /// until we find something that is not local. Returns None if we + /// never do so. + fn non_local_bound( + &self, + relation: &TransitiveRelation, + fr0: RegionVid, + ) -> Option { + // This method assumes that `fr0` is one of the universally + // quantified region variables. + assert!(self.universal_regions.is_universal_region(fr0)); + + let mut external_parents = vec![]; + let mut queue = vec![&fr0]; + + // Keep expanding `fr` into its parents until we reach + // non-local regions. + while let Some(fr) = queue.pop() { + if !self.universal_regions.is_local_free_region(*fr) { + external_parents.push(fr); + continue; + } + + queue.extend(relation.parents(fr)); + } + + debug!("non_local_bound: external_parents={:?}", external_parents); + + // In case we find more than one, reduce to one for + // convenience. This is to prevent us from generating more + // complex constraints, but it will cause spurious errors. + let post_dom = relation + .mutual_immediate_postdominator(external_parents) + .cloned(); + + debug!("non_local_bound: post_dom={:?}", post_dom); + + post_dom.and_then(|post_dom| { + // If the mutual immediate postdom is not local, then + // there is no non-local result we can return. + if !self.universal_regions.is_local_free_region(post_dom) { + Some(post_dom) + } else { + None + } + }) + } + + /// True if fr1 is known to outlive fr2. + /// + /// This will only ever be true for universally quantified regions. + crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { + self.outlives.contains(&fr1, &fr2) + } + + /// Returns a vector of free regions `x` such that `fr1: x` is + /// known to hold. + crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> { + self.outlives.reachable_from(&fr1) + } } struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> { @@ -223,3 +326,16 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { } } } + +/// This trait is used by the `impl-trait` constraint code to abstract +/// over the `FreeRegionMap` from lexical regions and +/// `UniversalRegions` (from NLL)`. +impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> { + fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool { + let shorter = shorter.to_region_vid(); + assert!(self.universal_regions.is_universal_region(shorter)); + let longer = longer.to_region_vid(); + assert!(self.universal_regions.is_universal_region(longer)); + self.outlives(longer, shorter) + } +} diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index ea0dc200b7df3..8571ac3235c33 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -18,6 +18,7 @@ //! contain revealed `impl Trait` values). use borrow_check::nll::renumber; +use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use borrow_check::nll::universal_regions::UniversalRegions; use rustc::hir::def_id::DefId; use rustc::infer::InferOk; @@ -37,6 +38,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { mir: &Mir<'tcx>, mir_def_id: DefId, universal_regions: &UniversalRegions<'tcx>, + universal_region_relations: &UniversalRegionRelations<'tcx>, ) { let tcx = self.infcx.tcx; @@ -160,7 +162,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Locations::All, CustomTypeOp::new( |_cx| { - infcx.constrain_anon_types(&anon_type_map, universal_regions); + infcx.constrain_anon_types(&anon_type_map, universal_region_relations); Ok(InferOk { value: (), obligations: vec![], diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index be14819b64895..15deb5fb2f498 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -17,9 +17,10 @@ use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; use borrow_check::nll::facts::AllFacts; use borrow_check::nll::region_infer::values::{RegionValueElements, LivenessValues}; use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; +use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use borrow_check::nll::universal_regions::UniversalRegions; -use borrow_check::nll::ToRegionVid; use borrow_check::nll::LocalWithRegion; +use borrow_check::nll::ToRegionVid; use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; use dataflow::MaybeInitializedPlaces; @@ -36,12 +37,12 @@ use rustc::traits::query::type_op; use rustc::traits::query::{Fallible, NoSolution}; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; +use rustc_errors::Diagnostic; use std::fmt; use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; use transform::{MirPass, MirSource}; use util::liveness::LivenessResults; -use rustc_errors::Diagnostic; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; @@ -71,7 +72,7 @@ macro_rules! span_mirbug_and_err { } mod constraint_conversion; -mod free_region_relations; +pub mod free_region_relations; mod input_output; mod liveness; mod relate_tys; @@ -120,7 +121,10 @@ pub(crate) fn type_check<'gcx, 'tcx>( move_data: &MoveData<'tcx>, elements: &Rc, errors_buffer: &mut Vec, -) -> MirTypeckRegionConstraints<'tcx> { +) -> ( + MirTypeckRegionConstraints<'tcx>, + Rc>, +) { let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); let mut constraints = MirTypeckRegionConstraints { liveness_constraints: LivenessValues::new(elements), @@ -128,16 +132,17 @@ pub(crate) fn type_check<'gcx, 'tcx>( type_tests: Vec::default(), }; - let _urr = free_region_relations::UniversalRegionRelations::create( - infcx, - mir_def_id, - param_env, - location_table, - Some(implicit_region_bound), - universal_regions, - &mut constraints, - all_facts, - ); + let universal_region_relations = + Rc::new(free_region_relations::UniversalRegionRelations::create( + infcx, + mir_def_id, + param_env, + location_table, + Some(implicit_region_bound), + universal_regions, + &mut constraints, + all_facts, + )); { let mut borrowck_context = BorrowCheckContext { @@ -153,17 +158,23 @@ pub(crate) fn type_check<'gcx, 'tcx>( mir_def_id, param_env, mir, - &universal_regions.region_bound_pairs, + &universal_region_relations.region_bound_pairs, Some(implicit_region_bound), Some(&mut borrowck_context), Some(errors_buffer), |cx| { liveness::generate(cx, mir, liveness, flow_inits, move_data); - cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions); + cx.equate_inputs_and_outputs( + mir, + mir_def_id, + universal_regions, + &universal_region_relations, + ); }, ); } - constraints + + (constraints, universal_region_relations) } fn type_check_internal<'a, 'gcx, 'tcx, F>( @@ -176,8 +187,8 @@ fn type_check_internal<'a, 'gcx, 'tcx, F>( borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, errors_buffer: Option<&mut Vec>, mut extra: F, -) - where F: FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) +) where + F: FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>), { let mut checker = TypeChecker::new( infcx, @@ -319,8 +330,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // don't have a handy function for that, so for // now we just ignore `value.val` regions. - let instantiated_predicates = - tcx.predicates_of(def_id).instantiate(tcx, substs); + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); type_checker.normalize_and_prove_instantiated_predicates( instantiated_predicates, location.boring(), @@ -1035,9 +1045,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // all the inputs that fed into it were live. for &late_bound_region in map.values() { if let Some(ref mut borrowck_context) = self.borrowck_context { - let region_vid = borrowck_context.universal_regions.to_region_vid( - late_bound_region); - borrowck_context.constraints + let region_vid = borrowck_context + .universal_regions + .to_region_vid(late_bound_region); + borrowck_context + .constraints .liveness_constraints .add_element(region_vid, term_location); } @@ -1253,12 +1265,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn check_local(&mut self, - mir: &Mir<'tcx>, - local: Local, - local_decl: &LocalDecl<'tcx>, - errors_buffer: &mut Option<&mut Vec>) - { + fn check_local( + &mut self, + mir: &Mir<'tcx>, + local: Local, + local_decl: &LocalDecl<'tcx>, + errors_buffer: &mut Option<&mut Vec>, + ) { match mir.local_kind(local) { LocalKind::ReturnPointer | LocalKind::Arg => { // return values of normal functions are required to be @@ -1286,12 +1299,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // slot or local, so to find all unsized rvalues it is enough // to check all temps, return slots and locals. if let None = self.reported_errors.replace((ty, span)) { - let mut diag = struct_span_err!(self.tcx().sess, - span, - E0161, - "cannot move a value of type {0}: the size of {0} \ - cannot be statically determined", - ty); + let mut diag = struct_span_err!( + self.tcx().sess, + span, + E0161, + "cannot move a value of type {0}: the size of {0} \ + cannot be statically determined", + ty + ); if let Some(ref mut errors_buffer) = *errors_buffer { diag.buffer(errors_buffer); } else { @@ -1589,13 +1604,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.sty { ty::TyRef(ref_region, _, mutbl) => { - constraints - .outlives_constraints - .push(OutlivesConstraint { - sup: ref_region.to_region_vid(), - sub: borrow_region.to_region_vid(), - locations: location.boring(), - }); + constraints.outlives_constraints.push(OutlivesConstraint { + sup: ref_region.to_region_vid(), + sub: borrow_region.to_region_vid(), + locations: location.boring(), + }); if let Some(all_facts) = all_facts { all_facts.outlives.push(( @@ -1780,10 +1793,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }) } - fn typeck_mir(&mut self, - mir: &Mir<'tcx>, - mut errors_buffer: Option<&mut Vec>) - { + fn typeck_mir(&mut self, mir: &Mir<'tcx>, mut errors_buffer: Option<&mut Vec>) { self.last_span = mir.span; debug!("run_on_mir: {:?}", mir.span); @@ -1853,7 +1863,17 @@ impl MirPass for TypeckMir { let param_env = tcx.param_env(def_id); tcx.infer_ctxt().enter(|infcx| { - type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, None, |_| ()); + type_check_internal( + &infcx, + def_id, + param_env, + mir, + &[], + None, + None, + None, + |_| (), + ); // For verification purposes, we just ignore the resulting // region constraint sets. Not our problem. =) diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index 9bb7d12313349..765c4cf906e68 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -25,16 +25,12 @@ use either::Either; use rustc::hir::def_id::DefId; use rustc::hir::{self, BodyOwnerKind, HirId}; -use rustc::infer::outlives::free_region_map::FreeRegionRelations; -use rustc::infer::region_constraints::GenericKind; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; -use rustc::traits::query::outlives_bounds::{self, OutlivesBound}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::transitive_relation::TransitiveRelation; use std::iter; use syntax::ast; @@ -85,21 +81,7 @@ pub struct UniversalRegions<'tcx> { /// as the name suggests. =) pub unnormalized_input_tys: &'tcx [Ty<'tcx>], - /// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to - /// be true. These encode relationships like `T: 'a` that are - /// added via implicit bounds. - /// - /// Each region here is guaranteed to be a key in the `indices` - /// map. We use the "original" regions (i.e., the keys from the - /// map, and not the values) because the code in - /// `process_registered_region_obligations` has some special-cased - /// logic expecting to see (e.g.) `ReStatic`, and if we supplied - /// our special inference variable there, we would mess that up. - pub region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, - pub yield_ty: Option>, - - relations: UniversalRegionRelations, } /// The "defining type" for this MIR. The key feature of the "defining @@ -171,20 +153,6 @@ struct UniversalRegionIndices<'tcx> { indices: FxHashMap, RegionVid>, } -#[derive(Debug)] -struct UniversalRegionRelations { - /// Stores the outlives relations that are known to hold from the - /// implied bounds, in-scope where clauses, and that sort of - /// thing. - outlives: TransitiveRelation, - - /// This is the `<=` relation; that is, if `a: b`, then `b <= a`, - /// and we store that here. This is useful when figuring out how - /// to express some local region in terms of external regions our - /// caller will understand. - inverse_outlives: TransitiveRelation, -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum RegionClassification { /// A **global** region is one that can be named from @@ -249,11 +217,6 @@ impl<'tcx> UniversalRegions<'tcx> { mir_node_id, mir_hir_id, param_env, - region_bound_pairs: vec![], - relations: UniversalRegionRelations { - outlives: TransitiveRelation::new(), - inverse_outlives: TransitiveRelation::new(), - }, }.build() } @@ -326,45 +289,6 @@ impl<'tcx> UniversalRegions<'tcx> { self.num_universals } - /// Given two universal regions, returns the postdominating - /// upper-bound (effectively the least upper bound). - /// - /// (See `TransitiveRelation::postdom_upper_bound` for details on - /// the postdominating upper bound in general.) - pub fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { - assert!(self.is_universal_region(fr1)); - assert!(self.is_universal_region(fr2)); - *self.relations - .inverse_outlives - .postdom_upper_bound(&fr1, &fr2) - .unwrap_or(&self.fr_static) - } - - /// Finds an "upper bound" for `fr` that is not local. In other - /// words, returns the smallest (*) known region `fr1` that (a) - /// outlives `fr` and (b) is not local. This cannot fail, because - /// we will always find `'static` at worst. - /// - /// (*) If there are multiple competing choices, we pick the "postdominating" - /// one. See `TransitiveRelation::postdom_upper_bound` for details. - pub fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { - debug!("non_local_upper_bound(fr={:?})", fr); - self.non_local_bound(&self.relations.inverse_outlives, fr) - .unwrap_or(self.fr_static) - } - - /// Finds a "lower bound" for `fr` that is not local. In other - /// words, returns the largest (*) known region `fr1` that (a) is - /// outlived by `fr` and (b) is not local. This cannot fail, - /// because we will always find `'static` at worst. - /// - /// (*) If there are multiple competing choices, we pick the "postdominating" - /// one. See `TransitiveRelation::postdom_upper_bound` for details. - pub fn non_local_lower_bound(&self, fr: RegionVid) -> Option { - debug!("non_local_lower_bound(fr={:?})", fr); - self.non_local_bound(&self.relations.outlives, fr) - } - /// Returns the number of global plus external universal regions. /// For closures, these are the regions that appear free in the /// closure type (versus those bound in the closure @@ -374,68 +298,6 @@ impl<'tcx> UniversalRegions<'tcx> { self.first_local_index } - /// Helper for `non_local_upper_bound` and - /// `non_local_lower_bound`. Repeatedly invokes `postdom_parent` - /// until we find something that is not local. Returns None if we - /// never do so. - fn non_local_bound( - &self, - relation: &TransitiveRelation, - fr0: RegionVid, - ) -> Option { - // This method assumes that `fr0` is one of the universally - // quantified region variables. - assert!(self.is_universal_region(fr0)); - - let mut external_parents = vec![]; - let mut queue = vec![&fr0]; - - // Keep expanding `fr` into its parents until we reach - // non-local regions. - while let Some(fr) = queue.pop() { - if !self.is_local_free_region(*fr) { - external_parents.push(fr); - continue; - } - - queue.extend(relation.parents(fr)); - } - - debug!("non_local_bound: external_parents={:?}", external_parents); - - // In case we find more than one, reduce to one for - // convenience. This is to prevent us from generating more - // complex constraints, but it will cause spurious errors. - let post_dom = relation - .mutual_immediate_postdominator(external_parents) - .cloned(); - - debug!("non_local_bound: post_dom={:?}", post_dom); - - post_dom.and_then(|post_dom| { - // If the mutual immediate postdom is not local, then - // there is no non-local result we can return. - if !self.is_local_free_region(post_dom) { - Some(post_dom) - } else { - None - } - }) - } - - /// True if fr1 is known to outlive fr2. - /// - /// This will only ever be true for universally quantified regions. - pub fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { - self.relations.outlives.contains(&fr1, &fr2) - } - - /// Returns a vector of free regions `x` such that `fr1: x` is - /// known to hold. - pub fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> { - self.relations.outlives.reachable_from(&fr1) - } - /// Get an iterator over all the early-bound regions that have names. pub fn named_universal_regions<'s>( &'s self, @@ -455,14 +317,12 @@ struct UniversalRegionsBuilder<'cx, 'gcx: 'tcx, 'tcx: 'cx> { mir_hir_id: HirId, mir_node_id: ast::NodeId, param_env: ty::ParamEnv<'tcx>, - region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, - relations: UniversalRegionRelations, } const FR: NLLRegionVariableOrigin = NLLRegionVariableOrigin::FreeRegion; impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { - fn build(mut self) -> UniversalRegions<'tcx> { + fn build(self) -> UniversalRegions<'tcx> { debug!("build(mir_def_id={:?})", self.mir_def_id); let param_env = self.param_env; @@ -519,33 +379,6 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid(); let num_universals = self.infcx.num_region_vars(); - // Insert the facts we know from the predicates. Why? Why not. - self.add_outlives_bounds( - &indices, - outlives_bounds::explicit_outlives_bounds(param_env), - ); - - // Add the implied bounds from inputs and outputs. - for ty in inputs_and_output { - debug!("build: input_or_output={:?}", ty); - self.add_implied_bounds(&indices, ty); - } - - // Finally: - // - outlives is reflexive, so `'r: 'r` for every region `'r` - // - `'static: 'r` for every region `'r` - // - `'r: 'fn_body` for every (other) universally quantified - // region `'r`, all of which are provided by our caller - for fr in (FIRST_GLOBAL_INDEX..num_universals).map(RegionVid::new) { - debug!( - "build: relating free region {:?} to itself and to 'static", - fr - ); - self.relations.relate_universal_regions(fr, fr); - self.relations.relate_universal_regions(fr_static, fr); - self.relations.relate_universal_regions(fr, fr_fn_body); - } - let (unnormalized_output_ty, unnormalized_input_tys) = inputs_and_output.split_last().unwrap(); @@ -579,9 +412,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { defining_ty, unnormalized_output_ty, unnormalized_input_tys, - region_bound_pairs: self.region_bound_pairs, yield_ty: yield_ty, - relations: self.relations, } } @@ -730,64 +561,6 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { } } } - - /// Update the type of a single local, which should represent - /// either the return type of the MIR or one of its arguments. At - /// the same time, compute and add any implied bounds that come - /// from this local. - /// - /// Assumes that `universal_regions` indices map is fully constructed. - fn add_implied_bounds(&mut self, indices: &UniversalRegionIndices<'tcx>, ty: Ty<'tcx>) { - debug!("add_implied_bounds(ty={:?})", ty); - let span = self.infcx.tcx.def_span(self.mir_def_id); - let bounds = self.infcx - .implied_outlives_bounds(self.param_env, self.mir_node_id, ty, span); - self.add_outlives_bounds(indices, bounds); - } - - /// Registers the `OutlivesBound` items from `outlives_bounds` in - /// the outlives relation as well as the region-bound pairs - /// listing. - fn add_outlives_bounds(&mut self, indices: &UniversalRegionIndices<'tcx>, outlives_bounds: I) - where - I: IntoIterator>, - { - for outlives_bound in outlives_bounds { - debug!("add_outlives_bounds(bound={:?})", outlives_bound); - - match outlives_bound { - OutlivesBound::RegionSubRegion(r1, r2) => { - // The bound says that `r1 <= r2`; we store `r2: r1`. - let r1 = indices.to_region_vid(r1); - let r2 = indices.to_region_vid(r2); - self.relations.relate_universal_regions(r2, r1); - } - - OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs - .push((r_a, GenericKind::Param(param_b))); - } - - OutlivesBound::RegionSubProjection(r_a, projection_b) => { - self.region_bound_pairs - .push((r_a, GenericKind::Projection(projection_b))); - } - } - } - } -} - -impl UniversalRegionRelations { - /// Records in the `outlives_relation` (and - /// `inverse_outlives_relation`) that `fr_a: fr_b`. - fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { - debug!( - "relate_universal_regions: fr_a={:?} outlives fr_b={:?}", - fr_a, fr_b - ); - self.outlives.add(fr_a, fr_b); - self.inverse_outlives.add(fr_b, fr_a); - } } trait InferCtxtExt<'tcx> { @@ -925,19 +698,6 @@ impl<'tcx> UniversalRegionIndices<'tcx> { } } -/// This trait is used by the `impl-trait` constraint code to abstract -/// over the `FreeRegionMap` from lexical regions and -/// `UniversalRegions` (from NLL)`. -impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegions<'tcx> { - fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool { - let shorter = shorter.to_region_vid(); - assert!(self.is_universal_region(shorter)); - let longer = longer.to_region_vid(); - assert!(self.is_universal_region(longer)); - self.outlives(longer, shorter) - } -} - /// Iterates over the late-bound regions defined on fn_def_id and /// invokes `f` with the liberated form of each one. fn for_each_late_bound_region_defined_on<'tcx>( From d42bc58b1dc881883444142e7898206a12bf5064 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 14:38:40 +0300 Subject: [PATCH 3/8] add regression test for #52057 Fixes #52057 --- src/test/ui/issue-52057.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/test/ui/issue-52057.rs diff --git a/src/test/ui/issue-52057.rs b/src/test/ui/issue-52057.rs new file mode 100644 index 0000000000000..533623fd38900 --- /dev/null +++ b/src/test/ui/issue-52057.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #52057. There is an implied bound +// that `I: 'a` where `'a` is the lifetime of `self` in `parse_first`; +// but to observe that, one must normalize first. +// +// run-pass + +#![feature(nll)] + +pub trait Parser { + type Input; + + #[inline(always)] + fn parse_first(input: &mut Self::Input); +} + +impl<'a, I, P: ?Sized> Parser for &'a mut P +where + P: Parser, +{ + type Input = I; + + fn parse_first(_: &mut Self::Input) {} +} + +fn main() {} From 1e1f18ddba20b370d6cdd85d60e7e415a94094b5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 14:49:45 +0300 Subject: [PATCH 4/8] make a free fn for creating the URR --- .../nll/type_check/free_region_relations.rs | 64 +++++++++---------- .../borrow_check/nll/type_check/mod.rs | 21 +++--- 2 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index d2850f8f32443..a539bf5f3aa96 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -9,11 +9,11 @@ // except according to those terms. use borrow_check::location::LocationTable; -use borrow_check::nll::ToRegionVid; use borrow_check::nll::facts::AllFacts; use borrow_check::nll::type_check::constraint_conversion; use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints}; use borrow_check::nll::universal_regions::UniversalRegions; +use borrow_check::nll::ToRegionVid; use rustc::hir::def_id::DefId; use rustc::infer::outlives::free_region_map::FreeRegionRelations; use rustc::infer::region_constraints::GenericKind; @@ -53,37 +53,37 @@ crate struct UniversalRegionRelations<'tcx> { inverse_outlives: TransitiveRelation, } -impl UniversalRegionRelations<'tcx> { - crate fn create( - infcx: &InferCtxt<'_, '_, 'tcx>, - mir_def_id: DefId, - param_env: ty::ParamEnv<'tcx>, - location_table: &LocationTable, - implicit_region_bound: Option>, - universal_regions: &Rc>, - constraints: &mut MirTypeckRegionConstraints<'tcx>, - all_facts: &mut Option, - ) -> Self { - let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap(); - UniversalRegionRelationsBuilder { - infcx, - mir_def_id, - mir_node_id, - param_env, - implicit_region_bound, - constraints, - location_table, - all_facts, +crate fn create( + infcx: &InferCtxt<'_, '_, 'tcx>, + mir_def_id: DefId, + param_env: ty::ParamEnv<'tcx>, + location_table: &LocationTable, + implicit_region_bound: Option>, + universal_regions: &Rc>, + constraints: &mut MirTypeckRegionConstraints<'tcx>, + all_facts: &mut Option, +) -> Rc> { + let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap(); + UniversalRegionRelationsBuilder { + infcx, + mir_def_id, + mir_node_id, + param_env, + implicit_region_bound, + constraints, + location_table, + all_facts, + universal_regions: universal_regions.clone(), + relations: UniversalRegionRelations { universal_regions: universal_regions.clone(), - relations: UniversalRegionRelations { - universal_regions: universal_regions.clone(), - region_bound_pairs: Vec::new(), - outlives: TransitiveRelation::new(), - inverse_outlives: TransitiveRelation::new(), - }, - }.create() - } + region_bound_pairs: Vec::new(), + outlives: TransitiveRelation::new(), + inverse_outlives: TransitiveRelation::new(), + }, + }.create() +} +impl UniversalRegionRelations<'tcx> { /// Records in the `outlives_relation` (and /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the /// builder below. @@ -212,7 +212,7 @@ struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> { } impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { - crate fn create(mut self) -> UniversalRegionRelations<'tcx> { + crate fn create(mut self) -> Rc> { let unnormalized_input_output_tys = self .universal_regions .unnormalized_input_tys @@ -277,7 +277,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { ).convert_all(&data); } - self.relations + Rc::new(self.relations) } /// Update the type of a single local, which should represent diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 15deb5fb2f498..d4a4e17849c8e 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -132,17 +132,16 @@ pub(crate) fn type_check<'gcx, 'tcx>( type_tests: Vec::default(), }; - let universal_region_relations = - Rc::new(free_region_relations::UniversalRegionRelations::create( - infcx, - mir_def_id, - param_env, - location_table, - Some(implicit_region_bound), - universal_regions, - &mut constraints, - all_facts, - )); + let universal_region_relations = free_region_relations::create( + infcx, + mir_def_id, + param_env, + location_table, + Some(implicit_region_bound), + universal_regions, + &mut constraints, + all_facts, + ); { let mut borrowck_context = BorrowCheckContext { From 490928f7099b8b5523eb8708919798e82006b054 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 14:52:56 +0300 Subject: [PATCH 5/8] remove `region_bound_pairs` from FRR as they are not needed later --- .../nll/type_check/free_region_relations.rs | 47 ++++++++++--------- .../borrow_check/nll/type_check/mod.rs | 4 +- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index a539bf5f3aa96..26a694a30a27f 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -29,18 +29,6 @@ use syntax::ast; crate struct UniversalRegionRelations<'tcx> { universal_regions: Rc>, - /// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to - /// be true. These encode relationships like `T: 'a` that are - /// added via implicit bounds. - /// - /// Each region here is guaranteed to be a key in the `indices` - /// map. We use the "original" regions (i.e., the keys from the - /// map, and not the values) because the code in - /// `process_registered_region_obligations` has some special-cased - /// logic expecting to see (e.g.) `ReStatic`, and if we supplied - /// our special inference variable there, we would mess that up. - crate region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, - /// Stores the outlives relations that are known to hold from the /// implied bounds, in-scope where clauses, and that sort of /// thing. @@ -53,6 +41,18 @@ crate struct UniversalRegionRelations<'tcx> { inverse_outlives: TransitiveRelation, } +/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to +/// be true. These encode relationships like `T: 'a` that are +/// added via implicit bounds. +/// +/// Each region here is guaranteed to be a key in the `indices` +/// map. We use the "original" regions (i.e., the keys from the +/// map, and not the values) because the code in +/// `process_registered_region_obligations` has some special-cased +/// logic expecting to see (e.g.) `ReStatic`, and if we supplied +/// our special inference variable there, we would mess that up. +type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; + crate fn create( infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, @@ -62,7 +62,7 @@ crate fn create( universal_regions: &Rc>, constraints: &mut MirTypeckRegionConstraints<'tcx>, all_facts: &mut Option, -) -> Rc> { +) -> (Rc>, RegionBoundPairs<'tcx>) { let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap(); UniversalRegionRelationsBuilder { infcx, @@ -74,9 +74,9 @@ crate fn create( location_table, all_facts, universal_regions: universal_regions.clone(), + region_bound_pairs: Vec::new(), relations: UniversalRegionRelations { universal_regions: universal_regions.clone(), - region_bound_pairs: Vec::new(), outlives: TransitiveRelation::new(), inverse_outlives: TransitiveRelation::new(), }, @@ -205,14 +205,17 @@ struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> { param_env: ty::ParamEnv<'tcx>, location_table: &'this LocationTable, universal_regions: Rc>, - relations: UniversalRegionRelations<'tcx>, implicit_region_bound: Option>, constraints: &'this mut MirTypeckRegionConstraints<'tcx>, all_facts: &'this mut Option, + + // outputs: + relations: UniversalRegionRelations<'tcx>, + region_bound_pairs: RegionBoundPairs<'tcx>, } impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { - crate fn create(mut self) -> Rc> { + crate fn create(mut self) -> (Rc>, RegionBoundPairs<'tcx>) { let unnormalized_input_output_tys = self .universal_regions .unnormalized_input_tys @@ -225,7 +228,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { // constraints, which we buffer up because we are // not ready to process them yet. // - Then compute the implied bounds. This will adjust - // the `relations.region_bound_pairs` and so forth. + // the `region_bound_pairs` and so forth. // - After this is done, we'll process the constraints, once // the `relations` is built. let constraint_sets: Vec<_> = unnormalized_input_output_tys @@ -267,7 +270,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { self.infcx.tcx, &self.universal_regions, &self.location_table, - &self.relations.region_bound_pairs, + &self.region_bound_pairs, self.implicit_region_bound, self.param_env, Locations::All, @@ -277,7 +280,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { ).convert_all(&data); } - Rc::new(self.relations) + (Rc::new(self.relations), self.region_bound_pairs) } /// Update the type of a single local, which should represent @@ -312,14 +315,12 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { } OutlivesBound::RegionSubParam(r_a, param_b) => { - self.relations - .region_bound_pairs + self.region_bound_pairs .push((r_a, GenericKind::Param(param_b))); } OutlivesBound::RegionSubProjection(r_a, projection_b) => { - self.relations - .region_bound_pairs + self.region_bound_pairs .push((r_a, GenericKind::Projection(projection_b))); } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index d4a4e17849c8e..eb18a56523eb6 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -132,7 +132,7 @@ pub(crate) fn type_check<'gcx, 'tcx>( type_tests: Vec::default(), }; - let universal_region_relations = free_region_relations::create( + let (universal_region_relations, region_bound_pairs) = free_region_relations::create( infcx, mir_def_id, param_env, @@ -157,7 +157,7 @@ pub(crate) fn type_check<'gcx, 'tcx>( mir_def_id, param_env, mir, - &universal_region_relations.region_bound_pairs, + ®ion_bound_pairs, Some(implicit_region_bound), Some(&mut borrowck_context), Some(errors_buffer), From 68c2a39a720163db2e6b586aad2fb7d96040beda Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 15:07:22 +0300 Subject: [PATCH 6/8] free RegionBoundPairs earlier and avoid normalizing twice Normalization results are memoized, so this may not be worth it, but it seems easy enough to do. --- .../nll/type_check/free_region_relations.rs | 25 +++++++++++++-- .../nll/type_check/input_output.rs | 31 +++++++------------ .../borrow_check/nll/type_check/mod.rs | 9 ++++-- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index 26a694a30a27f..e4b1aacd34f71 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -53,6 +53,18 @@ crate struct UniversalRegionRelations<'tcx> { /// our special inference variable there, we would mess that up. type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; +/// As part of computing the free region relations, we also have to +/// normalize the input-output types, which we then need later. So we +/// return those. This vector consists of first the input types and +/// then the output type as the last element. +type NormalizedInputsAndOutput<'tcx> = Vec>; + +crate struct CreateResult<'tcx> { + crate universal_region_relations: Rc>, + crate region_bound_pairs: RegionBoundPairs<'tcx>, + crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, +} + crate fn create( infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, @@ -62,7 +74,7 @@ crate fn create( universal_regions: &Rc>, constraints: &mut MirTypeckRegionConstraints<'tcx>, all_facts: &mut Option, -) -> (Rc>, RegionBoundPairs<'tcx>) { +) -> CreateResult<'tcx> { let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap(); UniversalRegionRelationsBuilder { infcx, @@ -215,7 +227,7 @@ struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> { } impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { - crate fn create(mut self) -> (Rc>, RegionBoundPairs<'tcx>) { + crate fn create(mut self) -> CreateResult<'tcx> { let unnormalized_input_output_tys = self .universal_regions .unnormalized_input_tys @@ -231,6 +243,8 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { // the `region_bound_pairs` and so forth. // - After this is done, we'll process the constraints, once // the `relations` is built. + let mut normalized_inputs_and_output = + Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1); let constraint_sets: Vec<_> = unnormalized_input_output_tys .flat_map(|ty| { debug!("build: input_or_output={:?}", ty); @@ -240,6 +254,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { .fully_perform(self.infcx) .unwrap_or_else(|_| bug!("failed to normalize {:?}", ty)); self.add_implied_bounds(ty); + normalized_inputs_and_output.push(ty); constraints }) .collect(); @@ -280,7 +295,11 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { ).convert_all(&data); } - (Rc::new(self.relations), self.region_bound_pairs) + CreateResult { + universal_region_relations: Rc::new(self.relations), + region_bound_pairs: self.region_bound_pairs, + normalized_inputs_and_output, + } } /// Update the type of a single local, which should represent diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index 8571ac3235c33..af42667016780 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -39,22 +39,24 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { mir_def_id: DefId, universal_regions: &UniversalRegions<'tcx>, universal_region_relations: &UniversalRegionRelations<'tcx>, + normalized_inputs_and_output: &[Ty<'tcx>], ) { let tcx = self.infcx.tcx; - let &UniversalRegions { - unnormalized_output_ty, - unnormalized_input_tys, - .. - } = universal_regions; + let (&normalized_output_ty, normalized_input_tys) = + normalized_inputs_and_output.split_last().unwrap(); let infcx = self.infcx; // Equate expected input tys with those in the MIR. let argument_locals = (1..).map(Local::new); - for (&unnormalized_input_ty, local) in unnormalized_input_tys.iter().zip(argument_locals) { - let input_ty = self.normalize(unnormalized_input_ty, Locations::All); + for (&normalized_input_ty, local) in normalized_input_tys.iter().zip(argument_locals) { + debug!( + "equate_inputs_and_outputs: normalized_input_ty = {:?}", + normalized_input_ty + ); + let mir_input_ty = mir.local_decls[local].ty; - self.equate_normalized_input_or_output(input_ty, mir_input_ty); + self.equate_normalized_input_or_output(normalized_input_ty, mir_input_ty); } assert!( @@ -68,15 +70,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // Return types are a bit more complex. They may contain existential `impl Trait` // types. - debug!( - "equate_inputs_and_outputs: unnormalized_output_ty={:?}", - unnormalized_output_ty - ); - let output_ty = self.normalize(unnormalized_output_ty, Locations::All); - debug!( - "equate_inputs_and_outputs: normalized output_ty={:?}", - output_ty - ); let param_env = self.param_env; let mir_output_ty = mir.local_decls[RETURN_PLACE].ty; let anon_type_map = @@ -92,7 +85,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { mir_def_id, dummy_body_id, param_env, - &output_ty, + &normalized_output_ty, )); debug!( "equate_inputs_and_outputs: instantiated output_ty={:?}", @@ -146,7 +139,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self, Location::START, "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", - output_ty, + normalized_output_ty, mir_output_ty, terr ); diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index eb18a56523eb6..a18e2368bf724 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -17,7 +17,7 @@ use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; use borrow_check::nll::facts::AllFacts; use borrow_check::nll::region_infer::values::{RegionValueElements, LivenessValues}; use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; -use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; +use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations}; use borrow_check::nll::universal_regions::UniversalRegions; use borrow_check::nll::LocalWithRegion; use borrow_check::nll::ToRegionVid; @@ -132,7 +132,11 @@ pub(crate) fn type_check<'gcx, 'tcx>( type_tests: Vec::default(), }; - let (universal_region_relations, region_bound_pairs) = free_region_relations::create( + let CreateResult { + universal_region_relations, + region_bound_pairs, + normalized_inputs_and_output, + } = free_region_relations::create( infcx, mir_def_id, param_env, @@ -168,6 +172,7 @@ pub(crate) fn type_check<'gcx, 'tcx>( mir_def_id, universal_regions, &universal_region_relations, + &normalized_inputs_and_output, ); }, ); From 9baf01363cfe579e6a04b7f4d821dcff5d27831d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 15:19:21 +0300 Subject: [PATCH 7/8] assert no region obligations on entering custom type op Fixes #51649 --- src/librustc/traits/query/type_op/custom.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/librustc/traits/query/type_op/custom.rs b/src/librustc/traits/query/type_op/custom.rs index 3d10ce805853d..cc752d21ab2b8 100644 --- a/src/librustc/traits/query/type_op/custom.rs +++ b/src/librustc/traits/query/type_op/custom.rs @@ -75,6 +75,19 @@ fn scrape_region_constraints<'gcx, 'tcx, R>( ) -> Fallible<(R, Option>>>)> { let mut fulfill_cx = TraitEngine::new(infcx.tcx); let dummy_body_id = ObligationCause::dummy().body_id; + + // During NLL, we expect that nobody will register region + // obligations **except** as part of a custom type op (and, at the + // end of each custom type op, we scrape out the region + // obligations that resulted). So this vector should be empty on + // entry. + let pre_obligations = infcx.take_registered_region_obligations(); + assert!( + pre_obligations.is_empty(), + "scrape_region_constraints: incoming region obligations = {:#?}", + pre_obligations, + ); + let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id)); fulfill_cx.register_predicate_obligations(infcx, obligations); From b9652aee6533378bc3116969f04551058d3667e9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 26 Jul 2018 15:38:18 +0300 Subject: [PATCH 8/8] region_infer: rustfmt, pacifying the mercilous tidy --- .../borrow_check/nll/region_infer/mod.rs | 72 ++++++++++++------- 1 file changed, 48 insertions(+), 24 deletions(-) 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 6281b5dd4b64c..afd4e2859aced 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -14,8 +14,8 @@ use borrow_check::nll::constraints::{ ConstraintIndex, ConstraintSccIndex, ConstraintSet, OutlivesConstraint, }; use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex}; -use borrow_check::nll::type_check::Locations; use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; +use borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::region_constraints::{GenericKind, VarInfos}; @@ -313,8 +313,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { for (external_name, variable) in self.universal_regions.named_universal_regions() { debug!( "init_universal_regions: region {:?} has external name {:?}", - variable, - external_name + variable, external_name ); self.definitions[variable].external_name = Some(external_name); } @@ -424,10 +423,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { }; self.check_type_tests( - infcx, mir, mir_def_id, outlives_requirements.as_mut(), errors_buffer); + infcx, + mir, + mir_def_id, + outlives_requirements.as_mut(), + errors_buffer, + ); self.check_universal_regions( - infcx, mir, mir_def_id, outlives_requirements.as_mut(), errors_buffer); + infcx, + mir, + mir_def_id, + outlives_requirements.as_mut(), + errors_buffer, + ); let outlives_requirements = outlives_requirements.unwrap_or(vec![]); @@ -586,13 +595,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let Some(lower_bound_region) = lower_bound_region { let region_scope_tree = &tcx.region_scope_tree(mir_def_id); let type_test_span = type_test.locations.span(mir); - infcx.construct_generic_bound_failure( - region_scope_tree, - type_test_span, - None, - type_test.generic_kind, - lower_bound_region, - ).buffer(errors_buffer); + infcx + .construct_generic_bound_failure( + region_scope_tree, + type_test_span, + None, + type_test.generic_kind, + lower_bound_region, + ) + .buffer(errors_buffer); } else { // FIXME. We should handle this case better. It // indicates that we have e.g. some region variable @@ -604,10 +615,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { // iterating over the universal regions and reporting // an error that multiple bounds are required. let type_test_span = type_test.locations.span(mir); - tcx.sess.struct_span_err( - type_test_span, - &format!("`{}` does not live long enough", type_test.generic_kind,), - ).buffer(errors_buffer); + tcx.sess + .struct_span_err( + type_test_span, + &format!("`{}` does not live long enough", type_test.generic_kind,), + ) + .buffer(errors_buffer); } } } @@ -659,8 +672,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { // region, which ensures it can be encoded in a `ClosureOutlivesRequirement`. let lower_bound_plus = self.non_local_universal_upper_bound(*lower_bound); assert!(self.universal_regions.is_universal_region(lower_bound_plus)); - assert!(!self.universal_regions - .is_local_free_region(lower_bound_plus)); + assert!( + !self + .universal_regions + .is_local_free_region(lower_bound_plus) + ); propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject, @@ -892,7 +908,8 @@ 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 @@ -982,7 +999,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // (because `fr` includes `end(o)`). for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) { // 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) + { continue; } @@ -996,14 +1016,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `fr` until we find a non-local region (if we do). // We'll call that `fr-` -- it's ever so slightly smaller than `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); // Grow `shorter_fr` until we find a non-local // region. (We always will.) We'll call that // `shorter_fr+` -- it's ever so slightly larger than // `fr`. - let shorter_fr_plus = self.universal_region_relations.non_local_upper_bound(shorter_fr); + let shorter_fr_plus = self + .universal_region_relations + .non_local_upper_bound(shorter_fr); debug!( "check_universal_region: shorter_fr_plus={:?}", shorter_fr_plus @@ -1026,8 +1051,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Note: in this case, we use the unapproximated regions // to report the error. This gives better error messages // in some cases. - self.report_error( - mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer); + self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer); } }