Auto merge of #139781 - jhpratt:rollup-qadsjvb, r=jhpratt
Rollup of 9 pull requests Successful merges: - #138336 (Improve `-Z crate-attr` diagnostics) - #139636 (Encode dep node edge count as u32 instead of usize) - #139666 (cleanup `mir_borrowck`) - #139695 (compiletest: consistently use `camino::{Utf8Path,Utf8PathBuf}` throughout) - #139699 (Proactively update coroutine drop shim's phase to account for later passes applied during shim query) - #139718 (enforce unsafe attributes in pre-2024 editions by default) - #139722 (Move some things to rustc_type_ir) - #139760 (UI tests: migrate remaining compile time `error-pattern`s to line annotations when possible) - #139776 (Switch attrs to `diagnostic::on_unimplemented`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5961e5ba3d
152 changed files with 1818 additions and 1713 deletions
|
@ -627,7 +627,7 @@ pub fn mk_doc_comment(
|
|||
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
|
||||
}
|
||||
|
||||
pub fn mk_attr(
|
||||
fn mk_attr(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
|
|
|
@ -21,6 +21,7 @@ use std::cell::RefCell;
|
|||
use std::marker::PhantomData;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
||||
use borrow_set::LocalsStateAtExit;
|
||||
use root_cx::BorrowCheckRootCtxt;
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
|
@ -303,33 +304,13 @@ fn do_mir_borrowck<'tcx>(
|
|||
root_cx.set_tainted_by_errors(e);
|
||||
}
|
||||
|
||||
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
|
||||
for var_debug_info in &input_body.var_debug_info {
|
||||
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
|
||||
if let Some(local) = place.as_local() {
|
||||
if let Some(prev_name) = local_names[local]
|
||||
&& var_debug_info.name != prev_name
|
||||
{
|
||||
span_bug!(
|
||||
var_debug_info.source_info.span,
|
||||
"local {:?} has many names (`{}` vs `{}`)",
|
||||
local,
|
||||
prev_name,
|
||||
var_debug_info.name
|
||||
);
|
||||
}
|
||||
local_names[local] = Some(var_debug_info.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace all regions with fresh inference variables. This
|
||||
// requires first making our own copy of the MIR. This copy will
|
||||
// be modified (in place) to contain non-lexical lifetimes. It
|
||||
// will have a lifetime tied to the inference context.
|
||||
let mut body_owned = input_body.clone();
|
||||
let mut promoted = input_promoted.to_owned();
|
||||
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
|
||||
let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
|
||||
let body = &body_owned; // no further changes
|
||||
|
||||
let location_table = PoloniusLocationTable::new(body);
|
||||
|
@ -354,7 +335,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
} = nll::compute_regions(
|
||||
root_cx,
|
||||
&infcx,
|
||||
free_regions,
|
||||
universal_regions,
|
||||
body,
|
||||
&promoted,
|
||||
&location_table,
|
||||
|
@ -367,24 +348,23 @@ fn do_mir_borrowck<'tcx>(
|
|||
// Dump MIR results into a file, if that is enabled. This lets us
|
||||
// write unit-tests, as well as helping with debugging.
|
||||
nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
|
||||
polonius::dump_polonius_mir(
|
||||
&infcx,
|
||||
body,
|
||||
®ioncx,
|
||||
&opt_closure_req,
|
||||
&borrow_set,
|
||||
polonius_diagnostics.as_ref(),
|
||||
);
|
||||
|
||||
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
||||
// information.
|
||||
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
|
||||
|
||||
let movable_coroutine = body.coroutine.is_some()
|
||||
&& tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
|
||||
|
||||
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
|
||||
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, diags_buffer);
|
||||
|
||||
let movable_coroutine =
|
||||
// The first argument is the coroutine type passed by value
|
||||
if let Some(local) = body.local_decls.raw.get(1)
|
||||
// Get the interior types and args which typeck computed
|
||||
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
|
||||
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// While promoteds should mostly be correct by construction, we need to check them for
|
||||
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
|
||||
for promoted_body in &promoted {
|
||||
|
@ -402,7 +382,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
location_table: &location_table,
|
||||
movable_coroutine,
|
||||
fn_self_span_reported: Default::default(),
|
||||
locals_are_invalidated_at_exit,
|
||||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
uninitialized_error_reported: Default::default(),
|
||||
|
@ -434,6 +413,26 @@ fn do_mir_borrowck<'tcx>(
|
|||
promoted_mbcx.report_move_errors();
|
||||
}
|
||||
|
||||
let mut local_names = IndexVec::from_elem(None, &body.local_decls);
|
||||
for var_debug_info in &body.var_debug_info {
|
||||
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
|
||||
if let Some(local) = place.as_local() {
|
||||
if let Some(prev_name) = local_names[local]
|
||||
&& var_debug_info.name != prev_name
|
||||
{
|
||||
span_bug!(
|
||||
var_debug_info.source_info.span,
|
||||
"local {:?} has many names (`{}` vs `{}`)",
|
||||
local,
|
||||
prev_name,
|
||||
var_debug_info.name
|
||||
);
|
||||
}
|
||||
local_names[local] = Some(var_debug_info.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut mbcx = MirBorrowckCtxt {
|
||||
root_cx,
|
||||
infcx: &infcx,
|
||||
|
@ -441,7 +440,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
move_data: &move_data,
|
||||
location_table: &location_table,
|
||||
movable_coroutine,
|
||||
locals_are_invalidated_at_exit,
|
||||
fn_self_span_reported: Default::default(),
|
||||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
|
@ -454,9 +452,9 @@ fn do_mir_borrowck<'tcx>(
|
|||
local_names,
|
||||
region_names: RefCell::default(),
|
||||
next_region_name: RefCell::new(1),
|
||||
polonius_output,
|
||||
move_errors: Vec::new(),
|
||||
diags_buffer,
|
||||
polonius_output: polonius_output.as_deref(),
|
||||
polonius_diagnostics: polonius_diagnostics.as_ref(),
|
||||
};
|
||||
|
||||
|
@ -473,16 +471,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
|
||||
mbcx.report_move_errors();
|
||||
|
||||
// If requested, dump polonius MIR.
|
||||
polonius::dump_polonius_mir(
|
||||
&infcx,
|
||||
body,
|
||||
®ioncx,
|
||||
&borrow_set,
|
||||
polonius_diagnostics.as_ref(),
|
||||
&opt_closure_req,
|
||||
);
|
||||
|
||||
// For each non-user used mutable variable, check if it's been assigned from
|
||||
// a user-declared local. If so, then put that local into the used_mut set.
|
||||
// Note that this set is expected to be small - only upvars from closures
|
||||
|
@ -513,7 +501,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
};
|
||||
|
||||
let body_with_facts = if consumer_options.is_some() {
|
||||
let output_facts = mbcx.polonius_output;
|
||||
Some(Box::new(BodyWithBorrowckFacts {
|
||||
body: body_owned,
|
||||
promoted,
|
||||
|
@ -521,7 +508,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
region_inference_context: regioncx,
|
||||
location_table: polonius_input.as_ref().map(|_| location_table),
|
||||
input_facts: polonius_input,
|
||||
output_facts,
|
||||
output_facts: polonius_output,
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
|
@ -654,13 +641,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
location_table: &'a PoloniusLocationTable,
|
||||
|
||||
movable_coroutine: bool,
|
||||
/// This keeps track of whether local variables are free-ed when the function
|
||||
/// exits even without a `StorageDead`, which appears to be the case for
|
||||
/// constants.
|
||||
///
|
||||
/// I'm not sure this is the right approach - @eddyb could you try and
|
||||
/// figure this out?
|
||||
locals_are_invalidated_at_exit: bool,
|
||||
/// This field keeps track of when borrow errors are reported in the access_place function
|
||||
/// so that there is no duplicate reporting. This field cannot also be used for the conflicting
|
||||
/// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
|
||||
|
@ -708,12 +688,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
/// The counter for generating new region names.
|
||||
next_region_name: RefCell<usize>,
|
||||
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<Box<PoloniusOutput>>,
|
||||
|
||||
diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
|
||||
move_errors: Vec<MoveError<'tcx>>,
|
||||
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<&'a PoloniusOutput>,
|
||||
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
|
||||
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
|
||||
}
|
||||
|
@ -937,13 +916,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
|
|||
| TerminatorKind::Return
|
||||
| TerminatorKind::TailCall { .. }
|
||||
| TerminatorKind::CoroutineDrop => {
|
||||
// Returning from the function implicitly kills storage for all locals and statics.
|
||||
// Often, the storage will already have been killed by an explicit
|
||||
// StorageDead, but we don't always emit those (notably on unwind paths),
|
||||
// so this "extra check" serves as a kind of backup.
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_invalidation_at_exit(loc, borrow, span);
|
||||
match self.borrow_set.locals_state_at_exit() {
|
||||
LocalsStateAtExit::AllAreInvalidated => {
|
||||
// Returning from the function implicitly kills storage for all locals and statics.
|
||||
// Often, the storage will already have been killed by an explicit
|
||||
// StorageDead, but we don't always emit those (notably on unwind paths),
|
||||
// so this "extra check" serves as a kind of backup.
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_invalidation_at_exit(loc, borrow, span);
|
||||
}
|
||||
}
|
||||
// If we do not implicitly invalidate all locals on exit,
|
||||
// we check for conflicts when dropping or moving this local.
|
||||
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1715,22 +1701,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
// we'll have a memory leak) and assume that all statics have a destructor.
|
||||
//
|
||||
// FIXME: allow thread-locals to borrow other thread locals?
|
||||
|
||||
let (might_be_alive, will_be_dropped) =
|
||||
if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
|
||||
// Thread-locals might be dropped after the function exits
|
||||
// We have to dereference the outer reference because
|
||||
// borrows don't conflict behind shared references.
|
||||
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
|
||||
(true, true)
|
||||
} else {
|
||||
(false, self.locals_are_invalidated_at_exit)
|
||||
};
|
||||
|
||||
if !will_be_dropped {
|
||||
debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
|
||||
return;
|
||||
}
|
||||
let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
|
||||
// Thread-locals might be dropped after the function exits
|
||||
// We have to dereference the outer reference because
|
||||
// borrows don't conflict behind shared references.
|
||||
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let sd = if might_be_alive { Deep } else { Shallow(None) };
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::consumers::ConsumerOptions;
|
||||
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
|
||||
use crate::diagnostics::RegionErrors;
|
||||
use crate::polonius::PoloniusDiagnosticsContext;
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
|
@ -117,11 +117,6 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
Rc::clone(&location_map),
|
||||
);
|
||||
|
||||
// Create the region inference context, taking ownership of the
|
||||
// region inference data that was contained in `infcx`, and the
|
||||
// base constraints generated by the type-check.
|
||||
let var_infos = infcx.get_region_var_infos();
|
||||
|
||||
// If requested, emit legacy polonius facts.
|
||||
polonius::legacy::emit_facts(
|
||||
&mut polonius_facts,
|
||||
|
@ -134,13 +129,8 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
&constraints,
|
||||
);
|
||||
|
||||
let mut regioncx = RegionInferenceContext::new(
|
||||
infcx,
|
||||
var_infos,
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
location_map,
|
||||
);
|
||||
let mut regioncx =
|
||||
RegionInferenceContext::new(infcx, constraints, universal_region_relations, location_map);
|
||||
|
||||
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
|
||||
// and use them to compute loan liveness.
|
||||
|
@ -297,7 +287,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
|||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
||||
|
@ -335,13 +324,11 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
|||
} else {
|
||||
let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements");
|
||||
regioncx.annotate(tcx, &mut err);
|
||||
|
||||
err
|
||||
};
|
||||
|
||||
// FIXME(@lcnr): We currently don't dump the inferred hidden types here.
|
||||
|
||||
diagnostics_buffer.buffer_non_error(err);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn for_each_region_constraint<'tcx>(
|
||||
|
|
|
@ -24,9 +24,9 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_errors::Diag;
|
|||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::outlives::test_type_match;
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq};
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{
|
||||
|
@ -145,7 +145,7 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
/// variables are identified by their index (`RegionVid`). The
|
||||
/// definition contains information about where the region came
|
||||
/// from as well as its final inferred value.
|
||||
pub(crate) definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
|
||||
pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
|
||||
|
||||
/// The liveness constraints added to each region. For most
|
||||
/// regions, these start out empty and steadily grow, though for
|
||||
|
@ -385,6 +385,26 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
|
|||
debug!("SCC edges {:#?}", scc_node_to_edges);
|
||||
}
|
||||
|
||||
fn create_definitions<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) -> Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>> {
|
||||
// Create a RegionDefinition for each inference variable.
|
||||
let mut definitions: IndexVec<_, _> = infcx
|
||||
.get_region_var_infos()
|
||||
.iter()
|
||||
.map(|info| RegionDefinition::new(info.universe, info.origin))
|
||||
.collect();
|
||||
|
||||
// Add the external name for all universal regions.
|
||||
for (external_name, variable) in universal_regions.named_universal_regions_iter() {
|
||||
debug!("region {variable:?} has external name {external_name:?}");
|
||||
definitions[variable].external_name = Some(external_name);
|
||||
}
|
||||
|
||||
Frozen::freeze(definitions)
|
||||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Creates a new region inference context with a total of
|
||||
/// `num_region_variables` valid inference variables; the first N
|
||||
|
@ -395,7 +415,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// of constraints produced by the MIR type check.
|
||||
pub(crate) fn new(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
var_infos: VarInfos,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
|
@ -426,11 +445,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
// Create a RegionDefinition for each inference variable.
|
||||
let definitions: IndexVec<_, _> = var_infos
|
||||
.iter()
|
||||
.map(|info| RegionDefinition::new(info.universe, info.origin))
|
||||
.collect();
|
||||
let definitions = create_definitions(infcx, &universal_regions);
|
||||
|
||||
let constraint_sccs =
|
||||
outlives_constraints.add_outlives_static(&universal_regions, &definitions);
|
||||
|
@ -526,18 +541,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// means that the `R1: !1` constraint here will cause
|
||||
/// `R1` to become `'static`.
|
||||
fn init_free_and_bound_regions(&mut self) {
|
||||
// Update the names (if any)
|
||||
// This iterator has unstable order but we collect it all into an IndexVec
|
||||
for (external_name, variable) in
|
||||
self.universal_region_relations.universal_regions.named_universal_regions_iter()
|
||||
{
|
||||
debug!(
|
||||
"init_free_and_bound_regions: region {:?} has external name {:?}",
|
||||
variable, external_name
|
||||
);
|
||||
self.definitions[variable].external_name = Some(external_name);
|
||||
}
|
||||
|
||||
for variable in self.definitions.indices() {
|
||||
let scc = self.constraint_sccs.scc(variable);
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategor
|
|||
|
||||
pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
/// Each RBP `GK: 'a` is assumed to be true. These encode
|
||||
/// relationships like `T: 'a` that are added via implicit bounds
|
||||
|
@ -34,7 +33,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
|||
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
|
||||
/// our special inference variable there, we would mess that up.
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
|
@ -49,7 +47,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
infcx: &'a InferCtxt<'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
|
@ -59,10 +56,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
) -> Self {
|
||||
Self {
|
||||
infcx,
|
||||
tcx: infcx.tcx,
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
|
@ -96,7 +91,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
// into a vector. These are the regions that we will be
|
||||
// relating to one another.
|
||||
let closure_mapping = &UniversalRegions::closure_mapping(
|
||||
self.tcx,
|
||||
self.infcx.tcx,
|
||||
closure_args,
|
||||
closure_requirements.num_external_vids,
|
||||
closure_def_id,
|
||||
|
@ -111,7 +106,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
let subject = match outlives_requirement.subject {
|
||||
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
|
||||
ClosureOutlivesSubject::Ty(subject_ty) => {
|
||||
subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
|
||||
subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into()
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -127,14 +122,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
|
||||
constraint_category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
let tcx = self.infcx.tcx;
|
||||
debug!("generate: constraints at: {:#?}", self.locations);
|
||||
|
||||
// Extract out various useful fields we'll need below.
|
||||
let ConstraintConversion {
|
||||
tcx,
|
||||
infcx,
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
known_type_outlives_obligations,
|
||||
..
|
||||
} = *self;
|
||||
|
@ -145,7 +140,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
break;
|
||||
}
|
||||
|
||||
if !self.tcx.recursion_limit().value_within_limit(iteration) {
|
||||
if !tcx.recursion_limit().value_within_limit(iteration) {
|
||||
bug!(
|
||||
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
|
||||
);
|
||||
|
@ -170,10 +165,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
let implicit_region_bound =
|
||||
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
|
||||
// we don't actually use this for anything, but
|
||||
// the `TypeOutlives` code needs an origin.
|
||||
let origin = infer::RelateParamBound(self.span, t1, None);
|
||||
|
||||
TypeOutlives::new(
|
||||
&mut *self,
|
||||
tcx,
|
||||
|
@ -205,7 +201,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
/// are dealt with during trait solving.
|
||||
fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
|
||||
if value.has_placeholders() {
|
||||
fold_regions(self.tcx, value, |r, _| match r.kind() {
|
||||
fold_regions(self.infcx.tcx, value, |r, _| match r.kind() {
|
||||
ty::RePlaceholder(placeholder) => {
|
||||
self.constraints.placeholder_region(self.infcx, placeholder)
|
||||
}
|
||||
|
|
|
@ -49,14 +49,12 @@ pub(crate) struct CreateResult<'tcx> {
|
|||
pub(crate) fn create<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
) -> CreateResult<'tcx> {
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
param_env,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
universal_regions,
|
||||
region_bound_pairs: Default::default(),
|
||||
|
@ -181,7 +179,6 @@ struct UniversalRegionRelationsBuilder<'a, 'tcx> {
|
|||
infcx: &'a InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
|
||||
// outputs:
|
||||
|
@ -320,7 +317,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
self.infcx,
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
param_env,
|
||||
&known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
|
|
|
@ -113,7 +113,6 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
move_data: &MoveData<'tcx>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
||||
let mut constraints = MirTypeckRegionConstraints {
|
||||
placeholder_indices: PlaceholderIndices::default(),
|
||||
placeholder_index_to_region: IndexVec::default(),
|
||||
|
@ -129,13 +128,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
known_type_outlives_obligations,
|
||||
} = free_region_relations::create(
|
||||
infcx,
|
||||
infcx.param_env,
|
||||
implicit_region_bound,
|
||||
universal_regions,
|
||||
&mut constraints,
|
||||
);
|
||||
} = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints);
|
||||
|
||||
let pre_obligations = infcx.take_registered_region_obligations();
|
||||
assert!(
|
||||
|
@ -160,7 +153,6 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
user_type_annotations: &body.user_type_annotations,
|
||||
region_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
reported_errors: Default::default(),
|
||||
universal_regions: &universal_region_relations.universal_regions,
|
||||
location_table,
|
||||
|
@ -226,7 +218,6 @@ struct TypeChecker<'a, 'tcx> {
|
|||
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
|
||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
|
@ -422,7 +413,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.infcx,
|
||||
self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.infcx.param_env,
|
||||
&self.known_type_outlives_obligations,
|
||||
locations,
|
||||
|
@ -2507,7 +2497,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.infcx,
|
||||
self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.infcx.param_env,
|
||||
&self.known_type_outlives_obligations,
|
||||
locations,
|
||||
|
|
|
@ -438,6 +438,10 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn implicit_region_bound(&self) -> RegionVid {
|
||||
self.fr_fn_body
|
||||
}
|
||||
|
||||
pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.indices.tainted_by_errors.get()
|
||||
}
|
||||
|
|
|
@ -231,8 +231,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
|
|||
|
||||
builtin_macros_format_use_positional = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_invalid_crate_attribute = invalid crate attribute
|
||||
|
||||
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
|
||||
.note = only one `#[default]` attribute is needed
|
||||
.label = `#[default]` used here
|
||||
|
|
|
@ -1,44 +1,37 @@
|
|||
//! Attributes injected into the crate root from command line using `-Z crate-attr`.
|
||||
|
||||
use rustc_ast::attr::mk_attr;
|
||||
use rustc_ast::{self as ast, AttrItem, AttrStyle, token};
|
||||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_ast::{self as ast};
|
||||
use rustc_errors::Diag;
|
||||
use rustc_parse::parser::attr::InnerAttrPolicy;
|
||||
use rustc_parse::{parse_in, source_str_to_stream};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::FileName;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
|
||||
for raw_attr in attrs {
|
||||
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
|
||||
psess,
|
||||
FileName::cli_crate_attr_source_code(raw_attr),
|
||||
raw_attr.clone(),
|
||||
));
|
||||
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { unsafety, path, args, tokens: _ } =
|
||||
match parser.parse_attr_item(ForceCollect::No) {
|
||||
Ok(ai) => ai,
|
||||
Err(err) => {
|
||||
let source = format!("#![{raw_attr}]");
|
||||
let parse = || -> Result<ast::Attribute, Vec<Diag<'_>>> {
|
||||
let tokens = source_str_to_stream(
|
||||
psess,
|
||||
FileName::cli_crate_attr_source_code(raw_attr),
|
||||
source,
|
||||
None,
|
||||
)?;
|
||||
parse_in(psess, tokens, "<crate attribute>", |p| {
|
||||
p.parse_attribute(InnerAttrPolicy::Permitted)
|
||||
})
|
||||
.map_err(|e| vec![e])
|
||||
};
|
||||
let meta = match parse() {
|
||||
Ok(meta) => meta,
|
||||
Err(errs) => {
|
||||
for err in errs {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let end_span = parser.token.span;
|
||||
if parser.token != token::Eof {
|
||||
psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
krate.attrs.push(mk_attr(
|
||||
&psess.attr_id_generator,
|
||||
AttrStyle::Inner,
|
||||
unsafety,
|
||||
path,
|
||||
args,
|
||||
start_span.to(end_span),
|
||||
));
|
||||
krate.attrs.push(meta);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,13 +109,6 @@ pub(crate) struct ProcMacro {
|
|||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_invalid_crate_attribute)]
|
||||
pub(crate) struct InvalidCrateAttr {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_non_abi)]
|
||||
pub(crate) struct NonABI {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use std::alloc::Allocator;
|
||||
|
||||
#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
|
||||
#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
|
||||
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")]
|
||||
// This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()`
|
||||
// is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a
|
||||
// `Send` type in `IntoDynSyncSend` will create a `DynSend` type.
|
||||
pub unsafe auto trait DynSend {}
|
||||
|
||||
#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
|
||||
#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
|
||||
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`")]
|
||||
// This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()`
|
||||
// is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a
|
||||
|
|
|
@ -5,7 +5,7 @@ Erroneous code example:
|
|||
```compile_fail,E0755
|
||||
#![feature(ffi_pure)]
|
||||
|
||||
#[ffi_pure] // error!
|
||||
#[unsafe(ffi_pure)] // error!
|
||||
pub fn foo() {}
|
||||
# fn main() {}
|
||||
```
|
||||
|
@ -17,7 +17,7 @@ side effects or infinite loops:
|
|||
#![feature(ffi_pure)]
|
||||
|
||||
extern "C" {
|
||||
#[ffi_pure] // ok!
|
||||
#[unsafe(ffi_pure)] // ok!
|
||||
pub fn strlen(s: *const i8) -> isize;
|
||||
}
|
||||
# fn main() {}
|
||||
|
|
|
@ -6,7 +6,7 @@ Erroneous code example:
|
|||
```compile_fail,E0756
|
||||
#![feature(ffi_const)]
|
||||
|
||||
#[ffi_const] // error!
|
||||
#[unsafe(ffi_const)] // error!
|
||||
pub fn foo() {}
|
||||
# fn main() {}
|
||||
```
|
||||
|
@ -18,7 +18,7 @@ which have no side effects except for their return value:
|
|||
#![feature(ffi_const)]
|
||||
|
||||
extern "C" {
|
||||
#[ffi_const] // ok!
|
||||
#[unsafe(ffi_const)] // ok!
|
||||
pub fn strlen(s: *const i8) -> i32;
|
||||
}
|
||||
# fn main() {}
|
||||
|
|
|
@ -6,8 +6,9 @@ Erroneous code example:
|
|||
#![feature(ffi_const, ffi_pure)]
|
||||
|
||||
extern "C" {
|
||||
#[ffi_const]
|
||||
#[ffi_pure] // error: `#[ffi_const]` function cannot be `#[ffi_pure]`
|
||||
#[unsafe(ffi_const)]
|
||||
#[unsafe(ffi_pure)]
|
||||
//~^ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]`
|
||||
pub fn square(num: i32) -> i32;
|
||||
}
|
||||
```
|
||||
|
@ -19,7 +20,7 @@ As `ffi_const` provides stronger guarantees than `ffi_pure`, remove the
|
|||
#![feature(ffi_const)]
|
||||
|
||||
extern "C" {
|
||||
#[ffi_const]
|
||||
#[unsafe(ffi_const)]
|
||||
pub fn square(num: i32) -> i32;
|
||||
}
|
||||
```
|
||||
|
|
|
@ -6,6 +6,7 @@ use AttributeDuplicates::*;
|
|||
use AttributeGate::*;
|
||||
use AttributeType::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::{Features, Stability};
|
||||
|
@ -65,9 +66,12 @@ pub enum AttributeSafety {
|
|||
/// Normal attribute that does not need `#[unsafe(...)]`
|
||||
Normal,
|
||||
|
||||
/// Unsafe attribute that requires safety obligations
|
||||
/// to be discharged
|
||||
Unsafe,
|
||||
/// Unsafe attribute that requires safety obligations to be discharged.
|
||||
///
|
||||
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
|
||||
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
|
||||
/// earlier editions, but become unsafe in later ones.
|
||||
Unsafe { unsafe_since: Option<Edition> },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -187,12 +191,23 @@ macro_rules! template {
|
|||
}
|
||||
|
||||
macro_rules! ungated {
|
||||
(unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
|
||||
template: $tpl,
|
||||
gate: Ungated,
|
||||
duplicates: $duplicates,
|
||||
}
|
||||
};
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe,
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
gate: Ungated,
|
||||
duplicates: $duplicates,
|
||||
|
@ -217,7 +232,7 @@ macro_rules! gated {
|
|||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe,
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
|
||||
|
@ -228,7 +243,7 @@ macro_rules! gated {
|
|||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe,
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
|
||||
|
@ -423,9 +438,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
|
||||
ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
|
||||
|
||||
|
|
|
@ -89,7 +89,6 @@ macro_rules! arena_types {
|
|||
[] name_set: rustc_data_structures::unord::UnordSet<rustc_span::Symbol>,
|
||||
[] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem,
|
||||
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>,
|
||||
[] pats: rustc_middle::ty::PatternKind<'tcx>,
|
||||
[] valtree: rustc_middle::ty::ValTreeKind<'tcx>,
|
||||
|
||||
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::borrow::Cow;
|
|||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::walk::TypeWalker;
|
||||
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
|
||||
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
|
@ -243,4 +244,18 @@ impl<'tcx> Const<'tcx> {
|
|||
pub fn is_ct_infer(self) -> bool {
|
||||
matches!(self.kind(), ty::ConstKind::Infer(_))
|
||||
}
|
||||
|
||||
/// Iterator that walks `self` and any types reachable from
|
||||
/// `self`, in depth-first order. Note that just walks the types
|
||||
/// that appear in `self`, it does not descend into the fields of
|
||||
/// structs or variants. For example:
|
||||
///
|
||||
/// ```text
|
||||
/// isize => { isize }
|
||||
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
|
||||
/// [isize] => { [isize], isize }
|
||||
/// ```
|
||||
pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
|
||||
TypeWalker::new(self.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -870,7 +870,7 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
Ty(Interned::new_unchecked(
|
||||
self.type_
|
||||
.intern(kind, |kind| {
|
||||
let flags = super::flags::FlagComputation::for_kind(&kind);
|
||||
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_kind(&kind);
|
||||
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
|
||||
|
||||
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
|
||||
|
@ -896,7 +896,7 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
Const(Interned::new_unchecked(
|
||||
self.const_
|
||||
.intern(kind, |kind: ty::ConstKind<'_>| {
|
||||
let flags = super::flags::FlagComputation::for_const_kind(&kind);
|
||||
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_const_kind(&kind);
|
||||
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
|
||||
|
||||
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
|
||||
|
@ -912,7 +912,7 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
|
||||
fn stable_hash<'a, T: HashStable<StableHashingContext<'a>>>(
|
||||
&self,
|
||||
flags: &ty::flags::FlagComputation,
|
||||
flags: &ty::FlagComputation<TyCtxt<'tcx>>,
|
||||
sess: &'a Session,
|
||||
untracked: &'a Untracked,
|
||||
val: &T,
|
||||
|
@ -940,7 +940,7 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
Predicate(Interned::new_unchecked(
|
||||
self.predicate
|
||||
.intern(kind, |kind| {
|
||||
let flags = super::flags::FlagComputation::for_predicate(kind);
|
||||
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_predicate(kind);
|
||||
|
||||
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
|
||||
|
||||
|
@ -961,7 +961,7 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
} else {
|
||||
self.clauses
|
||||
.intern_ref(clauses, || {
|
||||
let flags = super::flags::FlagComputation::for_clauses(clauses);
|
||||
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_clauses(clauses);
|
||||
|
||||
InternedInSet(ListWithCachedTypeInfo::from_arena(
|
||||
&*self.arena,
|
||||
|
|
|
@ -1,359 +0,0 @@
|
|||
use std::slice;
|
||||
|
||||
use crate::ty::{self, GenericArg, GenericArgKind, InferConst, Ty, TypeFlags};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FlagComputation {
|
||||
pub flags: TypeFlags,
|
||||
|
||||
/// see `Ty::outer_exclusive_binder` for details
|
||||
pub outer_exclusive_binder: ty::DebruijnIndex,
|
||||
}
|
||||
|
||||
impl FlagComputation {
|
||||
fn new() -> FlagComputation {
|
||||
FlagComputation { flags: TypeFlags::empty(), outer_exclusive_binder: ty::INNERMOST }
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
pub fn for_kind(kind: &ty::TyKind<'_>) -> FlagComputation {
|
||||
let mut result = FlagComputation::new();
|
||||
result.add_kind(kind);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn for_predicate(binder: ty::Binder<'_, ty::PredicateKind<'_>>) -> FlagComputation {
|
||||
let mut result = FlagComputation::new();
|
||||
result.add_predicate(binder);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn for_const_kind(kind: &ty::ConstKind<'_>) -> FlagComputation {
|
||||
let mut result = FlagComputation::new();
|
||||
result.add_const_kind(kind);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation {
|
||||
let mut result = FlagComputation::new();
|
||||
for c in clauses {
|
||||
result.add_flags(c.as_predicate().flags());
|
||||
result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn add_flags(&mut self, flags: TypeFlags) {
|
||||
self.flags = self.flags | flags;
|
||||
}
|
||||
|
||||
/// indicates that `self` refers to something at binding level `binder`
|
||||
fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
|
||||
let exclusive_binder = binder.shifted_in(1);
|
||||
self.add_exclusive_binder(exclusive_binder);
|
||||
}
|
||||
|
||||
/// indicates that `self` refers to something *inside* binding
|
||||
/// level `binder` -- not bound by `binder`, but bound by the next
|
||||
/// binder internal to it
|
||||
fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
|
||||
self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
|
||||
}
|
||||
|
||||
/// Adds the flags/depth from a set of types that appear within the current type, but within a
|
||||
/// region binder.
|
||||
fn bound_computation<T, F>(&mut self, value: ty::Binder<'_, T>, f: F)
|
||||
where
|
||||
F: FnOnce(&mut Self, T),
|
||||
{
|
||||
let mut computation = FlagComputation::new();
|
||||
|
||||
if !value.bound_vars().is_empty() {
|
||||
computation.add_flags(TypeFlags::HAS_BINDER_VARS);
|
||||
}
|
||||
|
||||
f(&mut computation, value.skip_binder());
|
||||
|
||||
self.add_flags(computation.flags);
|
||||
|
||||
// The types that contributed to `computation` occurred within
|
||||
// a region binder, so subtract one from the region depth
|
||||
// within when adding the depth to `self`.
|
||||
let outer_exclusive_binder = computation.outer_exclusive_binder;
|
||||
if outer_exclusive_binder > ty::INNERMOST {
|
||||
self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
|
||||
} // otherwise, this binder captures nothing
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
|
||||
match kind {
|
||||
&ty::Bool
|
||||
| &ty::Char
|
||||
| &ty::Int(_)
|
||||
| &ty::Float(_)
|
||||
| &ty::Uint(_)
|
||||
| &ty::Never
|
||||
| &ty::Str
|
||||
| &ty::Foreign(..) => {}
|
||||
|
||||
&ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
|
||||
|
||||
&ty::Param(_) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_PARAM);
|
||||
}
|
||||
|
||||
&ty::Closure(_, args)
|
||||
| &ty::Coroutine(_, args)
|
||||
| &ty::CoroutineClosure(_, args)
|
||||
| &ty::CoroutineWitness(_, args) => {
|
||||
self.add_args(args);
|
||||
}
|
||||
|
||||
&ty::Bound(debruijn, _) => {
|
||||
self.add_bound_var(debruijn);
|
||||
self.add_flags(TypeFlags::HAS_TY_BOUND);
|
||||
}
|
||||
|
||||
&ty::Placeholder(..) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
|
||||
}
|
||||
|
||||
&ty::Infer(infer) => match infer {
|
||||
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_FRESH)
|
||||
}
|
||||
|
||||
ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_INFER)
|
||||
}
|
||||
},
|
||||
|
||||
&ty::Adt(_, args) => {
|
||||
self.add_args(args);
|
||||
}
|
||||
|
||||
&ty::Alias(kind, data) => {
|
||||
self.add_flags(match kind {
|
||||
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
|
||||
ty::Weak => TypeFlags::HAS_TY_WEAK,
|
||||
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
|
||||
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
|
||||
});
|
||||
|
||||
self.add_alias_ty(data);
|
||||
}
|
||||
|
||||
&ty::Dynamic(obj, r, _) => {
|
||||
for predicate in obj.iter() {
|
||||
self.bound_computation(predicate, |computation, predicate| match predicate {
|
||||
ty::ExistentialPredicate::Trait(tr) => computation.add_args(tr.args),
|
||||
ty::ExistentialPredicate::Projection(p) => {
|
||||
computation.add_existential_projection(&p);
|
||||
}
|
||||
ty::ExistentialPredicate::AutoTrait(_) => {}
|
||||
});
|
||||
}
|
||||
|
||||
self.add_region(r);
|
||||
}
|
||||
|
||||
&ty::Array(tt, len) => {
|
||||
self.add_ty(tt);
|
||||
self.add_const(len);
|
||||
}
|
||||
|
||||
&ty::Pat(ty, pat) => {
|
||||
self.add_ty(ty);
|
||||
match *pat {
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
self.add_const(start);
|
||||
self.add_const(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&ty::Slice(tt) => self.add_ty(tt),
|
||||
|
||||
&ty::RawPtr(ty, _) => {
|
||||
self.add_ty(ty);
|
||||
}
|
||||
|
||||
&ty::Ref(r, ty, _) => {
|
||||
self.add_region(r);
|
||||
self.add_ty(ty);
|
||||
}
|
||||
|
||||
&ty::Tuple(types) => {
|
||||
self.add_tys(types);
|
||||
}
|
||||
|
||||
&ty::FnDef(_, args) => {
|
||||
self.add_args(args);
|
||||
}
|
||||
|
||||
&ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
|
||||
computation.add_tys(sig_tys.inputs_and_output);
|
||||
}),
|
||||
|
||||
&ty::UnsafeBinder(bound_ty) => {
|
||||
self.bound_computation(bound_ty.into(), |computation, ty| {
|
||||
computation.add_ty(ty);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) {
|
||||
self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
|
||||
}
|
||||
|
||||
fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
|
||||
match atom {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
|
||||
self.add_args(trait_pred.trait_ref.args);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
|
||||
trait_ref,
|
||||
constness: _,
|
||||
})) => {
|
||||
self.add_args(trait_ref.args);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
|
||||
a,
|
||||
b,
|
||||
))) => {
|
||||
self.add_region(a);
|
||||
self.add_region(b);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
|
||||
ty,
|
||||
region,
|
||||
))) => {
|
||||
self.add_ty(ty);
|
||||
self.add_region(region);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
|
||||
self.add_const(ct);
|
||||
self.add_ty(ty);
|
||||
}
|
||||
ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
|
||||
self.add_ty(a);
|
||||
self.add_ty(b);
|
||||
}
|
||||
ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
|
||||
self.add_ty(a);
|
||||
self.add_ty(b);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
|
||||
projection_term,
|
||||
term,
|
||||
})) => {
|
||||
self.add_alias_term(projection_term);
|
||||
self.add_term(term);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
|
||||
self.add_args(slice::from_ref(&arg));
|
||||
}
|
||||
ty::PredicateKind::DynCompatible(_def_id) => {}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
|
||||
self.add_const(uv);
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(expected, found) => {
|
||||
self.add_const(expected);
|
||||
self.add_const(found);
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
|
||||
self.add_alias_term(alias);
|
||||
self.add_term(term);
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(t1, t2, _) => {
|
||||
self.add_term(t1);
|
||||
self.add_term(t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_ty(&mut self, ty: Ty<'_>) {
|
||||
self.add_flags(ty.flags());
|
||||
self.add_exclusive_binder(ty.outer_exclusive_binder());
|
||||
}
|
||||
|
||||
fn add_tys(&mut self, tys: &[Ty<'_>]) {
|
||||
for &ty in tys {
|
||||
self.add_ty(ty);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_region(&mut self, r: ty::Region<'_>) {
|
||||
self.add_flags(r.type_flags());
|
||||
if let ty::ReBound(debruijn, _) = r.kind() {
|
||||
self.add_bound_var(debruijn);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_const(&mut self, c: ty::Const<'_>) {
|
||||
self.add_flags(c.flags());
|
||||
self.add_exclusive_binder(c.outer_exclusive_binder());
|
||||
}
|
||||
|
||||
fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) {
|
||||
match *c {
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
self.add_args(uv.args);
|
||||
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
|
||||
}
|
||||
ty::ConstKind::Infer(infer) => match infer {
|
||||
InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
|
||||
InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
|
||||
},
|
||||
ty::ConstKind::Bound(debruijn, _) => {
|
||||
self.add_bound_var(debruijn);
|
||||
self.add_flags(TypeFlags::HAS_CT_BOUND);
|
||||
}
|
||||
ty::ConstKind::Param(_) => {
|
||||
self.add_flags(TypeFlags::HAS_CT_PARAM);
|
||||
}
|
||||
ty::ConstKind::Placeholder(_) => {
|
||||
self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
|
||||
}
|
||||
ty::ConstKind::Value(cv) => self.add_ty(cv.ty),
|
||||
ty::ConstKind::Expr(e) => self.add_args(e.args()),
|
||||
ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
|
||||
self.add_args(projection.args);
|
||||
match projection.term.unpack() {
|
||||
ty::TermKind::Ty(ty) => self.add_ty(ty),
|
||||
ty::TermKind::Const(ct) => self.add_const(ct),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<'_>) {
|
||||
self.add_args(alias_ty.args);
|
||||
}
|
||||
|
||||
fn add_alias_term(&mut self, alias_term: ty::AliasTerm<'_>) {
|
||||
self.add_args(alias_term.args);
|
||||
}
|
||||
|
||||
fn add_args(&mut self, args: &[GenericArg<'_>]) {
|
||||
for kind in args {
|
||||
match kind.unpack() {
|
||||
GenericArgKind::Type(ty) => self.add_ty(ty),
|
||||
GenericArgKind::Lifetime(lt) => self.add_region(lt),
|
||||
GenericArgKind::Const(ct) => self.add_const(ct),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_term(&mut self, term: ty::Term<'_>) {
|
||||
match term.unpack() {
|
||||
ty::TermKind::Ty(ty) => self.add_ty(ty),
|
||||
ty::TermKind::Const(ct) => self.add_const(ct),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_type_ir::WithCachedTypeInfo;
|
||||
use rustc_type_ir::walk::TypeWalker;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||
|
@ -297,6 +298,20 @@ impl<'tcx> GenericArg<'tcx> {
|
|||
GenericArgKind::Const(ct) => ct.is_ct_infer(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator that walks `self` and any types reachable from
|
||||
/// `self`, in depth-first order. Note that just walks the types
|
||||
/// that appear in `self`, it does not descend into the fields of
|
||||
/// structs or variants. For example:
|
||||
///
|
||||
/// ```text
|
||||
/// isize => { isize }
|
||||
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
|
||||
/// [isize] => { [isize], isize }
|
||||
/// ```
|
||||
pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
|
||||
TypeWalker::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for GenericArg<'a> {
|
||||
|
|
|
@ -7,9 +7,9 @@ use std::{fmt, iter, mem, ptr, slice};
|
|||
use rustc_data_structures::aligned::{Aligned, align_of};
|
||||
use rustc_data_structures::sync::DynSync;
|
||||
use rustc_serialize::{Encodable, Encoder};
|
||||
use rustc_type_ir::FlagComputation;
|
||||
|
||||
use super::flags::FlagComputation;
|
||||
use super::{DebruijnIndex, TypeFlags};
|
||||
use super::{DebruijnIndex, TyCtxt, TypeFlags};
|
||||
use crate::arena::Arena;
|
||||
|
||||
/// `List<T>` is a bit like `&[T]`, but with some critical differences.
|
||||
|
@ -299,8 +299,8 @@ impl TypeInfo {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<FlagComputation> for TypeInfo {
|
||||
fn from(computation: FlagComputation) -> TypeInfo {
|
||||
impl<'tcx> From<FlagComputation<TyCtxt<'tcx>>> for TypeInfo {
|
||||
fn from(computation: FlagComputation<TyCtxt<'tcx>>) -> TypeInfo {
|
||||
TypeInfo {
|
||||
flags: computation.flags,
|
||||
outer_exclusive_binder: computation.outer_exclusive_binder,
|
||||
|
|
|
@ -117,7 +117,6 @@ pub mod cast;
|
|||
pub mod codec;
|
||||
pub mod error;
|
||||
pub mod fast_reject;
|
||||
pub mod flags;
|
||||
pub mod inhabitedness;
|
||||
pub mod layout;
|
||||
pub mod normalize_erasing_regions;
|
||||
|
@ -128,7 +127,6 @@ pub mod significant_drop_order;
|
|||
pub mod trait_def;
|
||||
pub mod util;
|
||||
pub mod vtable;
|
||||
pub mod walk;
|
||||
|
||||
mod adt;
|
||||
mod assoc;
|
||||
|
|
|
@ -1,14 +1,40 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::ir_print::IrPrint;
|
||||
use rustc_type_ir::{
|
||||
FlagComputation, Flags, {self as ir},
|
||||
};
|
||||
|
||||
use super::TyCtxt;
|
||||
use crate::ty;
|
||||
|
||||
pub type PatternKind<'tcx> = ir::PatternKind<TyCtxt<'tcx>>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>);
|
||||
|
||||
impl<'tcx> Flags for Pattern<'tcx> {
|
||||
fn flags(&self) -> rustc_type_ir::TypeFlags {
|
||||
match &**self {
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
FlagComputation::for_const_kind(&start.kind()).flags
|
||||
| FlagComputation::for_const_kind(&end.kind()).flags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
|
||||
match &**self {
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
start.outer_exclusive_binder().max(end.outer_exclusive_binder())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> std::ops::Deref for Pattern<'tcx> {
|
||||
type Target = PatternKind<'tcx>;
|
||||
|
||||
|
@ -23,9 +49,9 @@ impl<'tcx> fmt::Debug for Pattern<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for PatternKind<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
impl<'tcx> IrPrint<PatternKind<'tcx>> for TyCtxt<'tcx> {
|
||||
fn print(t: &PatternKind<'tcx>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *t {
|
||||
PatternKind::Range { start, end } => {
|
||||
write!(f, "{start}")?;
|
||||
|
||||
|
@ -53,10 +79,15 @@ impl<'tcx> fmt::Debug for PatternKind<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_debug(t: &PatternKind<'tcx>, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Self::print(t, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
|
||||
pub enum PatternKind<'tcx> {
|
||||
Range { start: ty::Const<'tcx>, end: ty::Const<'tcx> },
|
||||
impl<'tcx> rustc_type_ir::inherent::IntoKind for Pattern<'tcx> {
|
||||
type Kind = PatternKind<'tcx>;
|
||||
fn kind(self) -> Self::Kind {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::walk::TypeWalker;
|
||||
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate};
|
||||
use tracing::instrument;
|
||||
use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
|
||||
|
@ -2029,6 +2030,20 @@ impl<'tcx> Ty<'tcx> {
|
|||
pub fn is_known_rigid(self) -> bool {
|
||||
self.kind().is_known_rigid()
|
||||
}
|
||||
|
||||
/// Iterator that walks `self` and any types reachable from
|
||||
/// `self`, in depth-first order. Note that just walks the types
|
||||
/// that appear in `self`, it does not descend into the fields of
|
||||
/// structs or variants. For example:
|
||||
///
|
||||
/// ```text
|
||||
/// isize => { isize }
|
||||
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
|
||||
/// [isize] => { [isize], isize }
|
||||
/// ```
|
||||
pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
|
||||
TypeWalker::new(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
|
||||
|
|
|
@ -1169,6 +1169,13 @@ fn create_coroutine_drop_shim<'tcx>(
|
|||
dump_mir(tcx, false, "coroutine_drop", &0, &body, |_, _| Ok(()));
|
||||
body.source.instance = drop_instance;
|
||||
|
||||
// Creating a coroutine drop shim happens on `Analysis(PostCleanup) -> Runtime(Initial)`
|
||||
// but the pass manager doesn't update the phase of the coroutine drop shim. Update the
|
||||
// phase of the drop shim so that later on when we run the pass manager on the shim, in
|
||||
// the `mir_shims` query, we don't ICE on the intra-pass validation before we've updated
|
||||
// the phase of the body from analysis.
|
||||
body.phase = MirPhase::Runtime(RuntimePhase::Initial);
|
||||
|
||||
body
|
||||
}
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
|
|||
pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) {
|
||||
let attr_item = attr.get_normal_item();
|
||||
|
||||
if safety == AttributeSafety::Unsafe {
|
||||
if let AttributeSafety::Unsafe { unsafe_since } = safety {
|
||||
if let ast::Safety::Default = attr_item.unsafety {
|
||||
let path_span = attr_item.path.span;
|
||||
|
||||
|
@ -167,7 +167,13 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
|
|||
// square bracket respectively.
|
||||
let diag_span = attr_item.span();
|
||||
|
||||
if attr.span.at_least_rust_2024() {
|
||||
// Attributes can be safe in earlier editions, and become unsafe in later ones.
|
||||
let emit_error = match unsafe_since {
|
||||
None => true,
|
||||
Some(unsafe_since) => attr.span.edition() >= unsafe_since,
|
||||
};
|
||||
|
||||
if emit_error {
|
||||
psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
|
||||
span: path_span,
|
||||
suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion {
|
||||
|
|
|
@ -226,12 +226,12 @@ impl SerializedDepGraph {
|
|||
|
||||
// If the length of this node's edge list is small, the length is stored in the header.
|
||||
// If it is not, we fall back to another decoder call.
|
||||
let num_edges = node_header.len().unwrap_or_else(|| d.read_usize());
|
||||
let num_edges = node_header.len().unwrap_or_else(|| d.read_u32());
|
||||
|
||||
// The edges index list uses the same varint strategy as rmeta tables; we select the
|
||||
// number of byte elements per-array not per-element. This lets us read the whole edge
|
||||
// list for a node with one decoder call and also use the on-disk format in memory.
|
||||
let edges_len_bytes = node_header.bytes_per_index() * num_edges;
|
||||
let edges_len_bytes = node_header.bytes_per_index() * (num_edges as usize);
|
||||
// The in-memory structure for the edges list stores the byte width of the edges on
|
||||
// this node with the offset into the global edge data array.
|
||||
let edges_header = node_header.edges_header(&edge_list_data);
|
||||
|
@ -296,7 +296,7 @@ struct SerializedNodeHeader<D> {
|
|||
// The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only
|
||||
// to make the implementation of `SerializedNodeHeader` simpler.
|
||||
struct Unpacked {
|
||||
len: Option<usize>,
|
||||
len: Option<u32>,
|
||||
bytes_per_index: usize,
|
||||
kind: DepKind,
|
||||
hash: PackedFingerprint,
|
||||
|
@ -352,7 +352,7 @@ impl<D: Deps> SerializedNodeHeader<D> {
|
|||
assert_eq!(fingerprint, res.fingerprint());
|
||||
assert_eq!(node, res.node());
|
||||
if let Some(len) = res.len() {
|
||||
assert_eq!(edge_count, len);
|
||||
assert_eq!(edge_count, len as usize);
|
||||
}
|
||||
}
|
||||
Self { bytes, _marker: PhantomData }
|
||||
|
@ -366,7 +366,7 @@ impl<D: Deps> SerializedNodeHeader<D> {
|
|||
|
||||
let kind = head & mask(Self::KIND_BITS) as u16;
|
||||
let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16;
|
||||
let len = (head as usize) >> (Self::WIDTH_BITS + Self::KIND_BITS);
|
||||
let len = (head as u32) >> (Self::WIDTH_BITS + Self::KIND_BITS);
|
||||
|
||||
Unpacked {
|
||||
len: len.checked_sub(1),
|
||||
|
@ -378,7 +378,7 @@ impl<D: Deps> SerializedNodeHeader<D> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn len(&self) -> Option<usize> {
|
||||
fn len(&self) -> Option<u32> {
|
||||
self.unpack().len
|
||||
}
|
||||
|
||||
|
@ -421,7 +421,8 @@ impl NodeInfo {
|
|||
e.write_array(header.bytes);
|
||||
|
||||
if header.len().is_none() {
|
||||
e.emit_usize(edges.len());
|
||||
// The edges are all unique and the number of unique indices is less than u32::MAX.
|
||||
e.emit_u32(edges.len().try_into().unwrap());
|
||||
}
|
||||
|
||||
let bytes_per_index = header.bytes_per_index();
|
||||
|
@ -456,7 +457,8 @@ impl NodeInfo {
|
|||
e.write_array(header.bytes);
|
||||
|
||||
if header.len().is_none() {
|
||||
e.emit_usize(edge_count);
|
||||
// The edges are all unique and the number of unique indices is less than u32::MAX.
|
||||
e.emit_u32(edge_count.try_into().unwrap());
|
||||
}
|
||||
|
||||
let bytes_per_index = header.bytes_per_index();
|
||||
|
|
|
@ -268,8 +268,8 @@ trait_selection_oc_type_compat = type not compatible with trait
|
|||
trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
|
||||
.label = opaque type defined here
|
||||
trait_selection_opaque_type_non_generic_param =
|
||||
expected generic {$kind} parameter, found `{$ty}`
|
||||
.label = {STREQ($ty, "'static") ->
|
||||
expected generic {$kind} parameter, found `{$arg}`
|
||||
.label = {STREQ($arg, "'static") ->
|
||||
[true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
|
||||
*[other] this generic parameter must be used with a generic {$kind} parameter
|
||||
}
|
||||
|
|
|
@ -1926,7 +1926,7 @@ impl Subdiagnostic for AddPreciseCapturingForOvercapture {
|
|||
#[derive(Diagnostic)]
|
||||
#[diag(trait_selection_opaque_type_non_generic_param, code = E0792)]
|
||||
pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
|
||||
pub ty: GenericArg<'tcx>,
|
||||
pub arg: GenericArg<'tcx>,
|
||||
pub kind: &'a str,
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
|
@ -70,7 +70,7 @@ pub fn check_opaque_type_parameter_valid<'tcx>(
|
|||
opaque_env.param_is_error(i)?;
|
||||
|
||||
return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam {
|
||||
ty: arg,
|
||||
arg,
|
||||
kind,
|
||||
span,
|
||||
param_span: tcx.def_span(opaque_param.def_id),
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
use std::slice;
|
||||
|
||||
use crate::inherent::*;
|
||||
use crate::visit::Flags;
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
bitflags::bitflags! {
|
||||
/// Flags that we track on types. These flags are propagated upwards
|
||||
/// through the type during type construction, so that we can quickly check
|
||||
|
@ -128,3 +134,362 @@ bitflags::bitflags! {
|
|||
const HAS_BINDER_VARS = 1 << 23;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FlagComputation<I> {
|
||||
pub flags: TypeFlags,
|
||||
|
||||
/// see `Ty::outer_exclusive_binder` for details
|
||||
pub outer_exclusive_binder: ty::DebruijnIndex,
|
||||
|
||||
interner: std::marker::PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I: Interner> FlagComputation<I> {
|
||||
fn new() -> FlagComputation<I> {
|
||||
FlagComputation {
|
||||
flags: TypeFlags::empty(),
|
||||
outer_exclusive_binder: ty::INNERMOST,
|
||||
interner: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
pub fn for_kind(kind: &ty::TyKind<I>) -> FlagComputation<I> {
|
||||
let mut result = FlagComputation::new();
|
||||
result.add_kind(kind);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn for_predicate(binder: ty::Binder<I, ty::PredicateKind<I>>) -> FlagComputation<I> {
|
||||
let mut result = FlagComputation::new();
|
||||
result.add_predicate(binder);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn for_const_kind(kind: &ty::ConstKind<I>) -> FlagComputation<I> {
|
||||
let mut result = FlagComputation::new();
|
||||
result.add_const_kind(kind);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn for_clauses(clauses: &[I::Clause]) -> FlagComputation<I> {
|
||||
let mut result = FlagComputation::new();
|
||||
for c in clauses {
|
||||
result.add_flags(c.as_predicate().flags());
|
||||
result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn add_flags(&mut self, flags: TypeFlags) {
|
||||
self.flags = self.flags | flags;
|
||||
}
|
||||
|
||||
/// indicates that `self` refers to something at binding level `binder`
|
||||
fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
|
||||
let exclusive_binder = binder.shifted_in(1);
|
||||
self.add_exclusive_binder(exclusive_binder);
|
||||
}
|
||||
|
||||
/// indicates that `self` refers to something *inside* binding
|
||||
/// level `binder` -- not bound by `binder`, but bound by the next
|
||||
/// binder internal to it
|
||||
fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
|
||||
self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
|
||||
}
|
||||
|
||||
/// Adds the flags/depth from a set of types that appear within the current type, but within a
|
||||
/// region binder.
|
||||
fn bound_computation<T, F>(&mut self, value: ty::Binder<I, T>, f: F)
|
||||
where
|
||||
F: FnOnce(&mut Self, T),
|
||||
{
|
||||
let mut computation = FlagComputation::new();
|
||||
|
||||
if !value.bound_vars().is_empty() {
|
||||
computation.add_flags(TypeFlags::HAS_BINDER_VARS);
|
||||
}
|
||||
|
||||
f(&mut computation, value.skip_binder());
|
||||
|
||||
self.add_flags(computation.flags);
|
||||
|
||||
// The types that contributed to `computation` occurred within
|
||||
// a region binder, so subtract one from the region depth
|
||||
// within when adding the depth to `self`.
|
||||
let outer_exclusive_binder = computation.outer_exclusive_binder;
|
||||
if outer_exclusive_binder > ty::INNERMOST {
|
||||
self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
|
||||
} // otherwise, this binder captures nothing
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
fn add_kind(&mut self, kind: &ty::TyKind<I>) {
|
||||
match *kind {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Float(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Never
|
||||
| ty::Str
|
||||
| ty::Foreign(..) => {}
|
||||
|
||||
ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
|
||||
|
||||
ty::Param(_) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_PARAM);
|
||||
}
|
||||
|
||||
ty::Closure(_, args)
|
||||
| ty::Coroutine(_, args)
|
||||
| ty::CoroutineClosure(_, args)
|
||||
| ty::CoroutineWitness(_, args) => {
|
||||
self.add_args(args.as_slice());
|
||||
}
|
||||
|
||||
ty::Bound(debruijn, _) => {
|
||||
self.add_bound_var(debruijn);
|
||||
self.add_flags(TypeFlags::HAS_TY_BOUND);
|
||||
}
|
||||
|
||||
ty::Placeholder(..) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
|
||||
}
|
||||
|
||||
ty::Infer(infer) => match infer {
|
||||
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_FRESH)
|
||||
}
|
||||
|
||||
ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
|
||||
self.add_flags(TypeFlags::HAS_TY_INFER)
|
||||
}
|
||||
},
|
||||
|
||||
ty::Adt(_, args) => {
|
||||
self.add_args(args.as_slice());
|
||||
}
|
||||
|
||||
ty::Alias(kind, data) => {
|
||||
self.add_flags(match kind {
|
||||
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
|
||||
ty::Weak => TypeFlags::HAS_TY_WEAK,
|
||||
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
|
||||
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
|
||||
});
|
||||
|
||||
self.add_alias_ty(data);
|
||||
}
|
||||
|
||||
ty::Dynamic(obj, r, _) => {
|
||||
for predicate in obj.iter() {
|
||||
self.bound_computation(predicate, |computation, predicate| match predicate {
|
||||
ty::ExistentialPredicate::Trait(tr) => {
|
||||
computation.add_args(tr.args.as_slice())
|
||||
}
|
||||
ty::ExistentialPredicate::Projection(p) => {
|
||||
computation.add_existential_projection(&p);
|
||||
}
|
||||
ty::ExistentialPredicate::AutoTrait(_) => {}
|
||||
});
|
||||
}
|
||||
|
||||
self.add_region(r);
|
||||
}
|
||||
|
||||
ty::Array(tt, len) => {
|
||||
self.add_ty(tt);
|
||||
self.add_const(len);
|
||||
}
|
||||
|
||||
ty::Pat(ty, pat) => {
|
||||
self.add_ty(ty);
|
||||
self.add_flags(pat.flags());
|
||||
}
|
||||
|
||||
ty::Slice(tt) => self.add_ty(tt),
|
||||
|
||||
ty::RawPtr(ty, _) => {
|
||||
self.add_ty(ty);
|
||||
}
|
||||
|
||||
ty::Ref(r, ty, _) => {
|
||||
self.add_region(r);
|
||||
self.add_ty(ty);
|
||||
}
|
||||
|
||||
ty::Tuple(types) => {
|
||||
self.add_tys(types);
|
||||
}
|
||||
|
||||
ty::FnDef(_, args) => {
|
||||
self.add_args(args.as_slice());
|
||||
}
|
||||
|
||||
ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
|
||||
computation.add_tys(sig_tys.inputs_and_output);
|
||||
}),
|
||||
|
||||
ty::UnsafeBinder(bound_ty) => {
|
||||
self.bound_computation(bound_ty.into(), |computation, ty| {
|
||||
computation.add_ty(ty);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_predicate(&mut self, binder: ty::Binder<I, ty::PredicateKind<I>>) {
|
||||
self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
|
||||
}
|
||||
|
||||
fn add_predicate_atom(&mut self, atom: ty::PredicateKind<I>) {
|
||||
match atom {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
|
||||
self.add_args(trait_pred.trait_ref.args.as_slice());
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
|
||||
trait_ref,
|
||||
constness: _,
|
||||
})) => {
|
||||
self.add_args(trait_ref.args.as_slice());
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
|
||||
a,
|
||||
b,
|
||||
))) => {
|
||||
self.add_region(a);
|
||||
self.add_region(b);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
|
||||
ty,
|
||||
region,
|
||||
))) => {
|
||||
self.add_ty(ty);
|
||||
self.add_region(region);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
|
||||
self.add_const(ct);
|
||||
self.add_ty(ty);
|
||||
}
|
||||
ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
|
||||
self.add_ty(a);
|
||||
self.add_ty(b);
|
||||
}
|
||||
ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
|
||||
self.add_ty(a);
|
||||
self.add_ty(b);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
|
||||
projection_term,
|
||||
term,
|
||||
})) => {
|
||||
self.add_alias_term(projection_term);
|
||||
self.add_term(term);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
|
||||
self.add_args(slice::from_ref(&arg));
|
||||
}
|
||||
ty::PredicateKind::DynCompatible(_def_id) => {}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
|
||||
self.add_const(uv);
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(expected, found) => {
|
||||
self.add_const(expected);
|
||||
self.add_const(found);
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
|
||||
self.add_alias_term(alias);
|
||||
self.add_term(term);
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(t1, t2, _) => {
|
||||
self.add_term(t1);
|
||||
self.add_term(t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_ty(&mut self, ty: I::Ty) {
|
||||
self.add_flags(ty.flags());
|
||||
self.add_exclusive_binder(ty.outer_exclusive_binder());
|
||||
}
|
||||
|
||||
fn add_tys(&mut self, tys: I::Tys) {
|
||||
for ty in tys.iter() {
|
||||
self.add_ty(ty);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_region(&mut self, r: I::Region) {
|
||||
self.add_flags(r.flags());
|
||||
if let ty::ReBound(debruijn, _) = r.kind() {
|
||||
self.add_bound_var(debruijn);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_const(&mut self, c: I::Const) {
|
||||
self.add_flags(c.flags());
|
||||
self.add_exclusive_binder(c.outer_exclusive_binder());
|
||||
}
|
||||
|
||||
fn add_const_kind(&mut self, c: &ty::ConstKind<I>) {
|
||||
match *c {
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
self.add_args(uv.args.as_slice());
|
||||
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
|
||||
}
|
||||
ty::ConstKind::Infer(infer) => match infer {
|
||||
ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
|
||||
ty::InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
|
||||
},
|
||||
ty::ConstKind::Bound(debruijn, _) => {
|
||||
self.add_bound_var(debruijn);
|
||||
self.add_flags(TypeFlags::HAS_CT_BOUND);
|
||||
}
|
||||
ty::ConstKind::Param(_) => {
|
||||
self.add_flags(TypeFlags::HAS_CT_PARAM);
|
||||
}
|
||||
ty::ConstKind::Placeholder(_) => {
|
||||
self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
|
||||
}
|
||||
ty::ConstKind::Value(cv) => self.add_ty(cv.ty()),
|
||||
ty::ConstKind::Expr(e) => self.add_args(e.args().as_slice()),
|
||||
ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<I>) {
|
||||
self.add_args(projection.args.as_slice());
|
||||
match projection.term.kind() {
|
||||
ty::TermKind::Ty(ty) => self.add_ty(ty),
|
||||
ty::TermKind::Const(ct) => self.add_const(ct),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<I>) {
|
||||
self.add_args(alias_ty.args.as_slice());
|
||||
}
|
||||
|
||||
fn add_alias_term(&mut self, alias_term: ty::AliasTerm<I>) {
|
||||
self.add_args(alias_term.args.as_slice());
|
||||
}
|
||||
|
||||
fn add_args(&mut self, args: &[I::GenericArg]) {
|
||||
for kind in args {
|
||||
match kind.kind() {
|
||||
ty::GenericArgKind::Type(ty) => self.add_ty(ty),
|
||||
ty::GenericArgKind::Lifetime(lt) => self.add_region(lt),
|
||||
ty::GenericArgKind::Const(ct) => self.add_const(ct),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_term(&mut self, term: I::Term) {
|
||||
match term.kind() {
|
||||
ty::TermKind::Ty(ty) => self.add_ty(ty),
|
||||
ty::TermKind::Const(ct) => self.add_const(ct),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -583,7 +583,7 @@ pub trait Span<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
|
|||
|
||||
pub trait SliceLike: Sized + Copy {
|
||||
type Item: Copy;
|
||||
type IntoIter: Iterator<Item = Self::Item>;
|
||||
type IntoIter: Iterator<Item = Self::Item> + DoubleEndedIterator;
|
||||
|
||||
fn iter(self) -> Self::IntoIter;
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ pub trait Interner:
|
|||
+ IrPrint<ty::SubtypePredicate<Self>>
|
||||
+ IrPrint<ty::CoercePredicate<Self>>
|
||||
+ IrPrint<ty::FnSig<Self>>
|
||||
+ IrPrint<ty::PatternKind<Self>>
|
||||
{
|
||||
type DefId: DefId<Self>;
|
||||
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
|
||||
|
@ -104,7 +105,14 @@ pub trait Interner:
|
|||
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
|
||||
type BoundExistentialPredicates: BoundExistentialPredicates<Self>;
|
||||
type AllocId: Copy + Debug + Hash + Eq;
|
||||
type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
|
||||
type Pat: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ Debug
|
||||
+ Relate<Self>
|
||||
+ Flags
|
||||
+ IntoKind<Kind = ty::PatternKind<Self>>;
|
||||
type Safety: Safety<Self>;
|
||||
type Abi: Abi<Self>;
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ use std::fmt;
|
|||
|
||||
use crate::{
|
||||
AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
|
||||
HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate,
|
||||
SubtypePredicate, TraitPredicate, TraitRef,
|
||||
HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, PatternKind,
|
||||
ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
|
||||
};
|
||||
|
||||
pub trait IrPrint<T> {
|
||||
|
@ -57,9 +57,10 @@ define_display_via_print!(
|
|||
AliasTy,
|
||||
AliasTerm,
|
||||
FnSig,
|
||||
PatternKind,
|
||||
);
|
||||
|
||||
define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
|
||||
define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection, PatternKind);
|
||||
|
||||
impl<I: Interner, T> fmt::Display for OutlivesPredicate<I, T>
|
||||
where
|
||||
|
|
|
@ -31,6 +31,7 @@ pub mod outlives;
|
|||
pub mod relate;
|
||||
pub mod search_graph;
|
||||
pub mod solve;
|
||||
pub mod walk;
|
||||
|
||||
// These modules are not `pub` since they are glob-imported.
|
||||
#[macro_use]
|
||||
|
@ -44,6 +45,7 @@ mod generic_arg;
|
|||
mod infer_ctxt;
|
||||
mod interner;
|
||||
mod opaque_ty;
|
||||
mod pattern;
|
||||
mod predicate;
|
||||
mod predicate_kind;
|
||||
mod region_kind;
|
||||
|
@ -67,6 +69,7 @@ pub use generic_arg::*;
|
|||
pub use infer_ctxt::*;
|
||||
pub use interner::*;
|
||||
pub use opaque_ty::*;
|
||||
pub use pattern::*;
|
||||
pub use predicate::*;
|
||||
pub use predicate_kind::*;
|
||||
pub use region_kind::*;
|
||||
|
|
16
compiler/rustc_type_ir/src/pattern.rs
Normal file
16
compiler/rustc_type_ir/src/pattern.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use derive_where::derive_where;
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
|
||||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
|
||||
use crate::Interner;
|
||||
|
||||
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
|
||||
)]
|
||||
pub enum PatternKind<I: Interner> {
|
||||
Range { start: I::Const, end: I::Const },
|
||||
}
|
|
@ -1,20 +1,21 @@
|
|||
//! An iterator over the type substructure.
|
||||
//! WARNING: this does not keep track of the region depth.
|
||||
|
||||
use rustc_data_structures::sso::SsoHashSet;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::ty::{self, GenericArg, GenericArgKind, Ty};
|
||||
use crate::data_structures::SsoHashSet;
|
||||
use crate::inherent::*;
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
// The TypeWalker's stack is hot enough that it's worth going to some effort to
|
||||
// avoid heap allocations.
|
||||
type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
|
||||
type TypeWalkerStack<I> = SmallVec<[<I as Interner>::GenericArg; 8]>;
|
||||
|
||||
pub struct TypeWalker<'tcx> {
|
||||
stack: TypeWalkerStack<'tcx>,
|
||||
pub struct TypeWalker<I: Interner> {
|
||||
stack: TypeWalkerStack<I>,
|
||||
last_subtree: usize,
|
||||
pub visited: SsoHashSet<GenericArg<'tcx>>,
|
||||
pub visited: SsoHashSet<I::GenericArg>,
|
||||
}
|
||||
|
||||
/// An iterator for walking the type tree.
|
||||
|
@ -25,8 +26,8 @@ pub struct TypeWalker<'tcx> {
|
|||
/// in this situation walker only visits each type once.
|
||||
/// It maintains a set of visited types and
|
||||
/// skips any types that are already there.
|
||||
impl<'tcx> TypeWalker<'tcx> {
|
||||
pub fn new(root: GenericArg<'tcx>) -> Self {
|
||||
impl<I: Interner> TypeWalker<I> {
|
||||
pub fn new(root: I::GenericArg) -> Self {
|
||||
Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
|
||||
}
|
||||
|
||||
|
@ -47,16 +48,16 @@ impl<'tcx> TypeWalker<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Iterator for TypeWalker<'tcx> {
|
||||
type Item = GenericArg<'tcx>;
|
||||
impl<I: Interner> Iterator for TypeWalker<I> {
|
||||
type Item = I::GenericArg;
|
||||
|
||||
fn next(&mut self) -> Option<GenericArg<'tcx>> {
|
||||
fn next(&mut self) -> Option<I::GenericArg> {
|
||||
debug!("next(): stack={:?}", self.stack);
|
||||
loop {
|
||||
let next = self.stack.pop()?;
|
||||
self.last_subtree = self.stack.len();
|
||||
if self.visited.insert(next) {
|
||||
push_inner(&mut self.stack, next);
|
||||
push_inner::<I>(&mut self.stack, next);
|
||||
debug!("next: stack={:?}", self.stack);
|
||||
return Some(next);
|
||||
}
|
||||
|
@ -64,63 +65,15 @@ impl<'tcx> Iterator for TypeWalker<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> GenericArg<'tcx> {
|
||||
/// Iterator that walks `self` and any types reachable from
|
||||
/// `self`, in depth-first order. Note that just walks the types
|
||||
/// that appear in `self`, it does not descend into the fields of
|
||||
/// structs or variants. For example:
|
||||
///
|
||||
/// ```text
|
||||
/// isize => { isize }
|
||||
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
|
||||
/// [isize] => { [isize], isize }
|
||||
/// ```
|
||||
pub fn walk(self) -> TypeWalker<'tcx> {
|
||||
TypeWalker::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Ty<'tcx> {
|
||||
/// Iterator that walks `self` and any types reachable from
|
||||
/// `self`, in depth-first order. Note that just walks the types
|
||||
/// that appear in `self`, it does not descend into the fields of
|
||||
/// structs or variants. For example:
|
||||
///
|
||||
/// ```text
|
||||
/// isize => { isize }
|
||||
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
|
||||
/// [isize] => { [isize], isize }
|
||||
/// ```
|
||||
pub fn walk(self) -> TypeWalker<'tcx> {
|
||||
TypeWalker::new(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ty::Const<'tcx> {
|
||||
/// Iterator that walks `self` and any types reachable from
|
||||
/// `self`, in depth-first order. Note that just walks the types
|
||||
/// that appear in `self`, it does not descend into the fields of
|
||||
/// structs or variants. For example:
|
||||
///
|
||||
/// ```text
|
||||
/// isize => { isize }
|
||||
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
|
||||
/// [isize] => { [isize], isize }
|
||||
/// ```
|
||||
pub fn walk(self) -> TypeWalker<'tcx> {
|
||||
TypeWalker::new(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// We push `GenericArg`s on the stack in reverse order so as to
|
||||
/// maintain a pre-order traversal. As of the time of this
|
||||
/// writing, the fact that the traversal is pre-order is not
|
||||
/// known to be significant to any code, but it seems like the
|
||||
/// natural order one would expect (basically, the order of the
|
||||
/// types as they are written).
|
||||
fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) {
|
||||
match parent.unpack() {
|
||||
GenericArgKind::Type(parent_ty) => match *parent_ty.kind() {
|
||||
fn push_inner<I: Interner>(stack: &mut TypeWalkerStack<I>, parent: I::GenericArg) {
|
||||
match parent.kind() {
|
||||
ty::GenericArgKind::Type(parent_ty) => match parent_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
|
@ -136,7 +89,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
|||
| ty::Foreign(..) => {}
|
||||
|
||||
ty::Pat(ty, pat) => {
|
||||
match *pat {
|
||||
match pat.kind() {
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
stack.push(end.into());
|
||||
stack.push(start.into());
|
||||
|
@ -163,22 +116,25 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
|||
}
|
||||
ty::Dynamic(obj, lt, _) => {
|
||||
stack.push(lt.into());
|
||||
stack.extend(obj.iter().rev().flat_map(|predicate| {
|
||||
let (args, opt_ty) = match predicate.skip_binder() {
|
||||
ty::ExistentialPredicate::Trait(tr) => (tr.args, None),
|
||||
ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)),
|
||||
ty::ExistentialPredicate::AutoTrait(_) =>
|
||||
// Empty iterator
|
||||
{
|
||||
(ty::GenericArgs::empty(), None)
|
||||
}
|
||||
};
|
||||
stack.extend(
|
||||
obj.iter()
|
||||
.rev()
|
||||
.filter_map(|predicate| {
|
||||
let (args, opt_ty) = match predicate.skip_binder() {
|
||||
ty::ExistentialPredicate::Trait(tr) => (tr.args, None),
|
||||
ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)),
|
||||
ty::ExistentialPredicate::AutoTrait(_) => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
args.iter().rev().chain(opt_ty.map(|term| match term.unpack() {
|
||||
ty::TermKind::Ty(ty) => ty.into(),
|
||||
ty::TermKind::Const(ct) => ct.into(),
|
||||
}))
|
||||
}));
|
||||
Some(args.iter().rev().chain(opt_ty.map(|term| match term.kind() {
|
||||
ty::TermKind::Ty(ty) => ty.into(),
|
||||
ty::TermKind::Const(ct) => ct.into(),
|
||||
})))
|
||||
})
|
||||
.flatten(),
|
||||
);
|
||||
}
|
||||
ty::Adt(_, args)
|
||||
| ty::Closure(_, args)
|
||||
|
@ -188,7 +144,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
|||
| ty::FnDef(_, args) => {
|
||||
stack.extend(args.iter().rev());
|
||||
}
|
||||
ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)),
|
||||
ty::Tuple(ts) => stack.extend(ts.iter().rev().map(|ty| ty.into())),
|
||||
ty::FnPtr(sig_tys, _hdr) => {
|
||||
stack.extend(
|
||||
sig_tys.skip_binder().inputs_and_output.iter().rev().map(|ty| ty.into()),
|
||||
|
@ -198,15 +154,15 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
|||
stack.push(bound_ty.skip_binder().into());
|
||||
}
|
||||
},
|
||||
GenericArgKind::Lifetime(_) => {}
|
||||
GenericArgKind::Const(parent_ct) => match parent_ct.kind() {
|
||||
ty::GenericArgKind::Lifetime(_) => {}
|
||||
ty::GenericArgKind::Const(parent_ct) => match parent_ct.kind() {
|
||||
ty::ConstKind::Infer(_)
|
||||
| ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Bound(..)
|
||||
| ty::ConstKind::Error(_) => {}
|
||||
|
||||
ty::ConstKind::Value(cv) => stack.push(cv.ty.into()),
|
||||
ty::ConstKind::Value(cv) => stack.push(cv.ty().into()),
|
||||
|
||||
ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()),
|
||||
ty::ConstKind::Unevaluated(ct) => {
|
Loading…
Add table
Add a link
Reference in a new issue