Rollup merge of #134378 - lqd:polonius-next-episode-2, r=jackh726

An octuple of polonius fact generation cleanups

This PR is extracted from https://github.com/rust-lang/rust/pull/134268 for easier review and contains its first 8 commits. They have already been reviewed by ````@jackh726```` over there.

r? ````@jackh726````
This commit is contained in:
Matthias Krüger 2024-12-17 22:34:43 +01:00 committed by GitHub
commit 264566fc61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 240 additions and 260 deletions

View file

@ -124,6 +124,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
borrow_set,
move_data,
&universal_region_relations,
&constraints,
);
let mut regioncx = RegionInferenceContext::new(

View file

@ -0,0 +1,85 @@
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{Body, Local, Location, Place};
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::move_paths::{LookupResult, MoveData};
use tracing::debug;
use crate::def_use::{self, DefUse};
use crate::facts::AllFacts;
use crate::location::{LocationIndex, LocationTable};
use crate::universal_regions::UniversalRegions;
/// Emit polonius facts for variable defs, uses, drops, and path accesses.
pub(crate) fn emit_access_facts<'tcx>(
tcx: TyCtxt<'tcx>,
facts: &mut AllFacts,
body: &Body<'tcx>,
location_table: &LocationTable,
move_data: &MoveData<'tcx>,
universal_regions: &UniversalRegions<'tcx>,
) {
let mut extractor = AccessFactsExtractor { facts, move_data, location_table };
extractor.visit_body(body);
for (local, local_decl) in body.local_decls.iter_enumerated() {
debug!("add use_of_var_derefs_origin facts - local={:?}, type={:?}", local, local_decl.ty);
tcx.for_each_free_region(&local_decl.ty, |region| {
let region_vid = universal_regions.to_region_vid(region);
facts.use_of_var_derefs_origin.push((local, region_vid.into()));
});
}
}
/// MIR visitor extracting point-wise facts about accesses.
struct AccessFactsExtractor<'a, 'tcx> {
facts: &'a mut AllFacts,
move_data: &'a MoveData<'tcx>,
location_table: &'a LocationTable,
}
impl<'tcx> AccessFactsExtractor<'_, 'tcx> {
fn location_to_index(&self, location: Location) -> LocationIndex {
self.location_table.mid_index(location)
}
}
impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> {
fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
match def_use::categorize(context) {
Some(DefUse::Def) => {
debug!("AccessFactsExtractor - emit def");
self.facts.var_defined_at.push((local, self.location_to_index(location)));
}
Some(DefUse::Use) => {
debug!("AccessFactsExtractor - emit use");
self.facts.var_used_at.push((local, self.location_to_index(location)));
}
Some(DefUse::Drop) => {
debug!("AccessFactsExtractor - emit drop");
self.facts.var_dropped_at.push((local, self.location_to_index(location)));
}
_ => (),
}
}
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
self.super_place(place, context, location);
match context {
PlaceContext::NonMutatingUse(_)
| PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
let path = match self.move_data.rev_lookup.find(place.as_ref()) {
LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path,
_ => {
// There's no path access to emit.
return;
}
};
debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})");
self.facts.path_accessed_at_base.push((path, self.location_to_index(location)));
}
_ => {}
}
}
}

View file

