Skip to content

Commit

Permalink
Rollup merge of rust-lang#69189 - matthewjasper:erase-the-world, r=ni…
Browse files Browse the repository at this point in the history
…komatsakis

Erase regions in writeback

Regions in `TypeckTables` (except canonicalized user annotations) are now erased. Further, we no longer do lexical region solving on item bodies with `-Zborrowck=mir`.

cc rust-lang#68261
r? @nikomatsakis
  • Loading branch information
Centril authored Mar 18, 2020
2 parents 0789d63 + 1ee5829 commit ecf19c3
Show file tree
Hide file tree
Showing 34 changed files with 264 additions and 237 deletions.
9 changes: 0 additions & 9 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use crate::mir::{
};
use crate::traits;
use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals};
use crate::ty::free_region_map::FreeRegionMap;
use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
use crate::ty::query;
use crate::ty::steal::Steal;
Expand Down Expand Up @@ -416,11 +415,6 @@ pub struct TypeckTables<'tcx> {
/// this field will be set to `true`.
pub tainted_by_errors: bool,

/// Stores the free-region relationships that were deduced from
/// its where-clauses and parameter types. These are then
/// read-again by borrowck.
pub free_region_map: FreeRegionMap<'tcx>,

/// All the opaque types that are restricted to concrete types
/// by this function.
pub concrete_opaque_types: FxHashMap<DefId, ResolvedOpaqueTy<'tcx>>,
Expand Down Expand Up @@ -456,7 +450,6 @@ impl<'tcx> TypeckTables<'tcx> {
coercion_casts: Default::default(),
used_trait_imports: Lrc::new(Default::default()),
tainted_by_errors: false,
free_region_map: Default::default(),
concrete_opaque_types: Default::default(),
upvar_list: Default::default(),
generator_interior_types: Default::default(),
Expand Down Expand Up @@ -719,7 +712,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {

ref used_trait_imports,
tainted_by_errors,
ref free_region_map,
ref concrete_opaque_types,
ref upvar_list,
ref generator_interior_types,
Expand Down Expand Up @@ -757,7 +749,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
coercion_casts.hash_stable(hcx, hasher);
used_trait_imports.hash_stable(hcx, hasher);
tainted_by_errors.hash_stable(hcx, hasher);
free_region_map.hash_stable(hcx, hasher);
concrete_opaque_types.hash_stable(hcx, hasher);
upvar_list.hash_stable(hcx, hasher);
generator_interior_types.hash_stable(hcx, hasher);
Expand Down
13 changes: 2 additions & 11 deletions src/librustc_infer/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use super::lexical_region_resolve::RegionResolutionError;
use super::region_constraints::GenericKind;
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};

use crate::infer::{self, SuppressRegionErrors};
use crate::infer;
use crate::traits::error_reporting::report_object_safety_error;
use crate::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
Expand Down Expand Up @@ -372,17 +372,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&self,
region_scope_tree: &region::ScopeTree,
errors: &Vec<RegionResolutionError<'tcx>>,
suppress: SuppressRegionErrors,
) {
debug!(
"report_region_errors(): {} errors to start, suppress = {:?}",
errors.len(),
suppress
);

if suppress.suppressed() {
return;
}
debug!("report_region_errors(): {} errors to start", errors.len());

// try to pre-process the errors, which will group some of them
// together into a `ProcessedErrors` group:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::SubregionOrigin;
use rustc::util::common::ErrorReported;

use rustc_errors::struct_span_err;
Expand Down Expand Up @@ -47,6 +49,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
let (span, sub, sup) = self.regions()?;

if let Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::ReferenceOutlivesReferent(..),
..,
)) = self.error
{
// This error doesn't make much sense in this case.
return None;
}

// Determine whether the sub and sup consist of both anonymous (elided) regions.
let anon_reg_sup = self.tcx().is_suitable_region(sup)?;

Expand Down
19 changes: 4 additions & 15 deletions src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,28 @@ mod util;

impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
if let Some(tables) = self.in_progress_tables {
let tables = tables.borrow();
NiceRegionError::new(self, error.clone(), Some(&tables)).try_report().is_some()
} else {
NiceRegionError::new(self, error.clone(), None).try_report().is_some()
}
NiceRegionError::new(self, error.clone()).try_report().is_some()
}
}

pub struct NiceRegionError<'cx, 'tcx> {
infcx: &'cx InferCtxt<'cx, 'tcx>,
error: Option<RegionResolutionError<'tcx>>,
regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
tables: Option<&'cx ty::TypeckTables<'tcx>>,
}

impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
pub fn new(
infcx: &'cx InferCtxt<'cx, 'tcx>,
error: RegionResolutionError<'tcx>,
tables: Option<&'cx ty::TypeckTables<'tcx>>,
) -> Self {
Self { infcx, error: Some(error), regions: None, tables }
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
Self { infcx, error: Some(error), regions: None }
}

pub fn new_from_span(
infcx: &'cx InferCtxt<'cx, 'tcx>,
span: Span,
sub: ty::Region<'tcx>,
sup: ty::Region<'tcx>,
tables: Option<&'cx ty::TypeckTables<'tcx>>,
) -> Self {
Self { infcx, error: None, regions: Some((span, sub, sup)), tables }
Self { infcx, error: None, regions: Some((span, sub, sup)) }
}

fn tcx(&self) -> TyCtxt<'tcx> {
Expand Down
78 changes: 35 additions & 43 deletions src/librustc_infer/infer/error_reporting/nice_region_error/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,52 +51,44 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
};

let hir = &self.tcx().hir();
if let Some(hir_id) = hir.as_local_hir_id(id) {
if let Some(body_id) = hir.maybe_body_owned_by(hir_id) {
let body = hir.body(body_id);
let owner_id = hir.body_owner(body_id);
let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
if let Some(tables) = self.tables {
body.params
.iter()
.enumerate()
.filter_map(|(index, param)| {
// May return None; sometimes the tables are not yet populated.
let ty_hir_id = fn_decl.inputs[index].hir_id;
let param_ty_span = hir.span(ty_hir_id);
let ty = tables.node_type_opt(param.hir_id)?;
let mut found_anon_region = false;
let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| {
if *r == *anon_region {
found_anon_region = true;
replace_region
} else {
r
}
});
if found_anon_region {
let is_first = index == 0;
Some(AnonymousParamInfo {
param,
param_ty: new_param_ty,
param_ty_span,
bound_region,
is_first,
})
} else {
None
}
})
.next()
let hir_id = hir.as_local_hir_id(id)?;
let body_id = hir.maybe_body_owned_by(hir_id)?;
let body = hir.body(body_id);
let owner_id = hir.body_owner(body_id);
let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
let poly_fn_sig = self.tcx().fn_sig(id);
let fn_sig = self.tcx().liberate_late_bound_regions(id, &poly_fn_sig);
body.params
.iter()
.enumerate()
.filter_map(|(index, param)| {
// May return None; sometimes the tables are not yet populated.
let ty = fn_sig.inputs()[index];
let mut found_anon_region = false;
let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| {
if *r == *anon_region {
found_anon_region = true;
replace_region
} else {
r
}
});
if found_anon_region {
let ty_hir_id = fn_decl.inputs[index].hir_id;
let param_ty_span = hir.span(ty_hir_id);
let is_first = index == 0;
Some(AnonymousParamInfo {
param,
param_ty: new_param_ty,
param_ty_span,
bound_region,
is_first,
})
} else {
None
}
} else {
None
}
} else {
None
}
})
.next()
}

// Here, we check for the case where the anonymous region
Expand Down
35 changes: 33 additions & 2 deletions src/librustc_infer/infer/lexical_region_resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::infer::region_constraints::RegionConstraintData;
use crate::infer::region_constraints::VarInfos;
use crate::infer::region_constraints::VerifyBound;
use crate::infer::RegionVariableOrigin;
use crate::infer::RegionckMode;
use crate::infer::SubregionOrigin;
use rustc::middle::free_region::RegionRelations;
use rustc::ty::fold::TypeFoldable;
Expand All @@ -33,12 +34,29 @@ pub fn resolve<'tcx>(
region_rels: &RegionRelations<'_, 'tcx>,
var_infos: VarInfos,
data: RegionConstraintData<'tcx>,
mode: RegionckMode,
) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
debug!("RegionConstraintData: resolve_regions()");
let mut errors = vec![];
let mut resolver = LexicalResolver { region_rels, var_infos, data };
let values = resolver.infer_variable_values(&mut errors);
(values, errors)
match mode {
RegionckMode::Solve => {
let values = resolver.infer_variable_values(&mut errors);
(values, errors)
}
RegionckMode::Erase { suppress_errors: false } => {
// Do real inference to get errors, then erase the results.
let mut values = resolver.infer_variable_values(&mut errors);
let re_erased = region_rels.tcx.lifetimes.re_erased;

values.values.iter_mut().for_each(|v| *v = VarValue::Value(re_erased));
(values, errors)
}
RegionckMode::Erase { suppress_errors: true } => {
// Skip region inference entirely.
(resolver.erased_data(region_rels.tcx), Vec::new())
}
}
}

/// Contains the result of lexical region resolution. Offers methods
Expand Down Expand Up @@ -163,6 +181,19 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}

/// An erased version of the lexical region resolutions. Used when we're
/// erasing regions and suppressing errors: in item bodies with
/// `-Zborrowck=mir`.
fn erased_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
LexicalRegionResolutions {
error_region: tcx.lifetimes.re_static,
values: IndexVec::from_elem_n(
VarValue::Value(tcx.lifetimes.re_erased),
self.num_vars(),
),
}
}

fn dump_constraints(&self, free_regions: &RegionRelations<'_, 'tcx>) {
debug!("----() Start constraint listing (context={:?}) ()----", free_regions.context);
for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
Expand Down
62 changes: 41 additions & 21 deletions src/librustc_infer/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,31 +79,50 @@ pub type Bound<T> = Option<T>;
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"

/// A flag that is used to suppress region errors. This is normally
/// false, but sometimes -- when we are doing region checks that the
/// NLL borrow checker will also do -- it might be set to true.
#[derive(Copy, Clone, Default, Debug)]
pub struct SuppressRegionErrors {
suppressed: bool,
/// How we should handle region solving.
///
/// This is used so that the region values inferred by HIR region solving are
/// not exposed, and so that we can avoid doing work in HIR typeck that MIR
/// typeck will also do.
#[derive(Copy, Clone, Debug)]
pub enum RegionckMode {
/// The default mode: report region errors, don't erase regions.
Solve,
/// Erase the results of region after solving.
Erase {
/// A flag that is used to suppress region errors, when we are doing
/// region checks that the NLL borrow checker will also do -- it might
/// be set to true.
suppress_errors: bool,
},
}

impl Default for RegionckMode {
fn default() -> Self {
RegionckMode::Solve
}
}

impl SuppressRegionErrors {
impl RegionckMode {
pub fn suppressed(self) -> bool {
self.suppressed
match self {
Self::Solve => false,
Self::Erase { suppress_errors } => suppress_errors,
}
}

/// Indicates that the MIR borrowck will repeat these region
/// checks, so we should ignore errors if NLL is (unconditionally)
/// enabled.
pub fn when_nll_is_enabled(tcx: TyCtxt<'_>) -> Self {
pub fn for_item_body(tcx: TyCtxt<'_>) -> Self {
// FIXME(Centril): Once we actually remove `::Migrate` also make
// this always `true` and then proceed to eliminate the dead code.
match tcx.borrowck_mode() {
// If we're on Migrate mode, report AST region errors
BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false },
BorrowckMode::Migrate => RegionckMode::Erase { suppress_errors: false },

// If we're on MIR, don't report AST region errors as they should be reported by NLL
BorrowckMode::Mir => SuppressRegionErrors { suppressed: true },
BorrowckMode::Mir => RegionckMode::Erase { suppress_errors: true },
}
}
}
Expand Down Expand Up @@ -1207,29 +1226,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
region_context: DefId,
region_map: &region::ScopeTree,
outlives_env: &OutlivesEnvironment<'tcx>,
suppress: SuppressRegionErrors,
mode: RegionckMode,
) {
assert!(
self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(),
"region_obligations not empty: {:#?}",
self.inner.borrow().region_obligations
);

let region_rels = &RegionRelations::new(
self.tcx,
region_context,
region_map,
outlives_env.free_region_map(),
);
let (var_infos, data) = self
.inner
.borrow_mut()
.region_constraints
.take()
.expect("regions already resolved")
.into_infos_and_data();

let region_rels = &RegionRelations::new(
self.tcx,
region_context,
region_map,
outlives_env.free_region_map(),
);

let (lexical_region_resolutions, errors) =
lexical_region_resolve::resolve(region_rels, var_infos, data);
lexical_region_resolve::resolve(region_rels, var_infos, data, mode);

let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
assert!(old_value.is_none());
Expand All @@ -1240,7 +1260,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// this infcx was in use. This is totally hokey but
// otherwise we have a hard time separating legit region
// errors from silly ones.
self.report_region_errors(region_map, &errors, suppress);
self.report_region_errors(region_map, &errors);
}
}

Expand Down
Loading

0 comments on commit ecf19c3

Please sign in to comment.