Skip to content

Commit

Permalink
Generate encoding tests
Browse files Browse the repository at this point in the history
This found at least one mistake, tensorByDequantizingToType:scale:bias:
in MLCompute, which seems to take a float internally that it doesn't
declare in the header!

This might also allow us to remove encoding testing at runtime from
`extern_methods!` in the future.
  • Loading branch information
madsmtm committed Dec 17, 2024
1 parent e71b884 commit 3100e5f
Show file tree
Hide file tree
Showing 25 changed files with 1,180 additions and 62 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,18 @@ jobs:
- name: Verify that no files changed
run: git diff --exit-code --submodule=diff

- name: Run auto-generated framework tests
if: ${{ github.ref_name == 'ci-full' }}
run: cargo test -ptest-frameworks --features=test-frameworks

- name: Install Mac Catalyst
if: ${{ github.ref_name == 'ci-full' }}
run: rustup target add aarch64-apple-ios-macabi

- name: Run auto-generated framework tests on Mac Catalyst
if: ${{ github.ref_name == 'ci-full' }}
run: cargo test -ptest-frameworks --features=test-frameworks --target=aarch64-apple-ios-macabi

check-framework-features:
# This will take ~40 minutes
if: ${{ github.ref_name == 'ci-full' }}
Expand Down
99 changes: 99 additions & 0 deletions Cargo.lock

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

166 changes: 164 additions & 2 deletions crates/header-translator/src/availability.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::fmt;
use std::{
cmp::Ordering,
fmt::{self, Display},
};

use clang::{Entity, PlatformAvailability, Version};

use crate::context::Context;
use crate::{context::Context, display_helper::FormatterFn};

#[derive(Debug, Clone, PartialEq, Default)]
struct Unavailable {
Expand All @@ -24,6 +27,77 @@ pub struct Versions {
pub(crate) visionos: Option<Version>,
}

impl Versions {
const NONE: Self = Self {
macos: None,
maccatalyst: None,
ios: None,
tvos: None,
watchos: None,
visionos: None,
};

const RUST_OS_MIN: Self = Self {
macos: Some(Version {
x: 10,
y: Some(12),
z: None,
}),
maccatalyst: Some(Version {
x: 13,
y: Some(1),
z: None,
}),
ios: Some(Version {
x: 10,
y: Some(0),
z: None,
}),
tvos: Some(Version {
x: 10,
y: Some(0),
z: None,
}),
watchos: Some(Version {
x: 5,
y: Some(0),
z: None,
}),
visionos: Some(Version {
x: 1,
y: Some(0),
z: None,
}),
};

fn emit_if(&self, bound: &Self, condition: impl Fn(Version, Version) -> bool) -> Self {
let filter = |this, bound| {
if let Some(this) = this {
if let Some(bound) = bound {
if (condition)(this, bound) {
Some(this)
} else {
None
}
} else {
Some(this)
}
} else {
None
}
};

Self {
macos: filter(self.macos, bound.macos),
maccatalyst: filter(self.maccatalyst, bound.maccatalyst),
ios: filter(self.ios, bound.ios),
tvos: filter(self.tvos, bound.tvos),
watchos: filter(self.watchos, bound.watchos),
visionos: filter(self.visionos, bound.visionos),
}
}
}

/// <https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID583>
#[derive(Debug, Clone, PartialEq)]
pub struct Availability {
Expand All @@ -34,6 +108,32 @@ pub struct Availability {
_swift: Option<PlatformAvailability>,
}

fn format_version(version: Version) -> impl Display {
FormatterFn(move |f| {
write!(f, "{}", version.x)?;

if let Some(y) = version.y {
write!(f, ".{}", y)?;

if let Some(z) = version.z {
write!(f, ".{}", z)?;
}
} else if let Some(z) = version.z {
// Probably never gonna happen, but just to make sure
write!(f, ".0.{}", z)?;
}

Ok(())
})
}

fn version_cmp(left: Version, right: Version) -> Ordering {
left.x
.cmp(&right.x)
.then_with(|| left.y.unwrap_or(0).cmp(&right.y.unwrap_or(0)))
.then_with(|| left.z.unwrap_or(0).cmp(&right.z.unwrap_or(0)))
}

impl Availability {
pub fn parse(entity: &Entity<'_>, _context: &Context<'_>) -> Self {
let availabilities = entity
Expand Down Expand Up @@ -142,6 +242,68 @@ impl Availability {
}
)
}

pub fn check_is_available(&self) -> Option<impl Display + '_> {
let mut introduced = self.introduced.emit_if(&Versions::RUST_OS_MIN, |v, rust| {
version_cmp(v, rust).is_gt()
});

let unavailable = &self.unavailable;

let max = Some(Version {
x: 9999,
y: None,
z: None,
});
if unavailable.macos {
introduced.macos = max;
}
if unavailable.maccatalyst {
introduced.maccatalyst = max;
}
if unavailable.ios {
introduced.ios = max;
}
if unavailable.tvos {
introduced.tvos = max;
}
if unavailable.watchos {
introduced.watchos = max;
}
if unavailable.visionos {
introduced.visionos = max;
}

if introduced == Versions::NONE {
return None;
}

Some(FormatterFn(move |f| {
write!(f, "available!(")?;

if let Some(version) = introduced.macos {
write!(f, "macos = {}, ", format_version(version))?;
}
if let Some(version) = introduced.ios {
write!(f, "ios = {}, ", format_version(version))?;
}
if let Some(version) = introduced.tvos {
write!(f, "tvos = {}, ", format_version(version))?;
}
if let Some(version) = introduced.watchos {
write!(f, "watchos = {}, ", format_version(version))?;
}
if let Some(version) = introduced.visionos {
write!(f, "visionos = {}, ", format_version(version))?;
}

write!(f, "..)")?;

// TODO: Add cfg!(not(...)) based on self.unavailable

Ok(())
}))
}
}