@ -21,22 +21,22 @@ use crate::{
/// Emit `loan_invalidated_at` facts.
pub(super) fn emit_loan_invalidations<'tcx>(
tcx: TyCtxt<'tcx>,
all_facts: &mut AllFacts,
location_table: &LocationTable,
facts: &mut AllFacts,
body: &Body<'tcx>,
location_table: &LocationTable,
borrow_set: &BorrowSet<'tcx>,
) {
let dominators = body.basic_blocks.dominators();
let mut visitor =
LoanInvalidationsGenerator { all_facts, borrow_set, tcx, location_table, body, dominators };
LoanInvalidationsGenerator { facts, borrow_set, tcx, location_table, body, dominators };
visitor.visit_body(body);
}
struct LoanInvalidationsGenerator<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
all_facts: &'a mut AllFacts,
location_table: &'a LocationTable,
facts: &'a mut AllFacts,
body: &'a Body<'tcx>,
location_table: &'a LocationTable,
dominators: &'a Dominators<BasicBlock>,
borrow_set: &'a BorrowSet<'tcx>,
}
@ -151,7 +151,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
let resume = self.location_table.start_index(resume.start_location());
for (i, data) in borrow_set.iter_enumerated() {
if borrow_of_local_data(data.borrowed_place) {
self.all_facts.loan_invalidated_at.push((resume, i));
self.facts.loan_invalidated_at.push((resume, i));
}
}
@ -165,7 +165,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
let start = self.location_table.start_index(location);
for (i, data) in borrow_set.iter_enumerated() {
if borrow_of_local_data(data.borrowed_place) {
self.all_facts.loan_invalidated_at.push((start, i));
self.facts.loan_invalidated_at.push((start, i));
}
}
}
@ -409,7 +409,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
/// Generates a new `loan_invalidated_at(L, B)` fact.
fn emit_loan_invalidated_at(&mut self, b: BorrowIndex, l: Location) {
let lidx = self.location_table.start_index(l);
self.all_facts.loan_invalidated_at.push((lidx, b));
self.facts.loan_invalidated_at.push((lidx, b));
}
fn check_activations(&mut self, location: Location) {

View file

@ -14,12 +14,12 @@ use crate::places_conflict;
/// Emit `loan_killed_at` and `cfg_edge` facts at the same time.
pub(super) fn emit_loan_kills<'tcx>(
tcx: TyCtxt<'tcx>,
all_facts: &mut AllFacts,
location_table: &LocationTable,
facts: &mut AllFacts,
body: &Body<'tcx>,
location_table: &LocationTable,
borrow_set: &BorrowSet<'tcx>,
) {
let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, all_facts, body };
let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, facts, body };
for (bb, data) in body.basic_blocks.iter_enumerated() {
visitor.visit_basic_block_data(bb, data);
}
@ -27,7 +27,7 @@ pub(super) fn emit_loan_kills<'tcx>(
struct LoanKillsGenerator<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
all_facts: &'a mut AllFacts,
facts: &'a mut AllFacts,
location_table: &'a LocationTable,
borrow_set: &'a BorrowSet<'tcx>,
body: &'a Body<'tcx>,
@ -36,12 +36,12 @@ struct LoanKillsGenerator<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'a, 'tcx> {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
// Also record CFG facts here.
self.all_facts.cfg_edge.push((
self.facts.cfg_edge.push((
self.location_table.start_index(location),
self.location_table.mid_index(location),
));
self.all_facts.cfg_edge.push((
self.facts.cfg_edge.push((
self.location_table.mid_index(location),
self.location_table.start_index(location.successor_within_block()),
));
@ -63,15 +63,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'a, 'tcx> {
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
// Also record CFG facts here.
self.all_facts.cfg_edge.push((
self.facts.cfg_edge.push((
self.location_table.start_index(location),
self.location_table.mid_index(location),
));
let successor_blocks = terminator.successors();
self.all_facts.cfg_edge.reserve(successor_blocks.size_hint().0);
self.facts.cfg_edge.reserve(successor_blocks.size_hint().0);
for successor_block in successor_blocks {
self.all_facts.cfg_edge.push((
self.facts.cfg_edge.push((
self.location_table.mid_index(location),
self.location_table.start_index(successor_block.start_location()),
));
@ -128,7 +128,7 @@ impl<'tcx> LoanKillsGenerator<'_, 'tcx> {
if places_conflict {
let location_index = self.location_table.mid_index(location);
self.all_facts.loan_killed_at.push((borrow_index, location_index));
self.facts.loan_killed_at.push((borrow_index, location_index));
}
}
}
@ -140,9 +140,9 @@ impl<'tcx> LoanKillsGenerator<'_, 'tcx> {
fn record_killed_borrows_for_local(&mut self, local: Local, location: Location) {
if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
let location_index = self.location_table.mid_index(location);
self.all_facts.loan_killed_at.reserve(borrow_indices.len());
self.facts.loan_killed_at.reserve(borrow_indices.len());
for &borrow_index in borrow_indices {
self.all_facts.loan_killed_at.push((borrow_index, location_index));
self.facts.loan_killed_at.push((borrow_index, location_index));
}
}
}

View file

@ -3,16 +3,23 @@
//! Will be removed in the future, once the in-tree `-Zpolonius=next` implementation reaches feature
//! parity.
use rustc_middle::mir::{Body, LocalKind, Location, START_BLOCK};
use rustc_middle::ty::TyCtxt;
use std::iter;
use either::Either;
use rustc_middle::mir::{Body, Local, LocalKind, Location, START_BLOCK};
use rustc_middle::ty::{GenericArg, TyCtxt};
use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
use tracing::debug;
use crate::borrow_set::BorrowSet;
use crate::constraints::OutlivesConstraint;
use crate::facts::{AllFacts, PoloniusRegionVid};
use crate::location::LocationTable;
use crate::type_check::MirTypeckRegionConstraints;
use crate::type_check::free_region_relations::UniversalRegionRelations;
use crate::universal_regions::UniversalRegions;
mod accesses;
mod loan_invalidations;
mod loan_kills;
@ -22,6 +29,8 @@ mod loan_kills;
/// - CFG points and edges
/// - loan kills
/// - loan invalidations
/// - access facts such as variable definitions, uses, drops, and path accesses
/// - outlives constraints
///
/// The rest of the facts are emitted during typeck and liveness.
pub(crate) fn emit_facts<'tcx>(
@ -30,34 +39,42 @@ pub(crate) fn emit_facts<'tcx>(
location_table: &LocationTable,
body: &Body<'tcx>,
borrow_set: &BorrowSet<'tcx>,
move_data: &MoveData<'_>,
universal_region_relations: &UniversalRegionRelations<'_>,
move_data: &MoveData<'tcx>,
universal_region_relations: &UniversalRegionRelations<'tcx>,
constraints: &MirTypeckRegionConstraints<'tcx>,
) {
let Some(all_facts) = all_facts else {
let Some(facts) = all_facts else {
// We don't do anything if there are no facts to fill.
return;
};
let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
emit_move_facts(all_facts, move_data, location_table, body);
emit_universal_region_facts(all_facts, borrow_set, universal_region_relations);
emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set);
emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set);
emit_move_facts(facts, body, location_table, move_data);
emit_universal_region_facts(facts, borrow_set, universal_region_relations);
loan_kills::emit_loan_kills(tcx, facts, body, location_table, borrow_set);
loan_invalidations::emit_loan_invalidations(tcx, facts, body, location_table, borrow_set);
accesses::emit_access_facts(
tcx,
facts,
body,
location_table,
move_data,
&universal_region_relations.universal_regions,
);
emit_outlives_facts(facts, location_table, constraints);
}
/// Emit facts needed for move/init analysis: moves and assignments.
fn emit_move_facts(
all_facts: &mut AllFacts,
move_data: &MoveData<'_>,
location_table: &LocationTable,
facts: &mut AllFacts,
body: &Body<'_>,
location_table: &LocationTable,
move_data: &MoveData<'_>,
) {
all_facts
.path_is_var
.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
for (child, move_path) in move_data.move_paths.iter_enumerated() {
if let Some(parent) = move_path.parent {
all_facts.child_path.push((child, parent));
facts.child_path.push((child, parent));
}
}
@ -83,14 +100,14 @@ fn emit_move_facts(
// The initialization happened in (or rather, when arriving at)
// the successors, but not in the unwind block.
let first_statement = Location { block: successor, statement_index: 0 };
all_facts
facts
.path_assigned_at_base
.push((init.path, location_table.start_index(first_statement)));
}
} else {
// In all other cases, the initialization just happens at the
// midpoint, like any other effect.
all_facts
facts
.path_assigned_at_base
.push((init.path, location_table.mid_index(location)));
}
@ -98,7 +115,7 @@ fn emit_move_facts(
// Arguments are initialized on function entry
InitLocation::Argument(local) => {
assert!(body.local_kind(local) == LocalKind::Arg);
all_facts.path_assigned_at_base.push((init.path, fn_entry_start));
facts.path_assigned_at_base.push((init.path, fn_entry_start));
}
}
}
@ -107,20 +124,20 @@ fn emit_move_facts(
if body.local_kind(local) != LocalKind::Arg {
// Non-arguments start out deinitialised; we simulate this with an
// initial move:
all_facts.path_moved_at_base.push((path, fn_entry_start));
facts.path_moved_at_base.push((path, fn_entry_start));
}
}
// moved_out_at
// deinitialisation is assumed to always happen!
all_facts
facts
.path_moved_at_base
.extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source))));
}
/// Emit universal regions facts, and their relations.
fn emit_universal_region_facts(
all_facts: &mut AllFacts,
facts: &mut AllFacts,
borrow_set: &BorrowSet<'_>,
universal_region_relations: &UniversalRegionRelations<'_>,
) {
@ -131,7 +148,7 @@ fn emit_universal_region_facts(
// added to the existing number of loans, as if they succeeded them in the set.
//
let universal_regions = &universal_region_relations.universal_regions;
all_facts
facts
.universal_region
.extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from));
let borrow_count = borrow_set.len();
@ -144,7 +161,7 @@ fn emit_universal_region_facts(
for universal_region in universal_regions.universal_regions_iter() {
let universal_region_idx = universal_region.index();
let placeholder_loan_idx = borrow_count + universal_region_idx;
all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
}
// 2: the universal region relations `outlives` constraints are emitted as
@ -156,29 +173,51 @@ fn emit_universal_region_facts(
fr1={:?}, fr2={:?}",
fr1, fr2
);
all_facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
}
}
}
/// Emit facts about loan invalidations.
fn emit_loan_invalidations_facts<'tcx>(
all_facts: &mut AllFacts,
/// For every potentially drop()-touched region `region` in `local`'s type
/// (`kind`), emit a `drop_of_var_derefs_origin(local, origin)` fact.
pub(crate) fn emit_drop_facts<'tcx>(
tcx: TyCtxt<'tcx>,
location_table: &LocationTable,
body: &Body<'tcx>,
borrow_set: &BorrowSet<'tcx>,
local: Local,
kind: &GenericArg<'tcx>,
universal_regions: &UniversalRegions<'tcx>,
all_facts: &mut Option<AllFacts>,
) {
loan_invalidations::emit_loan_invalidations(tcx, all_facts, location_table, body, borrow_set);
debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind);
let Some(facts) = all_facts.as_mut() else { return };
let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
tcx.for_each_free_region(kind, |drop_live_region| {
let region_vid = universal_regions.to_region_vid(drop_live_region);
facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
});
}
/// Emit facts about CFG points and edges, as well as locations where loans are killed.
fn emit_cfg_and_loan_kills_facts<'tcx>(
all_facts: &mut AllFacts,
tcx: TyCtxt<'tcx>,
/// Emit facts about the outlives constraints: the `subset` base relation, i.e. not a transitive
/// closure.
fn emit_outlives_facts<'tcx>(
facts: &mut AllFacts,
location_table: &LocationTable,
body: &Body<'tcx>,
borrow_set: &BorrowSet<'tcx>,
constraints: &MirTypeckRegionConstraints<'tcx>,
) {
loan_kills::emit_loan_kills(tcx, all_facts, location_table, body, borrow_set);
facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map(
|constraint: &OutlivesConstraint<'_>| {
if let Some(from_location) = constraint.locations.from_location() {
Either::Left(iter::once((
constraint.sup.into(),
constraint.sub.into(),
location_table.mid_index(from_location),
)))
} else {
Either::Right(
location_table.all_points().map(move |location| {
(constraint.sup.into(), constraint.sub.into(), location)
}),
)
}
},
));
}

