Extract trivial extern type alias detection to module
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 31c88c9..4cedc28 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -22,6 +22,7 @@
pub mod symbol;
mod tokens;
mod toposort;
+pub mod trivial;
pub mod types;
use self::discriminant::Discriminant;
diff --git a/syntax/trivial.rs b/syntax/trivial.rs
new file mode 100644
index 0000000..7a77937
--- /dev/null
+++ b/syntax/trivial.rs
@@ -0,0 +1,131 @@
+use crate::syntax::set::OrderedSet as Set;
+use crate::syntax::{Api, Enum, ExternFn, ExternType, RustName, Struct, Type};
+use proc_macro2::Ident;
+use std::collections::BTreeMap as Map;
+use std::fmt::Display;
+
+#[derive(Copy, Clone)]
+pub enum TrivialReason<'a> {
+ StructField(&'a Struct),
+ FunctionArgument(&'a ExternFn),
+ FunctionReturn(&'a ExternFn),
+ BoxTarget,
+ VecElement,
+ UnpinnedMutArg(&'a ExternFn),
+}
+
+pub fn required_trivial_reasons<'a>(
+ apis: &'a [Api],
+ all: &Set<&'a Type>,
+ structs: &Map<&'a Ident, &'a Struct>,
+ enums: &Map<&'a Ident, &'a Enum>,
+ cxx: &Set<&'a Ident>,
+) -> Map<&'a Ident, Vec<TrivialReason<'a>>> {
+ let mut required_trivial = Map::new();
+
+ let mut insist_extern_types_are_trivial = |ident: &'a RustName, reason| {
+ if cxx.contains(&ident.rust)
+ && !structs.contains_key(&ident.rust)
+ && !enums.contains_key(&ident.rust)
+ {
+ required_trivial
+ .entry(&ident.rust)
+ .or_insert_with(Vec::new)
+ .push(reason);
+ }
+ };
+
+ for api in apis {
+ match api {
+ Api::Struct(strct) => {
+ for field in &strct.fields {
+ if let Type::Ident(ident) = &field.ty {
+ let reason = TrivialReason::StructField(strct);
+ insist_extern_types_are_trivial(ident, reason);
+ }
+ }
+ }
+ Api::CxxFunction(efn) | Api::RustFunction(efn) => {
+ if let Some(receiver) = &efn.receiver {
+ if receiver.mutable && !receiver.pinned {
+ let reason = TrivialReason::UnpinnedMutArg(efn);
+ insist_extern_types_are_trivial(&receiver.ty, reason);
+ }
+ }
+ for arg in &efn.args {
+ match &arg.ty {
+ Type::Ident(ident) => {
+ let reason = TrivialReason::FunctionArgument(efn);
+ insist_extern_types_are_trivial(ident, reason);
+ }
+ Type::Ref(ty) => {
+ if ty.mutable && !ty.pinned {
+ if let Type::Ident(ident) = &ty.inner {
+ let reason = TrivialReason::UnpinnedMutArg(efn);
+ insist_extern_types_are_trivial(ident, reason);
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ if let Some(ret) = &efn.ret {
+ if let Type::Ident(ident) = &ret {
+ let reason = TrivialReason::FunctionReturn(efn);
+ insist_extern_types_are_trivial(ident, reason);
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+
+ for ty in all {
+ match ty {
+ Type::RustBox(ty) => {
+ if let Type::Ident(ident) = &ty.inner {
+ let reason = TrivialReason::BoxTarget;
+ insist_extern_types_are_trivial(ident, reason);
+ }
+ }
+ Type::RustVec(ty) => {
+ if let Type::Ident(ident) = &ty.inner {
+ let reason = TrivialReason::VecElement;
+ insist_extern_types_are_trivial(ident, reason);
+ }
+ }
+ _ => {}
+ }
+ }
+
+ required_trivial
+}
+
+impl<'a> TrivialReason<'a> {
+ pub fn describe_in_context(&self, ety: &ExternType) -> String {
+ match self {
+ TrivialReason::BoxTarget => format!("Box<{}>", ety.name.rust),
+ TrivialReason::VecElement => format!("a vector element in Vec<{}>", ety.name.rust),
+ _ => self.to_string(),
+ }
+ }
+}
+
+impl<'a> Display for TrivialReason<'a> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ TrivialReason::StructField(strct) => write!(f, "a field of `{}`", strct.name.rust),
+ TrivialReason::FunctionArgument(efn) => write!(f, "an argument of `{}`", efn.name.rust),
+ TrivialReason::FunctionReturn(efn) => {
+ write!(f, "a return value of `{}`", efn.name.rust)
+ }
+ TrivialReason::BoxTarget => write!(f, "in a Box<...>"),
+ TrivialReason::VecElement => write!(f, "a Vec<...> element"),
+ TrivialReason::UnpinnedMutArg(efn) => write!(
+ f,
+ "a non-pinned mutable reference argument of {}",
+ efn.name.rust
+ ),
+ }
+ }
+}
diff --git a/syntax/types.rs b/syntax/types.rs
index 173610d..1056854 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -1,13 +1,13 @@
use crate::syntax::improper::ImproperCtype;
use crate::syntax::report::Errors;
use crate::syntax::set::{OrderedSet as Set, UnorderedSet};
+use crate::syntax::trivial::{self, TrivialReason};
use crate::syntax::{
- toposort, Api, Enum, ExternFn, ExternType, Impl, Pair, RustName, Struct, Type, TypeAlias,
+ toposort, Api, Enum, ExternType, Impl, Pair, RustName, Struct, Type, TypeAlias,
};
use proc_macro2::Ident;
use quote::ToTokens;
use std::collections::BTreeMap as Map;
-use std::fmt::Display;
pub struct Types<'a> {
pub all: Set<&'a Type>,
@@ -168,80 +168,8 @@
// we check that this is permissible. We do this _after_ scanning all
// the APIs above, in case some function or struct references a type
// which is declared subsequently.
- let mut required_trivial: Map<_, Vec<_>> = Map::new();
-
- let mut insist_extern_types_are_trivial = |ident: &'a RustName, reason| {
- if cxx.contains(&ident.rust)
- && !structs.contains_key(&ident.rust)
- && !enums.contains_key(&ident.rust)
- {
- required_trivial
- .entry(&ident.rust)
- .or_default()
- .push(reason);
- }
- };
- for api in apis {
- match api {
- Api::Struct(strct) => {
- for field in &strct.fields {
- if let Type::Ident(ident) = &field.ty {
- let reason = TrivialReason::StructField(strct);
- insist_extern_types_are_trivial(ident, reason);
- }
- }
- }
- Api::CxxFunction(efn) | Api::RustFunction(efn) => {
- if let Some(receiver) = &efn.receiver {
- if receiver.mutable && !receiver.pinned {
- let reason = TrivialReason::UnpinnedMutArg(efn);
- insist_extern_types_are_trivial(&receiver.ty, reason);
- }
- }
- for arg in &efn.args {
- match &arg.ty {
- Type::Ident(ident) => {
- let reason = TrivialReason::FunctionArgument(efn);
- insist_extern_types_are_trivial(ident, reason);
- }
- Type::Ref(ty) => {
- if ty.mutable && !ty.pinned {
- if let Type::Ident(ident) = &ty.inner {
- let reason = TrivialReason::UnpinnedMutArg(efn);
- insist_extern_types_are_trivial(ident, reason);
- }
- }
- }
- _ => {}
- }
- }
- if let Some(ret) = &efn.ret {
- if let Type::Ident(ident) = &ret {
- let reason = TrivialReason::FunctionReturn(efn);
- insist_extern_types_are_trivial(ident, reason);
- }
- }
- }
- _ => {}
- }
- }
- for ty in &all {
- match ty {
- Type::RustBox(ty) => {
- if let Type::Ident(ident) = &ty.inner {
- let reason = TrivialReason::BoxTarget;
- insist_extern_types_are_trivial(ident, reason);
- }
- }
- Type::RustVec(ty) => {
- if let Type::Ident(ident) = &ty.inner {
- let reason = TrivialReason::VecElement;
- insist_extern_types_are_trivial(ident, reason);
- }
- }
- _ => {}
- }
- }
+ let required_trivial =
+ trivial::required_trivial_reasons(apis, &all, &structs, &enums, &cxx);
let mut types = Types {
all,
@@ -321,45 +249,6 @@
}
}
-#[derive(Copy, Clone)]
-pub enum TrivialReason<'a> {
- StructField(&'a Struct),
- FunctionArgument(&'a ExternFn),
- FunctionReturn(&'a ExternFn),
- BoxTarget,
- VecElement,
- UnpinnedMutArg(&'a ExternFn),
-}
-
-impl<'a> TrivialReason<'a> {
- pub fn describe_in_context(&self, ety: &ExternType) -> String {
- match self {
- TrivialReason::BoxTarget => format!("Box<{}>", ety.name.rust),
- TrivialReason::VecElement => format!("a vector element in Vec<{}>", ety.name.rust),
- _ => self.to_string(),
- }
- }
-}
-
-impl<'a> Display for TrivialReason<'a> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- TrivialReason::StructField(strct) => write!(f, "a field of `{}`", strct.name.rust),
- TrivialReason::FunctionArgument(efn) => write!(f, "an argument of `{}`", efn.name.rust),
- TrivialReason::FunctionReturn(efn) => {
- write!(f, "a return value of `{}`", efn.name.rust)
- }
- TrivialReason::BoxTarget => write!(f, "in a Box<...>"),
- TrivialReason::VecElement => write!(f, "a Vec<...> element"),
- TrivialReason::UnpinnedMutArg(efn) => write!(
- f,
- "a non-pinned mutable reference argument of {}",
- efn.name.rust
- ),
- }
- }
-}
-
fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
let msg = format!("the name `{}` is defined multiple times", ident);
cx.error(sp, msg);