Rollup merge of #118215 - celinval:smir-def-paths, r=ouz-a

Add common trait for crate definitions

In stable mir, we specialize DefId, however some functionality is the same for every definition, such as def paths, and getting their crate. Use a trait to implement those.
This commit is contained in:
Michael Goulet 2023-11-24 07:29:12 -08:00 committed by GitHub
commit 8294352b2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 307 additions and 53 deletions

View File

@ -11,8 +11,8 @@
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
use stable_mir::ty::{
AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, TraitRef,
Ty, UintTy,
ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, Span,
TraitRef, Ty, UintTy,
};
use stable_mir::{CrateItem, DefId};
@ -279,6 +279,14 @@ fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
}
}
impl<'tcx> RustcInternal<'tcx> for Span {
type T = rustc_span::Span;
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
tables[*self]
}
}
impl<'tcx, T> RustcInternal<'tcx> for &T
where
T: RustcInternal<'tcx>,

View File

@ -14,6 +14,7 @@
use rustc_middle::mir;
use rustc_middle::mir::interpret::{alloc_range, AllocId};
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
use rustc_middle::ty::{self, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, Variance};
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_target::abi::FieldIdx;
@ -28,7 +29,7 @@
EarlyParamRegion, FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability,
RigidTy, Span, TyKind, UintTy,
};
use stable_mir::{self, opaque, Context, CrateItem, Error, Filename, ItemKind};
use stable_mir::{self, opaque, Context, Crate, CrateItem, Error, Filename, ItemKind, Symbol};
use std::cell::RefCell;
use tracing::debug;
@ -61,9 +62,18 @@ fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
crates
}
fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String {
fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol {
let tables = self.0.borrow();
tables.tcx.def_path_str(tables[def_id])
if trimmed {
with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
} else {
with_no_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
}
}
fn krate(&self, def_id: stable_mir::DefId) -> Crate {
let tables = self.0.borrow();
smir_crate(tables.tcx, tables[def_id].krate)
}
fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
@ -240,10 +250,27 @@ fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
tables.create_def_id(def_id)
}
fn instance_mangled_name(&self, def: InstanceDef) -> String {
fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
let tables = self.0.borrow_mut();
let instance = tables.instances[instance];
tables.tcx.symbol_name(instance).name.to_string()
}
/// Retrieve the instance name for diagnostic messages.
///
/// This will return the specialized name, e.g., `Vec<char>::new`.
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
let tables = self.0.borrow_mut();
let instance = tables.instances[def];
tables.tcx.symbol_name(instance).name.to_string()
if trimmed {
with_forced_trimmed_paths!(
tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
)
} else {
with_no_trimmed_paths!(
tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
)
}
}
fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {

View File

@ -0,0 +1,69 @@
//! Module that define a common trait for things that represent a crate definition,
//! such as, a function, a trait, an enum, and any other definitions.
use crate::ty::Span;
use crate::{with, Crate, Symbol};
/// A unique identification number for each item accessible for the current compilation unit.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct DefId(pub(crate) usize);
/// A trait for retrieving information about a particular definition.
///
/// Implementors must provide the implementation of `def_id` which will be used to retrieve
/// information about a crate's definition.
pub trait CrateDef {
/// Retrieve the unique identifier for the current definition.
fn def_id(&self) -> DefId;
/// Return the fully qualified name of the current definition.
fn name(&self) -> Symbol {
let def_id = self.def_id();
with(|cx| cx.def_name(def_id, false))
}
/// Return a trimmed name of this definition.
///
/// This can be used to print more user friendly diagnostic messages.
///
/// If a symbol name can only be imported from one place for a type, and as
/// long as it was not glob-imported anywhere in the current crate, we trim its
/// path and print only the name.
///
/// For example, this function may shorten `std::vec::Vec` to just `Vec`,
/// as long as there is no other `Vec` importable anywhere.
fn trimmed_name(&self) -> Symbol {
let def_id = self.def_id();
with(|cx| cx.def_name(def_id, true))
}
/// Return information about the crate where this definition is declared.
///
/// This will return the crate number and its name.
fn krate(&self) -> Crate {
let def_id = self.def_id();
with(|cx| cx.krate(def_id))
}
/// Return the span of this definition.
fn span(&self) -> Span {
let def_id = self.def_id();
with(|cx| cx.span_of_an_item(def_id))
}
}
macro_rules! crate_def {
( $(#[$attr:meta])*
$vis:vis $name:ident $(;)?
) => {
$(#[$attr])*
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
$vis struct $name(pub DefId);
impl CrateDef for $name {
fn def_id(&self) -> DefId {
self.0
}
}
};
}

View File

@ -31,12 +31,16 @@
#[macro_use]
extern crate scoped_tls;
#[macro_use]
pub mod crate_def;
#[macro_use]
pub mod error;
pub mod mir;
pub mod ty;
pub mod visitor;
pub use crate::crate_def::CrateDef;
pub use crate::crate_def::DefId;
use crate::mir::alloc::{AllocId, GlobalAlloc};
use crate::mir::pretty::function_name;
use crate::mir::Mutability;
@ -51,15 +55,11 @@
/// The number that identifies a crate.
pub type CrateNum = usize;
/// A unique identification number for each item accessible for the current compilation unit.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct DefId(usize);
impl Debug for DefId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DefId")
.field("id", &self.0)
.field("name", &with(|cx| cx.name_of_def_id(*self)))
.field("name", &with(|cx| cx.def_name(*self, false)))
.finish()
}
}
@ -100,9 +100,10 @@ pub enum ItemKind {
pub type Filename = String;
/// Holds information about an item in the crate.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct CrateItem(pub DefId);
crate_def! {
/// Holds information about an item in a crate.
pub CrateItem;
}
impl CrateItem {
pub fn body(&self) -> mir::Body {
@ -113,10 +114,6 @@ pub fn span(&self) -> Span {
with(|cx| cx.span_of_an_item(self.0))
}
pub fn name(&self) -> String {
with(|cx| cx.name_of_def_id(self.0))
}
pub fn kind(&self) -> ItemKind {
with(|cx| cx.item_kind(*self))
}
@ -205,7 +202,7 @@ pub trait Context {
fn find_crates(&self, name: &str) -> Vec<Crate>;
/// Returns the name of given `DefId`
fn name_of_def_id(&self, def_id: DefId) -> String;
fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol;
/// Returns printable, human readable form of `Span`
fn span_to_string(&self, span: Span) -> String;
@ -260,7 +257,7 @@ pub trait Context {
fn instance_def_id(&self, instance: InstanceDef) -> DefId;
/// Get the instance mangled name.
fn instance_mangled_name(&self, instance: InstanceDef) -> String;
fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol;
/// Convert a non-generic crate item into an instance.
/// This function will panic if the item is generic.
@ -294,6 +291,8 @@ fn resolve_closure(
/// Retrieve the id for the virtual table.
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
fn krate(&self, def_id: DefId) -> Crate;
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
}
// A thread local variable that stores a pointer to the tables mapping between TyCtxt

View File

@ -1,6 +1,7 @@
use crate::crate_def::CrateDef;
use crate::mir::Body;
use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque};
use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
use std::fmt::{Debug, Formatter};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -47,10 +48,29 @@ pub fn ty(&self) -> Ty {
with(|context| context.instance_ty(self.def))
}
pub fn mangled_name(&self) -> String {
/// Retrieve the instance's mangled name used for calling the given instance.
///
/// This will also look up the correct name of instances from upstream crates.
pub fn mangled_name(&self) -> Symbol {
with(|context| context.instance_mangled_name(self.def))
}
/// Retrieve the instance name for diagnostic messages.
///
/// This will return the specialized name, e.g., `std::vec::Vec<u8>::new`.
pub fn name(&self) -> Symbol {
with(|context| context.instance_name(self.def, false))
}
/// Return a trimmed name of the given instance including its args.
///
/// If a symbol name can only be imported from one place for a type, and as
/// long as it was not glob-imported anywhere in the current crate, we trim its
/// path and print only the name.
pub fn trimmed_name(&self) -> Symbol {
with(|context| context.instance_name(self.def, true))
}
/// Resolve an instance starting from a function definition and generic arguments.
pub fn resolve(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
with(|context| {
@ -104,6 +124,8 @@ impl TryFrom<CrateItem> for Instance {
fn try_from(item: CrateItem) -> Result<Self, Self::Error> {
with(|context| {
// FIXME(celinval):
// - Return `Err` if instance does not have a body.
if !context.requires_monomorphization(item.0) {
Ok(context.mono_instance(item))
} else {
@ -148,8 +170,10 @@ fn from(value: StaticDef) -> Self {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InstanceDef(usize);
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct StaticDef(pub DefId);
crate_def! {
/// Holds information about a static variable definition.
pub StaticDef;
}
impl TryFrom<CrateItem> for StaticDef {
type Error = crate::Error;

View File

@ -1,3 +1,4 @@
use crate::crate_def::CrateDef;
use crate::mir::{Operand, Rvalue, StatementKind};
use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy};
use crate::{with, Body, CrateItem, Mutability};

View File

@ -3,6 +3,7 @@
mir::{Body, Mutability},
with, DefId, Error, Symbol,
};
use crate::crate_def::CrateDef;
use crate::mir::alloc::AllocId;
use crate::{Filename, Opaque};
use std::fmt::{self, Debug, Display, Formatter};
@ -295,11 +296,15 @@ pub enum Movability {
Movable,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ForeignDef(pub DefId);
crate_def! {
/// Hold information about a ForeignItem in a crate.
pub ForeignDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct FnDef(pub DefId);
crate_def! {
/// Hold information about a function definition in a crate.
pub FnDef;
}
impl FnDef {
pub fn body(&self) -> Body {
@ -307,20 +312,25 @@ pub fn body(&self) -> Body {
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ClosureDef(pub DefId);
crate_def! {
pub ClosureDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct CoroutineDef(pub DefId);
crate_def! {
pub CoroutineDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ParamDef(pub DefId);
crate_def! {
pub ParamDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct BrNamedDef(pub DefId);
crate_def! {
pub BrNamedDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct AdtDef(pub DefId);
crate_def! {
pub AdtDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum AdtKind {
@ -363,26 +373,33 @@ pub fn is_union(&self) -> bool {
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct AliasDef(pub DefId);
crate_def! {
pub AliasDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct TraitDef(pub DefId);
crate_def! {
pub TraitDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct GenericDef(pub DefId);
crate_def! {
pub GenericDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ConstDef(pub DefId);
crate_def! {
pub ConstDef;
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct ImplDef(pub DefId);
crate_def! {
pub ImplDef;
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct RegionDef(pub DefId);
crate_def! {
pub RegionDef;
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct CoroutineWitnessDef(pub DefId);
crate_def! {
pub CoroutineWitnessDef;
}
/// A list of generic arguments.
#[derive(Clone, Debug, Eq, PartialEq)]

View File

@ -24,6 +24,7 @@
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use stable_mir::{CrateItem, CrateItems, ItemKind};
use stable_mir::crate_def::CrateDef;
use stable_mir::mir::alloc::GlobalAlloc;
use stable_mir::mir::mono::StaticDef;
use std::ascii::Char;

View File

@ -0,0 +1,106 @@
// run-pass
//! Test that users are able to use stable mir APIs to retrieve information about crate definitions.
// 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_middle;
#[macro_use]
extern crate rustc_smir;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate stable_mir;
use mir::{mono::Instance, TerminatorKind::*};
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use stable_mir::ty::{RigidTy, TyKind};
use stable_mir::*;
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_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
let entry = stable_mir::entry_fn().unwrap();
let main_fn = Instance::try_from(entry).unwrap();
assert_eq!(main_fn.name(), "main");
assert_eq!(main_fn.trimmed_name(), "main");
let instances = get_instances(main_fn.body().unwrap());
assert_eq!(instances.len(), 2);
test_fn(instances[0], "from_u32", "std::char::from_u32", "core");
test_fn(instances[1], "Vec::<u8>::new", "std::vec::Vec::<u8>::new", "alloc");
ControlFlow::Continue(())
}
fn test_fn(instance: Instance, expected_trimmed: &str, expected_qualified: &str, krate: &str) {
let trimmed = instance.trimmed_name();
let qualified = instance.name();
assert_eq!(&trimmed, expected_trimmed);
assert_eq!(&qualified, expected_qualified);
let item = CrateItem::try_from(instance).unwrap();
let trimmed = item.trimmed_name();
let qualified = item.name();
assert_eq!(trimmed, expected_trimmed.replace("u8", "T"));
assert_eq!(qualified, expected_qualified.replace("u8", "T"));
assert_eq!(&item.krate().name, krate);
}
/// Inspect the instance body
fn get_instances(body: mir::Body) -> Vec<Instance> {
body.blocks.iter().filter_map(|bb| {
match &bb.terminator.kind {
Call { func, .. } => {
let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { unreachable!
() };
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
Instance::resolve(def, &args).ok()
}
_ => {
None
}
}
}).collect::<Vec<_>>()
}
/// 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 = "defs_input.rs";
generate_input(&path).unwrap();
let args = vec![
"rustc".to_string(),
"-Cpanic=abort".to_string(),
"--crate-name".to_string(),
CRATE_NAME.to_string(),
path.to_string(),
];
run!(args, tcx, test_stable_mir(tcx)).unwrap();
}
fn generate_input(path: &str) -> std::io::Result<()> {
let mut file = std::fs::File::create(path)?;
write!(
file,
r#"
fn main() {{
let _c = core::char::from_u32(99);
let _v = Vec::<u8>::new();
}}
"#
)?;
Ok(())
}

View File

@ -23,6 +23,7 @@
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use stable_mir::ItemKind;
use stable_mir::crate_def::CrateDef;
use stable_mir::mir::mono::Instance;
use stable_mir::ty::{RigidTy, TyKind};
use std::assert_matches::assert_matches;

View File

@ -21,6 +21,7 @@
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use stable_mir::crate_def::CrateDef;
use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
use stable_mir::ty::{RigidTy, TyKind, UintTy};
use stable_mir::ItemKind;