Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new trait to retrieve StableMir definition Ty #126366

Merged
merged 1 commit into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion compiler/stable_mir/src/crate_def.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! 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::ty::{GenericArgs, Span, Ty};
use crate::{with, Crate, Symbol};

/// A unique identification number for each item accessible for the current compilation unit.
Expand Down Expand Up @@ -52,6 +52,23 @@ pub trait CrateDef {
}
}

/// A trait that can be used to retrieve a definition's type.
///
/// Note that not every CrateDef has a type `Ty`. They should not implement this trait.
pub trait CrateDefType: CrateDef {
/// Returns the type of this crate item.
fn ty(&self) -> Ty {
with(|cx| cx.def_ty(self.def_id()))
}

/// Retrieve the type of this definition by instantiating and normalizing it with `args`.
///
/// This will panic if instantiation fails.
fn ty_with_args(&self, args: &GenericArgs) -> Ty {
with(|cx| cx.def_ty_with_args(self.def_id(), args))
}
}

macro_rules! crate_def {
( $(#[$attr:meta])*
$vis:vis $name:ident $(;)?
Expand All @@ -67,3 +84,21 @@ macro_rules! crate_def {
}
};
}

macro_rules! crate_def_with_ty {
( $(#[$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
}
}

impl CrateDefType for $name {}
};
}
8 changes: 5 additions & 3 deletions compiler/stable_mir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ use std::fmt::Debug;
use std::io;

use crate::compiler_interface::with;
pub use crate::crate_def::CrateDef;
pub use crate::crate_def::DefId;
pub use crate::crate_def::{CrateDef, CrateDefType, DefId};
pub use crate::error::*;
use crate::mir::Body;
use crate::mir::Mutability;
Expand Down Expand Up @@ -115,12 +114,15 @@ pub enum CtorKind {

pub type Filename = String;

crate_def! {
crate_def_with_ty! {
/// Holds information about an item in a crate.
pub CrateItem;
}

impl CrateItem {
/// This will return the body of an item.
///
/// This will panic if no body is available.
pub fn body(&self) -> mir::Body {
with(|cx| cx.mir_body(self.0))
}
Expand Down
28 changes: 22 additions & 6 deletions compiler/stable_mir/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use super::{
with, DefId, Error, Symbol,
};
use crate::abi::Layout;
use crate::crate_def::{CrateDef, CrateDefType};
use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
use crate::mir::mono::StaticDef;
use crate::target::MachineInfo;
use crate::{crate_def::CrateDef, mir::mono::StaticDef};
use crate::{Filename, Opaque};
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::Range;
Expand Down Expand Up @@ -504,6 +505,15 @@ impl TyKind {
pub fn discriminant_ty(&self) -> Option<Ty> {
self.rigid().map(|ty| with(|cx| cx.rigid_ty_discriminant_ty(ty)))
}

/// Deconstruct a function type if this is one.
pub fn fn_def(&self) -> Option<(FnDef, &GenericArgs)> {
if let TyKind::RigidTy(RigidTy::FnDef(def, args)) = self {
Some((*def, args))
} else {
None
}
}
}

pub struct TypeAndMut {
Expand Down Expand Up @@ -629,7 +639,7 @@ impl ForeignModule {
}
}

crate_def! {
crate_def_with_ty! {
/// Hold information about a ForeignItem in a crate.
pub ForeignDef;
}
Expand All @@ -647,7 +657,7 @@ pub enum ForeignItemKind {
Type(Ty),
}

crate_def! {
crate_def_with_ty! {
/// Hold information about a function definition in a crate.
pub FnDef;
}
Expand All @@ -668,9 +678,15 @@ impl FnDef {
pub fn is_intrinsic(&self) -> bool {
self.as_intrinsic().is_some()
}

/// Get the function signature for this function definition.
pub fn fn_sig(&self) -> PolyFnSig {
let kind = self.ty().kind();
kind.fn_sig().unwrap()
}
}

crate_def! {
crate_def_with_ty! {
pub IntrinsicDef;
}

Expand Down Expand Up @@ -710,7 +726,7 @@ crate_def! {
pub BrNamedDef;
}

crate_def! {
crate_def_with_ty! {
pub AdtDef;
}

Expand Down Expand Up @@ -866,7 +882,7 @@ crate_def! {
pub GenericDef;
}

crate_def! {
crate_def_with_ty! {
pub ConstDef;
}

Expand Down
114 changes: 114 additions & 0 deletions tests/ui-fulldeps/stable-mir/check_def_ty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//@ run-pass
//! Test that users are able to use stable mir APIs to retrieve type information from a crate item
//! definition.

//@ 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)]

#[macro_use]
extern crate rustc_smir;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate stable_mir;

use rustc_smir::rustc_internal;
use stable_mir::ty::{Ty, ForeignItemKind};
use stable_mir::*;
use std::io::Write;
use std::ops::ControlFlow;

const CRATE_NAME: &str = "crate_def_ty";

/// Test if we can retrieve type information from different definitions.
fn test_def_tys() -> ControlFlow<()> {
let items = stable_mir::all_local_items();
for item in &items {
// Type from crate items.
let ty = item.ty();
match item.name().as_str() {
"STATIC_STR" => assert!(ty.kind().is_ref()),
"CONST_U32" => assert!(ty.kind().is_integral()),
"main" => { check_fn_def(ty) }
_ => unreachable!("Unexpected item: `{item:?}`")
}
}

let foreign_items = stable_mir::local_crate().foreign_modules();
for item in foreign_items[0].module().items() {
// Type from foreign items.
let ty = item.ty();
let item_kind = item.kind();
let name = item.name();
match item_kind {
ForeignItemKind::Fn(fn_def) => {
assert_eq!(&name, "extern_fn");
assert_eq!(ty, fn_def.ty());
check_fn_def(ty)
}
ForeignItemKind::Static(def) => {
assert_eq!(&name, "EXT_STATIC");
assert_eq!(ty, def.ty());
assert!(ty.kind().is_integral())
}
_ => unreachable!("Unexpected kind: {item_kind:?}")
};
}

ControlFlow::Continue(())
}

fn check_fn_def(ty: Ty) {
let kind = ty.kind();
let (def, args) = kind.fn_def().expect(&format!("Expected function type, but found: {ty}"));
assert!(def.ty().kind().is_fn());
assert_eq!(def.ty_with_args(args), ty);
}

/// 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_ty_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, test_def_tys).unwrap();
}

fn generate_input(path: &str) -> std::io::Result<()> {
let mut file = std::fs::File::create(path)?;
write!(
file,
r#"
// We would like to check intrinsic definition.
#![feature(core_intrinsics)]
static STATIC_STR: &str = "foo";
const CONST_U32: u32 = 0u32;

fn main() {{
let _c = core::char::from_u32(99);
let _v = Vec::<u8>::new();
let _i = std::intrinsics::size_of::<u8>();
}}

extern "C" {{
fn extern_fn(x: i32) -> i32;
static EXT_STATIC: i32;
}}
"#
)?;
Ok(())
}
Loading