Skip to content

Commit

Permalink
introduce JavapClassInfo for stuff from javap
Browse files Browse the repository at this point in the history
...and a trait that lets you be generic over
JavapClassInfo or ClassInfo.

Distinguishing `JavapClassInfo` means we know
when the data comes from the "source of truth"
vs the user, but it also means we can serialize
because there is no span.
  • Loading branch information
Niko Matsakis committed Oct 22, 2024
1 parent 68ca04a commit 7815fba
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 40 deletions.
2 changes: 0 additions & 2 deletions cargo-duchess/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::path::PathBuf;

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
Expand Down
6 changes: 3 additions & 3 deletions duchess-build-rs/src/shim_writer.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use std::{fmt::Display, io::Write};

use duchess_reflect::class_info::ClassInfo;
use duchess_reflect::reflect::JavapClassInfo;

use crate::code_writer::CodeWriter;

pub struct ShimWriter<'w> {
cw: CodeWriter<'w>,
shim_name: &'w str,
java_interface_info: &'w ClassInfo,
java_interface_info: &'w JavapClassInfo,
}

impl<'w> ShimWriter<'w> {
pub fn new(
writer: &'w mut impl Write,
shim_name: &'w str,
java_interface_info: &'w ClassInfo,
java_interface_info: &'w JavapClassInfo,
) -> Self {
ShimWriter {
cw: CodeWriter::new(writer),
Expand Down
6 changes: 4 additions & 2 deletions duchess-reflect/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashSet;

use crate::{
class_info::{ClassInfo, ClassRef, Constructor, Flags, Method, RefType, RootMap, Type},
reflect::Reflector,
reflect::{JavapClassInfo, Reflector},
};

impl RootMap {
Expand Down Expand Up @@ -116,8 +116,10 @@ impl ClassInfo {
&mut push_error_message,
);

let refl = JavapClassInfo::from(self.clone());

for c in &self.constructors {
let c_method_sig = c.to_method_sig(self);
let c_method_sig = c.to_method_sig(&refl);

c.check(root_map, &mut |m| {
push_error_message(format!(
Expand Down
71 changes: 62 additions & 9 deletions duchess-reflect/src/class_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use quote::quote_spanned;

use crate::{
parse::{Parse, TextAccum},
reflect::JavapClassInfo,
upcasts::Upcasts,
};

Expand Down Expand Up @@ -150,21 +151,73 @@ pub struct ClassInfo {
pub methods: Vec<Method>,
}

impl ClassInfo {
pub fn parse(text: &str, span: Span) -> syn::Result<ClassInfo> {
javap::parse_class_info(span, &text)
}

pub fn this_ref(&self) -> ClassRef {
/// Trait that allows code to be generic over [`ClassInfo`][]
/// or [`JavapClassInfo`][].
pub trait ClassInfoAccessors {
fn flags(&self) -> &Flags;
fn name(&self) -> &DotId;
fn kind(&self) -> ClassKind;
fn generics(&self) -> &Vec<Generic>;
fn extends(&self) -> &Vec<ClassRef>;
fn implements(&self) -> &Vec<ClassRef>;
fn constructors(&self) -> &Vec<Constructor>;
fn fields(&self) -> &Vec<Field>;
fn methods(&self) -> &Vec<Method>;

fn this_ref(&self) -> ClassRef {
ClassRef {
name: self.name.clone(),
name: self.name().clone(),
generics: self
.generics
.generics()
.iter()
.map(|g| RefType::TypeParameter(g.id.clone()))
.collect(),
}
}
}

impl ClassInfoAccessors for ClassInfo {
fn flags(&self) -> &Flags {
&self.flags
}

fn name(&self) -> &DotId {
&self.name
}

fn kind(&self) -> ClassKind {
self.kind
}

fn generics(&self) -> &Vec<Generic> {
&self.generics
}

fn extends(&self) -> &Vec<ClassRef> {
&self.extends
}

fn implements(&self) -> &Vec<ClassRef> {
&self.implements
}

fn constructors(&self) -> &Vec<Constructor> {
&self.constructors
}

fn fields(&self) -> &Vec<Field> {
&self.fields
}

fn methods(&self) -> &Vec<Method> {
&self.methods
}
}

impl ClassInfo {
pub fn parse(text: &str, span: Span) -> syn::Result<ClassInfo> {
javap::parse_class_info(span, &text)
}

/// Indicates whether a member with the given privacy level should be reflected in Rust.
/// We always mirror things declared as public.
Expand Down Expand Up @@ -283,7 +336,7 @@ pub struct Constructor {
}

impl Constructor {
pub fn to_method_sig(&self, class: &ClassInfo) -> MethodSig {
pub fn to_method_sig(&self, class: &JavapClassInfo) -> MethodSig {
MethodSig {
name: class.name.class_name().clone(),
generics: self.generics.clone(),
Expand Down
103 changes: 94 additions & 9 deletions duchess-reflect/src/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use proc_macro2::Span;
use crate::{
argument::{DuchessDeclaration, Ident, JavaPackage, MethodSelector},
class_info::{
ClassDeclKind, ClassInfo, DotId, Generic, Id, Method, RootMap, SpannedPackageInfo, Type,
ClassDeclKind, ClassInfo, ClassInfoAccessors, ClassKind, ClassRef, Constructor, DotId,
Field, Flags, Generic, Id, Method, RootMap, SpannedPackageInfo, Type,
},
config::Configuration,
upcasts::Upcasts,
Expand Down Expand Up @@ -80,9 +81,8 @@ impl JavaPackage {
(
dot_id,
Arc::new(ClassInfo {
span: c.span,
kind: c.kind,
..(*info).clone()
..info.to_class_info(c.span)
}),
)
}
Expand Down Expand Up @@ -131,7 +131,7 @@ impl JavaPackage {
/// look up info about their interfaces.
pub struct Reflector {
configuration: Configuration,
classes: RefCell<BTreeMap<DotId, Arc<ClassInfo>>>,
classes: RefCell<BTreeMap<DotId, Arc<JavapClassInfo>>>,
}

impl Reflector {
Expand All @@ -143,7 +143,7 @@ impl Reflector {
}

/// Returns the (potentially cached) info about `class_name`;
pub fn reflect(&self, class_name: &DotId, span: Span) -> syn::Result<Arc<ClassInfo>> {
pub fn reflect(&self, class_name: &DotId, span: Span) -> syn::Result<Arc<JavapClassInfo>> {
// yields an error if we cannot reflect on that class.
if let Some(class) = self.classes.borrow().get(class_name).map(Arc::clone) {
return Ok(class);
Expand Down Expand Up @@ -190,11 +190,11 @@ impl Reflector {
}
};

let mut ci = ClassInfo::parse(&s, span)?;
let ci = ClassInfo::parse(&s, span)?;
let ci = JavapClassInfo::from(ci);

// reset the span for the cached data to the call site so that when others look it up,
// they get the same span.
ci.span = Span::call_site();
Ok(self
.classes
.borrow_mut()
Expand All @@ -208,7 +208,7 @@ impl Reflector {
match method_selector {
MethodSelector::ClassName(cn) => {
let dot_id = cn.to_dot_id();
let class_info = self.reflect(&dot_id, cn.span)?;
let class_info = Arc::new(self.reflect(&dot_id, cn.span)?.to_class_info(cn.span));
match class_info.constructors.len() {
1 => Ok(ReflectedMethod::Constructor(class_info, 0)),
0 => Err(syn::Error::new(cn.span, "no constructors found".to_string())),
Expand All @@ -217,7 +217,7 @@ impl Reflector {
}
MethodSelector::MethodName(cn, mn) => {
let dot_id = cn.to_dot_id();
let class_info = self.reflect(&dot_id, cn.span)?;
let class_info = Arc::new(self.reflect(&dot_id, cn.span)?.to_class_info(cn.span));
let methods: Vec<(MethodIndex, &Method)> = class_info
.methods
.iter()
Expand All @@ -238,6 +238,91 @@ impl Reflector {
}
}

#[derive(Clone, Debug)]
pub struct JavapClassInfo {
#[allow(dead_code)] // FIXME: replace with `#[expect]` once that stabilizes
pub flags: Flags,
pub name: DotId,
pub kind: ClassKind,
pub generics: Vec<Generic>,
pub extends: Vec<ClassRef>,
pub implements: Vec<ClassRef>,
pub constructors: Vec<Constructor>,
pub fields: Vec<Field>,
pub methods: Vec<Method>,
}

impl ClassInfoAccessors for JavapClassInfo {
fn flags(&self) -> &Flags {
&self.flags
}

fn name(&self) -> &DotId {
&self.name
}

fn kind(&self) -> ClassKind {
self.kind
}

fn generics(&self) -> &Vec<Generic> {
&self.generics
}

fn extends(&self) -> &Vec<ClassRef> {
&self.extends
}

fn implements(&self) -> &Vec<ClassRef> {
&self.implements
}

fn constructors(&self) -> &Vec<Constructor> {
&self.constructors
}

fn fields(&self) -> &Vec<Field> {
&self.fields
}

fn methods(&self) -> &Vec<Method> {
&self.methods
}
}

impl From<ClassInfo> for JavapClassInfo {
fn from(ci: ClassInfo) -> Self {
Self {
flags: ci.flags,
name: ci.name,
kind: ci.kind,
generics: ci.generics,
extends: ci.extends,
implements: ci.implements,
constructors: ci.constructors,
fields: ci.fields,
methods: ci.methods,
}
}
}

impl JavapClassInfo {
pub fn to_class_info(&self, span: Span) -> ClassInfo {
ClassInfo {
span: span,
flags: self.flags,
name: self.name.clone(),
kind: self.kind,
generics: self.generics.clone(),
extends: self.extends.clone(),
implements: self.implements.clone(),
constructors: self.constructors.clone(),
fields: self.fields.clone(),
methods: self.methods.clone(),
}
}
}

pub type ConstructorIndex = usize;
pub type MethodIndex = usize;

Expand Down
19 changes: 11 additions & 8 deletions duchess-reflect/src/upcasts.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::{BTreeMap, BTreeSet};

use crate::{
class_info::{ClassInfo, ClassRef, DotId, Id},
class_info::{ClassInfoAccessors, ClassRef, DotId, Id},
substitution::{Substitute, Substitution},
};

Expand All @@ -23,8 +23,11 @@ pub struct ClassUpcasts {
extends: BTreeSet<ClassRef>,
}

impl<'a> FromIterator<&'a ClassInfo> for Upcasts {
fn from_iter<T: IntoIterator<Item = &'a ClassInfo>>(iter: T) -> Self {
impl<'a, CI> FromIterator<&'a CI> for Upcasts
where
CI: ClassInfoAccessors,
{
fn from_iter<T: IntoIterator<Item = &'a CI>>(iter: T) -> Self {
let mut upcasts = Upcasts::default();

for class_info in iter {
Expand All @@ -48,27 +51,27 @@ impl Upcasts {
}

/// Insert the direct (declared by user) superclasses of `class` into the map.
fn insert_direct_upcasts(&mut self, class: &ClassInfo) {
fn insert_direct_upcasts(&mut self, class: &dyn ClassInfoAccessors) {
let mut upcasts = ClassUpcasts {
generics: class.generics.iter().map(|g| g.id.clone()).collect(),
generics: class.generics().iter().map(|g| g.id.clone()).collect(),
extends: BTreeSet::default(),
};

// Include direct upcasts declared by the user.
for c in class.extends.iter().chain(&class.implements) {
for c in class.extends().iter().chain(class.implements()) {
upcasts.extends.insert(c.clone());
}

// Everything can be upcast to object.
let object = DotId::object();
if class.name != object {
if *class.name() != object {
upcasts.extends.insert(ClassRef {
name: object,
generics: vec![],
});
}

let old_value = self.map.insert(class.name.clone(), upcasts);
let old_value = self.map.insert(class.name().clone(), upcasts);
assert!(old_value.is_none());
}

Expand Down
Loading

0 comments on commit 7815fba

Please sign in to comment.