Erase regions in writeback
Also skip duplicated region solving entirely with `-Zborrowck=mir`.
This commit is contained in:
parent
cefd0305b1
commit
0a7f16e7d8
9 changed files with 103 additions and 64 deletions
|
|
@ -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,
|
||||
|
|
@ -372,17 +372,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
region_scope_tree: ®ion::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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 SuppressRegionErrors {
|
||||
impl Default for RegionckMode {
|
||||
fn default() -> Self {
|
||||
RegionckMode::Solve
|
||||
}
|
||||
}
|
||||
|
||||
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 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1207,20 +1226,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
region_context: DefId,
|
||||
region_map: ®ion::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()
|
||||
|
|
@ -1228,8 +1240,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
.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());
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ mod util;
|
|||
pub mod wf;
|
||||
|
||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
use crate::infer::{InferCtxt, SuppressRegionErrors, TyCtxtInferExt};
|
||||
use crate::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
|
||||
use crate::traits::error_reporting::InferCtxtExt as _;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc::middle::region;
|
||||
|
|
@ -244,7 +244,7 @@ fn do_normalize_predicates<'tcx>(
|
|||
region_context,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
RegionckMode::default(),
|
||||
);
|
||||
|
||||
let predicates = match infcx.fully_resolve(&predicates) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc::ty::subst::{Subst, SubstsRef};
|
|||
use rustc::ty::{self, Predicate, Ty, TyCtxt};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{InferOk, SuppressRegionErrors, TyCtxtInferExt};
|
||||
use rustc_infer::infer::{InferOk, RegionckMode, TyCtxtInferExt};
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
|
|
@ -139,7 +139,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
|||
drop_impl_did,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
RegionckMode::default(),
|
||||
);
|
||||
Ok(())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::PatKind;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{self, RegionObligation, SuppressRegionErrors};
|
||||
use rustc_infer::infer::{self, RegionObligation, RegionckMode};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::infer::OutlivesEnvironmentExt;
|
||||
use rustc_trait_selection::opaque_types::InferCtxtExt;
|
||||
|
|
@ -124,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
rcx.visit_body(body);
|
||||
rcx.visit_region_obligations(id);
|
||||
}
|
||||
rcx.resolve_regions_and_report_errors(SuppressRegionErrors::when_nll_is_enabled(self.tcx));
|
||||
rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx));
|
||||
}
|
||||
|
||||
/// Region checking during the WF phase for items. `wf_tys` are the
|
||||
|
|
@ -142,7 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span);
|
||||
rcx.outlives_environment.save_implied_bounds(item_id);
|
||||
rcx.visit_region_obligations(item_id);
|
||||
rcx.resolve_regions_and_report_errors(SuppressRegionErrors::default());
|
||||
rcx.resolve_regions_and_report_errors(RegionckMode::default());
|
||||
}
|
||||
|
||||
/// Region check a function body. Not invoked on closures, but
|
||||
|
|
@ -165,7 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id));
|
||||
}
|
||||
|
||||
rcx.resolve_regions_and_report_errors(SuppressRegionErrors::when_nll_is_enabled(self.tcx));
|
||||
rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -346,7 +346,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
|
|||
self.select_all_obligations_or_error();
|
||||
}
|
||||
|
||||
fn resolve_regions_and_report_errors(&self, suppress: SuppressRegionErrors) {
|
||||
fn resolve_regions_and_report_errors(&self, mode: RegionckMode) {
|
||||
self.infcx.process_registered_region_obligations(
|
||||
self.outlives_environment.region_bound_pairs_map(),
|
||||
self.implicit_region_bound,
|
||||
|
|
@ -357,7 +357,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
|
|||
self.subject_def_id,
|
||||
&self.region_scope_tree,
|
||||
&self.outlives_environment,
|
||||
suppress,
|
||||
mode,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
|
||||
fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
|
||||
debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty);
|
||||
assert!(!ty.needs_infer() && !ty.has_placeholders());
|
||||
assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions());
|
||||
self.tables.node_types_mut().insert(hir_id, ty);
|
||||
}
|
||||
|
||||
|
|
@ -326,9 +326,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
let new_upvar_capture = match *upvar_capture {
|
||||
ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
|
||||
ty::UpvarCapture::ByRef(ref upvar_borrow) => {
|
||||
let r = upvar_borrow.region;
|
||||
let r = self.resolve(&r, &upvar_id.var_path.hir_id);
|
||||
ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: upvar_borrow.kind, region: r })
|
||||
ty::UpvarCapture::ByRef(ty::UpvarBorrow {
|
||||
kind: upvar_borrow.kind,
|
||||
region: self.tcx().lifetimes.re_erased,
|
||||
})
|
||||
}
|
||||
};
|
||||
debug!("Upvar capture for {:?} resolved to {:?}", upvar_id, new_upvar_capture);
|
||||
|
|
@ -421,8 +422,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
fn visit_opaque_types(&mut self, span: Span) {
|
||||
for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
|
||||
let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap();
|
||||
let instantiated_ty =
|
||||
self.tcx().erase_regions(&self.resolve(&opaque_defn.concrete_ty, &hir_id));
|
||||
let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id);
|
||||
|
||||
debug_assert!(!instantiated_ty.has_escaping_bound_vars());
|
||||
|
||||
|
|
@ -611,10 +611,8 @@ impl Locatable for hir::HirId {
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The Resolver. This is the type folding engine that detects
|
||||
// unresolved types and so forth.
|
||||
|
||||
/// The Resolver. This is the type folding engine that detects
|
||||
/// unresolved types and so forth.
|
||||
struct Resolver<'cx, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
|
|
@ -647,7 +645,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
|
|||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match self.infcx.fully_resolve(&t) {
|
||||
Ok(t) => t,
|
||||
Ok(t) => self.infcx.tcx.erase_regions(&t),
|
||||
Err(_) => {
|
||||
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
|
||||
self.report_error(t);
|
||||
|
|
@ -656,15 +654,14 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME This should be carefully checked
|
||||
// We could use `self.report_error` but it doesn't accept a ty::Region, right now.
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
self.infcx.fully_resolve(&r).unwrap_or(self.tcx.lifetimes.re_static)
|
||||
debug_assert!(!r.is_late_bound(), "Should not be resolving bound region.");
|
||||
self.tcx.lifetimes.re_erased
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
match self.infcx.fully_resolve(&ct) {
|
||||
Ok(ct) => ct,
|
||||
Ok(ct) => self.infcx.tcx.erase_regions(&ct),
|
||||
Err(_) => {
|
||||
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
|
||||
// FIXME: we'd like to use `self.report_error`, but it doesn't yet
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::ItemKind;
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{SuppressRegionErrors, TyCtxtInferExt};
|
||||
use rustc_infer::infer::{RegionckMode, TyCtxtInferExt};
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
|
||||
use rustc_trait_selection::traits::predicate_for_trait_def;
|
||||
|
|
@ -307,7 +307,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) {
|
|||
impl_did,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
RegionckMode::default(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -568,7 +568,7 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI
|
|||
impl_did,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
RegionckMode::default(),
|
||||
);
|
||||
|
||||
CoerceUnsizedInfo { custom_kind: kind }
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{InferCtxt, SuppressRegionErrors, TyCtxtInferExt};
|
||||
use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
|
||||
use rustc_infer::traits::specialization_graph::Node;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::{self, translate_substs, wf};
|
||||
|
|
@ -162,7 +162,7 @@ fn get_impl_substs<'tcx>(
|
|||
impl1_def_id,
|
||||
&ScopeTree::default(),
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
RegionckMode::default(),
|
||||
);
|
||||
let impl2_substs = match infcx.fully_resolve(&impl2_substs) {
|
||||
Ok(s) => s,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue