Skip to content

Commit 5f4114c

Browse files
committed
Expose more info about ADTs and functions in rustc_public
This allows users of `rustc_public` to do more complex navigation through data structures by exposing the following info: * `AdtDef::generics_of` - Get the generics for the ADT. * `AdtDef::inherent_impls` - Get all the impls for the ADT. * `FnDef::associated_item` - Get the trait or impl block that contains the function if it exists. * `FnDef::generics_of` - get the generics for a given function. * `ImplDef::generics_of` - Get the generics for the impl block. * `ImplDef` implements `CrateDefType` - figure out the type of the impl block with `CrateDefType::ty()` or get the normalized type with `CrateDefType::ty_with_args()`. This was partially written with the help of Gemini, but I reviewed the code it generated.
1 parent c712ea9 commit 5f4114c

7 files changed

Lines changed: 483 additions & 9 deletions

File tree

compiler/rustc_public/src/compiler_interface.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ use crate::mir::mono::{Instance, InstanceDef, StaticDef};
1717
use crate::mir::{BinOp, Body, Place, UnOp};
1818
use crate::target::{MachineInfo, MachineSize};
1919
use crate::ty::{
20-
AdtDef, AdtKind, Allocation, Asyncness, ClosureDef, ClosureKind, Constness, CoroutineDef,
21-
Discr, FieldDef, FnDef, ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef,
22-
GenericArgs, GenericPredicates, Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst,
23-
PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, TraitRef, Ty, TyConst, TyConstId, TyKind,
24-
UintTy, VariantDef, VariantIdx, VtblEntry,
20+
AdtDef, AdtKind, Allocation, AssocItem, Asyncness, ClosureDef, ClosureKind, Constness,
21+
CoroutineDef, Discr, FieldDef, FnDef, ForeignDef, ForeignItemKind, ForeignModule,
22+
ForeignModuleDef, GenericArgs, GenericPredicates, Generics, ImplDef, ImplTrait, IntrinsicDef,
23+
LineInfo, MirConst, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, TraitRef, Ty, TyConst,
24+
TyConstId, TyKind, UintTy, VariantDef, VariantIdx, VtblEntry,
2525
};
2626
use crate::unstable::{RustcInternal, Stable, new_item_kind};
2727
use crate::{
@@ -210,6 +210,14 @@ impl<'tcx> CompilerInterface<'tcx> {
210210
})
211211
}
212212

213+
/// Retrieve the inherent implementations for this ADT.
214+
pub(crate) fn inherent_impls(&self, adt: AdtDef) -> Vec<ImplDef> {
215+
self.with_cx(|tables, cx| {
216+
let def_id = tables[adt.0];
217+
cx.inherent_impls(def_id).iter().map(|&did| tables.impl_def(did)).collect()
218+
})
219+
}
220+
213221
pub(crate) fn predicates_of(&self, def_id: DefId) -> GenericPredicates {
214222
self.with_cx(|tables, cx| {
215223
let did = tables[def_id];
@@ -821,6 +829,14 @@ impl<'tcx> CompilerInterface<'tcx> {
821829
})
822830
}
823831

832+
/// Get the associated item of a definition if it is one.
833+
pub(crate) fn associated_item(&self, def_id: DefId) -> Option<AssocItem> {
834+
self.with_cx(|tables, cx| {
835+
let did = tables[def_id];
836+
cx.associated_item(did).map(|assoc| assoc.stable(tables, cx))
837+
})
838+
}
839+
824840
/// Get all associated items of a definition.
825841
pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems {
826842
self.with_cx(|tables, cx| {

compiler/rustc_public/src/ty.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,16 @@ impl FnDef {
727727
let kind = self.ty().kind();
728728
kind.fn_sig().unwrap()
729729
}
730+
731+
/// Get the generics of this function definition.
732+
pub fn generics_of(&self) -> Generics {
733+
with(|cx| cx.generics_of(self.0))
734+
}
735+
736+
/// Get the associated item information if this function is one.
737+
pub fn associated_item(&self) -> Option<AssocItem> {
738+
with(|cx| cx.associated_item(self.0))
739+
}
730740
}
731741

732742
crate_def_with_ty! {
@@ -863,6 +873,16 @@ impl AdtDef {
863873
pub fn discriminant_for_variant(&self, idx: VariantIdx) -> Discr {
864874
with(|cx| cx.adt_discr_for_variant(*self, idx))
865875
}
876+
877+
/// Get the generics of this ADT definition.
878+
pub fn generics_of(&self) -> Generics {
879+
with(|cx| cx.generics_of(self.0))
880+
}
881+
882+
/// Retrieve the inherent implementations for this ADT.
883+
pub fn inherent_impls(&self) -> Vec<ImplDef> {
884+
with(|cx| cx.inherent_impls(*self))
885+
}
866886
}
867887

868888
pub struct Discr {
@@ -970,7 +990,7 @@ crate_def_with_ty! {
970990
pub ConstDef;
971991
}
972992

973-
crate_def! {
993+
crate_def_with_ty! {
974994
/// A trait impl definition.
975995
#[derive(Serialize)]
976996
pub ImplDef;
@@ -985,6 +1005,11 @@ impl ImplDef {
9851005
pub fn associated_items(&self) -> AssocItems {
9861006
with(|cx| cx.associated_items(self.def_id()))
9871007
}
1008+
1009+
/// Get the generics of this implementation.
1010+
pub fn generics_of(&self) -> Generics {
1011+
with(|cx| cx.generics_of(self.0))
1012+
}
9881013
}
9891014

9901015
crate_def! {

compiler/rustc_public_bridge/src/context/impls.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ impl<'tcx, B: Bridge> CompilerCtxt<'tcx, B> {
201201
self.tcx.trait_impls_in_crate(crate_num).iter().map(|impl_def_id| *impl_def_id).collect()
202202
}
203203

204+
/// Returns the inherent implementations of the given definition.
205+
pub fn inherent_impls(&self, def_id: DefId) -> Vec<DefId> {
206+
self.tcx.inherent_impls(def_id).iter().copied().collect()
207+
}
208+
204209
pub fn trait_impl(&self, impl_def: DefId) -> EarlyBinder<'tcx, TraitRef<'tcx>> {
205210
self.tcx.impl_trait_ref(impl_def)
206211
}
@@ -778,6 +783,11 @@ impl<'tcx, B: Bridge> CompilerCtxt<'tcx, B> {
778783
assoc_items
779784
}
780785

786+
/// Returns the associated item of the given `DefId`, or `None` if it is not an associated item.
787+
pub fn associated_item(&self, def_id: DefId) -> Option<AssocItem> {
788+
self.tcx.opt_associated_item(def_id)
789+
}
790+
781791
/// Get all vtable entries of a trait.
782792
pub fn vtable_entries(&self, trait_ref: TraitRef<'tcx>) -> Vec<VtblEntry<'tcx>> {
783793
self.tcx.vtable_entries(trait_ref).to_vec()
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//@ run-pass
2+
//! Test that alias type conversion (projection/opaque types) works and returns TyKind::Alias.
3+
4+
//@ ignore-stage1
5+
//@ ignore-cross-compile
6+
//@ ignore-remote
7+
//@ edition: 2021
8+
9+
#![feature(rustc_private)]
10+
11+
extern crate rustc_middle;
12+
13+
extern crate rustc_driver;
14+
extern crate rustc_interface;
15+
#[macro_use]
16+
extern crate rustc_public;
17+
18+
use rustc_public::CrateDef;
19+
use rustc_public::ty::{TyKind, AliasKind};
20+
use std::ops::ControlFlow;
21+
22+
const CRATE_NAME: &str = "crate_alias";
23+
24+
fn test_alias() -> ControlFlow<()> {
25+
let local_crate = rustc_public::local_crate();
26+
let fn_defs = local_crate.fn_defs();
27+
let alias_fn = fn_defs
28+
.iter()
29+
.find(|f| f.trimmed_name().as_str() == "alias_fn")
30+
.expect("Failed to find alias_fn");
31+
let fn_sig = alias_fn.fn_sig().skip_binder();
32+
let inputs = fn_sig.inputs();
33+
assert_eq!(inputs.len(), 1);
34+
let input_ty = &inputs[0];
35+
match input_ty.kind() {
36+
TyKind::Alias(alias_kind, alias_ty) => {
37+
assert_eq!(alias_kind, AliasKind::Projection);
38+
assert_eq!(alias_ty.def_id.trimmed_name().as_str(), "MyTrait::Assoc");
39+
}
40+
_ => panic!("Expected TyKind::Alias for input type, found {:?}", input_ty),
41+
}
42+
43+
ControlFlow::Continue(())
44+
}
45+
46+
fn main() {
47+
let path = "alias.rs";
48+
generate_input(&path).unwrap();
49+
let args = &[
50+
"rustc".to_string(),
51+
"--crate-type=lib".to_string(),
52+
"--crate-name".to_string(),
53+
CRATE_NAME.to_string(),
54+
path.to_string(),
55+
];
56+
run!(args, test_alias).unwrap();
57+
}
58+
59+
fn generate_input(path: &str) -> std::io::Result<()> {
60+
std::fs::write(
61+
path,
62+
r#"
63+
pub trait MyTrait {
64+
type Assoc;
65+
}
66+
67+
impl MyTrait for i32 {
68+
type Assoc = bool;
69+
}
70+
71+
pub fn alias_fn<T: MyTrait>(val: T::Assoc) {}
72+
"#
73+
)
74+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//@ run-pass
2+
//! Test that users are able to retrieve generic parameters from various definitions.
3+
4+
//@ ignore-stage1
5+
//@ ignore-cross-compile
6+
//@ ignore-remote
7+
//@ edition: 2021
8+
9+
#![feature(rustc_private)]
10+
11+
extern crate rustc_middle;
12+
13+
extern crate rustc_driver;
14+
extern crate rustc_interface;
15+
#[macro_use]
16+
extern crate rustc_public;
17+
18+
use rustc_public::CrateDef;
19+
use rustc_public::ty::GenericParamDefKind;
20+
use std::ops::ControlFlow;
21+
22+
const CRATE_NAME: &str = "crate_generics";
23+
24+
fn test_generics() -> ControlFlow<()> {
25+
let local_crate = rustc_public::local_crate();
26+
27+
// Check ADT generics
28+
let adts = local_crate.adts();
29+
let my_struct =
30+
adts.iter().find(|adt| adt.trimmed_name() == "MyStruct").expect("Failed to find MyStruct");
31+
let adt_generics = my_struct.generics_of();
32+
assert_eq!(adt_generics.params.len(), 1);
33+
assert_eq!(adt_generics.params[0].name.as_str(), "T");
34+
match &adt_generics.params[0].kind {
35+
GenericParamDefKind::Type { .. } => {}
36+
_ => panic!("Expected type parameter"),
37+
}
38+
39+
// Check Fn generics
40+
let fn_defs = local_crate.fn_defs();
41+
let my_fn = fn_defs
42+
.iter()
43+
.find(|f| f.trimmed_name().as_str() == "my_fn")
44+
.expect("Failed to find my_fn");
45+
let fn_generics = my_fn.generics_of();
46+
assert_eq!(fn_generics.params.len(), 1);
47+
assert_eq!(fn_generics.params[0].name.as_str(), "U");
48+
49+
ControlFlow::Continue(())
50+
}
51+
52+
fn main() {
53+
let path = "generics.rs";
54+
generate_input(&path).unwrap();
55+
let args = &[
56+
"rustc".to_string(),
57+
"--crate-type=lib".to_string(),
58+
"--crate-name".to_string(),
59+
CRATE_NAME.to_string(),
60+
path.to_string(),
61+
];
62+
run!(args, test_generics).unwrap();
63+
}
64+
65+
fn generate_input(path: &str) -> std::io::Result<()> {
66+
std::fs::write(
67+
path,
68+
r#"
69+
pub struct MyStruct<T> {
70+
value: T,
71+
}
72+
73+
pub fn my_fn<U>() {}
74+
"#
75+
)
76+
}

0 commit comments

Comments
 (0)