Skip to content

Commit

Permalink
Unrolled build for rust-lang#126366
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#126366 - celinval:issue-0080-def-ty, r=oli-obk

Add a new trait to retrieve StableMir definition Ty

We implement the trait only for definitions that should have a type. It's possible that I missed a few definitions, but we can add them later if needed.

Fixes rust-lang/project-stable-mir#80
  • Loading branch information
rust-timer authored Jun 13, 2024
2 parents 921645c + 6d4a825 commit 30f9973
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 10 deletions.
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(())
}

0 comments on commit 30f9973

Please sign in to comment.