View file

@ -17,7 +17,6 @@ use crate::region_infer::values::LivenessValues;
use crate::universal_regions::UniversalRegions;
mod local_use_map;
mod polonius;
mod trace;
/// Combines liveness analysis with initialization analysis to
@ -45,8 +44,6 @@ pub(super) fn generate<'a, 'tcx>(
let (relevant_live_locals, boring_locals) =
compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
polonius::emit_access_facts(typeck, body, move_data);
trace::trace(
typeck,
body,

View file

@ -1,123 +0,0 @@
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{Body, Local, Location, Place};
use rustc_middle::ty::GenericArg;
use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
use tracing::debug;
use super::TypeChecker;
use crate::def_use::{self, DefUse};
use crate::location::{LocationIndex, LocationTable};
type VarPointRelation = Vec<(Local, LocationIndex)>;
type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>;
/// Emit polonius facts for variable defs, uses, drops, and path accesses.
pub(super) fn emit_access_facts<'a, 'tcx>(
typeck: &mut TypeChecker<'a, 'tcx>,
body: &Body<'tcx>,
move_data: &MoveData<'tcx>,
) {
if let Some(facts) = typeck.all_facts.as_mut() {
debug!("emit_access_facts()");
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
let location_table = typeck.location_table;
let mut extractor = AccessFactsExtractor {
var_defined_at: &mut facts.var_defined_at,
var_used_at: &mut facts.var_used_at,
var_dropped_at: &mut facts.var_dropped_at,
path_accessed_at_base: &mut facts.path_accessed_at_base,
location_table,
move_data,
};
extractor.visit_body(body);
for (local, local_decl) in body.local_decls.iter_enumerated() {
debug!(
"add use_of_var_derefs_origin facts - local={:?}, type={:?}",
local, local_decl.ty
);
let universal_regions = &typeck.universal_regions;
typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
let region_vid = universal_regions.to_region_vid(region);
facts.use_of_var_derefs_origin.push((local, region_vid.into()));
});
}
}
}
/// For every potentially drop()-touched region `region` in `local`'s type
/// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact.
pub(super) fn emit_drop_facts<'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
local: Local,
kind: &GenericArg<'tcx>,
) {
debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind);
if let Some(facts) = typeck.all_facts.as_mut() {
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
let universal_regions = &typeck.universal_regions;
typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
let region_vid = universal_regions.to_region_vid(drop_live_region);
facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
});
}
}
/// MIR visitor extracting point-wise facts about accesses.
struct AccessFactsExtractor<'a, 'tcx> {
var_defined_at: &'a mut VarPointRelation,
var_used_at: &'a mut VarPointRelation,
location_table: &'a LocationTable,
var_dropped_at: &'a mut VarPointRelation,
move_data: &'a MoveData<'tcx>,
path_accessed_at_base: &'a mut PathPointRelation,
}
impl<'tcx> AccessFactsExtractor<'_, 'tcx> {
fn location_to_index(&self, location: Location) -> LocationIndex {
self.location_table.mid_index(location)
}
}
impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> {
fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
match def_use::categorize(context) {
Some(DefUse::Def) => {
debug!("AccessFactsExtractor - emit def");
self.var_defined_at.push((local, self.location_to_index(location)));
}
Some(DefUse::Use) => {
debug!("AccessFactsExtractor - emit use");
self.var_used_at.push((local, self.location_to_index(location)));
}
Some(DefUse::Drop) => {
debug!("AccessFactsExtractor - emit drop");
self.var_dropped_at.push((local, self.location_to_index(location)));
}
_ => (),
}
}
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
self.super_place(place, context, location);
match context {
PlaceContext::NonMutatingUse(_)
| PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
let path = match self.move_data.rev_lookup.find(place.as_ref()) {
LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path,
_ => {
// There's no path access to emit.
return;
}
};
debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})");
self.path_accessed_at_base.push((path, self.location_to_index(location)));
}
_ => {}
}
}
}

View file

@ -15,9 +15,9 @@ use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, Type
use tracing::debug;
use crate::location::RichLocation;
use crate::polonius;
use crate::region_infer::values::{self, LiveLoans};
use crate::type_check::liveness::local_use_map::LocalUseMap;
use crate::type_check::liveness::polonius;
use crate::type_check::{NormalizeLocation, TypeChecker};
/// This is the heart of the liveness computation. For each variable X
@ -590,7 +590,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
// the destructor and must be live at this point.
for &kind in &drop_data.dropck_result.kinds {
Self::make_all_regions_live(self.elements, self.typeck, kind, live_at);
polonius::emit_drop_facts(self.typeck, dropped_local, &kind);
polonius::legacy::emit_drop_facts(
self.typeck.tcx(),
dropped_local,
&kind,
self.typeck.universal_regions,
self.typeck.all_facts,
);
}
}

View file

@ -3,7 +3,6 @@
use std::rc::Rc;
use std::{fmt, iter, mem};
use either::Either;
use rustc_abi::{FIRST_VARIANT, FieldIdx};
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@ -107,7 +106,6 @@ mod relate_tys;
/// # Parameters
///
/// - `infcx` -- inference context to use
/// - `param_env` -- parameter environment to use for trait solving
/// - `body` -- MIR body to type-check
/// - `promoted` -- map of promoted constants within `body`
/// - `universal_regions` -- the universal regions from `body`s function signature
@ -155,7 +153,7 @@ pub(crate) fn type_check<'a, 'tcx>(
debug!(?normalized_inputs_and_output);
let mut checker = TypeChecker {
let mut typeck = TypeChecker {
infcx,
last_span: body.span,
body,
@ -171,24 +169,22 @@ pub(crate) fn type_check<'a, 'tcx>(
constraints: &mut constraints,
};
checker.check_user_type_annotations();
typeck.check_user_type_annotations();
let mut verifier = TypeVerifier { cx: &mut checker, promoted, last_span: body.span };
let mut verifier = TypeVerifier { typeck: &mut typeck, promoted, last_span: body.span };
verifier.visit_body(body);
checker.typeck_mir(body);
checker.equate_inputs_and_outputs(body, &normalized_inputs_and_output);
checker.check_signature_annotation(body);
typeck.typeck_mir(body);
typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output);
typeck.check_signature_annotation(body);
liveness::generate(&mut checker, body, &elements, flow_inits, move_data);
liveness::generate(&mut typeck, body, &elements, flow_inits, move_data);
translate_outlives_facts(&mut checker);
let opaque_type_values = infcx.take_opaque_types();
let opaque_type_values = opaque_type_values
let opaque_type_values = infcx
.take_opaque_types()
.into_iter()
.map(|(opaque_type_key, decl)| {
let _: Result<_, ErrorGuaranteed> = checker.fully_perform_op(
let _: Result<_, ErrorGuaranteed> = typeck.fully_perform_op(
Locations::All(body.span),
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
@ -218,11 +214,11 @@ pub(crate) fn type_check<'a, 'tcx>(
match region.kind() {
ty::ReVar(_) => region,
ty::RePlaceholder(placeholder) => {
checker.constraints.placeholder_region(infcx, placeholder)
typeck.constraints.placeholder_region(infcx, placeholder)
}
_ => ty::Region::new_var(
infcx.tcx,
checker.universal_regions.to_region_vid(region),
typeck.universal_regions.to_region_vid(region),
),
}
});
@ -234,30 +230,6 @@ pub(crate) fn type_check<'a, 'tcx>(
MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
}
fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
if let Some(facts) = typeck.all_facts {
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
let location_table = typeck.location_table;
facts.subset_base.extend(
typeck.constraints.outlives_constraints.outlives().iter().flat_map(
|constraint: &OutlivesConstraint<'_>| {
if let Some(from_location) = constraint.locations.from_location() {
Either::Left(iter::once((
constraint.sup.into(),
constraint.sub.into(),
location_table.mid_index(from_location),
)))
} else {
Either::Right(location_table.all_points().map(move |location| {
(constraint.sup.into(), constraint.sub.into(), location)
}))
}
},
),
);
}
}
#[track_caller]
fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) {
// We sometimes see MIR failures (notably predicate failures) due to
@ -276,7 +248,7 @@ enum FieldAccessError {
/// type, calling `span_mirbug` and returning an error type if there
/// is a problem.
struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
typeck: &'a mut TypeChecker<'b, 'tcx>,
promoted: &'b IndexSlice<Promoted, Body<'tcx>>,
last_span: Span,
}
@ -298,9 +270,9 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
self.super_const_operand(constant, location);
let ty = self.sanitize_type(constant, constant.const_.ty());
self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
let live_region_vid = self.cx.universal_regions.to_region_vid(live_region);
self.cx.constraints.liveness_constraints.add_location(live_region_vid, location);
self.typeck.infcx.tcx.for_each_free_region(&ty, |live_region| {
let live_region_vid = self.typeck.universal_regions.to_region_vid(live_region);
self.typeck.constraints.liveness_constraints.add_location(live_region_vid, location);
});
// HACK(compiler-errors): Constants that are gathered into Body.required_consts
@ -312,14 +284,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
};
if let Some(annotation_index) = constant.user_ty {
if let Err(terr) = self.cx.relate_type_and_user_type(
if let Err(terr) = self.typeck.relate_type_and_user_type(
constant.const_.ty(),
ty::Invariant,
&UserTypeProjection { base: annotation_index, projs: vec![] },
locations,
ConstraintCategory::Boring,
) {
let annotation = &self.cx.user_type_annotations[annotation_index];
let annotation = &self.typeck.user_type_annotations[annotation_index];
span_mirbug!(
self,
constant,
@ -348,9 +320,12 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
promoted: &Body<'tcx>,
ty,
san_ty| {
if let Err(terr) =
verifier.cx.eq_types(ty, san_ty, locations, ConstraintCategory::Boring)
{
if let Err(terr) = verifier.typeck.eq_types(
ty,
san_ty,
locations,
ConstraintCategory::Boring,
) {
span_mirbug!(
verifier,
promoted,
@ -368,21 +343,21 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
let promoted_ty = promoted_body.return_ty();
check_err(self, promoted_body, ty, promoted_ty);
} else {
self.cx.ascribe_user_type(
self.typeck.ascribe_user_type(
constant.const_.ty(),
ty::UserType::new(ty::UserTypeKind::TypeOf(uv.def, UserArgs {
args: uv.args,
user_self_ty: None,
})),
locations.span(self.cx.body),
locations.span(self.typeck.body),
);
}
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity();
let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
let normalized_ty = self.typeck.normalize(unnormalized_ty, locations);
let literal_ty = constant.const_.ty().builtin_deref(true).unwrap();
if let Err(terr) = self.cx.eq_types(
if let Err(terr) = self.typeck.eq_types(
literal_ty,
normalized_ty,
locations,
@ -394,7 +369,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() {
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args);
self.cx.normalize_and_prove_instantiated_predicates(
self.typeck.normalize_and_prove_instantiated_predicates(
def_id,
instantiated_predicates,
locations,
@ -404,7 +379,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)),
Some(DefKind::Impl { of_trait: true })
));
self.cx.prove_predicates(
self.typeck.prove_predicates(
args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())),
locations,
ConstraintCategory::Boring,
@ -438,7 +413,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
local_decl.ty
};
if let Err(terr) = self.cx.relate_type_and_user_type(
if let Err(terr) = self.typeck.relate_type_and_user_type(
ty,
ty::Invariant,
user_ty,
@ -468,11 +443,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
fn body(&self) -> &Body<'tcx> {
self.cx.body
self.typeck.body
}
fn tcx(&self) -> TyCtxt<'tcx> {
self.cx.infcx.tcx
self.typeck.infcx.tcx
}
fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
@ -522,7 +497,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// whether the bounds fully apply: in effect, the rule is
// that if a value of some type could implement `Copy`, then
// it must.
self.cx.prove_trait_ref(
self.typeck.prove_trait_ref(
trait_ref,
location.to_locations(),
ConstraintCategory::CopyBound,
@ -537,7 +512,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// checker on the promoted MIR, then transfer the constraints back to
// the main MIR, changing the locations to the provided location.
let parent_body = mem::replace(&mut self.cx.body, promoted_body);
let parent_body = mem::replace(&mut self.typeck.body, promoted_body);
// Use new sets of constraints and closure bounds so that we can
// modify their locations.
@ -548,18 +523,18 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// Don't try to add borrow_region facts for the promoted MIR
let mut swap_constraints = |this: &mut Self| {
mem::swap(this.cx.all_facts, all_facts);
mem::swap(&mut this.cx.constraints.outlives_constraints, &mut constraints);
mem::swap(&mut this.cx.constraints.liveness_constraints, &mut liveness_constraints);
mem::swap(this.typeck.all_facts, all_facts);
mem::swap(&mut this.typeck.constraints.outlives_constraints, &mut constraints);
mem::swap(&mut this.typeck.constraints.liveness_constraints, &mut liveness_constraints);
};
swap_constraints(self);
self.visit_body(promoted_body);
self.cx.typeck_mir(promoted_body);
self.typeck.typeck_mir(promoted_body);
self.cx.body = parent_body;
self.typeck.body = parent_body;
// Merge the outlives constraints back in, at the given location.
swap_constraints(self);
@ -575,7 +550,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// temporary from the user's point of view.
constraint.category = ConstraintCategory::Boring;
}
self.cx.constraints.outlives_constraints.push(constraint)
self.typeck.constraints.outlives_constraints.push(constraint)
}
// If the region is live at least one location in the promoted MIR,
// then add a liveness constraint to the main MIR for this region
@ -585,7 +560,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// unordered.
#[allow(rustc::potential_query_instability)]
for region in liveness_constraints.live_regions_unordered() {
self.cx.constraints.liveness_constraints.add_location(region, location);
self.typeck.constraints.liveness_constraints.add_location(region, location);
}
}
@ -669,13 +644,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
},
ProjectionElem::Field(field, fty) => {
let fty = self.sanitize_type(place, fty);
let fty = self.cx.normalize(fty, location);
let fty = self.typeck.normalize(fty, location);
match self.field_ty(place, base, field, location) {
Ok(ty) => {
let ty = self.cx.normalize(ty, location);
let ty = self.typeck.normalize(ty, location);
debug!(?fty, ?ty);
if let Err(terr) = self.cx.relate_types(
if let Err(terr) = self.typeck.relate_types(
ty,
self.get_ambient_variance(context),
fty,
@ -707,8 +682,8 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
ProjectionElem::OpaqueCast(ty) => {
let ty = self.sanitize_type(place, ty);
let ty = self.cx.normalize(ty, location);
self.cx
let ty = self.typeck.normalize(ty, location);
self.typeck
.relate_types(
ty,
self.get_ambient_variance(context),
@ -817,7 +792,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
};
if let Some(field) = variant.fields.get(field) {
Ok(self.cx.normalize(field.ty(tcx, args), location))
Ok(self.typeck.normalize(field.ty(tcx, args), location))
} else {
Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
}