Skip to content

Commit

Permalink
refactor(*): move common code to core and tidy up imports (#931)
Browse files Browse the repository at this point in the history
Signed-off-by: Jiaxiao Zhou (Mossaka) <duibao55328@gmail.com>
  • Loading branch information
Mossaka authored Apr 22, 2024
1 parent 269fb7c commit b3c42db
Show file tree
Hide file tree
Showing 11 changed files with 311 additions and 349 deletions.
26 changes: 9 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ version = "0.24.0"
[workspace.dependencies]
anyhow = "1.0.72"
bitflags = "2.3.3"
heck = { version = "0.4", features = ["unicode"] }
heck = { version = "0.5" }
pulldown-cmark = { version = "0.9", default-features = false }
clap = { version = "4.3.19", features = ["derive"] }
indexmap = "2.0.0"
Expand Down
1 change: 1 addition & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ doctest = false
[dependencies]
wit-parser = { workspace = true }
anyhow = { workspace = true }
heck = { workspace = true }
228 changes: 4 additions & 224 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::fmt::Write;

use anyhow::Result;
Expand All @@ -9,6 +8,10 @@ mod ns;
pub use ns::Ns;
pub mod source;
pub use source::{Files, Source};
mod types;
pub use types::{TypeInfo, Types};
mod path;
pub use path::name_package_module;

#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
pub enum Direction {
Expand All @@ -17,229 +20,6 @@ pub enum Direction {
Export,
}

#[derive(Default)]
pub struct Types {
type_info: HashMap<TypeId, TypeInfo>,
}

#[derive(Default, Clone, Copy, Debug)]
pub struct TypeInfo {
/// Whether or not this type is ever used (transitively) within the
/// parameter of an imported function.
///
/// This means that it's used in a context where ownership isn't
/// relinquished.
pub borrowed: bool,

/// Whether or not this type is ever used (transitively) within the
/// parameter or result of an export, or the result of an import.
///
/// This means that it's used in a context where ownership is required and
/// memory management is necessary.
pub owned: bool,

/// Whether or not this type is ever used (transitively) within the
/// error case in the result of a function.
pub error: bool,

/// Whether or not this type (transitively) has a list (or string).
pub has_list: bool,

/// Whether or not this type (transitively) has a resource (or handle).
pub has_resource: bool,

/// Whether or not this type (transitively) has a borrow handle.
pub has_borrow_handle: bool,

/// Whether or not this type (transitively) has an own handle.
pub has_own_handle: bool,
}

impl std::ops::BitOrAssign for TypeInfo {
fn bitor_assign(&mut self, rhs: Self) {
self.borrowed |= rhs.borrowed;
self.owned |= rhs.owned;
self.error |= rhs.error;
self.has_list |= rhs.has_list;
self.has_resource |= rhs.has_resource;
self.has_borrow_handle |= rhs.has_borrow_handle;
self.has_own_handle |= rhs.has_own_handle;
}
}

impl TypeInfo {
pub fn is_clone(&self) -> bool {
!self.has_resource
}
pub fn is_copy(&self) -> bool {
!self.has_list && !self.has_resource
}
}

impl Types {
pub fn analyze(&mut self, resolve: &Resolve) {
for (t, _) in resolve.types.iter() {
self.type_id_info(resolve, t);
}
for (_, world) in resolve.worlds.iter() {
for (import, (_, item)) in world
.imports
.iter()
.map(|i| (true, i))
.chain(world.exports.iter().map(|i| (false, i)))
{
match item {
WorldItem::Function(f) => {
self.type_info_func(resolve, f, import);
}
WorldItem::Interface(id) => {
for (_, f) in resolve.interfaces[*id].functions.iter() {
self.type_info_func(resolve, f, import);
}
}
WorldItem::Type(_) => {}
}
}
}
}

fn type_info_func(&mut self, resolve: &Resolve, func: &Function, import: bool) {
let mut live = LiveTypes::default();
for (_, ty) in func.params.iter() {
self.type_info(resolve, ty);
live.add_type(resolve, ty);
}
for id in live.iter() {
if resolve.types[id].name.is_some() {
let info = self.type_info.get_mut(&id).unwrap();
if import {
info.borrowed = true;
} else {
info.owned = true;
}
}
}
let mut live = LiveTypes::default();
for ty in func.results.iter_types() {
self.type_info(resolve, ty);
live.add_type(resolve, ty);
}
for id in live.iter() {
if resolve.types[id].name.is_some() {
self.type_info.get_mut(&id).unwrap().owned = true;
}
}

for ty in func.results.iter_types() {
let id = match ty {
Type::Id(id) => *id,
_ => continue,
};
let err = match &resolve.types[id].kind {
TypeDefKind::Result(Result_ { err, .. }) => err,
_ => continue,
};
if let Some(Type::Id(id)) = err {
// When an interface `use`s a type from another interface, it creates a new typeid
// referring to the definition typeid. Chase any chain of references down to the
// typeid of the definition.
fn resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId {
loop {
match resolve.types[id].kind {
TypeDefKind::Type(Type::Id(def_id)) => id = def_id,
_ => return id,
}
}
}
let id = resolve_type_definition_id(resolve, *id);
self.type_info.get_mut(&id).unwrap().error = true;
}
}
}

pub fn get(&self, id: TypeId) -> TypeInfo {
self.type_info[&id]
}

pub fn type_id_info(&mut self, resolve: &Resolve, ty: TypeId) -> TypeInfo {
if let Some(info) = self.type_info.get(&ty) {
return *info;
}
let mut info = TypeInfo::default();
match &resolve.types[ty].kind {
TypeDefKind::Record(r) => {
for field in r.fields.iter() {
info |= self.type_info(resolve, &field.ty);
}
}
TypeDefKind::Resource => {
info.has_resource = true;
}
TypeDefKind::Handle(handle) => {
match handle {
Handle::Borrow(_) => info.has_borrow_handle = true,
Handle::Own(_) => info.has_own_handle = true,
}
info.has_resource = true;
}
TypeDefKind::Tuple(t) => {
for ty in t.types.iter() {
info |= self.type_info(resolve, ty);
}
}
TypeDefKind::Flags(_) => {}
TypeDefKind::Enum(_) => {}
TypeDefKind::Variant(v) => {
for case in v.cases.iter() {
info |= self.optional_type_info(resolve, case.ty.as_ref());
}
}
TypeDefKind::List(ty) => {
info = self.type_info(resolve, ty);
info.has_list = true;
}
TypeDefKind::Type(ty) => {
info = self.type_info(resolve, ty);
}
TypeDefKind::Option(ty) => {
info = self.type_info(resolve, ty);
}
TypeDefKind::Result(r) => {
info = self.optional_type_info(resolve, r.ok.as_ref());
info |= self.optional_type_info(resolve, r.err.as_ref());
}
TypeDefKind::Future(ty) => {
info = self.optional_type_info(resolve, ty.as_ref());
}
TypeDefKind::Stream(stream) => {
info = self.optional_type_info(resolve, stream.element.as_ref());
info |= self.optional_type_info(resolve, stream.end.as_ref());
}
TypeDefKind::Unknown => unreachable!(),
}
let prev = self.type_info.insert(ty, info);
assert!(prev.is_none());
info
}

pub fn type_info(&mut self, resolve: &Resolve, ty: &Type) -> TypeInfo {
let mut info = TypeInfo::default();
match ty {
Type::String => info.has_list = true,
Type::Id(id) => return self.type_id_info(resolve, *id),
_ => {}
}
info
}

fn optional_type_info(&mut self, resolve: &Resolve, ty: Option<&Type>) -> TypeInfo {
match ty {
Some(ty) => self.type_info(resolve, ty),
None => TypeInfo::default(),
}
}
}

pub trait WorldGenerator {
fn generate(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) -> Result<()> {
let world = &resolve.worlds[id];
Expand Down
Loading

0 comments on commit b3c42db

Please sign in to comment.