From b1585983ccd83c8bf15e5e19ec594c00b8a37a2e Mon Sep 17 00:00:00 2001 From: Kirby Linvill Date: Thu, 2 Nov 2023 09:05:35 -0600 Subject: [PATCH 01/19] Add stable MIR Projections support based on MIR structure This commit includes richer projections for both Places and UserTypeProjections. However, the tests only touch on Places. There are also outstanding TODOs regarding how projections should be resolved to produce Place types, and regarding if UserTypeProjections should just contain ProjectionElem<(),()> objects as in MIR. --- compiler/rustc_smir/src/rustc_smir/mod.rs | 69 +++++++++++- compiler/stable_mir/src/mir/body.rs | 117 ++++++++++++++++++++- tests/ui-fulldeps/stable-mir/crate-info.rs | 103 ++++++++++++++++++ 3 files changed, 283 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 27596c08f1c1..83bacfb8263f 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -682,10 +682,39 @@ impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> { impl<'tcx> Stable<'tcx> for mir::Place<'tcx> { type T = stable_mir::mir::Place; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { stable_mir::mir::Place { local: self.local.as_usize(), - projection: format!("{:?}", self.projection), + projection: self.projection.iter().map(|e| e.stable(tables)).collect(), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { + type T = stable_mir::mir::ProjectionElem; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use mir::ProjectionElem::*; + match self { + Deref => stable_mir::mir::ProjectionElem::Deref, + Field(idx, ty) => { + stable_mir::mir::ProjectionElem::Field(idx.stable(tables), ty.stable(tables)) + } + Index(local) => stable_mir::mir::ProjectionElem::Index(local.stable(tables)), + ConstantIndex { offset, min_length, from_end } => { + stable_mir::mir::ProjectionElem::ConstantIndex { + offset: *offset, + min_length: *min_length, + from_end: *from_end, + } + } + Subslice { from, to, from_end } => stable_mir::mir::ProjectionElem::Subslice { + from: *from, + to: *to, + from_end: *from_end, + }, + Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)), + OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)), + Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)), } } } @@ -693,8 +722,40 @@ impl<'tcx> Stable<'tcx> for mir::Place<'tcx> { impl<'tcx> Stable<'tcx> for mir::UserTypeProjection { type T = stable_mir::mir::UserTypeProjection; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - UserTypeProjection { base: self.base.as_usize(), projection: format!("{:?}", self.projs) } + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + UserTypeProjection { + base: self.base.as_usize(), + projection: self.projs.iter().map(|e| e.stable(tables)).collect(), + } + } +} + +// ProjectionKind is nearly identical to PlaceElem, except its generic arguments are units. We +// therefore don't need to resolve any arguments with the generic types. +impl<'tcx> Stable<'tcx> for mir::ProjectionKind { + type T = stable_mir::mir::ProjectionElem<(), ()>; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use mir::ProjectionElem::*; + match self { + Deref => stable_mir::mir::ProjectionElem::Deref, + Field(idx, ty) => stable_mir::mir::ProjectionElem::Field(idx.stable(tables), *ty), + Index(local) => stable_mir::mir::ProjectionElem::Index(*local), + ConstantIndex { offset, min_length, from_end } => { + stable_mir::mir::ProjectionElem::ConstantIndex { + offset: *offset, + min_length: *min_length, + from_end: *from_end, + } + } + Subslice { from, to, from_end } => stable_mir::mir::ProjectionElem::Subslice { + from: *from, + to: *to, + from_end: *from_end, + }, + Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)), + OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(*ty), + Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(*ty), + } } } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 069337836853..69e83efdf43a 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -398,22 +398,133 @@ pub enum Operand { pub struct Place { pub local: Local, /// projection out of a place (access a field, deref a pointer, etc) - pub projection: String, + pub projection: Vec>, +} + +// TODO(klinvill): in MIR ProjectionElem is parameterized on the second Field argument and the Index +// argument. This is so it can be used for both the rust provided Places (for which the projection +// elements are of type ProjectionElem) and user-provided type annotations (for which the +// projection elements are of type ProjectionElem<(), ()>). Should we do the same thing in Stable MIR? +#[derive(Clone, Debug)] +pub enum ProjectionElem { + /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place. + Deref, + + /// A field projection (e.g., `f` in `_1.f`) project to a field in the base place. The field is + /// referenced by source-order index rather than the name of the field. The fields type is also + /// given. + Field(FieldIdx, T), + + /// Index into a slice/array. The value of the index is computed at runtime using the `V` + /// argument. + /// + /// Note that this does not also dereference, and so it does not exactly correspond to slice + /// indexing in Rust. In other words, in the below Rust code: + /// + /// ```rust + /// let x = &[1, 2, 3, 4]; + /// let i = 2; + /// x[i]; + /// ``` + /// + /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same + /// thing is true of the `ConstantIndex` and `Subslice` projections below. + Index(V), + + /// Index into a slice/array given by offsets. + /// + /// These indices are generated by slice patterns. Easiest to explain by example: + /// + /// ```ignore (illustrative) + /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, + /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, + /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, + /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, + /// ``` + ConstantIndex { + /// index or -index (in Python terms), depending on from_end + offset: u64, + /// The thing being indexed must be at least this long. For arrays this + /// is always the exact length. + min_length: u64, + /// Counting backwards from end? This is always false when indexing an + /// array. + from_end: bool, + }, + + /// Projects a slice from the base place. + /// + /// These indices are generated by slice patterns. If `from_end` is true, this represents + /// `slice[from..slice.len() - to]`. Otherwise it represents `array[from..to]`. + Subslice { + from: u64, + to: u64, + /// Whether `to` counts from the start or end of the array/slice. + from_end: bool, + }, + + /// "Downcast" to a variant of an enum or a coroutine. + // + // TODO(klinvill): MIR includes an Option argument that is the name of the variant, used + // for printing MIR. However I don't see it used anywhere. Is such a field needed or can we just + // include the VariantIdx which could be used to recover the field name if needed? + Downcast(VariantIdx), + + /// Like an explicit cast from an opaque type to a concrete type, but without + /// requiring an intermediate variable. + OpaqueCast(T), + + /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where + /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping + /// explicit during optimizations and codegen. + /// + /// This projection doesn't impact the runtime behavior of the program except for potentially changing + /// some type metadata of the interpreter or codegen backend. + Subtype(T), } #[derive(Clone, Debug, Eq, PartialEq)] pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, - pub projection: String, + + /// `UserTypeProjection` projections need neither the `V` parameter for `Index` nor the `T` for + /// `Field`. + pub projection: Vec>, } pub type Local = usize; pub const RETURN_LOCAL: Local = 0; +/// The source-order index of a field in a variant. +/// +/// For example, in the following types, +/// ```rust +/// enum Demo1 { +/// Variant0 { a: bool, b: i32 }, +/// Variant1 { c: u8, d: u64 }, +/// } +/// struct Demo2 { e: u8, f: u16, g: u8 } +/// ``` +/// `a`'s `FieldIdx` is `0`, +/// `b`'s `FieldIdx` is `1`, +/// `c`'s `FieldIdx` is `0`, and +/// `g`'s `FieldIdx` is `2`. type FieldIdx = usize; /// The source-order index of a variant in a type. +/// +/// For example, in the following types, +/// ```rust +/// enum Demo1 { +/// Variant0 { a: bool, b: i32 }, +/// Variant1 { c: u8, d: u64 }, +/// } +/// struct Demo2 { e: u8, f: u16, g: u8 } +/// ``` +/// `a` is in the variant with the `VariantIdx` of `0`, +/// `c` is in the variant with the `VariantIdx` of `1`, and +/// `g` is in the variant with the `VariantIdx` of `0`. pub type VariantIdx = usize; type UserTypeAnnotationIndex = usize; @@ -536,6 +647,8 @@ impl Constant { } impl Place { + // TODO(klinvill): What is the expected behavior of this function? Should it resolve down the + // chain of projections so that `*(_1.f)` would end up returning the type referenced by `f`? pub fn ty(&self, locals: &[LocalDecl]) -> Ty { let _start_ty = locals[self.local].ty; todo!("Implement projection") diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index ed6b786f5e1d..c6aaea148720 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -23,6 +23,7 @@ use rustc_hir::def::DefKind; use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::mir::mono::Instance; +use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind}; use stable_mir::ty::{RigidTy, TyKind}; use std::assert_matches::assert_matches; use std::io::Write; @@ -163,6 +164,99 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool) ); + let projections_fn = get_item(&items, (DefKind::Fn, "projections")).unwrap(); + let body = projections_fn.body(); + assert_eq!(body.blocks.len(), 4); + // The first statement assigns `&s.c` to a local. The projections include a deref for `s`, since + // `s` is passed as a reference argument, and a field access for field `c`. + match &body.blocks[0].statements[0].kind { + StatementKind::Assign( + stable_mir::mir::Place { local: _, projection: local_proj }, + Rvalue::Ref(_, _, stable_mir::mir::Place { local: _, projection: r_proj }), + ) => { + // We can't match on vecs, only on slices. Comparing for equality wouldn't be any easier + // since we'd then have to add in the expected local and region values instead of + // matching on wildcards. + assert_matches!(local_proj[..], []); + match &r_proj[..] { + // Similarly we can't match against a type, only against its kind. + [ProjectionElem::Deref, ProjectionElem::Field(2, ty)] => assert_matches!( + ty.kind(), + TyKind::RigidTy(RigidTy::Uint(stable_mir::ty::UintTy::U8)) + ), + other => panic!( + "Unable to match against expected rvalue projection. Expected the projection \ + for `s.c`, which is a Deref and u8 Field. Got: {:?}", + other + ), + }; + } + other => panic!( + "Unable to match against expected Assign statement with a Ref rvalue. Expected the \ + statement to assign `&s.c` to a local. Got: {:?}", + other + ), + }; + // This statement assigns `slice[1]` to a local. The projections include a deref for `slice`, + // since `slice` is a reference, and an index. + match &body.blocks[2].statements[0].kind { + StatementKind::Assign( + stable_mir::mir::Place { local: _, projection: local_proj }, + Rvalue::Use(stable_mir::mir::Operand::Copy(stable_mir::mir::Place { + local: _, + projection: r_proj, + })), + ) => { + // We can't match on vecs, only on slices. Comparing for equality wouldn't be any easier + // since we'd then have to add in the expected local values instead of matching on + // wildcards. + assert_matches!(local_proj[..], []); + assert_matches!(r_proj[..], [ProjectionElem::Deref, ProjectionElem::Index(_)]); + } + other => panic!( + "Unable to match against expected Assign statement with a Use rvalue. Expected the \ + statement to assign `slice[1]` to a local. Got: {:?}", + other + ), + }; + // The first terminator gets a slice of an array via the Index operation. Specifically it + // performs `&vals[1..3]`. There are no projections in this case, the arguments are just locals. + match &body.blocks[0].terminator.kind { + stable_mir::mir::TerminatorKind::Call { args, .. } => + // We can't match on vecs, only on slices. Comparing for equality wouldn't be any easier + // since we'd then have to add in the expected local values instead of matching on + // wildcards. + { + match &args[..] { + [ + stable_mir::mir::Operand::Move(stable_mir::mir::Place { + local: _, + projection: arg1_proj, + }), + stable_mir::mir::Operand::Move(stable_mir::mir::Place { + local: _, + projection: arg2_proj, + }), + ] => { + assert_matches!(arg1_proj[..], []); + assert_matches!(arg2_proj[..], []); + } + other => { + panic!( + "Unable to match against expected arguments to Index call. Expected two \ + move operands. Got: {:?}", + other + ) + } + } + } + other => panic!( + "Unable to match against expected Call terminator. Expected a terminator that calls \ + the Index operation. Got: {:?}", + other + ), + }; + ControlFlow::Continue(()) } @@ -242,6 +336,15 @@ fn generate_input(path: &str) -> std::io::Result<()> { }} else {{ 'b' }} + }} + + pub struct Struct1 {{ _a: u8, _b: u16, c: u8 }} + + pub fn projections(s: &Struct1) -> u8 {{ + let v = &s.c; + let vals = [1, 2, 3, 4]; + let slice = &vals[1..3]; + v + slice[1] }}"# )?; Ok(()) From 98228e67bc11a15e03c4db1bd61ffda6b4620ecb Mon Sep 17 00:00:00 2001 From: Kirby Linvill Date: Thu, 9 Nov 2023 17:59:24 -0700 Subject: [PATCH 02/19] Move SMIR projections tests to new file --- tests/ui-fulldeps/stable-mir/crate-info.rs | 103 ------------ tests/ui-fulldeps/stable-mir/projections.rs | 175 ++++++++++++++++++++ 2 files changed, 175 insertions(+), 103 deletions(-) create mode 100644 tests/ui-fulldeps/stable-mir/projections.rs diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index c6aaea148720..ed6b786f5e1d 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -23,7 +23,6 @@ use rustc_hir::def::DefKind; use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::mir::mono::Instance; -use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind}; use stable_mir::ty::{RigidTy, TyKind}; use std::assert_matches::assert_matches; use std::io::Write; @@ -164,99 +163,6 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool) ); - let projections_fn = get_item(&items, (DefKind::Fn, "projections")).unwrap(); - let body = projections_fn.body(); - assert_eq!(body.blocks.len(), 4); - // The first statement assigns `&s.c` to a local. The projections include a deref for `s`, since - // `s` is passed as a reference argument, and a field access for field `c`. - match &body.blocks[0].statements[0].kind { - StatementKind::Assign( - stable_mir::mir::Place { local: _, projection: local_proj }, - Rvalue::Ref(_, _, stable_mir::mir::Place { local: _, projection: r_proj }), - ) => { - // We can't match on vecs, only on slices. Comparing for equality wouldn't be any easier - // since we'd then have to add in the expected local and region values instead of - // matching on wildcards. - assert_matches!(local_proj[..], []); - match &r_proj[..] { - // Similarly we can't match against a type, only against its kind. - [ProjectionElem::Deref, ProjectionElem::Field(2, ty)] => assert_matches!( - ty.kind(), - TyKind::RigidTy(RigidTy::Uint(stable_mir::ty::UintTy::U8)) - ), - other => panic!( - "Unable to match against expected rvalue projection. Expected the projection \ - for `s.c`, which is a Deref and u8 Field. Got: {:?}", - other - ), - }; - } - other => panic!( - "Unable to match against expected Assign statement with a Ref rvalue. Expected the \ - statement to assign `&s.c` to a local. Got: {:?}", - other - ), - }; - // This statement assigns `slice[1]` to a local. The projections include a deref for `slice`, - // since `slice` is a reference, and an index. - match &body.blocks[2].statements[0].kind { - StatementKind::Assign( - stable_mir::mir::Place { local: _, projection: local_proj }, - Rvalue::Use(stable_mir::mir::Operand::Copy(stable_mir::mir::Place { - local: _, - projection: r_proj, - })), - ) => { - // We can't match on vecs, only on slices. Comparing for equality wouldn't be any easier - // since we'd then have to add in the expected local values instead of matching on - // wildcards. - assert_matches!(local_proj[..], []); - assert_matches!(r_proj[..], [ProjectionElem::Deref, ProjectionElem::Index(_)]); - } - other => panic!( - "Unable to match against expected Assign statement with a Use rvalue. Expected the \ - statement to assign `slice[1]` to a local. Got: {:?}", - other - ), - }; - // The first terminator gets a slice of an array via the Index operation. Specifically it - // performs `&vals[1..3]`. There are no projections in this case, the arguments are just locals. - match &body.blocks[0].terminator.kind { - stable_mir::mir::TerminatorKind::Call { args, .. } => - // We can't match on vecs, only on slices. Comparing for equality wouldn't be any easier - // since we'd then have to add in the expected local values instead of matching on - // wildcards. - { - match &args[..] { - [ - stable_mir::mir::Operand::Move(stable_mir::mir::Place { - local: _, - projection: arg1_proj, - }), - stable_mir::mir::Operand::Move(stable_mir::mir::Place { - local: _, - projection: arg2_proj, - }), - ] => { - assert_matches!(arg1_proj[..], []); - assert_matches!(arg2_proj[..], []); - } - other => { - panic!( - "Unable to match against expected arguments to Index call. Expected two \ - move operands. Got: {:?}", - other - ) - } - } - } - other => panic!( - "Unable to match against expected Call terminator. Expected a terminator that calls \ - the Index operation. Got: {:?}", - other - ), - }; - ControlFlow::Continue(()) } @@ -336,15 +242,6 @@ fn generate_input(path: &str) -> std::io::Result<()> { }} else {{ 'b' }} - }} - - pub struct Struct1 {{ _a: u8, _b: u16, c: u8 }} - - pub fn projections(s: &Struct1) -> u8 {{ - let v = &s.c; - let vals = [1, 2, 3, 4]; - let slice = &vals[1..3]; - v + slice[1] }}"# )?; Ok(()) diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs new file mode 100644 index 000000000000..d1b4fc5b28ed --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -0,0 +1,175 @@ +// run-pass +// Tests the Stable MIR projections API + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +// edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +extern crate rustc_hir; +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_hir::def::DefKind; +use rustc_middle::ty::TyCtxt; +use rustc_smir::rustc_internal; +use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind}; +use stable_mir::ty::{RigidTy, TyKind}; +use std::assert_matches::assert_matches; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + // Find items in the local crate. + let items = stable_mir::all_local_items(); + + let body = get_item(&items, (DefKind::Fn, "projections")).unwrap().body(); + assert_eq!(body.blocks.len(), 4); + // The first statement assigns `&s.c` to a local. The projections include a deref for `s`, since + // `s` is passed as a reference argument, and a field access for field `c`. + match &body.blocks[0].statements[0].kind { + StatementKind::Assign( + stable_mir::mir::Place { local: _, projection: local_proj }, + Rvalue::Ref(_, _, stable_mir::mir::Place { local: _, projection: r_proj }), + ) => { + // We can't match on vecs, only on slices. Comparing statements for equality wouldn't be + // any easier since we'd then have to add in the expected local and region values + // instead of matching on wildcards. + assert_matches!(local_proj[..], []); + match &r_proj[..] { + // Similarly we can't match against a type, only against its kind. + [ProjectionElem::Deref, ProjectionElem::Field(2, ty)] => assert_matches!( + ty.kind(), + TyKind::RigidTy(RigidTy::Uint(stable_mir::ty::UintTy::U8)) + ), + other => panic!( + "Unable to match against expected rvalue projection. Expected the projection \ + for `s.c`, which is a Deref and u8 Field. Got: {:?}", + other + ), + }; + } + other => panic!( + "Unable to match against expected Assign statement with a Ref rvalue. Expected the \ + statement to assign `&s.c` to a local. Got: {:?}", + other + ), + }; + // This statement assigns `slice[1]` to a local. The projections include a deref for `slice`, + // since `slice` is a reference, and an index. + match &body.blocks[2].statements[0].kind { + StatementKind::Assign( + stable_mir::mir::Place { local: _, projection: local_proj }, + Rvalue::Use(stable_mir::mir::Operand::Copy(stable_mir::mir::Place { + local: _, + projection: r_proj, + })), + ) => { + // We can't match on vecs, only on slices. Comparing for equality wouldn't be any easier + // since we'd then have to add in the expected local values instead of matching on + // wildcards. + assert_matches!(local_proj[..], []); + assert_matches!(r_proj[..], [ProjectionElem::Deref, ProjectionElem::Index(_)]); + } + other => panic!( + "Unable to match against expected Assign statement with a Use rvalue. Expected the \ + statement to assign `slice[1]` to a local. Got: {:?}", + other + ), + }; + // The first terminator gets a slice of an array via the Index operation. Specifically it + // performs `&vals[1..3]`. There are no projections in this case, the arguments are just locals. + match &body.blocks[0].terminator.kind { + stable_mir::mir::TerminatorKind::Call { args, .. } => + // We can't match on vecs, only on slices. Comparing for equality wouldn't be any easier + // since we'd then have to add in the expected local values instead of matching on + // wildcards. + { + match &args[..] { + [ + stable_mir::mir::Operand::Move(stable_mir::mir::Place { + local: _, + projection: arg1_proj, + }), + stable_mir::mir::Operand::Move(stable_mir::mir::Place { + local: _, + projection: arg2_proj, + }), + ] => { + assert_matches!(arg1_proj[..], []); + assert_matches!(arg2_proj[..], []); + } + other => { + panic!( + "Unable to match against expected arguments to Index call. Expected two \ + move operands. Got: {:?}", + other + ) + } + } + } + other => panic!( + "Unable to match against expected Call terminator. Expected a terminator that calls \ + the Index operation. Got: {:?}", + other + ), + }; + + ControlFlow::Continue(()) +} + +// Use internal API to find a function in a crate. +fn get_item<'a>( + items: &'a stable_mir::CrateItems, + item: (DefKind, &str), +) -> Option<&'a stable_mir::CrateItem> { + items.iter().find(|crate_item| { + crate_item.kind().to_string() == format!("{:?}", item.0) && crate_item.name() == item.1 + }) +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-type=lib".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, tcx, test_projections(tcx)).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + pub struct Struct1 {{ _a: u8, _b: u16, c: u8 }} + + pub fn projections(s: &Struct1) -> u8 {{ + let v = &s.c; + let vals = [1, 2, 3, 4]; + let slice = &vals[1..3]; + v + slice[1] + }}"# + )?; + Ok(()) +} From 30d6733eb3dd4c393c517056fd3cc276b288b57f Mon Sep 17 00:00:00 2001 From: Kirby Linvill Date: Thu, 9 Nov 2023 18:05:10 -0700 Subject: [PATCH 03/19] Replace match assertions against empty slices with is_empty assertions Asserting is_empty is slightly more concise. --- tests/ui-fulldeps/stable-mir/projections.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index d1b4fc5b28ed..c3fbf4b6e912 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -30,11 +30,9 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -/// This function uses the Stable MIR APIs to get information about the test crate. -fn test_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> { - // Find items in the local crate. +/// Tests projections within Place objects +fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> { let items = stable_mir::all_local_items(); - let body = get_item(&items, (DefKind::Fn, "projections")).unwrap().body(); assert_eq!(body.blocks.len(), 4); // The first statement assigns `&s.c` to a local. The projections include a deref for `s`, since @@ -47,7 +45,7 @@ fn test_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> { // We can't match on vecs, only on slices. Comparing statements for equality wouldn't be // any easier since we'd then have to add in the expected local and region values // instead of matching on wildcards. - assert_matches!(local_proj[..], []); + assert!(local_proj.is_empty()); match &r_proj[..] { // Similarly we can't match against a type, only against its kind. [ProjectionElem::Deref, ProjectionElem::Field(2, ty)] => assert_matches!( @@ -80,7 +78,7 @@ fn test_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> { // We can't match on vecs, only on slices. Comparing for equality wouldn't be any easier // since we'd then have to add in the expected local values instead of matching on // wildcards. - assert_matches!(local_proj[..], []); + assert!(local_proj.is_empty()); assert_matches!(r_proj[..], [ProjectionElem::Deref, ProjectionElem::Index(_)]); } other => panic!( @@ -108,8 +106,8 @@ fn test_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> { projection: arg2_proj, }), ] => { - assert_matches!(arg1_proj[..], []); - assert_matches!(arg2_proj[..], []); + assert!(arg1_proj.is_empty()); + assert!(arg2_proj.is_empty()); } other => { panic!( From 2e70d95cdba8ea185c5d695c410744590785e4ac Mon Sep 17 00:00:00 2001 From: Kirby Linvill Date: Thu, 9 Nov 2023 20:34:30 -0700 Subject: [PATCH 04/19] Remove rich UserTypeProjection projections in SMIR It's not clear to me (klinvill) that UserTypeProjections are produced anymore with the removal of type ascriptions as per https://github.com/rust-lang/rfcs/pull/3307. Furthermore, it's not clear to me which variants of ProjectionElem could appear in such projections. For these reasons, I'm reverting projections in UserTypeProjections to simple strings until I can get more clarity on UserTypeProjections. --- compiler/rustc_smir/src/rustc_smir/mod.rs | 38 ++------------------- compiler/stable_mir/src/mir/body.rs | 25 +++++++------- tests/ui-fulldeps/stable-mir/projections.rs | 2 +- 3 files changed, 16 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 83bacfb8263f..a4d83debb57b 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -691,7 +691,7 @@ impl<'tcx> Stable<'tcx> for mir::Place<'tcx> { } impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { - type T = stable_mir::mir::ProjectionElem; + type T = stable_mir::mir::ProjectionElem; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use mir::ProjectionElem::*; match self { @@ -722,40 +722,8 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { impl<'tcx> Stable<'tcx> for mir::UserTypeProjection { type T = stable_mir::mir::UserTypeProjection; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - UserTypeProjection { - base: self.base.as_usize(), - projection: self.projs.iter().map(|e| e.stable(tables)).collect(), - } - } -} - -// ProjectionKind is nearly identical to PlaceElem, except its generic arguments are units. We -// therefore don't need to resolve any arguments with the generic types. -impl<'tcx> Stable<'tcx> for mir::ProjectionKind { - type T = stable_mir::mir::ProjectionElem<(), ()>; - fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - use mir::ProjectionElem::*; - match self { - Deref => stable_mir::mir::ProjectionElem::Deref, - Field(idx, ty) => stable_mir::mir::ProjectionElem::Field(idx.stable(tables), *ty), - Index(local) => stable_mir::mir::ProjectionElem::Index(*local), - ConstantIndex { offset, min_length, from_end } => { - stable_mir::mir::ProjectionElem::ConstantIndex { - offset: *offset, - min_length: *min_length, - from_end: *from_end, - } - } - Subslice { from, to, from_end } => stable_mir::mir::ProjectionElem::Subslice { - from: *from, - to: *to, - from_end: *from_end, - }, - Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)), - OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(*ty), - Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(*ty), - } + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + UserTypeProjection { base: self.base.as_usize(), projection: format!("{:?}", self.projs) } } } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 69e83efdf43a..49b85d665b1b 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -398,22 +398,23 @@ pub enum Operand { pub struct Place { pub local: Local, /// projection out of a place (access a field, deref a pointer, etc) - pub projection: Vec>, + pub projection: Vec, } -// TODO(klinvill): in MIR ProjectionElem is parameterized on the second Field argument and the Index -// argument. This is so it can be used for both the rust provided Places (for which the projection -// elements are of type ProjectionElem) and user-provided type annotations (for which the -// projection elements are of type ProjectionElem<(), ()>). Should we do the same thing in Stable MIR? +// In MIR ProjectionElem is parameterized on the second Field argument and the Index argument. This +// is so it can be used for both Places (for which the projection elements are of type +// ProjectionElem) and user-provided type annotations (for which the projection elements +// are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use +// ProjectionElem for Places. #[derive(Clone, Debug)] -pub enum ProjectionElem { +pub enum ProjectionElem { /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place. Deref, /// A field projection (e.g., `f` in `_1.f`) project to a field in the base place. The field is /// referenced by source-order index rather than the name of the field. The fields type is also /// given. - Field(FieldIdx, T), + Field(FieldIdx, Ty), /// Index into a slice/array. The value of the index is computed at runtime using the `V` /// argument. @@ -429,7 +430,7 @@ pub enum ProjectionElem { /// /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same /// thing is true of the `ConstantIndex` and `Subslice` projections below. - Index(V), + Index(Local), /// Index into a slice/array given by offsets. /// @@ -472,7 +473,7 @@ pub enum ProjectionElem { /// Like an explicit cast from an opaque type to a concrete type, but without /// requiring an intermediate variable. - OpaqueCast(T), + OpaqueCast(Ty), /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping @@ -480,16 +481,14 @@ pub enum ProjectionElem { /// /// This projection doesn't impact the runtime behavior of the program except for potentially changing /// some type metadata of the interpreter or codegen backend. - Subtype(T), + Subtype(Ty), } #[derive(Clone, Debug, Eq, PartialEq)] pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, - /// `UserTypeProjection` projections need neither the `V` parameter for `Index` nor the `T` for - /// `Field`. - pub projection: Vec>, + pub projection: String, } pub type Local = usize; diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index c3fbf4b6e912..9c649a2effc7 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -152,7 +152,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_projections(tcx)).unwrap(); + run!(args, tcx, test_place_projections(tcx)).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { From 998aa383ba159bc7c6a6eba13ce020c191988f82 Mon Sep 17 00:00:00 2001 From: Kirby Linvill Date: Thu, 9 Nov 2023 20:43:05 -0700 Subject: [PATCH 05/19] Defer Place ty implementation in Stable Mir to later PR --- compiler/stable_mir/src/mir/body.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 49b85d665b1b..625e52c983ed 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -646,8 +646,10 @@ impl Constant { } impl Place { - // TODO(klinvill): What is the expected behavior of this function? Should it resolve down the - // chain of projections so that `*(_1.f)` would end up returning the type referenced by `f`? + // FIXME(klinvill): This function is expected to resolve down the chain of projections to get + // the type referenced at the end of it. E.g. calling `ty()` on `*(_1.f)` should end up + // returning the type referenced by `f`. The information needed to do this may not currently be + // present in Stable MIR since at least an implementation for AdtDef is probably needed. pub fn ty(&self, locals: &[LocalDecl]) -> Ty { let _start_ty = locals[self.local].ty; todo!("Implement projection") From d517a1cbda49309c8364daaedfee040371e616fb Mon Sep 17 00:00:00 2001 From: Kirby Linvill Date: Fri, 10 Nov 2023 11:21:46 -0700 Subject: [PATCH 06/19] Add SMIR visitor for Places and projections --- compiler/stable_mir/src/mir/body.rs | 2 +- compiler/stable_mir/src/mir/visit.rs | 33 +++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 625e52c983ed..48d4a3d37e2c 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -406,7 +406,7 @@ pub struct Place { // ProjectionElem) and user-provided type annotations (for which the projection elements // are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use // ProjectionElem for Places. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub enum ProjectionElem { /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place. Deref, diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 806dced71ff3..475d6e9763d9 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -76,6 +76,15 @@ pub trait MirVisitor { self.super_place(place, ptx, location) } + fn visit_projection_elem( + &mut self, + elem: &ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + self.super_projection_elem(elem, ptx, location); + } + fn visit_local(&mut self, local: &Local, ptx: PlaceContext, location: Location) { let _ = (local, ptx, location); } @@ -264,7 +273,29 @@ pub trait MirVisitor { fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) { let _ = location; let _ = ptx; - visit_opaque(&Opaque(place.projection.clone())); + self.visit_local(&place.local, ptx, location); + + for elem in &place.projection { + self.visit_projection_elem(elem, ptx, location); + } + } + + fn super_projection_elem( + &mut self, + elem: &ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + match elem { + ProjectionElem::Deref => {} + ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), + ProjectionElem::Index(local) => self.visit_local(local, ptx, location), + ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {} + ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} + ProjectionElem::Downcast(_idx) => {} + ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), + ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), + } } fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) { From ae1726bfceffa271131d9ef852c1d553688aa6a4 Mon Sep 17 00:00:00 2001 From: Kirby Linvill Date: Fri, 10 Nov 2023 17:18:59 -0700 Subject: [PATCH 07/19] Ignore FieldIdx and VariantIdx examples in docs --- compiler/stable_mir/src/mir/body.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 48d4a3d37e2c..a5b51ce6a34d 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -498,7 +498,7 @@ pub const RETURN_LOCAL: Local = 0; /// The source-order index of a field in a variant. /// /// For example, in the following types, -/// ```rust +/// ```ignore(illustrative) /// enum Demo1 { /// Variant0 { a: bool, b: i32 }, /// Variant1 { c: u8, d: u64 }, @@ -514,7 +514,7 @@ type FieldIdx = usize; /// The source-order index of a variant in a type. /// /// For example, in the following types, -/// ```rust +/// ```ignore(illustrative) /// enum Demo1 { /// Variant0 { a: bool, b: i32 }, /// Variant1 { c: u8, d: u64 }, From 581a317bbbbad807fd88eab490516787f1e9249e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Nov 2023 13:34:20 +0100 Subject: [PATCH 08/19] rustc_log: provide a way to init logging based on the values, not names, of the env vars --- compiler/rustc_driver_impl/src/lib.rs | 10 +++--- compiler/rustc_log/src/lib.rs | 45 +++++++++++++++++++------ src/librustdoc/lib.rs | 3 +- src/tools/error_index_generator/main.rs | 3 +- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 84ae45d6a2b6..37c2a0094951 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1524,14 +1524,14 @@ fn report_ice( /// This allows tools to enable rust logging without having to magically match rustc's /// tracing crate version. pub fn init_rustc_env_logger(handler: &EarlyErrorHandler) { - init_env_logger(handler, "RUSTC_LOG"); + init_logger(handler, rustc_log::LoggerConfig::from_env("RUSTC_LOG")); } /// This allows tools to enable rust logging without having to magically match rustc's -/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var -/// other than `RUSTC_LOG`. -pub fn init_env_logger(handler: &EarlyErrorHandler, env: &str) { - if let Err(error) = rustc_log::init_env_logger(env) { +/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose +/// the values directly rather than having to set an environment variable. +pub fn init_logger(handler: &EarlyErrorHandler, cfg: rustc_log::LoggerConfig) { + if let Err(error) = rustc_log::init_logger(cfg) { handler.early_error(error.to_string()); } } diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index 0c9ec556549f..e3464cb8a2df 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -14,7 +14,7 @@ //! //! ``` //! fn main() { -//! rustc_log::init_env_logger("LOG").unwrap(); +//! rustc_log::init_logger(rustc_log::LoggerConfig::from_env("LOG")).unwrap(); //! //! let edition = rustc_span::edition::Edition::Edition2021; //! rustc_span::create_session_globals_then(edition, || { @@ -52,13 +52,36 @@ use tracing_subscriber::fmt::{ }; use tracing_subscriber::layer::SubscriberExt; -pub fn init_env_logger(env: &str) -> Result<(), Error> { - let filter = match env::var(env) { +/// The values of all the environment variables that matter for configuring a logger. +/// Errors are explicitly preserved so that we can share error handling. +pub struct LoggerConfig { + pub filter: Result, + pub color_logs: Result, + pub verbose_entry_exit: Result, + pub verbose_thread_ids: Result, + pub backtrace: Result, +} + +impl LoggerConfig { + pub fn from_env(env: &str) -> Self { + LoggerConfig { + filter: env::var(env), + color_logs: env::var(format!("{env}_COLOR")), + verbose_entry_exit: env::var(format!("{env}_ENTRY_EXIT")), + verbose_thread_ids: env::var(format!("{env}_THREAD_IDS")), + backtrace: env::var(format!("{env}_BACKTRACE")), + } + } +} + +/// Initialize the logger with the given values for the filter, coloring, and other options env variables. +pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> { + let filter = match cfg.filter { Ok(env) => EnvFilter::new(env), _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)), }; - let color_logs = match env::var(String::from(env) + "_COLOR") { + let color_logs = match cfg.color_logs { Ok(value) => match value.as_ref() { "always" => true, "never" => false, @@ -69,14 +92,14 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> { Err(VarError::NotUnicode(_value)) => return Err(Error::NonUnicodeColorValue), }; - let verbose_entry_exit = match env::var_os(String::from(env) + "_ENTRY_EXIT") { - None => false, - Some(v) => &v != "0", + let verbose_entry_exit = match cfg.verbose_entry_exit { + Ok(v) => &v != "0", + Err(_) => false, }; - let verbose_thread_ids = match env::var_os(String::from(env) + "_THREAD_IDS") { - None => false, - Some(v) => &v == "1", + let verbose_thread_ids = match cfg.verbose_thread_ids { + Ok(v) => &v == "1", + Err(_) => false, }; let layer = tracing_tree::HierarchicalLayer::default() @@ -91,7 +114,7 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> { .with_thread_names(verbose_thread_ids); let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); - match env::var(format!("{env}_BACKTRACE")) { + match cfg.backtrace { Ok(str) => { let fmt_layer = tracing_subscriber::fmt::layer() .with_writer(io::stderr) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index dda06d4c9c1d..a43ea5582b78 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -53,6 +53,7 @@ extern crate rustc_interface; extern crate rustc_lexer; extern crate rustc_lint; extern crate rustc_lint_defs; +extern crate rustc_log; extern crate rustc_macros; extern crate rustc_metadata; extern crate rustc_middle; @@ -175,7 +176,7 @@ pub fn main() { // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml). init_logging(&handler); - rustc_driver::init_env_logger(&handler, "RUSTDOC_LOG"); + rustc_driver::init_logger(&handler, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")); let exit_code = rustc_driver::catch_with_exit_code(|| match get_args(&handler) { Some(args) => main_args(&mut handler, &args, using_internal_features), diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 62a58576da55..3a23ff7fe6a7 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -1,6 +1,7 @@ #![feature(rustc_private)] extern crate rustc_driver; +extern crate rustc_log; extern crate rustc_session; use std::env; @@ -173,7 +174,7 @@ fn parse_args() -> (OutputFormat, PathBuf) { fn main() { let handler = rustc_session::EarlyErrorHandler::new(rustc_session::config::ErrorOutputType::default()); - rustc_driver::init_env_logger(&handler, "RUST_LOG"); + rustc_driver::init_logger(&handler, rustc_log::LoggerConfig::from_env("RUST_LOG")); let (format, dst) = parse_args(); let result = main_with_result(format, &dst); if let Err(e) = result { From 86e5d36c19d2cd53f55e8a2e0b8589f756ff7d66 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Nov 2023 13:44:45 +0100 Subject: [PATCH 09/19] Miri: use new init_logger function, avoid calling env::set_var --- src/tools/miri/src/bin/miri.rs | 68 +++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index cd628444fed9..7f777cd4727a 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -9,11 +9,12 @@ extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; +extern crate rustc_log; extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; -use std::env; +use std::env::{self, VarError}; use std::num::NonZeroU64; use std::path::PathBuf; use std::str::FromStr; @@ -183,45 +184,54 @@ macro_rules! show_error { ($($tt:tt)*) => { show_error(&format_args!($($tt)*)) }; } -fn init_early_loggers(handler: &EarlyErrorHandler) { - // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to - // initialize them both, and we always initialize `miri`'s first. - let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); - env_logger::init_from_env(env); - // Enable verbose entry/exit logging by default if MIRI_LOG is set. - if env::var_os("MIRI_LOG").is_some() && env::var_os("RUSTC_LOG_ENTRY_EXIT").is_none() { - env::set_var("RUSTC_LOG_ENTRY_EXIT", "1"); - } - // We only initialize `rustc` if the env var is set (so the user asked for it). - // If it is not set, we avoid initializing now so that we can initialize - // later with our custom settings, and *not* log anything for what happens before - // `miri` gets started. - if env::var_os("RUSTC_LOG").is_some() { - rustc_driver::init_rustc_env_logger(handler); - } -} +fn rustc_logger_config() -> rustc_log::LoggerConfig { + // Start with the usual env vars. + let mut cfg = rustc_log::LoggerConfig::from_env("RUSTC_LOG"); -fn init_late_loggers(handler: &EarlyErrorHandler, tcx: TyCtxt<'_>) { - // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG` - // env var if it is not set, control it based on `MIRI_LOG`. - // (FIXME: use `var_os`, but then we need to manually concatenate instead of `format!`.) + // Overwrite if MIRI_LOG is set. if let Ok(var) = env::var("MIRI_LOG") { - if env::var_os("RUSTC_LOG").is_none() { + // MIRI_LOG serves as default for RUSTC_LOG, if that is not set. + if matches!(cfg.filter, Err(VarError::NotPresent)) { // We try to be a bit clever here: if `MIRI_LOG` is just a single level // used for everything, we only apply it to the parts of rustc that are // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`. // This way, if you set `MIRI_LOG=trace`, you get only the right parts of // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_const_eval::interpret=debug`. if log::Level::from_str(&var).is_ok() { - env::set_var( - "RUSTC_LOG", - format!("rustc_middle::mir::interpret={var},rustc_const_eval::interpret={var}"), - ); + cfg.filter = Ok(format!( + "rustc_middle::mir::interpret={var},rustc_const_eval::interpret={var}" + )); } else { - env::set_var("RUSTC_LOG", &var); + cfg.filter = Ok(var); } - rustc_driver::init_rustc_env_logger(handler); } + // Enable verbose entry/exit logging by default if MIRI_LOG is set. + if matches!(cfg.verbose_entry_exit, Err(VarError::NotPresent)) { + cfg.verbose_entry_exit = Ok(format!("1")); + } + } + + cfg +} + +fn init_early_loggers(handler: &EarlyErrorHandler) { + // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to + // initialize them both, and we always initialize `miri`'s first. + let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); + env_logger::init_from_env(env); + // Now for rustc. We only initialize `rustc` if the env var is set (so the user asked for it). + // If it is not set, we avoid initializing now so that we can initialize later with our custom + // settings, and *not* log anything for what happens before `miri` gets started. + if env::var_os("RUSTC_LOG").is_some() { + rustc_driver::init_logger(handler, rustc_logger_config()); + } +} + +fn init_late_loggers(handler: &EarlyErrorHandler, tcx: TyCtxt<'_>) { + // If `RUSTC_LOG` is not set, then `init_early_loggers` did not call + // `rustc_driver::init_logger`, so we have to do this now. + if env::var_os("RUSTC_LOG").is_none() { + rustc_driver::init_logger(handler, rustc_logger_config()); } // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`. From 732b4bb664e2d393dcb42dca0008d1570bd6d3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 11 Nov 2023 15:48:13 +0100 Subject: [PATCH 10/19] Make rustc_parse_format compile on stable again --- compiler/rustc_parse_format/src/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 7b6153eea09b..e886db3da296 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -9,13 +9,10 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] -#![cfg_attr(not(bootstrap), doc(rust_logo))] -#![cfg_attr(not(bootstrap), allow(internal_features))] -#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -// We want to be able to build this crate with a stable compiler, so no -// `#![feature]` attributes should be added. +// WARNING: We want to be able to build this crate with a stable compiler, +// so no `#![feature]` attributes should be added! use rustc_lexer::unescape; pub use Alignment::*; From 2e6b57541dc28cdd954b1ce2300b88ccc5c29d5c Mon Sep 17 00:00:00 2001 From: Paul Menage Date: Mon, 9 Oct 2023 02:22:14 -0700 Subject: [PATCH 11/19] Add -Z llvm_module_flag Allow adding values to the `!llvm.module.flags` metadata for a generated module. The syntax is `-Z llvm_module_flag=:::` Currently only u32 values are supported but the type is required to be specified for forward compatibility. The `behavior` element must match one of the named LLVM metadata behaviors.viors. This flag is expected to be perma-unstable. --- compiler/rustc_codegen_llvm/src/context.rs | 18 +++++++++++ compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 30 +++++++++++++++++++ .../src/compiler-flags/llvm-module-flag.md | 12 ++++++++ tests/codegen/llvm_module_flags.rs | 7 +++++ 5 files changed, 68 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/llvm-module-flag.md create mode 100644 tests/codegen/llvm_module_flags.rs diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4dd6372b5e04..242c6aed906b 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -368,6 +368,24 @@ pub unsafe fn create_module<'ll>( llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), ); + // Add module flags specified via -Z llvm_module_flag + for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag { + let key = format!("{key}\0"); + let behavior = match behavior.as_str() { + "error" => llvm::LLVMModFlagBehavior::Error, + "warning" => llvm::LLVMModFlagBehavior::Warning, + "require" => llvm::LLVMModFlagBehavior::Require, + "override" => llvm::LLVMModFlagBehavior::Override, + "append" => llvm::LLVMModFlagBehavior::Append, + "appendunique" => llvm::LLVMModFlagBehavior::AppendUnique, + "max" => llvm::LLVMModFlagBehavior::Max, + "min" => llvm::LLVMModFlagBehavior::Min, + // We already checked this during option parsing + _ => unreachable!(), + }; + llvm::LLVMRustAddModuleFlag(llmod, behavior, key.as_ptr().cast(), *value) + } + llmod } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index d30816955231..8be23f8e4f30 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -771,6 +771,7 @@ fn test_unstable_options_tracking_hash() { tracked!(instrument_xray, Some(InstrumentXRay::default())); tracked!(link_directives, false); tracked!(link_only, true); + tracked!(llvm_module_flag, vec![("bar".to_string(), 123, "max".to_string())]); tracked!(llvm_plugins, vec![String::from("plugin_name")]); tracked!(location_detail, LocationDetail { file: true, line: false, column: false }); tracked!(maximal_hir_to_mir_coverage, true); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 76d69646f1df..2840c783aa80 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -429,6 +429,7 @@ mod desc { pub const parse_remap_path_scope: &str = "comma separated list of scopes: `macro`, `diagnostics`, `unsplit-debuginfo`, `split-debuginfo`, `split-debuginfo-path`, `object`, `all`"; pub const parse_inlining_threshold: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; + pub const parse_llvm_module_flag: &str = ":::. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; } mod parse { @@ -1331,6 +1332,33 @@ mod parse { } true } + + pub(crate) fn parse_llvm_module_flag( + slot: &mut Vec<(String, u32, String)>, + v: Option<&str>, + ) -> bool { + let elements = v.unwrap_or_default().split(':').collect::>(); + let [key, md_type, value, behavior] = elements.as_slice() else { + return false; + }; + if *md_type != "u32" { + // Currently we only support u32 metadata flags, but require the + // type for forward-compatibility. + return false; + } + let Ok(value) = value.parse::() else { + return false; + }; + let behavior = behavior.to_lowercase(); + let all_behaviors = + ["error", "warning", "require", "override", "append", "appendunique", "max", "min"]; + if !all_behaviors.contains(&behavior.as_str()) { + return false; + } + + slot.push((key.to_string(), value, behavior)); + true + } } options! { @@ -1631,6 +1659,8 @@ options! { "link native libraries in the linker invocation (default: yes)"), link_only: bool = (false, parse_bool, [TRACKED], "link the `.rlink` file generated by `-Z no-link` (default: no)"), + llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED], + "a list of module flags to pass to LLVM (space separated)"), llvm_plugins: Vec = (Vec::new(), parse_list, [TRACKED], "a list LLVM plugins to enable (space separated)"), llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/doc/unstable-book/src/compiler-flags/llvm-module-flag.md b/src/doc/unstable-book/src/compiler-flags/llvm-module-flag.md new file mode 100644 index 000000000000..454ad0a9a6dd --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/llvm-module-flag.md @@ -0,0 +1,12 @@ +# `llvm-module-flag` + +--------------------- + +This flag allows adding a key/value to the `!llvm.module.flags` metadata in the +LLVM-IR for a compiled Rust module. The syntax is + +`-Z llvm_module_flag=:::` + +Currently only u32 values are supported but the type is required to be specified +for forward compatibility. The `behavior` element must match one of the named +LLVM [metadata behaviors](https://llvm.org/docs/LangRef.html#module-flags-metadata) diff --git a/tests/codegen/llvm_module_flags.rs b/tests/codegen/llvm_module_flags.rs new file mode 100644 index 000000000000..acc035086de2 --- /dev/null +++ b/tests/codegen/llvm_module_flags.rs @@ -0,0 +1,7 @@ +// Test for -Z llvm_module_flags +// compile-flags: -Z llvm_module_flag=foo:u32:123:error -Z llvm_module_flag=bar:u32:42:max + +fn main() {} + +// CHECK: !{i32 1, !"foo", i32 123} +// CHECK: !{i32 7, !"bar", i32 42} From 99664b0bbf0ef05ae2b004017c8da63a3ffbdbe9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 12 Nov 2023 19:59:04 +0000 Subject: [PATCH 12/19] Don't expect a rcvr in print_disambiguation_help --- .../rustc_hir_typeck/src/method/suggest.rs | 8 +++-- tests/ui/methods/method-ambiguity-no-rcvr.rs | 14 ++++++++ .../methods/method-ambiguity-no-rcvr.stderr | 32 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 tests/ui/methods/method-ambiguity-no-rcvr.rs create mode 100644 tests/ui/methods/method-ambiguity-no-rcvr.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index b1a2df8ace40..62cad095c184 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3264,8 +3264,12 @@ fn print_disambiguation_help<'tcx>( { let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id); let item_name = item.ident(tcx); - let rcvr_ref = tcx.fn_sig(item.def_id).skip_binder().skip_binder().inputs()[0] - .ref_mutability() + let rcvr_ref = tcx.fn_sig(item.def_id) + .skip_binder() + .skip_binder() + .inputs() + .get(0) + .and_then(|ty| ty.ref_mutability()) .map_or("", |mutbl| mutbl.ref_prefix_str()); let args = format!( "({}{})", diff --git a/tests/ui/methods/method-ambiguity-no-rcvr.rs b/tests/ui/methods/method-ambiguity-no-rcvr.rs new file mode 100644 index 000000000000..8f36011d41f9 --- /dev/null +++ b/tests/ui/methods/method-ambiguity-no-rcvr.rs @@ -0,0 +1,14 @@ +struct Qux; + +trait Foo { + fn foo(); +} + +trait FooBar { + fn foo() {} +} + +fn main() { + Qux.foo(); + //~^ ERROR no method named `foo` found for struct `Qux` in the current scope +} diff --git a/tests/ui/methods/method-ambiguity-no-rcvr.stderr b/tests/ui/methods/method-ambiguity-no-rcvr.stderr new file mode 100644 index 000000000000..95c9d7ebac02 --- /dev/null +++ b/tests/ui/methods/method-ambiguity-no-rcvr.stderr @@ -0,0 +1,32 @@ +error[E0599]: no method named `foo` found for struct `Qux` in the current scope + --> $DIR/method-ambiguity-no-rcvr.rs:12:9 + | +LL | struct Qux; + | ---------- method `foo` not found for this struct +... +LL | Qux.foo(); + | ^^^ this is an associated function, not a method + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: candidate #1 is defined in the trait `Foo` + --> $DIR/method-ambiguity-no-rcvr.rs:4:5 + | +LL | fn foo(); + | ^^^^^^^^^ +note: candidate #2 is defined in the trait `FooBar` + --> $DIR/method-ambiguity-no-rcvr.rs:8:5 + | +LL | fn foo() {} + | ^^^^^^^^ +help: disambiguate the associated function for candidate #1 + | +LL | ::foo(Qux); + | ~~~~~~~~~~~~~~~~~~~~~~ +help: disambiguate the associated function for candidate #2 + | +LL | ::foo(Qux); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. From 60d99ab8837e973c0df5fe518a2ed136c8ac0f20 Mon Sep 17 00:00:00 2001 From: Gavin Gray Date: Mon, 13 Nov 2023 16:36:01 +0100 Subject: [PATCH 13/19] Fix overflow and cycle bound for ProofTreeVisitor. --- compiler/rustc_trait_selection/src/solve/inspect/analyse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 69bfdd4688ca..951080ac61a5 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -58,7 +58,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { visitor: &mut V, ) -> ControlFlow { // HACK: An arbitrary cutoff to avoid dealing with overflow and cycles. - if self.goal.depth >= 10 { + if self.goal.depth <= 10 { let infcx = self.goal.infcx; infcx.probe(|_| { let mut instantiated_goals = vec![]; From caae1e08ecfa67f5ab3ccf8b7edf20c252c2268a Mon Sep 17 00:00:00 2001 From: Gavin Gray Date: Tue, 14 Nov 2023 13:55:59 +0100 Subject: [PATCH 14/19] Add guard checking for associated types before computing intercrate ambiguity of projections. Bless test with more specific notes on the ambiguity cause. --- compiler/rustc_trait_selection/src/traits/coherence.rs | 8 +++++++- tests/ui/impl-trait/auto-trait-coherence.next.stderr | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index dcf5fd869290..87cc8b09c0ee 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -20,6 +20,7 @@ use crate::traits::{ }; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{util, TraitEngine}; @@ -1002,7 +1003,12 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { // and then prove the resulting predicate as a nested goal. let trait_ref = match predicate.kind().no_bound_vars() { Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref, - Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))) => { + Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))) + if matches!( + infcx.tcx.def_kind(proj.projection_ty.def_id), + DefKind::AssocTy | DefKind::AssocConst + ) => + { proj.projection_ty.trait_ref(infcx.tcx) } _ => return ControlFlow::Continue(()), diff --git a/tests/ui/impl-trait/auto-trait-coherence.next.stderr b/tests/ui/impl-trait/auto-trait-coherence.next.stderr index 7833ac688bab..cee359997b4f 100644 --- a/tests/ui/impl-trait/auto-trait-coherence.next.stderr +++ b/tests/ui/impl-trait/auto-trait-coherence.next.stderr @@ -6,6 +6,8 @@ LL | impl AnotherTrait for T {} ... LL | impl AnotherTrait for D { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` + | + = note: upstream crates may add a new impl of trait `std::marker::Send` for type `OpaqueType` in future versions error: aborting due to previous error From 15f21562e627cb37e74d5e27f22eafc76cf4ec01 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 14 Nov 2023 13:13:27 +0000 Subject: [PATCH 15/19] finish `RegionKind` rename - `ReFree` -> `ReLateParam` - `ReEarlyBound` -> `ReEarlyParam` --- .../src/diagnostics/outlives_suggestion.rs | 4 +- .../src/diagnostics/region_errors.rs | 8 +-- .../src/diagnostics/region_name.rs | 43 +++++++------ .../src/region_infer/opaque_types.rs | 4 +- .../rustc_borrowck/src/universal_regions.rs | 8 +-- .../rustc_hir_analysis/src/astconv/mod.rs | 4 +- .../src/check/compare_impl_item.rs | 20 +++--- .../rustc_hir_analysis/src/check/dropck.rs | 3 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 12 ++-- .../src/coherence/builtin.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/collect/predicates_of.rs | 6 +- .../src/collect/resolve_bound_vars.rs | 2 +- .../src/constrained_generic_params.rs | 6 +- .../rustc_hir_analysis/src/outlives/utils.rs | 6 +- .../src/variance/constraints.rs | 4 +- .../rustc_hir_analysis/src/variance/mod.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 2 +- .../src/errors/note_and_explain.rs | 6 +- .../src/infer/canonical/canonicalizer.rs | 12 ++-- .../src/infer/error_reporting/mod.rs | 22 ++++--- .../nice_region_error/different_lifetimes.rs | 4 +- .../error_reporting/nice_region_error/util.rs | 4 +- .../rustc_infer/src/infer/free_regions.rs | 16 ++--- compiler/rustc_infer/src/infer/freshen.rs | 4 +- compiler/rustc_infer/src/infer/generalize.rs | 4 +- .../src/infer/lexical_region_resolve/mod.rs | 26 ++++---- compiler/rustc_infer/src/infer/mod.rs | 9 ++- .../rustc_infer/src/infer/outlives/env.rs | 4 +- .../src/infer/region_constraints/mod.rs | 4 +- compiler/rustc_lint/src/builtin.rs | 4 +- compiler/rustc_middle/src/infer/unify_key.rs | 4 +- compiler/rustc_middle/src/middle/region.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 34 +++++----- compiler/rustc_middle/src/ty/fold.rs | 2 +- compiler/rustc_middle/src/ty/generic_args.rs | 8 +-- compiler/rustc_middle/src/ty/generics.rs | 10 +-- compiler/rustc_middle/src/ty/mod.rs | 13 ++-- compiler/rustc_middle/src/ty/opaque_types.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 8 +-- .../rustc_middle/src/ty/structural_impls.rs | 6 +- compiler/rustc_middle/src/ty/sty.rs | 58 +++++++++-------- .../rustc_middle/src/ty/typeck_results.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 22 ++++--- compiler/rustc_smir/src/rustc_smir/mod.rs | 4 +- .../src/typeid/typeid_itanium_cxx_abi.rs | 6 +- .../src/solve/canonicalize.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 2 +- compiler/rustc_ty_utils/src/implied_bounds.rs | 18 +++--- compiler/rustc_ty_utils/src/opaque_types.rs | 8 +-- compiler/rustc_type_ir/src/flags.rs | 2 +- compiler/rustc_type_ir/src/interner.rs | 4 +- compiler/rustc_type_ir/src/region_kind.rs | 64 +++++++++++-------- compiler/stable_mir/src/ty.rs | 4 +- src/librustdoc/clean/auto_trait.rs | 4 +- src/librustdoc/clean/mod.rs | 10 +-- .../clippy_lints/src/pass_by_ref_or_value.rs | 2 +- src/tools/clippy/clippy_lints/src/ptr.rs | 4 +- ...erased-regions-in-hidden-ty.current.stderr | 2 +- .../erased-regions-in-hidden-ty.next.stderr | 2 +- .../ty-outlives/impl-trait-captures.stderr | 8 +-- 61 files changed, 300 insertions(+), 274 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index b6eb9ae980e4..94981c455820 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -50,8 +50,8 @@ impl OutlivesSuggestionBuilder { // naming the `'self` lifetime in methods, etc. fn region_name_is_suggestable(name: &RegionName) -> bool { match name.source { - RegionNameSource::NamedEarlyBoundRegion(..) - | RegionNameSource::NamedFreeRegion(..) + RegionNameSource::NamedEarlyParamRegion(..) + | RegionNameSource::NamedLateParamRegion(..) | RegionNameSource::Static => true, // Don't give suggestions for upvars, closure return types, or other unnameable diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index a0a809123c0f..e3927403939c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -181,8 +181,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// Returns `true` if a closure is inferred to be an `FnMut` closure. fn is_closure_fn_mut(&self, fr: RegionVid) -> bool { - if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref() - && let ty::BoundRegionKind::BrEnv = free_region.bound_region + if let Some(ty::ReLateParam(late_param)) = self.to_error_region(fr).as_deref() + && let ty::BoundRegionKind::BrEnv = late_param.bound_region && let DefiningTy::Closure(_, args) = self.regioncx.universal_regions().defining_ty { return args.as_closure().kind() == ty::ClosureKind::FnMut; @@ -995,7 +995,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .infcx .tcx .is_suitable_region(sub) - .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.boundregion)) + .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.bound_region)) else { return; }; @@ -1004,7 +1004,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .infcx .tcx .is_suitable_region(sup) - .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.boundregion)) + .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.bound_region)) else { return; }; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 9d6b0a0e91ba..fee35485cd7e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -23,14 +23,14 @@ pub(crate) struct RegionName { } /// Denotes the source of a region that is named by a `RegionName`. For example, a free region that -/// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`. +/// was named by the user would get `NamedLateParamRegion` and `'static` lifetime would get `Static`. /// This helps to print the right kinds of diagnostics. #[derive(Debug, Clone)] pub(crate) enum RegionNameSource { /// A bound (not free) region that was instantiated at the def site (not an HRTB). - NamedEarlyBoundRegion(Span), + NamedEarlyParamRegion(Span), /// A free region that the user has a name (`'a`) for. - NamedFreeRegion(Span), + NamedLateParamRegion(Span), /// The `'static` region. Static, /// The free region corresponding to the environment of a closure. @@ -69,8 +69,8 @@ pub(crate) enum RegionNameHighlight { impl RegionName { pub(crate) fn was_named(&self) -> bool { match self.source { - RegionNameSource::NamedEarlyBoundRegion(..) - | RegionNameSource::NamedFreeRegion(..) + RegionNameSource::NamedEarlyParamRegion(..) + | RegionNameSource::NamedLateParamRegion(..) | RegionNameSource::Static => true, RegionNameSource::SynthesizedFreeEnvRegion(..) | RegionNameSource::AnonRegionFromArgument(..) @@ -85,8 +85,8 @@ impl RegionName { pub(crate) fn span(&self) -> Option { match self.source { RegionNameSource::Static => None, - RegionNameSource::NamedEarlyBoundRegion(span) - | RegionNameSource::NamedFreeRegion(span) + RegionNameSource::NamedEarlyParamRegion(span) + | RegionNameSource::NamedLateParamRegion(span) | RegionNameSource::SynthesizedFreeEnvRegion(span, _) | RegionNameSource::AnonRegionFromUpvar(span, _) | RegionNameSource::AnonRegionFromYieldTy(span, _) @@ -104,8 +104,8 @@ impl RegionName { pub(crate) fn highlight_region_name(&self, diag: &mut Diagnostic) { match &self.source { - RegionNameSource::NamedFreeRegion(span) - | RegionNameSource::NamedEarlyBoundRegion(span) => { + RegionNameSource::NamedLateParamRegion(span) + | RegionNameSource::NamedEarlyParamRegion(span) => { diag.span_label(*span, format!("lifetime `{self}` defined here")); } RegionNameSource::SynthesizedFreeEnvRegion(span, note) => { @@ -280,28 +280,31 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { debug!("give_region_a_name: error_region = {:?}", error_region); match *error_region { - ty::ReEarlyBound(ebr) => ebr.has_name().then(|| { + ty::ReEarlyParam(ebr) => ebr.has_name().then(|| { let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP); - RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyBoundRegion(span) } + RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyParamRegion(span) } }), ty::ReStatic => { Some(RegionName { name: kw::StaticLifetime, source: RegionNameSource::Static }) } - ty::ReFree(free_region) => match free_region.bound_region { + ty::ReLateParam(late_param) => match late_param.bound_region { ty::BoundRegionKind::BrNamed(region_def_id, name) => { // Get the span to point to, even if we don't use the name. let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP); debug!( "bound region named: {:?}, is_named: {:?}", name, - free_region.bound_region.is_named() + late_param.bound_region.is_named() ); - if free_region.bound_region.is_named() { + if late_param.bound_region.is_named() { // A named region that is actually named. - Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) }) + Some(RegionName { + name, + source: RegionNameSource::NamedLateParamRegion(span), + }) } else if tcx.asyncness(self.mir_hir_id().owner).is_async() { // If we spuriously thought that the region is named, we should let the // system generate a true name for error messages. Currently this can @@ -847,7 +850,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { &self, fr: RegionVid, ) -> Option { - let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { + let ty::ReEarlyParam(region) = *self.to_error_region(fr)? else { return None; }; if region.has_name() { @@ -862,7 +865,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let found = tcx .any_free_region_meets(&tcx.type_of(region_parent).instantiate_identity(), |r| { - *r == ty::ReEarlyBound(region) + *r == ty::ReEarlyParam(region) }); Some(RegionName { @@ -881,7 +884,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { &self, fr: RegionVid, ) -> Option { - let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { + let ty::ReEarlyParam(region) = *self.to_error_region(fr)? else { return None; }; if region.has_name() { @@ -943,7 +946,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { &self, clauses: &[ty::Clause<'tcx>], ty: Ty<'tcx>, - region: ty::EarlyBoundRegion, + region: ty::EarlyParamRegion, ) -> bool { let tcx = self.infcx.tcx; ty.walk().any(|arg| { @@ -956,7 +959,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {} _ => return false, } - tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyBound(region)) + tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyParam(region)) }) } else { false diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index fb0e5811c267..c93cfa78832a 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -36,7 +36,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// call `infer_opaque_definition_from_instantiation` to get the inferred /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation` /// compares lifetimes directly, so we need to map the inference variables - /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`. + /// back to concrete lifetimes: `'static`, `ReEarlyParam` or `ReLateParam`. /// /// First we map all the lifetimes in the concrete type to an equal /// universal region that occurs in the concrete type's args, in this case @@ -386,7 +386,7 @@ fn check_opaque_type_parameter_valid( let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Lifetime(lt) if is_ty_alias => { - matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) + matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_)) } // FIXME(#113916): we can't currently check for unique lifetime params, // see that issue for more. We will also have to ignore unused lifetime diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index ae7f9c5244c3..02f94e5b9728 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -462,7 +462,6 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // "Liberate" the late-bound regions. These correspond to // "local" free regions. - let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( @@ -784,7 +783,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { debug!(?br); let liberated_region = - ty::Region::new_free(self.tcx, all_outlive_scope.to_def_id(), br.kind); + ty::Region::new_late_param(self.tcx, all_outlive_scope.to_def_id(), br.kind); let region_vid = { let name = match br.kind.get_name() { Some(name) => name, @@ -854,7 +853,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// Initially, the `UniversalRegionIndices` map contains only the /// early-bound regions in scope. Once that is all setup, we come /// in later and instantiate the late-bound regions, and then we - /// insert the `ReFree` version of those into the map as + /// insert the `ReLateParam` version of those into the map as /// well. These are used for error reporting. fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) { debug!("insert_late_bound_region({:?}, {:?})", r, vid); @@ -933,7 +932,8 @@ fn for_each_late_bound_region_in_item<'tcx>( let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; }; - let liberated_region = ty::Region::new_free(tcx, mir_def_id.to_def_id(), bound_region); + let liberated_region = + ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), bound_region); f(liberated_region); } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 5a9c67a6a9d2..8126b4511813 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -258,12 +258,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; - ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion { def_id, index, name }) + ty::Region::new_early_param(tcx, ty::EarlyParamRegion { def_id, index, name }) } Some(rbv::ResolvedArg::Free(scope, id)) => { let name = lifetime_name(id.expect_local()); - ty::Region::new_free(tcx, scope, ty::BrNamed(id, name)) + ty::Region::new_late_param(tcx, scope, ty::BrNamed(id, name)) // (*) -- not late-bound, won't change } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index d3a383ff7c55..f026f78cc2b4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -532,8 +532,8 @@ impl<'tcx> TypeFolder> for RemapLateBound<'_, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReFree(fr) = *r { - ty::Region::new_free( + if let ty::ReLateParam(fr) = *r { + ty::Region::new_late_param( self.tcx, fr.scope, self.mapping.get(&fr.bound_region).copied().unwrap_or(fr.bound_region), @@ -1078,20 +1078,20 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { region: ty::Region<'tcx>, ) -> Result, Self::Error> { match region.kind() { - // Remap all free regions, which correspond to late-bound regions in the function. - ty::ReFree(_) => {} + // Remap late-bound regions from the function. + ty::ReLateParam(_) => {} // Remap early-bound regions as long as they don't come from the `impl` itself, // in which case we don't really need to renumber them. - ty::ReEarlyBound(ebr) if self.tcx.parent(ebr.def_id) != self.impl_def_id => {} + ty::ReEarlyParam(ebr) if self.tcx.parent(ebr.def_id) != self.impl_def_id => {} _ => return Ok(region), } let e = if let Some(region) = self.map.get(®ion) { - if let ty::ReEarlyBound(e) = region.kind() { e } else { bug!() } + if let ty::ReEarlyParam(e) = region.kind() { e } else { bug!() } } else { let guar = match region.kind() { - ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) - | ty::ReFree(ty::FreeRegion { + ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. }) + | ty::ReLateParam(ty::LateParamRegion { bound_region: ty::BoundRegionKind::BrNamed(def_id, _), .. }) => { @@ -1119,9 +1119,9 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { return Err(guar); }; - Ok(ty::Region::new_early_bound( + Ok(ty::Region::new_early_param( self.tcx, - ty::EarlyBoundRegion { + ty::EarlyParamRegion { def_id: e.def_id, name: e.name, index: (e.index as usize - self.num_trait_args + self.num_impl_args) as u32, diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index dda3f7425697..0a05c1039b6e 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -81,8 +81,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( self_type_did: DefId, adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_args, CheckRegions::OnlyEarlyBound) - else { + let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_args, CheckRegions::OnlyParam) else { return Ok(()); }; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 729e9f2f1d17..d7b50d127cd8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -595,9 +595,9 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( // Same for the region. In our example, 'a corresponds // to the 'me parameter. let region_param = gat_generics.param_at(*region_a_idx, tcx); - let region_param = ty::Region::new_early_bound( + let region_param = ty::Region::new_early_param( tcx, - ty::EarlyBoundRegion { + ty::EarlyParamRegion { def_id: region_param.def_id, index: region_param.index, name: region_param.name, @@ -628,9 +628,9 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. let region_a_param = gat_generics.param_at(*region_a_idx, tcx); - let region_a_param = ty::Region::new_early_bound( + let region_a_param = ty::Region::new_early_param( tcx, - ty::EarlyBoundRegion { + ty::EarlyParamRegion { def_id: region_a_param.def_id, index: region_a_param.index, name: region_a_param.name, @@ -638,9 +638,9 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( ); // Same for the region. let region_b_param = gat_generics.param_at(*region_b_idx, tcx); - let region_b_param = ty::Region::new_early_bound( + let region_b_param = ty::Region::new_early_param( tcx, - ty::EarlyBoundRegion { + ty::EarlyParamRegion { def_id: region_b_param.def_id, index: region_b_param.index, name: region_b_param.name, diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index e5e192e0079b..f277badf275b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -550,7 +550,7 @@ fn infringing_fields_error( .entry((ty.clone(), predicate.clone())) .or_default() .push(origin.span()); - if let ty::RegionKind::ReEarlyBound(ebr) = *b + if let ty::RegionKind::ReEarlyParam(ebr) = *b && ebr.has_name() { bounds.push((b.to_string(), a.to_string(), None)); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 9636c6144461..1e75b8631655 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -443,7 +443,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx.replace_late_bound_regions_uncached( poly_trait_ref, |_| { - ty::Region::new_early_bound(self.tcx, ty::EarlyBoundRegion { + ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion { def_id: item_def_id, index: 0, name: Symbol::intern(<_name), diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 104da581e019..68d040d58460 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -362,10 +362,10 @@ fn compute_bidirectional_outlives_predicates<'tcx>( ) { for param in opaque_own_params { let orig_lifetime = tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()); - if let ty::ReEarlyBound(..) = *orig_lifetime { - let dup_lifetime = ty::Region::new_early_bound( + if let ty::ReEarlyParam(..) = *orig_lifetime { + let dup_lifetime = ty::Region::new_early_param( tcx, - ty::EarlyBoundRegion { def_id: param.def_id, index: param.index, name: param.name }, + ty::EarlyParamRegion { def_id: param.def_id, index: param.index, name: param.name }, ); let span = tcx.def_span(param.def_id); predicates.push(( diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index d51e9eb5983a..53efc2c6e828 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -2012,7 +2012,7 @@ fn is_late_bound_map( fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { debug!("r={:?}", r.kind()); - if let ty::RegionKind::ReEarlyBound(region) = r.kind() { + if let ty::RegionKind::ReEarlyParam(region) = r.kind() { self.arg_is_constrained[region.index as usize] = true; } diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index ed5e9dd2b5ad..65d1ffa40e2e 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -13,8 +13,8 @@ impl From for Parameter { } } -impl From for Parameter { - fn from(param: ty::EarlyBoundRegion) -> Self { +impl From for Parameter { + fn from(param: ty::EarlyParamRegion) -> Self { Parameter(param.index) } } @@ -73,7 +73,7 @@ impl<'tcx> TypeVisitor> for ParameterCollector { } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - if let ty::ReEarlyBound(data) = *r { + if let ty::ReEarlyParam(data) = *r { self.parameters.push(Parameter::from(data)); } ControlFlow::Continue(()) diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 85703c60c30a..218f658b061c 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -146,11 +146,11 @@ fn is_free_region(region: Region<'_>) -> bool { // These correspond to `T: 'a` relationships: // // struct Foo<'a, T> { - // field: &'a T, // this would generate a ReEarlyBound referencing `'a` + // field: &'a T, // this would generate a ReEarlyParam referencing `'a` // } // // We care about these, so fall through. - ty::ReEarlyBound(_) => true, + ty::ReEarlyParam(_) => true, // These correspond to `T: 'static` relationships which can be // rather surprising. @@ -173,7 +173,7 @@ fn is_free_region(region: Region<'_>) -> bool { ty::ReError(_) => false, // These regions don't appear in types from type declarations: - ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReFree(..) => { + ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReLateParam(..) => { bug!("unexpected region in outlives inference: {:?}", region); } } diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 6c1efb6470e8..f09594cbbc66 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -413,7 +413,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { variance: VarianceTermPtr<'a>, ) { match *region { - ty::ReEarlyBound(ref data) => { + ty::ReEarlyParam(ref data) => { self.add_constraint(current, data.index, variance); } @@ -428,7 +428,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::ReError(_) => {} - ty::ReFree(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => { + ty::ReLateParam(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => { // We don't expect to see anything but 'static or bound // regions when visiting member types or method types. bug!( diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 9fb39a0e93b6..410706110c96 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -106,7 +106,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc impl<'tcx> ty::TypeVisitor> for OpaqueTypeLifetimeCollector<'tcx> { #[instrument(level = "trace", skip(self), ret)] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() { + if let ty::RegionKind::ReEarlyParam(ebr) = r.kind() { self.variances[ebr.index as usize] = ty::Invariant; } ControlFlow::Continue(()) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index a1ce5983f30e..bd653e799132 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -238,7 +238,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option> { let v = match def { - Some(def) => infer::EarlyBoundRegion(span, def.name), + Some(def) => infer::RegionParameterDefinition(span, def.name), None => infer::MiscVariable(span), }; Some(self.next_region_var(v)) diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 869878420aeb..294bd9d1d54b 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -17,7 +17,7 @@ impl<'a> DescriptionCtx<'a> { alt_span: Option, ) -> Option { let (span, kind, arg) = match *region { - ty::ReEarlyBound(ref br) => { + ty::ReEarlyParam(ref br) => { let scope = region.free_region_binding_scope(tcx).expect_local(); let span = if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) @@ -32,7 +32,7 @@ impl<'a> DescriptionCtx<'a> { (Some(span), "as_defined_anon", String::new()) } } - ty::ReFree(ref fr) => { + ty::ReLateParam(ref fr) => { if !fr.bound_region.is_named() && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) { @@ -70,7 +70,7 @@ impl<'a> DescriptionCtx<'a> { ty::RePlaceholder(_) | ty::ReError(_) => return None, // FIXME(#13998) RePlaceholder should probably print like - // ReFree rather than dumping Debug output on the user. + // ReLateParam rather than dumping Debug output on the user. // // We shouldn't really be having unification failures with ReVar // and ReBound though. diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index ba7007d908f6..b502590c1bfb 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -172,7 +172,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { match *r { - ty::ReFree(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r, + ty::ReLateParam(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyParam(..) => r, ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region( CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) }, @@ -223,7 +223,11 @@ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation { r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { match *r { - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic | ty::ReError(_) => r, + ty::ReEarlyParam(_) + | ty::ReLateParam(_) + | ty::ReErased + | ty::ReStatic + | ty::ReError(_) => r, ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r), ty::RePlaceholder(..) | ty::ReBound(..) => { // We only expect region names that the user can type. @@ -359,9 +363,9 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } ty::ReStatic - | ty::ReEarlyBound(..) + | ty::ReEarlyParam(..) | ty::ReError(_) - | ty::ReFree(_) + | ty::ReLateParam(_) | ty::RePlaceholder(..) | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r), } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index f09a33be839b..0546f4e1afc3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -168,7 +168,7 @@ pub(super) fn note_and_explain_region<'tcx>( alt_span: Option, ) { let (description, span) = match *region { - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::RePlaceholder(_) | ty::ReStatic => { + ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => { msg_span_from_named_region(tcx, region, alt_span) } @@ -202,7 +202,7 @@ fn msg_span_from_named_region<'tcx>( alt_span: Option, ) -> (String, Option) { match *region { - ty::ReEarlyBound(ref br) => { + ty::ReEarlyParam(ref br) => { let scope = region.free_region_binding_scope(tcx).expect_local(); let span = if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) @@ -218,7 +218,7 @@ fn msg_span_from_named_region<'tcx>( }; (text, Some(span)) } - ty::ReFree(ref fr) => { + ty::ReLateParam(ref fr) => { if !fr.bound_region.is_named() && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) { @@ -315,7 +315,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( // Explain the region we are capturing. match *hidden_region { - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { + ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => { // Assuming regionck succeeded (*), we ought to always be // capturing *some* region from the fn header, and hence it // ought to be free. So under normal circumstances, we will go @@ -2364,7 +2364,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span, format!("{labeled_user_string} may not live long enough"), match sub.kind() { - ty::ReEarlyBound(_) | ty::ReFree(_) if sub.has_name() => error_code!(E0309), + ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => error_code!(E0309), ty::ReStatic => error_code!(E0310), _ => error_code!(E0311), }, @@ -2372,7 +2372,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { '_explain: { let (description, span) = match sub.kind() { - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { + ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => { msg_span_from_named_region(self.tcx, sub, Some(span)) } _ => (format!("lifetime `{sub}`"), Some(span)), @@ -2515,7 +2515,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (lifetime_def_id, lifetime_scope) = match self.tcx.is_suitable_region(lifetime) { Some(info) if !lifetime.has_name() => { - (info.boundregion.get_id().unwrap().expect_local(), info.def_id) + (info.bound_region.get_id().unwrap().expect_local(), info.def_id) } _ => return lifetime.get_name_or_anon().to_string(), }; @@ -2714,8 +2714,8 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - if (a.is_var() && b.is_free_or_static()) - || (b.is_var() && a.is_free_or_static()) + if (a.is_var() && b.is_free()) + || (b.is_var() && a.is_free()) || (a.is_var() && b.is_var()) || a == b { @@ -2779,7 +2779,9 @@ impl<'tcx> InferCtxt<'tcx> { br_string(br), self.tcx.associated_item(def_id).name ), - infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{name}`"), + infer::RegionParameterDefinition(_, name) => { + format!(" for lifetime parameter `{name}`") + } infer::UpvarRegion(ref upvar_id, _) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); format!(" for capture of `{var_name}` by closure") diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 1a60bab18dbd..f56d5d7d345b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -70,9 +70,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let anon_reg_sub = self.tcx().is_suitable_region(sub)?; let scope_def_id_sup = anon_reg_sup.def_id; - let bregion_sup = anon_reg_sup.boundregion; + let bregion_sup = anon_reg_sup.bound_region; let scope_def_id_sub = anon_reg_sub.def_id; - let bregion_sub = anon_reg_sub.boundregion; + let bregion_sub = anon_reg_sub.bound_region; let ty_sup = find_anon_type(self.tcx(), sup, &bregion_sup)?; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index be6d1a3750cd..7252a812466c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -41,8 +41,8 @@ pub fn find_param_with_region<'tcx>( replace_region: Region<'tcx>, ) -> Option> { let (id, bound_region) = match *anon_region { - ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), - ty::ReEarlyBound(ebr) => { + ty::ReLateParam(late_param) => (late_param.scope, late_param.bound_region), + ty::ReEarlyParam(ebr) => { (tcx.parent(ebr.def_id), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name)) } _ => return None, // not a free region diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index ed1a2a117190..fd507dac8d34 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -22,8 +22,8 @@ impl<'a, 'tcx> RegionRelations<'a, 'tcx> { Self { tcx, free_regions } } - pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> { - self.free_regions.lub_free_regions(self.tcx, r_a, r_b) + pub fn lub_param_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> { + self.free_regions.lub_param_regions(self.tcx, r_a, r_b) } } @@ -59,7 +59,7 @@ impl<'tcx> FreeRegionMap<'tcx> { r_a: Region<'tcx>, r_b: Region<'tcx>, ) -> bool { - assert!(r_a.is_free_or_static() && r_b.is_free_or_static()); + assert!(r_a.is_free() && r_b.is_free()); let re_static = tcx.lifetimes.re_static; if self.check_relation(re_static, r_b) { // `'a <= 'static` is always true, and not stored in the @@ -80,15 +80,15 @@ impl<'tcx> FreeRegionMap<'tcx> { /// cases, this is more conservative than necessary, in order to /// avoid making arbitrary choices. See /// `TransitiveRelation::postdom_upper_bound` for more details. - pub fn lub_free_regions( + pub fn lub_param_regions( &self, tcx: TyCtxt<'tcx>, r_a: Region<'tcx>, r_b: Region<'tcx>, ) -> Region<'tcx> { - debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b); - assert!(r_a.is_free()); - assert!(r_b.is_free()); + debug!("lub_param_regions(r_a={:?}, r_b={:?})", r_a, r_b); + assert!(r_a.is_late_or_early_param()); + assert!(r_b.is_late_or_early_param()); let result = if r_a == r_b { r_a } else { @@ -97,7 +97,7 @@ impl<'tcx> FreeRegionMap<'tcx> { Some(r) => r, } }; - debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result); + debug!("lub_param_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result); result } } diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index e212547eaafb..11ab86277c1b 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -115,8 +115,8 @@ impl<'a, 'tcx> TypeFolder> for TypeFreshener<'a, 'tcx> { r } - ty::ReEarlyBound(..) - | ty::ReFree(_) + ty::ReEarlyParam(..) + | ty::ReLateParam(_) | ty::ReVar(_) | ty::RePlaceholder(..) | ty::ReStatic diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs index 84891022720c..9e24b020510d 100644 --- a/compiler/rustc_infer/src/infer/generalize.rs +++ b/compiler/rustc_infer/src/infer/generalize.rs @@ -340,8 +340,8 @@ where ty::RePlaceholder(..) | ty::ReVar(..) | ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(..) => { + | ty::ReEarlyParam(..) + | ty::ReLateParam(..) => { // see common code below } } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 4ff9d7494226..800aee1f4d3b 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -17,7 +17,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReBound, RePlaceholder, ReVar}; -use rustc_middle::ty::{ReEarlyBound, ReErased, ReError, ReFree, ReStatic}; +use rustc_middle::ty::{ReEarlyParam, ReErased, ReError, ReLateParam, ReStatic}; use rustc_middle::ty::{Region, RegionVid}; use rustc_span::Span; use std::fmt; @@ -390,7 +390,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ); } - ReStatic | ReEarlyBound(_) | ReFree(_) => { + ReStatic | ReEarlyParam(_) | ReLateParam(_) => { // nothing lives longer than `'static` // All empty regions are less than early-bound, free, @@ -423,9 +423,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ); } - ReStatic | ReEarlyBound(_) | ReFree(_) => { + ReStatic | ReEarlyParam(_) | ReLateParam(_) => { // nothing lives longer than `'static` - // All empty regions are less than early-bound, free, + // All empty regions are less than early-bound, late-bound, // and scope regions. true } @@ -450,8 +450,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // Check for the case where we know that `'b: 'static` -- in that case, // `a <= b` for all `a`. - let b_free_or_static = b.is_free_or_static(); - if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) { + if b.is_free() && sub_free_regions(tcx.lifetimes.re_static, b) { return true; } @@ -460,8 +459,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // `lub` relationship defined below, since sometimes the "lub" // is actually the `postdom_upper_bound` (see // `TransitiveRelation` for more details). - let a_free_or_static = a.is_free_or_static(); - if a_free_or_static && b_free_or_static { + if a.is_free() && b.is_free() { return sub_free_regions(a, b); } @@ -501,8 +499,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { self.tcx().lifetimes.re_static } - (ReEarlyBound(_) | ReFree(_), ReEarlyBound(_) | ReFree(_)) => { - self.region_rels.lub_free_regions(a, b) + (ReEarlyParam(_) | ReLateParam(_), ReEarlyParam(_) | ReLateParam(_)) => { + self.region_rels.lub_param_regions(a, b) } // For these types, we cannot define any additional @@ -723,13 +721,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { return; } - // We place free regions first because we are special casing - // SubSupConflict(ReFree, ReFree) when reporting error, and so + // We place late-bound regions first because we are special casing + // SubSupConflict(ReLateParam, ReLateParam) when reporting error, and so // the user will more likely get a specific suggestion. fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 { match *x.region { - ReEarlyBound(_) => 0, - ReFree(_) => 1, + ReEarlyParam(_) => 0, + ReLateParam(_) => 1, _ => 2, } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 3c539f18eb92..956d097a5b2e 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -508,7 +508,10 @@ pub enum RegionVariableOrigin { Coercion(Span), /// Region variables created as the values for early-bound regions. - EarlyBoundRegion(Span, Symbol), + /// + /// FIXME(@lcnr): This can also store a `DefId`, similar to + /// `TypeVariableOriginKind::TypeParameterDefinition`. + RegionParameterDefinition(Span, Symbol), /// Region variables created when instantiating a binder with /// existential variables, e.g. when calling a function or method. @@ -1165,7 +1168,7 @@ impl<'tcx> InferCtxt<'tcx> { GenericParamDefKind::Lifetime => { // Create a region inference variable for the given // region parameter definition. - self.next_region_var(EarlyBoundRegion(span, param.name)).into() + self.next_region_var(RegionParameterDefinition(span, param.name)).into() } GenericParamDefKind::Type { .. } => { // Create a type inference variable for the given @@ -2041,7 +2044,7 @@ impl RegionVariableOrigin { | AddrOfRegion(a) | Autoref(a) | Coercion(a) - | EarlyBoundRegion(a, ..) + | RegionParameterDefinition(a, ..) | BoundRegion(a, ..) | UpvarRegion(_, a) => a, Nll(..) => bug!("NLL variable used with `span`"), diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 47e3dd762b08..f8dbfdde30c5 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -138,8 +138,8 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { } OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) { ( - ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_), - ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_), + ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), + ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), ) => self.region_relation.add(r_a, r_b), (ty::ReError(_), _) | (_, ty::ReError(_)) => {} // FIXME(#109628): We shouldn't have existential variables in implied bounds. diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index de142f05fb76..e888340bde3f 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -662,8 +662,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { match *region { ty::ReStatic | ty::ReErased - | ty::ReFree(..) - | ty::ReEarlyBound(..) + | ty::ReLateParam(..) + | ty::ReEarlyParam(..) | ty::ReError(_) => ty::UniverseIndex::ROOT, ty::RePlaceholder(placeholder) => placeholder.universe, ty::ReVar(vid) => self.var_universe(vid), diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6f6150a4172f..e3dd8faeedb3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1910,7 +1910,7 @@ impl ExplicitOutlivesRequirements { .iter() .filter_map(|(clause, _)| match clause.kind().skip_binder() { ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { - ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b), + ty::ReEarlyParam(ebr) if ebr.def_id == def_id => Some(b), _ => None, }, _ => None, @@ -1953,7 +1953,7 @@ impl ExplicitOutlivesRequirements { let is_inferred = match tcx.named_bound_var(lifetime.hir_id) { Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives .iter() - .any(|r| matches!(**r, ty::ReEarlyBound(ebr) if { ebr.def_id == def_id })), + .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { ebr.def_id == def_id })), _ => false, }; diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 92d1fcc7ed24..6e50e8940464 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -64,8 +64,8 @@ impl<'tcx> UnifyValue for UnifiedRegion<'tcx> { cmp::min_by_key(r1, r2, |r| match r.kind() { ty::ReStatic | ty::ReErased - | ty::ReFree(..) - | ty::ReEarlyBound(..) + | ty::ReLateParam(..) + | ty::ReEarlyParam(..) | ty::ReError(_) => ty::UniverseIndex::ROOT, ty::RePlaceholder(placeholder) => placeholder.universe, ty::ReVar(..) | ty::ReBound(..) => bug!("not a universal region"), diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 56fed05c63f7..b76d1d6e141d 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -77,7 +77,7 @@ use std::ops::Deref; /// picture, but rather the ending point. // // FIXME(pnkfelix): this currently derives `PartialOrd` and `Ord` to -// placate the same deriving in `ty::FreeRegion`, but we may want to +// placate the same deriving in `ty::LateParamRegion`, but we may want to // actually attach a more meaningful ordering to scopes than the one // generated via deriving here. #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Copy, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1598d05251d4..e635c3f96ec9 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -113,9 +113,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ExprConst = ty::Expr<'tcx>; type Region = Region<'tcx>; - type EarlyBoundRegion = ty::EarlyBoundRegion; + type EarlyParamRegion = ty::EarlyParamRegion; type BoundRegion = ty::BoundRegion; - type FreeRegion = ty::FreeRegion; + type LateParamRegion = ty::LateParamRegion; type InferRegion = ty::RegionVid; type PlaceholderRegion = ty::PlaceholderRegion; @@ -445,14 +445,14 @@ impl<'tcx> CommonConsts<'tcx> { } } -/// This struct contains information regarding the `ReFree(FreeRegion)` corresponding to a lifetime -/// conflict. +/// This struct contains information regarding a free parameter region, +/// either a `ReEarlyParam` or `ReLateParam`. #[derive(Debug)] pub struct FreeRegionInfo { - /// `LocalDefId` corresponding to FreeRegion + /// `LocalDefId` of the free region. pub def_id: LocalDefId, - /// the bound region corresponding to FreeRegion - pub boundregion: ty::BoundRegionKind, + /// the bound region corresponding to free region. + pub bound_region: ty::BoundRegionKind, /// checks if bound region is in Impl Item pub is_impl_item: bool, } @@ -1080,8 +1080,8 @@ impl<'tcx> TyCtxt<'tcx> { pub fn is_suitable_region(self, mut region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = loop { let def_id = match region.kind() { - ty::ReFree(fr) => fr.bound_region.get_id()?.as_local()?, - ty::ReEarlyBound(ebr) => ebr.def_id.expect_local(), + ty::ReLateParam(fr) => fr.bound_region.get_id()?.as_local()?, + ty::ReEarlyParam(ebr) => ebr.def_id.expect_local(), _ => return None, // not a free region }; let scope = self.local_parent(def_id); @@ -1102,11 +1102,7 @@ impl<'tcx> TyCtxt<'tcx> { _ => false, }; - Some(FreeRegionInfo { - def_id: suitable_region_binding_scope, - boundregion: bound_region, - is_impl_item, - }) + Some(FreeRegionInfo { def_id: suitable_region_binding_scope, bound_region, is_impl_item }) } /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type. @@ -1743,7 +1739,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { match param.kind { GenericParamDefKind::Lifetime => { - ty::Region::new_early_bound(self, param.to_early_bound_region_data()).into() + ty::Region::new_early_param(self, param.to_early_bound_region_data()).into() } GenericParamDefKind::Type { .. } => Ty::new_param(self, param.index, param.name).into(), GenericParamDefKind::Const { .. } => ty::Const::new_param( @@ -2040,7 +2036,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given the def-id of an early-bound lifetime on an RPIT corresponding to /// a duplicated captured lifetime, map it back to the early- or late-bound /// lifetime of the function from which it originally as captured. If it is - /// a late-bound lifetime, this will represent the liberated (`ReFree`) lifetime + /// a late-bound lifetime, this will represent the liberated (`ReLateParam`) lifetime /// of the signature. // FIXME(RPITIT): if we ever synthesize new lifetimes for RPITITs and not just // re-use the generics of the opaque, this function will need to be tweaked slightly. @@ -2079,9 +2075,9 @@ impl<'tcx> TyCtxt<'tcx> { } let generics = self.generics_of(new_parent); - return ty::Region::new_early_bound( + return ty::Region::new_early_param( self, - ty::EarlyBoundRegion { + ty::EarlyParamRegion { def_id: ebv, index: generics .param_def_id_to_index(self, ebv) @@ -2092,7 +2088,7 @@ impl<'tcx> TyCtxt<'tcx> { } Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => { let new_parent = self.parent(lbv); - return ty::Region::new_free( + return ty::Region::new_late_param( self, new_parent, ty::BoundRegionKind::BrNamed( diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index e8ff3b230cbb..cff0d4df6735 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -326,7 +326,7 @@ impl<'tcx> TyCtxt<'tcx> { T: TypeFoldable>, { self.replace_late_bound_regions_uncached(value, |br| { - ty::Region::new_free(self, all_outlive_scope, br.kind) + ty::Region::new_late_param(self, all_outlive_scope, br.kind) }) } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index c9607b2245a7..8fd08c724d2b 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -809,7 +809,7 @@ impl<'a, 'tcx> TypeFolder> for ArgFolder<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { #[cold] #[inline(never)] - fn region_param_out_of_range(data: ty::EarlyBoundRegion, args: &[GenericArg<'_>]) -> ! { + fn region_param_out_of_range(data: ty::EarlyParamRegion, args: &[GenericArg<'_>]) -> ! { bug!( "Region parameter out of range when substituting in region {} (index={}, args = {:?})", data.name, @@ -820,7 +820,7 @@ impl<'a, 'tcx> TypeFolder> for ArgFolder<'a, 'tcx> { #[cold] #[inline(never)] - fn region_param_invalid(data: ty::EarlyBoundRegion, other: GenericArgKind<'_>) -> ! { + fn region_param_invalid(data: ty::EarlyParamRegion, other: GenericArgKind<'_>) -> ! { bug!( "Unexpected parameter {:?} when substituting in region {} (index={})", other, @@ -835,7 +835,7 @@ impl<'a, 'tcx> TypeFolder> for ArgFolder<'a, 'tcx> { // regions that appear in a function signature is done using // the specialized routine `ty::replace_late_regions()`. match *r { - ty::ReEarlyBound(data) => { + ty::ReEarlyParam(data) => { let rk = self.args.get(data.index as usize).map(|k| k.unpack()); match rk { Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt), @@ -844,7 +844,7 @@ impl<'a, 'tcx> TypeFolder> for ArgFolder<'a, 'tcx> { } } ty::ReBound(..) - | ty::ReFree(_) + | ty::ReLateParam(_) | ty::ReStatic | ty::RePlaceholder(_) | ty::ReErased diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 888ee1d237ae..4a6e3cfacd3d 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt}; +use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt}; #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum GenericParamDefKind { @@ -62,9 +62,9 @@ pub struct GenericParamDef { } impl GenericParamDef { - pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion { + pub fn to_early_bound_region_data(&self) -> ty::EarlyParamRegion { if let GenericParamDefKind::Lifetime = self.kind { - ty::EarlyBoundRegion { def_id: self.def_id, index: self.index, name: self.name } + ty::EarlyParamRegion { def_id: self.def_id, index: self.index, name: self.name } } else { bug!("cannot convert a non-lifetime parameter def to an early bound region") } @@ -260,10 +260,10 @@ impl<'tcx> Generics { } } - /// Returns the `GenericParamDef` associated with this `EarlyBoundRegion`. + /// Returns the `GenericParamDef` associated with this `EarlyParamRegion`. pub fn region_param( &'tcx self, - param: &EarlyBoundRegion, + param: &ty::EarlyParamRegion, tcx: TyCtxt<'tcx>, ) -> &'tcx GenericParamDef { let param = self.param_at(param.index as usize, tcx); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e1c616ba0785..559bf9fb825d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -98,11 +98,12 @@ pub use self::sty::BoundRegionKind::*; pub use self::sty::{ AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, CanonicalPolyFnSig, ClauseKind, ClosureArgs, ClosureArgsParts, ConstKind, - ConstVid, CoroutineArgs, CoroutineArgsParts, EarlyBoundRegion, EffectVid, ExistentialPredicate, - ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, InlineConstArgs, - InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection, - PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, PredicateKind, Region, - RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, + ConstVid, CoroutineArgs, CoroutineArgsParts, EarlyParamRegion, EffectVid, ExistentialPredicate, + ExistentialProjection, ExistentialTraitRef, FnSig, GenSig, InlineConstArgs, + InlineConstArgsParts, LateParamRegion, ParamConst, ParamTy, PolyExistentialPredicate, + PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, + PredicateKind, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, + VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ @@ -463,7 +464,7 @@ pub struct CReaderCacheKey { #[rustc_pass_by_value] pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo>>); -impl ty::EarlyBoundRegion { +impl EarlyParamRegion { /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). pub fn has_name(&self) -> bool { diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index cabf2ab5dfec..1305f63bdbc2 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -113,7 +113,7 @@ impl<'tcx> TypeFolder> for ReverseMapper<'tcx> { ty::ReError(_) => return r, // The regions that we expect from borrow checking. - ty::ReEarlyBound(_) | ty::ReFree(_) => {} + ty::ReEarlyParam(_) | ty::ReLateParam(_) => {} ty::RePlaceholder(_) | ty::ReVar(_) => { // All of the regions in the type should either have been diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 21bf5b4b3b1b..ad070dcc9e38 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2158,10 +2158,10 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions; match *region { - ty::ReEarlyBound(ref data) => data.has_name(), + ty::ReEarlyParam(ref data) => data.has_name(), ty::ReBound(_, ty::BoundRegion { kind: br, .. }) - | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) + | ty::ReLateParam(ty::LateParamRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { bound: ty::BoundRegion { kind: br, .. }, .. }) => { @@ -2228,14 +2228,14 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { // to fit that into a short string. Hence the recommendation to use // `explain_region()` or `note_and_explain_region()`. match *region { - ty::ReEarlyBound(ref data) => { + ty::ReEarlyParam(ref data) => { if data.name != kw::Empty { p!(write("{}", data.name)); return Ok(()); } } ty::ReBound(_, ty::BoundRegion { kind: br, .. }) - | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) + | ty::ReLateParam(ty::LateParamRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { bound: ty::BoundRegion { kind: br, .. }, .. }) => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 6af68bc5dbab..e223ffd7c5d5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -79,9 +79,9 @@ impl fmt::Debug for ty::BoundRegionKind { } } -impl fmt::Debug for ty::FreeRegion { +impl fmt::Debug for ty::LateParamRegion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region) + write!(f, "ReLateParam({:?}, {:?})", self.scope, self.bound_region) } } @@ -444,7 +444,7 @@ TrivialTypeTraversalImpls! { crate::ty::Placeholder, crate::ty::Placeholder, crate::ty::Placeholder, - crate::ty::FreeRegion, + crate::ty::LateParamRegion, crate::ty::InferTy, crate::ty::IntVarValue, crate::ty::adjustment::PointerCoercion, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d0df4498a66e..87896970ed8f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -61,9 +61,9 @@ pub struct TypeAndMut<'tcx> { #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] #[derive(HashStable)] -/// A "free" region `fr` can be interpreted as "some region +/// The parameter representation of late-bound function parameters, "some region /// at least as big as the scope `fr.scope`". -pub struct FreeRegion { +pub struct LateParamRegion { pub scope: DefId, pub bound_region: BoundRegionKind, } @@ -1468,11 +1468,11 @@ pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); impl<'tcx> Region<'tcx> { #[inline] - pub fn new_early_bound( + pub fn new_early_param( tcx: TyCtxt<'tcx>, - early_bound_region: ty::EarlyBoundRegion, + early_bound_region: ty::EarlyParamRegion, ) -> Region<'tcx> { - tcx.intern_region(ty::ReEarlyBound(early_bound_region)) + tcx.intern_region(ty::ReEarlyParam(early_bound_region)) } #[inline] @@ -1493,12 +1493,12 @@ impl<'tcx> Region<'tcx> { } #[inline] - pub fn new_free( + pub fn new_late_param( tcx: TyCtxt<'tcx>, scope: DefId, bound_region: ty::BoundRegionKind, ) -> Region<'tcx> { - tcx.intern_region(ty::ReFree(ty::FreeRegion { scope, bound_region })) + tcx.intern_region(ty::ReLateParam(ty::LateParamRegion { scope, bound_region })) } #[inline] @@ -1549,10 +1549,10 @@ impl<'tcx> Region<'tcx> { /// to avoid the cost of the `match`. pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { match kind { - ty::ReEarlyBound(region) => Region::new_early_bound(tcx, region), + ty::ReEarlyParam(region) => Region::new_early_param(tcx, region), ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region), - ty::ReFree(ty::FreeRegion { scope, bound_region }) => { - Region::new_free(tcx, scope, bound_region) + ty::ReLateParam(ty::LateParamRegion { scope, bound_region }) => { + Region::new_late_param(tcx, scope, bound_region) } ty::ReStatic => tcx.lifetimes.re_static, ty::ReVar(vid) => Region::new_var(tcx, vid), @@ -1574,13 +1574,13 @@ impl<'tcx> Deref for Region<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] #[derive(HashStable)] -pub struct EarlyBoundRegion { +pub struct EarlyParamRegion { pub def_id: DefId, pub index: u32, pub name: Symbol, } -impl fmt::Debug for EarlyBoundRegion { +impl fmt::Debug for EarlyParamRegion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name) } @@ -1722,9 +1722,9 @@ impl<'tcx> Region<'tcx> { pub fn get_name(self) -> Option { if self.has_name() { match *self { - ty::ReEarlyBound(ebr) => Some(ebr.name), + ty::ReEarlyParam(ebr) => Some(ebr.name), ty::ReBound(_, br) => br.kind.get_name(), - ty::ReFree(fr) => fr.bound_region.get_name(), + ty::ReLateParam(fr) => fr.bound_region.get_name(), ty::ReStatic => Some(kw::StaticLifetime), ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(), _ => None, @@ -1744,9 +1744,9 @@ impl<'tcx> Region<'tcx> { /// Is this region named by the user? pub fn has_name(self) -> bool { match *self { - ty::ReEarlyBound(ebr) => ebr.has_name(), + ty::ReEarlyParam(ebr) => ebr.has_name(), ty::ReBound(_, br) => br.kind.is_named(), - ty::ReFree(fr) => fr.bound_region.is_named(), + ty::ReLateParam(fr) => fr.bound_region.is_named(), ty::ReStatic => true, ty::ReVar(..) => false, ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(), @@ -1802,12 +1802,12 @@ impl<'tcx> Region<'tcx> { flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; } - ty::ReEarlyBound(..) => { + ty::ReEarlyParam(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PARAM; } - ty::ReFree { .. } => { + ty::ReLateParam { .. } => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; } @@ -1851,22 +1851,28 @@ impl<'tcx> Region<'tcx> { /// function might return the `DefId` of a closure. pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId { match *self { - ty::ReEarlyBound(br) => tcx.parent(br.def_id), - ty::ReFree(fr) => fr.scope, + ty::ReEarlyParam(br) => tcx.parent(br.def_id), + ty::ReLateParam(fr) => fr.scope, _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self), } } /// True for free regions other than `'static`. - pub fn is_free(self) -> bool { - matches!(*self, ty::ReEarlyBound(_) | ty::ReFree(_)) + pub fn is_late_or_early_param(self) -> bool { + matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_)) } - /// True if `self` is a free region or static. - pub fn is_free_or_static(self) -> bool { + /// True for free region in the current context. + /// + /// This is the case for `'static` and param regions. + pub fn is_free(self) -> bool { match *self { - ty::ReStatic => true, - _ => self.is_free(), + ty::ReStatic | ty::ReEarlyParam(..) | ty::ReLateParam(..) => true, + ty::ReVar(..) + | ty::RePlaceholder(..) + | ty::ReBound(..) + | ty::ReErased + | ty::ReError(..) => false, } } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 1a76a8d350d2..914ff1fabd1b 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -126,7 +126,7 @@ pub struct TypeckResults<'tcx> { /// fn(&'a u32) -> u32 /// ``` /// - /// Note that `'a` is not bound (it would be an `ReFree`) and + /// Note that `'a` is not bound (it would be an `ReLateParam`) and /// that the `Foo` opaque type is replaced by its hidden type. liberated_fn_sigs: ItemLocalMap>, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 144e98f784a4..e9f65d99a2ef 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -35,12 +35,14 @@ pub struct Discr<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum CheckRegions { No, - /// Only permit early bound regions. This is useful for Adts which - /// can never have late bound regions. - OnlyEarlyBound, - /// Permit both late bound and early bound regions. Use this for functions, - /// which frequently have late bound regions. - Bound, + /// Only permit parameter regions. This should be used + /// for everything apart from functions, which may use + /// `ReBound` to represent late-bound regions. + OnlyParam, + /// Check region parameters from a function definition. + /// Allows `ReEarlyParam` and `ReBound` to handle early + /// and late-bound region parameters. + FromFunction, } #[derive(Copy, Clone, Debug)] @@ -431,7 +433,7 @@ impl<'tcx> TyCtxt<'tcx> { .filter(|&(_, k)| { match k.unpack() { GenericArgKind::Lifetime(region) => match region.kind() { - ty::ReEarlyBound(ref ebr) => { + ty::ReEarlyParam(ref ebr) => { !impl_generics.region_param(ebr, self).pure_wrt_drop } // Error: not a region param @@ -468,17 +470,17 @@ impl<'tcx> TyCtxt<'tcx> { for arg in args { match arg.unpack() { GenericArgKind::Lifetime(lt) => match (ignore_regions, lt.kind()) { - (CheckRegions::Bound, ty::ReBound(di, reg)) => { + (CheckRegions::FromFunction, ty::ReBound(di, reg)) => { if !seen_late.insert((di, reg)) { return Err(NotUniqueParam::DuplicateParam(lt.into())); } } - (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, ty::ReEarlyBound(p)) => { + (CheckRegions::OnlyParam | CheckRegions::FromFunction, ty::ReEarlyParam(p)) => { if !seen.insert(p.index) { return Err(NotUniqueParam::DuplicateParam(lt.into())); } } - (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, _) => { + (CheckRegions::OnlyParam | CheckRegions::FromFunction, _) => { return Err(NotUniqueParam::NotParam(lt.into())); } (CheckRegions::No, _) => {} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index d3bd87bb360e..a6685a22acc2 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -9,7 +9,7 @@ use crate::rustc_internal::{IndexMap, RustcInternal}; use crate::rustc_smir::hir::def::DefKind; -use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyBoundRegion, Region}; +use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyParamRegion, Region}; use rustc_hir as hir; use rustc_middle::mir; use rustc_middle::mir::interpret::{alloc_range, AllocId}; @@ -1691,7 +1691,7 @@ impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> { fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use stable_mir::ty::RegionKind; match self { - ty::ReEarlyBound(early_reg) => RegionKind::ReEarlyBound(EarlyBoundRegion { + ty::ReEarlyParam(early_reg) => RegionKind::ReEarlyParam(EarlyParamRegion { def_id: tables.region_def(early_reg.def_id), index: early_reg.index, name: early_reg.name.to_string(), diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 80dec80bf03a..1501e7d0cf75 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -282,12 +282,12 @@ fn encode_region<'tcx>( s.push('E'); compress(dict, DictKey::Region(region), &mut s); } - // FIXME(@lcnr): Why is `ReEarlyBound` reachable here. - RegionKind::ReEarlyBound(..) | RegionKind::ReErased => { + // FIXME(@lcnr): Why is `ReEarlyParam` reachable here. + RegionKind::ReEarlyParam(..) | RegionKind::ReErased => { s.push_str("u6region"); compress(dict, DictKey::Region(region), &mut s); } - RegionKind::ReFree(..) + RegionKind::ReLateParam(..) | RegionKind::ReStatic | RegionKind::ReError(_) | RegionKind::ReVar(..) diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 5f08bc0039ae..004dc45263c4 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -237,7 +237,7 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { CanonicalizeMode::Response { .. } => return r, }, - ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode { + ty::ReLateParam(_) | ty::ReEarlyParam(_) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"), }, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index fff5510bbfbb..2c004c659298 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -484,7 +484,7 @@ fn is_impossible_associated_item( t.super_visit_with(self) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - if let ty::ReEarlyBound(param) = r.kind() + if let ty::ReEarlyParam(param) = r.kind() && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 5c34df1ed502..24afd7dc3578 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -53,9 +53,9 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' DefKind::AssocTy if let Some(data) = tcx.opt_rpitit_info(def_id.to_def_id()) => { match data { ty::ImplTraitInTraitData::Trait { fn_def_id, .. } => { - // We need to remap all of the late-bound lifetimes in theassumed wf types - // of the fn (which are represented as ReFree) to the early-bound lifetimes - // of the RPITIT (which are represented by ReEarlyBound owned by the opaque). + // We need to remap all of the late-bound lifetimes in the assumed wf types + // of the fn (which are represented as ReLateParam) to the early-bound lifetimes + // of the RPITIT (which are represented by ReEarlyParam owned by the opaque). // Luckily, this is very easy to do because we already have that mapping // stored in the HIR of this RPITIT. // @@ -65,19 +65,19 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' let mut mapping = FxHashMap::default(); let generics = tcx.generics_of(def_id); - // For each captured opaque lifetime, if it's late-bound (`ReFree` in this case, - // since it has been liberated), map it back to the early-bound lifetime of + // For each captured opaque lifetime, if it's late-bound (`ReLateParam` in this + // case, since it has been liberated), map it back to the early-bound lifetime of // the GAT. Since RPITITs also have all of the fn's generics, we slice only // the end of the list corresponding to the opaque's generics. for param in &generics.params[tcx.generics_of(fn_def_id).params.len()..] { let orig_lt = tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()); - if matches!(*orig_lt, ty::ReFree(..)) { + if matches!(*orig_lt, ty::ReLateParam(..)) { mapping.insert( orig_lt, - ty::Region::new_early_bound( + ty::Region::new_early_param( tcx, - ty::EarlyBoundRegion { + ty::EarlyParamRegion { def_id: param.def_id, index: param.index, name: param.name, @@ -90,7 +90,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' let remapped_wf_tys = tcx.fold_regions( tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(), |region, _| { - // If `region` is a `ReFree` that is captured by the + // If `region` is a `ReLateParam` that is captured by the // opaque, remap it to its corresponding the early- // bound region. if let Some(remapped_region) = mapping.get(®ion) { diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 9242a1a751bc..7ca2da42042b 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -159,10 +159,10 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { // Only check that the parent generics of the TAIT/RPIT are unique. // the args owned by the opaque are going to always be duplicate // lifetime params for RPITs, and empty for TAITs. - match self - .tcx - .uses_unique_generic_params(&alias_ty.args[..parent_count], CheckRegions::Bound) - { + match self.tcx.uses_unique_generic_params( + &alias_ty.args[..parent_count], + CheckRegions::FromFunction, + ) { Ok(()) => { // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not // supported at all, so this is sound to do, but once we want to support them, you'll diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index d10927b0d939..af741a0a3a0b 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -8,7 +8,7 @@ bitflags! { // required. /// Does this have `Param`? const HAS_TY_PARAM = 1 << 0; - /// Does this have `ReEarlyBound`? + /// Does this have `ReEarlyParam`? const HAS_RE_PARAM = 1 << 1; /// Does this have `ConstKind::Param`? const HAS_CT_PARAM = 1 << 2; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7f75e5b35a20..da504c54fddd 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -47,9 +47,9 @@ pub trait Interner: Sized { // Kinds of regions type Region: Clone + DebugWithInfcx + Hash + Ord; - type EarlyBoundRegion: Clone + Debug + Hash + Ord; + type EarlyParamRegion: Clone + Debug + Hash + Ord; type BoundRegion: Clone + Debug + Hash + Ord; - type FreeRegion: Clone + Debug + Hash + Ord; + type LateParamRegion: Clone + Debug + Hash + Ord; type InferRegion: Clone + DebugWithInfcx + Hash + Ord; type PlaceholderRegion: Clone + Debug + Hash + Ord; diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index fc9eaf63ac82..cc6e45df6412 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -22,8 +22,8 @@ use self::RegionKind::*; /// ```text /// static ----------+-----...------+ (greatest) /// | | | -/// early-bound and | | -/// free regions | | +/// param regions | | +/// | | | /// | | | /// | | | /// empty(root) placeholder(U1) | @@ -88,8 +88,8 @@ use self::RegionKind::*; /// To do this, we replace the bound regions with placeholder markers, /// which don't satisfy any relation not explicitly provided. /// -/// There are two kinds of placeholder regions in rustc: `ReFree` and -/// `RePlaceholder`. When checking an item's body, `ReFree` is supposed +/// There are two kinds of placeholder regions in rustc: `ReLateParam` and +/// `RePlaceholder`. When checking an item's body, `ReLateParam` is supposed /// to be used. These also support explicit bounds: both the internally-stored /// *scope*, which the region is assumed to outlive, as well as other /// relations stored in the `FreeRegionMap`. Note that these relations @@ -123,26 +123,35 @@ use self::RegionKind::*; )] #[derive(TyEncodable, TyDecodable)] pub enum RegionKind { - /// Region bound in a type or fn declaration which will be - /// substituted 'early' -- that is, at the same time when type - /// parameters are substituted. - ReEarlyBound(I::EarlyBoundRegion), + /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`. + /// + /// There are some important differences between region and type parameters. + /// Not all region parameters in the source are represented via `ReEarlyParam`: + /// late-bound function parameters are instead lowered to a `ReBound`. Late-bound + /// regions get eagerly replaced with `ReLateParam` which behaves in the same way as + /// `ReEarlyParam`. Region parameters are also sometimes implicit, + /// e.g. in `impl Trait for &()`. + ReEarlyParam(I::EarlyParamRegion), /// A higher-ranked region. These represent either late-bound function parameters /// or bound variables from a `for<'a>`-binder. /// /// While inside of a function, e.g. during typeck, the late-bound function parameters - /// can be converted to `ReFree` by calling `tcx.liberate_late_bound_regions`. + /// can be converted to `ReLateParam` by calling `tcx.liberate_late_bound_regions`. /// /// Bound regions inside of types **must not** be erased, as they impact trait /// selection and the `TypeId` of that type. `for<'a> fn(&'a ())` and /// `fn(&'static ())` are different types and have to be treated as such. ReBound(DebruijnIndex, I::BoundRegion), - /// When checking a function body, the types of all arguments and so forth - /// that refer to bound region parameters are modified to refer to free - /// region parameters. - ReFree(I::FreeRegion), + /// Late-bound function parameters are represented using a `ReBound`. When + /// inside of a function, we convert these bound variables to placeholder + /// parameters via `tcx.liberate_late_bound_regions`. They are then treated + /// the same way as `ReEarlyParam` while inside of the function. + /// + /// See https://rustc-dev-guide.rust-lang.org/early-late-bound-summary.html for + /// more info about early and late bound lifetime parameters. + ReLateParam(I::LateParamRegion), /// Static data that has an "infinite" lifetime. Top in the region lattice. ReStatic, @@ -150,8 +159,11 @@ pub enum RegionKind { /// A region variable. Should not exist outside of type inference. ReVar(I::InferRegion), - /// A placeholder region -- basically, the higher-ranked version of `ReFree`. + /// A placeholder region -- the higher-ranked version of `ReLateParam`. /// Should not exist outside of type inference. + /// + /// Used when instantiating a `forall` binder via + /// `infcx.instantiate_binder_with_placeholders`. RePlaceholder(I::PlaceholderRegion), /// Erased region, used by trait selection, in MIR and during codegen. @@ -166,9 +178,9 @@ pub enum RegionKind { #[inline] const fn regionkind_discriminant(value: &RegionKind) -> usize { match value { - ReEarlyBound(_) => 0, + ReEarlyParam(_) => 0, ReBound(_, _) => 1, - ReFree(_) => 2, + ReLateParam(_) => 2, ReStatic => 3, ReVar(_) => 4, RePlaceholder(_) => 5, @@ -180,9 +192,9 @@ const fn regionkind_discriminant(value: &RegionKind) -> usize { // This is manually implemented because a derive would require `I: Copy` impl Copy for RegionKind where - I::EarlyBoundRegion: Copy, + I::EarlyParamRegion: Copy, I::BoundRegion: Copy, - I::FreeRegion: Copy, + I::LateParamRegion: Copy, I::InferRegion: Copy, I::PlaceholderRegion: Copy, I::ErrorGuaranteed: Copy, @@ -195,9 +207,9 @@ impl PartialEq for RegionKind { fn eq(&self, other: &RegionKind) -> bool { regionkind_discriminant(self) == regionkind_discriminant(other) && match (self, other) { - (ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r == b_r, + (ReEarlyParam(a_r), ReEarlyParam(b_r)) => a_r == b_r, (ReBound(a_d, a_r), ReBound(b_d, b_r)) => a_d == b_d && a_r == b_r, - (ReFree(a_r), ReFree(b_r)) => a_r == b_r, + (ReLateParam(a_r), ReLateParam(b_r)) => a_r == b_r, (ReStatic, ReStatic) => true, (ReVar(a_r), ReVar(b_r)) => a_r == b_r, (RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r, @@ -223,13 +235,13 @@ impl DebugWithInfcx for RegionKind { f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { match this.data { - ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"), + ReEarlyParam(data) => write!(f, "ReEarlyParam({data:?})"), ReBound(binder_id, bound_region) => { write!(f, "ReBound({binder_id:?}, {bound_region:?})") } - ReFree(fr) => write!(f, "{fr:?}"), + ReLateParam(fr) => write!(f, "{fr:?}"), ReStatic => f.write_str("ReStatic"), @@ -252,9 +264,9 @@ impl fmt::Debug for RegionKind { // This is not a derived impl because a derive would require `I: HashStable` impl HashStable for RegionKind where - I::EarlyBoundRegion: HashStable, + I::EarlyParamRegion: HashStable, I::BoundRegion: HashStable, - I::FreeRegion: HashStable, + I::LateParamRegion: HashStable, I::InferRegion: HashStable, I::PlaceholderRegion: HashStable, { @@ -269,10 +281,10 @@ where d.hash_stable(hcx, hasher); r.hash_stable(hcx, hasher); } - ReEarlyBound(r) => { + ReEarlyParam(r) => { r.hash_stable(hcx, hasher); } - ReFree(r) => { + ReLateParam(r) => { r.hash_stable(hcx, hasher); } RePlaceholder(r) => { diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index bd3feef60185..bb7425411ae2 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -61,7 +61,7 @@ pub struct Region { #[derive(Clone, Debug, Eq, PartialEq)] pub enum RegionKind { - ReEarlyBound(EarlyBoundRegion), + ReEarlyParam(EarlyParamRegion), ReBound(DebruijnIndex, BoundRegion), ReStatic, RePlaceholder(Placeholder), @@ -71,7 +71,7 @@ pub enum RegionKind { pub(crate) type DebruijnIndex = u32; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct EarlyBoundRegion { +pub struct EarlyParamRegion { pub def_id: RegionDef, pub index: u32, pub name: Symbol, diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index eb946e82f399..007c5e113b71 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -723,7 +723,7 @@ where fn region_name(region: Region<'_>) -> Option { match *region { - ty::ReEarlyBound(r) => Some(r.name), + ty::ReEarlyParam(r) => Some(r.name), _ => None, } } @@ -743,7 +743,7 @@ impl<'a, 'tcx> TypeFolder> for RegionReplacer<'a, 'tcx> { match *r { // These are the regions that can be seen in the AST. ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned().unwrap_or(r), - ty::ReEarlyBound(_) | ty::ReStatic | ty::ReBound(..) | ty::ReError(_) => r, + ty::ReEarlyParam(_) | ty::ReStatic | ty::ReBound(..) | ty::ReError(_) => r, r => bug!("unexpected region: {r:?}"), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d33e41dc2b39..429589f01fdf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -287,9 +287,9 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option Some(Lifetime::statik()), _ if !region.has_name() => None, ty::ReBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => Some(Lifetime(name)), - ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)), + ty::ReEarlyParam(ref data) => Some(Lifetime(data.name)), ty::ReBound(..) - | ty::ReFree(..) + | ty::ReLateParam(..) | ty::ReVar(..) | ty::ReError(_) | ty::RePlaceholder(..) @@ -1928,13 +1928,13 @@ fn clean_trait_object_lifetime_bound<'tcx>( // latter contrary to `clean_middle_region`. match *region { ty::ReStatic => Some(Lifetime::statik()), - ty::ReEarlyBound(region) if region.name != kw::Empty => Some(Lifetime(region.name)), + ty::ReEarlyParam(region) if region.name != kw::Empty => Some(Lifetime(region.name)), ty::ReBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) if name != kw::Empty => { Some(Lifetime(name)) } - ty::ReEarlyBound(_) + ty::ReEarlyParam(_) | ty::ReBound(..) - | ty::ReFree(_) + | ty::ReLateParam(_) | ty::ReVar(_) | ty::RePlaceholder(_) | ty::ReErased diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index d6fa742b7968..4db65b0d04fe 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -175,7 +175,7 @@ impl<'tcx> PassByRefOrValue { }, // Early bound regions on functions are either from the containing item, are bounded by another // lifetime, or are used as a bound for a type or lifetime. - RegionKind::ReEarlyBound(..) => continue, + RegionKind::ReEarlyParam(..) => continue, _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index c6ac96a4539c..1d4b4d10d501 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -465,9 +465,9 @@ fn check_fn_args<'cx, 'tcx: 'cx>( .walk() .filter_map(|arg| { arg.as_region().and_then(|lifetime| match lifetime.kind() { - ty::ReEarlyBound(r) => Some(r.def_id), + ty::ReEarlyParam(r) => Some(r.def_id), ty::ReBound(_, r) => r.kind.get_id(), - ty::ReFree(r) => r.bound_region.get_id(), + ty::ReLateParam(r) => r.bound_region.get_id(), ty::ReStatic | ty::ReVar(_) | ty::RePlaceholder(_) diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr index 84b61dc50448..4cd4febc4f0a 100644 --- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr @@ -1,4 +1,4 @@ -error: {foo::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} +error: {foo::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} --> $DIR/erased-regions-in-hidden-ty.rs:11:36 | LL | fn foo<'a: 'a>(x: &'a Vec) -> impl Fn() + 'static { diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr index 84b61dc50448..4cd4febc4f0a 100644 --- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr @@ -1,4 +1,4 @@ -error: {foo::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} +error: {foo::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} --> $DIR/erased-regions-in-hidden-ty.rs:11:36 | LL | fn foo<'a: 'a>(x: &'a Vec) -> impl Fn() + 'static { diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr index ba885d1b97eb..85f5edca6908 100644 --- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -1,16 +1,16 @@ -error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a)])` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyParam(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyParam(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a)])` captures lifetime that does not appear in bounds --> $DIR/impl-trait-captures.rs:11:5 | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { | -- ------------ opaque type defined here | | - | hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) T` captures the anonymous lifetime defined here + | hidden type `&ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) T` captures the anonymous lifetime defined here LL | x | ^ | -help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyBound(DefId(0:14 ~ impl_trait_captures[aeb9]::foo::{opaque#0}::'a), 2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound +help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyParam(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyParam(DefId(0:14 ~ impl_trait_captures[aeb9]::foo::{opaque#0}::'a), 2, 'a)])` captures `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound | -LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) { +LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) { | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error: aborting due to previous error From 8fcbd1991f7707a4c7566420af79f81605c583c0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 14 Nov 2023 13:41:28 +0000 Subject: [PATCH 16/19] review + fix CI --- compiler/rustc_infer/src/infer/free_regions.rs | 4 ++-- compiler/rustc_middle/src/ty/sty.rs | 2 +- tests/ui/nll/ty-outlives/impl-trait-captures.stderr | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index fd507dac8d34..0dde3082d48d 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -87,8 +87,8 @@ impl<'tcx> FreeRegionMap<'tcx> { r_b: Region<'tcx>, ) -> Region<'tcx> { debug!("lub_param_regions(r_a={:?}, r_b={:?})", r_a, r_b); - assert!(r_a.is_late_or_early_param()); - assert!(r_b.is_late_or_early_param()); + assert!(r_a.is_param()); + assert!(r_b.is_param()); let result = if r_a == r_b { r_a } else { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 87896970ed8f..2b1e57f58717 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1858,7 +1858,7 @@ impl<'tcx> Region<'tcx> { } /// True for free regions other than `'static`. - pub fn is_late_or_early_param(self) -> bool { + pub fn is_param(self) -> bool { matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_)) } diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr index 85f5edca6908..320f529624f0 100644 --- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -11,7 +11,7 @@ LL | x help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyParam(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyParam(DefId(0:14 ~ impl_trait_captures[aeb9]::foo::{opaque#0}::'a), 2, 'a)])` captures `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) { - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error: aborting due to previous error From 18281d39cf425eecfc3b6058875832ef4dba3bac Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 15 Nov 2023 01:24:44 +0000 Subject: [PATCH 17/19] fix doc link --- compiler/rustc_type_ir/src/region_kind.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index cc6e45df6412..5d3ce49bc8f7 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -149,7 +149,7 @@ pub enum RegionKind { /// parameters via `tcx.liberate_late_bound_regions`. They are then treated /// the same way as `ReEarlyParam` while inside of the function. /// - /// See https://rustc-dev-guide.rust-lang.org/early-late-bound-summary.html for + /// See for /// more info about early and late bound lifetime parameters. ReLateParam(I::LateParamRegion), From c036a10ed501cd2c4b501af03c920af3f28d360f Mon Sep 17 00:00:00 2001 From: Kirby Linvill Date: Tue, 14 Nov 2023 19:19:35 -0700 Subject: [PATCH 18/19] Make UserTypeProjection projections Opaque Also shifts comments explaining why Stable MIR drops an optional variant name field, for `Downcast` projection elements, to the `Place::stable` function. --- compiler/rustc_smir/src/rustc_smir/mod.rs | 7 ++++++- compiler/stable_mir/src/mir/body.rs | 6 +----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index a4d83debb57b..1bdcc805f63c 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -712,6 +712,11 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { to: *to, from_end: *from_end, }, + // MIR includes an `Option` argument for `Downcast` that is the name of the + // variant, used for printing MIR. However this information should also be accessible + // via a lookup using the `VariantIdx`. The `Option` argument is therefore + // dropped when converting to Stable MIR. A brief justification for this decision can be + // found at https://github.com/rust-lang/rust/pull/117517#issuecomment-1811683486 Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)), OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)), Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)), @@ -723,7 +728,7 @@ impl<'tcx> Stable<'tcx> for mir::UserTypeProjection { type T = stable_mir::mir::UserTypeProjection; fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { - UserTypeProjection { base: self.base.as_usize(), projection: format!("{:?}", self.projs) } + UserTypeProjection { base: self.base.as_usize(), projection: opaque(&self.projs) } } } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index a5b51ce6a34d..351e7bb69c3f 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -465,10 +465,6 @@ pub enum ProjectionElem { }, /// "Downcast" to a variant of an enum or a coroutine. - // - // TODO(klinvill): MIR includes an Option argument that is the name of the variant, used - // for printing MIR. However I don't see it used anywhere. Is such a field needed or can we just - // include the VariantIdx which could be used to recover the field name if needed? Downcast(VariantIdx), /// Like an explicit cast from an opaque type to a concrete type, but without @@ -488,7 +484,7 @@ pub enum ProjectionElem { pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, - pub projection: String, + pub projection: Opaque, } pub type Local = usize; From d7cecd3db24e3905a39f458e9202016a5685579a Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 15 Nov 2023 19:16:06 -0500 Subject: [PATCH 19/19] Let Miri see the AllocId for all TyCtxt allocations --- compiler/rustc_middle/src/mir/interpret/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index e360fb3eaaf3..b87c6885e04c 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -525,6 +525,13 @@ impl<'tcx> TyCtxt<'tcx> { self.alloc_map.lock().reserve() } + /// Miri's provenance GC needs to see all live allocations. The interpreter manages most + /// allocations but some are managed by [`TyCtxt`] and without this method the interpreter + /// doesn't know their [`AllocId`]s are in use. + pub fn iter_allocs(self, func: F) { + self.alloc_map.lock().alloc_map.keys().copied().for_each(func) + } + /// Reserves a new ID *if* this allocation has not been dedup-reserved before. /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we /// don't want to dedup IDs for "real" memory!