impl fmt::Display for Availability {
Expand Down
22 changes: 22 additions & 0 deletions crates/header-translator/src/cfgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ impl CfgState {
}
}

fn explicit(should_gate: bool) -> Self {
if should_gate {
Self::ShouldGate
} else {
Self::Omit
}
}

fn dependency(&mut self, dependency: bool) {
*self = match (*self, dependency) {
(Self::ShouldGate, true) => Self::ShouldGate,
Expand Down Expand Up @@ -75,6 +83,20 @@ impl PlatformCfg {
}
}

pub fn from_config_explicit(lib: &LibraryConfig) -> Self {
Self {
macos: CfgState::explicit(lib.macos.is_some()),
// FIXME: Temporarily disable Mac Catalyst, see above
maccatalyst: CfgState::AlreadyGated,
ios: CfgState::explicit(lib.ios.is_some()),
tvos: CfgState::explicit(lib.tvos.is_some()),
watchos: CfgState::explicit(lib.watchos.is_some()),
visionos: CfgState::explicit(lib.visionos.is_some()),
// FIXME: Support this better?
gnustep: CfgState::new(false),
}
}

pub fn dependency(&mut self, dependency: &LibraryConfig) {
self.macos.dependency(dependency.macos.is_some());
// FIXME: Temporarily disable Mac Catalyst, see above
Expand Down
4 changes: 3 additions & 1 deletion crates/header-translator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,20 @@ mod stmt;
mod thread_safety;
mod unexposed_attr;

pub use self::cfgs::PlatformCfg;
pub use self::config::{Config, LibraryConfig};
pub use self::context::{Context, MacroEntity, MacroLocation};
pub use self::global_analysis::global_analysis;
pub use self::id::{ItemIdentifier, Location};
pub use self::library::Library;
pub use self::library::{EntryExt, Library};
pub use self::module::Module;
pub use self::stmt::{Counterpart, Stmt};

pub fn run_cargo_fmt(packages: impl IntoIterator<Item = impl Display>) {
let status = Command::new("cargo")
.arg("fmt")
.args(packages.into_iter().map(|package| format!("-p{package}")))
.arg("-ptest-frameworks")
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap())
.status()
.expect("failed running cargo fmt");
Expand Down
Loading

0 comments on commit 3100e5f

Please sign in to comment.