Skip to content

Commit a830394

Browse files
authored
Rollup merge of rust-lang#116964 - celinval:smir-mono-body, r=oli-obk
Add stable Instance::body() and RustcInternal trait The `Instance::body()` returns a monomorphized body. For that, we had to implement visitor that monomorphize types and constants. We are also introducing the RustcInternal trait that will allow us to convert back from Stable to Internal. Note that this trait is not yet visible for our users as it depends on Tables. We should probably add a new trait that can be exposed. The tests here are very simple, and I'm planning on creating more exhaustive tests in the project-mir repo. But I was hoping to get some feedback here first. r? `@oli-obk`
2 parents da76602 + 6e643e1 commit a830394

File tree

10 files changed

+217
-7
lines changed

10 files changed

+217
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//! Module containing the translation from stable mir constructs to the rustc counterpart.
2+
//!
3+
//! This module will only include a few constructs to allow users to invoke internal rustc APIs
4+
//! due to incomplete stable coverage.
5+
6+
// Prefer importing stable_mir over internal rustc constructs to make this file more readable.
7+
use crate::rustc_smir::{MaybeStable, Tables};
8+
use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
9+
use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty};
10+
use stable_mir::DefId;
11+
12+
use super::RustcInternal;
13+
14+
impl<'tcx> RustcInternal<'tcx> for DefId {
15+
type T = rustc_span::def_id::DefId;
16+
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
17+
tables.def_ids[*self]
18+
}
19+
}
20+
21+
impl<'tcx> RustcInternal<'tcx> for GenericArgs {
22+
type T = rustc_ty::GenericArgsRef<'tcx>;
23+
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
24+
tables.tcx.mk_args_from_iter(self.0.iter().map(|arg| arg.internal(tables)))
25+
}
26+
}
27+
28+
impl<'tcx> RustcInternal<'tcx> for GenericArgKind {
29+
type T = rustc_ty::GenericArg<'tcx>;
30+
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
31+
match self {
32+
GenericArgKind::Lifetime(reg) => reg.internal(tables).into(),
33+
GenericArgKind::Type(ty) => ty.internal(tables).into(),
34+
GenericArgKind::Const(cnst) => cnst.internal(tables).into(),
35+
}
36+
}
37+
}
38+
39+
impl<'tcx> RustcInternal<'tcx> for Region {
40+
type T = rustc_ty::Region<'tcx>;
41+
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
42+
todo!()
43+
}
44+
}
45+
46+
impl<'tcx> RustcInternal<'tcx> for Ty {
47+
type T = InternalTy<'tcx>;
48+
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
49+
match tables.types[self.0] {
50+
MaybeStable::Stable(_) => todo!(),
51+
MaybeStable::Rustc(ty) => ty,
52+
}
53+
}
54+
}
55+
56+
impl<'tcx> RustcInternal<'tcx> for Const {
57+
type T = rustc_ty::Const<'tcx>;
58+
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
59+
todo!()
60+
}
61+
}

compiler/rustc_smir/src/rustc_internal/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use std::fmt::Debug;
2020
use std::hash::Hash;
2121
use std::ops::{ControlFlow, Index};
2222

23+
mod internal;
24+
2325
impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> {
2426
type Output = DefId;
2527

@@ -231,3 +233,11 @@ impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V
231233
k
232234
}
233235
}
236+
237+
/// Trait used to translate a stable construct to its rustc counterpart.
238+
///
239+
/// This is basically a mirror of [crate::rustc_smir::Stable].
240+
pub(crate) trait RustcInternal<'tcx> {
241+
type T;
242+
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T;
243+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//! Logic required to produce a monomorphic stable body.
2+
//!
3+
//! We first retrieve and monomorphize the rustc body representation, i.e., we generate a
4+
//! monomorphic body using internal representation.
5+
//! After that, we convert the internal representation into a stable one.
6+
use crate::rustc_smir::{Stable, Tables};
7+
use rustc_middle::mir;
8+
use rustc_middle::mir::visit::MutVisitor;
9+
use rustc_middle::ty::{self, Ty, TyCtxt};
10+
11+
/// Builds a monomorphic body for a given instance.
12+
pub struct BodyBuilder<'tcx> {
13+
tcx: TyCtxt<'tcx>,
14+
instance: ty::Instance<'tcx>,
15+
}
16+
17+
impl<'tcx> BodyBuilder<'tcx> {
18+
pub fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self {
19+
BodyBuilder { tcx, instance }
20+
}
21+
22+
pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body {
23+
let mut body = self.tcx.instance_mir(self.instance.def).clone();
24+
let generics = self.tcx.generics_of(self.instance.def_id());
25+
if generics.requires_monomorphization(self.tcx) {
26+
self.visit_body(&mut body);
27+
}
28+
body.stable(tables)
29+
}
30+
31+
fn monomorphize<T>(&self, value: T) -> T
32+
where
33+
T: ty::TypeFoldable<TyCtxt<'tcx>>,
34+
{
35+
self.instance.instantiate_mir_and_normalize_erasing_regions(
36+
self.tcx,
37+
ty::ParamEnv::reveal_all(),
38+
ty::EarlyBinder::bind(value),
39+
)
40+
}
41+
}
42+
43+
impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> {
44+
fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, _location: mir::Location) {
45+
*ct = self.monomorphize(*ct);
46+
}
47+
48+
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: mir::visit::TyContext) {
49+
*ty = self.monomorphize(*ty);
50+
}
51+
52+
fn tcx(&self) -> TyCtxt<'tcx> {
53+
self.tcx
54+
}
55+
}

compiler/rustc_smir/src/rustc_smir/mod.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//!
88
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
99
10-
use crate::rustc_internal::IndexMap;
10+
use crate::rustc_internal::{IndexMap, RustcInternal};
1111
use crate::rustc_smir::hir::def::DefKind;
1212
use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyBoundRegion, Region};
1313
use rustc_hir as hir;
@@ -26,6 +26,7 @@ use stable_mir::{self, opaque, Context, Filename};
2626
use tracing::debug;
2727

2828
mod alloc;
29+
mod builder;
2930

3031
impl<'tcx> Context for Tables<'tcx> {
3132
fn local_crate(&self) -> stable_mir::Crate {
@@ -171,8 +172,9 @@ impl<'tcx> Context for Tables<'tcx> {
171172
}
172173
}
173174

174-
fn instance_body(&mut self, _def: InstanceDef) -> Body {
175-
todo!("Monomorphize the body")
175+
fn instance_body(&mut self, def: InstanceDef) -> Body {
176+
let instance = self.instances[def];
177+
builder::BodyBuilder::new(self.tcx, instance).build(self)
176178
}
177179

178180
fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty {
@@ -195,9 +197,21 @@ impl<'tcx> Context for Tables<'tcx> {
195197
let def_id = self[def_id];
196198
let generics = self.tcx.generics_of(def_id);
197199
let result = generics.requires_monomorphization(self.tcx);
198-
println!("req {result}: {def_id:?}");
199200
result
200201
}
202+
203+
fn resolve_instance(
204+
&mut self,
205+
def: stable_mir::ty::FnDef,
206+
args: &stable_mir::ty::GenericArgs,
207+
) -> Option<stable_mir::mir::mono::Instance> {
208+
let def_id = def.0.internal(self);
209+
let args_ref = args.internal(self);
210+
match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
211+
Ok(Some(instance)) => Some(instance.stable(self)),
212+
Ok(None) | Err(_) => None,
213+
}
214+
}
201215
}
202216

203217
#[derive(Clone)]

compiler/stable_mir/src/error.rs

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! - [CompilerError]: This represents errors that can be raised when invoking the compiler.
55
//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled.
66
7+
use std::convert::From;
78
use std::fmt::{Debug, Display, Formatter};
89
use std::{error, fmt};
910

@@ -31,6 +32,12 @@ impl Error {
3132
}
3233
}
3334

35+
impl From<&str> for Error {
36+
fn from(value: &str) -> Self {
37+
Self(value.into())
38+
}
39+
}
40+
3441
impl Display for Error {
3542
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
3643
Display::fmt(&self.0, f)

compiler/stable_mir/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub mod visitor;
3939

4040
pub use error::*;
4141
use mir::mono::Instance;
42+
use ty::{FnDef, GenericArgs};
4243

4344
/// Use String for now but we should replace it.
4445
pub type Symbol = String;
@@ -233,6 +234,9 @@ pub trait Context {
233234

234235
/// Item requires monomorphization.
235236
fn requires_monomorphization(&self, def_id: DefId) -> bool;
237+
238+
/// Resolve an instance from the given function definition and generic arguments.
239+
fn resolve_instance(&mut self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
236240
}
237241

238242
// A thread local variable that stores a pointer to the tables mapping between TyCtxt

compiler/stable_mir/src/mir/body.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ use crate::{ty::Ty, Span};
55
#[derive(Clone, Debug)]
66
pub struct Body {
77
pub blocks: Vec<BasicBlock>,
8-
pub locals: Vec<LocalDecl>,
8+
pub locals: LocalDecls,
99
}
1010

11+
type LocalDecls = Vec<LocalDecl>;
12+
1113
#[derive(Clone, Debug)]
1214
pub struct LocalDecl {
1315
pub ty: Ty,
@@ -344,6 +346,7 @@ pub enum Operand {
344346
#[derive(Clone, Debug)]
345347
pub struct Place {
346348
pub local: Local,
349+
/// projection out of a place (access a field, deref a pointer, etc)
347350
pub projection: String,
348351
}
349352

@@ -462,3 +465,25 @@ pub enum NullOp {
462465
/// Returns the offset of a field.
463466
OffsetOf(Vec<FieldIdx>),
464467
}
468+
469+
impl Operand {
470+
pub fn ty(&self, locals: &LocalDecls) -> Ty {
471+
match self {
472+
Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
473+
Operand::Constant(c) => c.ty(),
474+
}
475+
}
476+
}
477+
478+
impl Constant {
479+
pub fn ty(&self) -> Ty {
480+
self.literal.ty
481+
}
482+
}
483+
484+
impl Place {
485+
pub fn ty(&self, locals: &LocalDecls) -> Ty {
486+
let _start_ty = locals[self.local].ty;
487+
todo!("Implement projection")
488+
}
489+
}

compiler/stable_mir/src/mir/mono.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::mir::Body;
2-
use crate::ty::{IndexedVal, Ty};
2+
use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty};
33
use crate::{with, CrateItem, DefId, Error, Opaque};
44
use std::fmt::Debug;
55

@@ -41,6 +41,15 @@ impl Instance {
4141
pub fn ty(&self) -> Ty {
4242
with(|context| context.instance_ty(self.def))
4343
}
44+
45+
/// Resolve an instance starting from a function definition and generic arguments.
46+
pub fn resolve(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
47+
with(|context| {
48+
context.resolve_instance(def, args).ok_or_else(|| {
49+
crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
50+
})
51+
})
52+
}
4453
}
4554

4655
/// Try to convert a crate item into an instance.

compiler/stable_mir/src/ty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ pub struct ImplDef(pub DefId);
225225
#[derive(Clone, PartialEq, Eq, Debug)]
226226
pub struct RegionDef(pub DefId);
227227

228+
/// A list of generic arguments.
228229
#[derive(Clone, Debug)]
229230
pub struct GenericArgs(pub Vec<GenericArgKind>);
230231

tests/ui-fulldeps/stable-mir/instance.rs tests/ui-fulldeps/stable-mir/check_instance.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ extern crate rustc_smir;
1515
extern crate stable_mir;
1616

1717
use rustc_middle::ty::TyCtxt;
18-
18+
use mir::{mono::Instance, TerminatorKind::*};
19+
use stable_mir::ty::{TyKind, RigidTy};
1920
use stable_mir::*;
2021
use rustc_smir::rustc_internal;
2122
use std::io::Write;
@@ -43,9 +44,28 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
4344
// For all generic items, try_from should fail.
4445
assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err()));
4546

47+
for instance in instances {
48+
test_body(instance.body())
49+
}
4650
ControlFlow::Continue(())
4751
}
4852

53+
/// Inspect the instance body
54+
fn test_body(body: mir::Body) {
55+
for term in body.blocks.iter().map(|bb| &bb.terminator) {
56+
match &term.kind {
57+
Call{ func, .. } => {
58+
let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() };
59+
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
60+
let result = Instance::resolve(def, &args);
61+
assert!(result.is_ok());
62+
}
63+
Goto {..} | Assert{..} | SwitchInt{..} | Return | Drop {..} => { /* Do nothing */}
64+
_ => { unreachable!("Unexpected terminator {term:?}") }
65+
}
66+
}
67+
}
68+
4969

5070
/// This test will generate and analyze a dummy crate using the stable mir.
5171
/// For that, it will first write the dummy crate into a file.
@@ -56,6 +76,7 @@ fn main() {
5676
generate_input(&path).unwrap();
5777
let args = vec![
5878
"rustc".to_string(),
79+
"-Cpanic=abort".to_string(),
5980
"--crate-type=lib".to_string(),
6081
"--crate-name".to_string(),
6182
CRATE_NAME.to_string(),
@@ -78,6 +99,9 @@ fn generate_input(path: &str) -> std::io::Result<()> {
7899
}}
79100
80101
pub fn monomorphic() {{
102+
let v = vec![10];
103+
let dup = ty_param(&v);
104+
assert_eq!(v, dup);
81105
}}
82106
83107
pub mod foo {{

0 commit comments

Comments
 (0)