From 6590869a12591404078ebad8b093ca0a9cd88f2a Mon Sep 17 00:00:00 2001 From: Mingwei Samuel Date: Wed, 11 Dec 2024 11:34:34 -0800 Subject: [PATCH 1/7] ci stable, no more z flags --- .cargo/config.toml | 4 --- .github/workflows/ci.yml | 64 ++++++++++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index be883d3e2fd4..e604c11a1087 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,12 +1,8 @@ [build] rustflags = [ - "-Zproc-macro-backtrace", # Flag to make build.rs scripts generate docs. Should only be used in this repository # internally, not by dependants. '--cfg=HYDROFLOW_GENERATE_DOCS', - # https://github.com/rust-lang/rust-clippy/issues/10087 - ## TODO(mingwei): Need rust-analyzer support: - # "-Aclippy::uninlined-format-args", ] [target.x86_64-apple-darwin] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7af071b226a0..4b4cc3b9e478 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,13 +36,13 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - rust_release: [pinned-nightly, latest-nightly] + rust_release: [pinned-nightly, latest-stable] exclude: # For non-pull requests, event_name != 'pull_request' will be true, and 'nothing' is # truthy, so the entire && operator will resolve to 'nothing'. Then the || operator will # resolve to 'nothing' so we will exclude 'nothing'. https://stackoverflow.com/a/73822998 - rust_release: ${{ (needs.pre_job.outputs.should_skip != 'true' && 'nothing') || 'pinned-nightly' }} - - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-nightly' }} + - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-stable' }} env: CARGO_TERM_COLOR: always @@ -55,12 +55,17 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Install nightly toolchain + - name: Override RUSTFLAGS + run: echo "RUSTFLAGS=--cfg noop" >> $GITHUB_ENV + shell: bash + if: matrix.rust_release == 'latest-stable' + + - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly - override: ${{ matrix.rust_release == 'latest-nightly' }} + toolchain: stable + override: ${{ matrix.rust_release == 'latest-stable' }} components: rustfmt, clippy - name: Run sccache-cache @@ -96,25 +101,30 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust_release: [pinned-nightly, latest-nightly] + rust_release: [pinned-nightly, latest-stable] exclude: # For non-pull requests, event_name != 'pull_request' will be true, and 'nothing' is # truthy, so the entire && operator will resolve to 'nothing'. Then the || operator will # resolve to 'nothing' so we will exclude 'nothing'. https://stackoverflow.com/a/73822998 - rust_release: ${{ (needs.pre_job.outputs.should_skip != 'true' && 'nothing') || 'pinned-nightly' }} - - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-nightly' }} + - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-stable' }} steps: - name: Checkout sources uses: actions/checkout@v3 - - name: Install nightly toolchain + - name: Override RUSTFLAGS + run: echo "RUSTFLAGS=--cfg noop" >> $GITHUB_ENV + shell: bash + if: matrix.rust_release == 'latest-stable' + + - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: stable target: wasm32-unknown-unknown - override: ${{ matrix.rust_release == 'latest-nightly' }} + override: ${{ matrix.rust_release == 'latest-stable' }} - name: Check hydroflow_lang uses: actions-rs/cargo@v1 @@ -132,13 +142,13 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - rust_release: [pinned-nightly, latest-nightly] + rust_release: [pinned-nightly, latest-stable] exclude: # For non-pull requests, event_name != 'pull_request' will be true, and 'nothing' is # truthy, so the entire && operator will resolve to 'nothing'. Then the || operator will # resolve to 'nothing' so we will exclude 'nothing'. https://stackoverflow.com/a/73822998 - rust_release: ${{ (needs.pre_job.outputs.should_skip != 'true' && 'nothing') || 'pinned-nightly' }} - - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-nightly' }} + - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-stable' }} - os: ${{ (github.event_name != 'pull_request' && 'nothing') || 'windows-latest' }} env: @@ -152,12 +162,17 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Install nightly toolchain + - name: Override RUSTFLAGS + run: echo "RUSTFLAGS=--cfg noop" >> $GITHUB_ENV + shell: bash + if: matrix.rust_release == 'latest-stable' + + - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly - override: ${{ matrix.rust_release == 'latest-nightly' }} + toolchain: stable + override: ${{ matrix.rust_release == 'latest-stable' }} - name: Run sccache-cache if: matrix.rust_release == 'pinned-nightly' @@ -235,25 +250,30 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust_release: [pinned-nightly, latest-nightly] + rust_release: [pinned-nightly, latest-stable] exclude: # For non-pull requests, event_name != 'pull_request' will be true, and 'nothing' is # truthy, so the entire && operator will resolve to 'nothing'. Then the || operator will # resolve to 'nothing' so we will exclude 'nothing'. https://stackoverflow.com/a/73822998 - rust_release: ${{ (needs.pre_job.outputs.should_skip != 'true' && 'nothing') || 'pinned-nightly' }} - - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-nightly' }} + - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-stable' }} steps: - name: Checkout sources uses: actions/checkout@v3 - - name: Install nightly toolchain + - name: Override RUSTFLAGS + run: echo "RUSTFLAGS=--cfg noop" >> $GITHUB_ENV + shell: bash + if: matrix.rust_release == 'latest-stable' + + - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: stable target: wasm32-unknown-unknown - override: ${{ matrix.rust_release == 'latest-nightly' }} + override: ${{ matrix.rust_release == 'latest-stable' }} - name: Get wasm-bindgen version id: wasm-bindgen-version @@ -299,7 +319,7 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Install nightly toolchain + - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal @@ -366,7 +386,7 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Install nightly toolchain + - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal From 646bb8ffd615dada4b83d57f52981433f0bc9515 Mon Sep 17 00:00:00 2001 From: Mingwei Samuel Date: Wed, 11 Dec 2024 11:36:28 -0800 Subject: [PATCH 2/7] remove rustflags override --- .github/workflows/ci.yml | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b4cc3b9e478..82eda5e7febf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,11 +55,6 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Override RUSTFLAGS - run: echo "RUSTFLAGS=--cfg noop" >> $GITHUB_ENV - shell: bash - if: matrix.rust_release == 'latest-stable' - - name: Install toolchain uses: actions-rs/toolchain@v1 with: @@ -113,11 +108,6 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Override RUSTFLAGS - run: echo "RUSTFLAGS=--cfg noop" >> $GITHUB_ENV - shell: bash - if: matrix.rust_release == 'latest-stable' - - name: Install toolchain uses: actions-rs/toolchain@v1 with: @@ -162,11 +152,6 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Override RUSTFLAGS - run: echo "RUSTFLAGS=--cfg noop" >> $GITHUB_ENV - shell: bash - if: matrix.rust_release == 'latest-stable' - - name: Install toolchain uses: actions-rs/toolchain@v1 with: @@ -262,11 +247,6 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Override RUSTFLAGS - run: echo "RUSTFLAGS=--cfg noop" >> $GITHUB_ENV - shell: bash - if: matrix.rust_release == 'latest-stable' - - name: Install toolchain uses: actions-rs/toolchain@v1 with: From 5b9b563053938518d3fe459199d9bf06237effc3 Mon Sep 17 00:00:00 2001 From: Mingwei Samuel Date: Wed, 11 Dec 2024 11:46:31 -0800 Subject: [PATCH 3/7] wip --- Cargo.lock | 12 ++++- hydroflow/Cargo.toml | 2 +- hydroflow_datalog/Cargo.toml | 3 -- hydroflow_datalog_core/Cargo.toml | 4 -- hydroflow_lang/Cargo.toml | 2 +- hydroflow_lang/build.rs | 10 ++++ hydroflow_lang/src/diagnostic.rs | 60 ++++++++++++++------- hydroflow_lang/src/graph/hydroflow_graph.rs | 6 +-- hydroflow_lang/src/lib.rs | 5 +- hydroflow_lang/src/pretty_span.rs | 4 +- hydroflow_macro/Cargo.toml | 3 -- hydroflow_plus/Cargo.toml | 1 - 12 files changed, 71 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca8aab2608b0..e762579e1353 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1560,6 +1560,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", + "rustc_version 0.4.1", "serde", "serde_json", "slotmap", @@ -2633,7 +2634,7 @@ dependencies = [ "byteorder", "libc", "nom 2.2.1", - "rustc_version", + "rustc_version 0.2.3", ] [[package]] @@ -3067,6 +3068,15 @@ dependencies = [ "semver 0.9.0", ] +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.23", +] + [[package]] name = "rustix" version = "0.38.34" diff --git a/hydroflow/Cargo.toml b/hydroflow/Cargo.toml index 7c0473f41ef8..e55322b13168 100644 --- a/hydroflow/Cargo.toml +++ b/hydroflow/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [features] default = [ "macros", "nightly", "debugging" ] -nightly = [ "hydroflow_macro", "hydroflow_macro/diagnostics" ] +nightly = [] macros = [ "hydroflow_macro", "hydroflow_datalog" ] hydroflow_macro = [ "dep:hydroflow_macro" ] hydroflow_datalog = [ "dep:hydroflow_datalog" ] diff --git a/hydroflow_datalog/Cargo.toml b/hydroflow_datalog/Cargo.toml index 58a62cab9d3b..c4771f901c7a 100644 --- a/hydroflow_datalog/Cargo.toml +++ b/hydroflow_datalog/Cargo.toml @@ -14,9 +14,6 @@ workspace = true proc-macro = true path = "src/lib.rs" -[features] -diagnostics = [ "hydroflow_datalog_core/diagnostics" ] - [dependencies] quote = "1.0.35" syn = { version = "2.0.46", features = [ "parsing", "extra-traits" ] } diff --git a/hydroflow_datalog_core/Cargo.toml b/hydroflow_datalog_core/Cargo.toml index 79b541b1bf30..ab7a2b1a7688 100644 --- a/hydroflow_datalog_core/Cargo.toml +++ b/hydroflow_datalog_core/Cargo.toml @@ -13,10 +13,6 @@ workspace = true [lib] path = "src/lib.rs" -[features] -default = [] -diagnostics = [ "hydroflow_lang/diagnostics" ] - [dependencies] quote = "1.0.35" slotmap = "1.0.0" diff --git a/hydroflow_lang/Cargo.toml b/hydroflow_lang/Cargo.toml index b1321b5ebf72..256d2b9269bb 100644 --- a/hydroflow_lang/Cargo.toml +++ b/hydroflow_lang/Cargo.toml @@ -12,7 +12,6 @@ workspace = true [features] default = [] -diagnostics = [] debugging = [ "dep:data-encoding", "dep:webbrowser", "clap-derive" ] clap-derive = [ "dep:clap" ] @@ -34,3 +33,4 @@ webbrowser = { version = "1.0.0", optional = true } [build-dependencies] syn = { version = "2.0.46", features = [ "extra-traits", "full", "parsing" ] } +rustc_version = "0.4.0" diff --git a/hydroflow_lang/build.rs b/hydroflow_lang/build.rs index d2e0af6f8487..fe39425917ac 100644 --- a/hydroflow_lang/build.rs +++ b/hydroflow_lang/build.rs @@ -4,6 +4,7 @@ use std::fs::File; use std::io::{BufWriter, Error, ErrorKind, Result, Write}; use std::path::PathBuf; +use rustc_version::{version_meta, Channel}; use syn::{ parse_quote, AttrStyle, Expr, ExprLit, Ident, Item, Lit, Member, Meta, MetaNameValue, Path, }; @@ -12,6 +13,15 @@ const OPS_PATH: &str = "src/graph/ops"; fn main() { println!("cargo::rerun-if-changed={}", OPS_PATH); + + println!("cargo::rustc-check-cfg=cfg(nightly)"); + if matches!( + version_meta().map(|meta| meta.channel), + Ok(Channel::Nightly) + ) { + println!("cargo:rustc-cfg=nightly"); + } + if Err(VarError::NotPresent) != var("CARGO_CFG_HYDROFLOW_GENERATE_DOCS") { if let Err(err) = generate_op_docs() { eprintln!("hydroflow_lang/build.rs error: {:?}", err); diff --git a/hydroflow_lang/src/diagnostic.rs b/hydroflow_lang/src/diagnostic.rs index 44ec8c588a8d..0941bfc319c1 100644 --- a/hydroflow_lang/src/diagnostic.rs +++ b/hydroflow_lang/src/diagnostic.rs @@ -40,8 +40,8 @@ impl Level { /// Diagnostic. A warning or error (or lower [`Level`]) with a message and span. Shown by IDEs /// usually as a squiggly red or yellow underline. /// -/// Must call [`Diagnostic::emit`] or manually emit the output of [`Diagnostic::to_tokens`] for the -/// diagnostic to show up. +/// Diagnostics must be emitted via [`Diagnostic::try_emit`], [`Diagnostic::to_tokens`], or +/// [`Diagnostic::try_emit_all`] for diagnostics to show up. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Diagnostic { /// Span (source code location). @@ -68,23 +68,47 @@ impl Diagnostic { } } - /// Emit the diagnostic. Only works from the `proc_macro` context. Does not work outside of - /// that e.g. in normal runtime execution or in tests. - pub fn emit(&self) { - #[cfg(feature = "diagnostics")] + /// Emit if possible, otherwise return `Err` containing a [`TokenStream`] of a + /// `compile_error!(...)` call. + pub fn try_emit(&self) -> Result<(), TokenStream> { + #[cfg(nightly)] { - let pm_diag = match self.level { - Level::Error => self.span.unwrap().error(&*self.message), - Level::Warning => self.span.unwrap().warning(&*self.message), - Level::Note => self.span.unwrap().note(&*self.message), - Level::Help => self.span.unwrap().help(&*self.message), - }; - pm_diag.emit(); + if let Ok(()) = std::panic::catch_unwind(|| { + let pm_diag = match self.level { + Level::Error => self.span.unwrap().error(&*self.message), + Level::Warning => self.span.unwrap().warning(&*self.message), + Level::Note => self.span.unwrap().note(&*self.message), + Level::Help => self.span.unwrap().help(&*self.message), + }; + pm_diag.emit() + }) { + return Ok(()); + } + } + Err(self.to_tokens()) + } + + /// Emits all if possible, otherwise returns `Err` containing a [`TokenStream`] of + /// `compile_error!(...)` calls. + pub fn try_emit_all<'a>( + diagnostics: impl IntoIterator, + ) -> Result<(), TokenStream> { + if let Some(tokens) = diagnostics + .into_iter() + .filter_map(|diag| diag.try_emit().err()) + .reduce(|mut tokens, next| { + tokens.extend(next); + tokens + }) + { + Err(tokens) + } else { + Ok(()) } } - /// Used to emulate [`Diagnostic::emit`] by turning this diagnostic into a properly spanned [`TokenStream`] - /// that emits an error with this diagnostic's message. + /// Used to emulate `proc_macro::Diagnostic::emit` by turning this diagnostic into a properly spanned [`TokenStream`] + /// that emits an error via `compile_error!(...)` with this diagnostic's message. pub fn to_tokens(&self) -> TokenStream { let msg_lit: Literal = Literal::string(&self.message); let unique_ident = { @@ -98,7 +122,7 @@ impl Diagnostic { if Level::Error == self.level { quote_spanned! {self.span=> { - ::std::compile_error!(#msg_lit); + ::core::compile_error!(#msg_lit); } } } else { @@ -169,7 +193,7 @@ pub struct SerdeSpan { } impl From for SerdeSpan { fn from(span: Span) -> Self { - #[cfg(feature = "diagnostics")] + #[cfg(nightly)] let path = span .unwrap() .source_file() @@ -178,7 +202,7 @@ impl From for SerdeSpan { .to_string() .into(); - #[cfg(not(feature = "diagnostics"))] + #[cfg(not(nightly))] let path = "unknown".into(); Self { diff --git a/hydroflow_lang/src/graph/hydroflow_graph.rs b/hydroflow_lang/src/graph/hydroflow_graph.rs index ac857f72cc5f..b174393631b2 100644 --- a/hydroflow_lang/src/graph/hydroflow_graph.rs +++ b/hydroflow_lang/src/graph/hydroflow_graph.rs @@ -1006,10 +1006,10 @@ impl HydroflowGraph { subgraph_op_iter_code.push(write_iterator); if include_type_guards { - #[cfg(not(feature = "diagnostics"))] + #[cfg(not(nightly))] let source_info = Option::::None; - #[cfg(feature = "diagnostics")] + #[cfg(nightly)] let source_info = std::panic::catch_unwind(|| op_span.unwrap()) .map(|op_span| { format!( @@ -1029,7 +1029,7 @@ impl HydroflowGraph { .ok(); #[cfg_attr( - not(feature = "diagnostics"), + not(nightly), expect( clippy::unnecessary_literal_unwrap, reason = "conditional compilation" diff --git a/hydroflow_lang/src/lib.rs b/hydroflow_lang/src/lib.rs index 91d06c49be0b..2b824532e81c 100644 --- a/hydroflow_lang/src/lib.rs +++ b/hydroflow_lang/src/lib.rs @@ -1,10 +1,7 @@ //! Hydroflow surface syntax #![warn(missing_docs)] -#![cfg_attr( - feature = "diagnostics", - feature(proc_macro_diagnostic, proc_macro_span) -)] +#![cfg_attr(nightly, feature(proc_macro_diagnostic, proc_macro_span))] pub mod diagnostic; pub mod graph; pub mod parse; diff --git a/hydroflow_lang/src/pretty_span.rs b/hydroflow_lang/src/pretty_span.rs index 8ad6ae6ee3dc..0af791ed0d94 100644 --- a/hydroflow_lang/src/pretty_span.rs +++ b/hydroflow_lang/src/pretty_span.rs @@ -5,7 +5,7 @@ pub struct PrettySpan(pub proc_macro2::Span); impl std::fmt::Display for PrettySpan { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - #[cfg(feature = "diagnostics")] + #[cfg(nightly)] { if let Ok(span) = std::panic::catch_unwind(|| self.0.unwrap()) { write!( @@ -21,7 +21,7 @@ impl std::fmt::Display for PrettySpan { write!( f, - "nopath:{}:{}", + "unknown:{}:{}", self.0.start().line, self.0.start().column ) diff --git a/hydroflow_macro/Cargo.toml b/hydroflow_macro/Cargo.toml index 947cd24a997e..16c9450b7fdd 100644 --- a/hydroflow_macro/Cargo.toml +++ b/hydroflow_macro/Cargo.toml @@ -13,9 +13,6 @@ workspace = true [lib] proc-macro = true -[features] -diagnostics = [ "hydroflow_lang/diagnostics" ] - [dependencies] # Note: If we ever compile this proc macro crate to WASM (e.g., if we are # building on a WASM host), we may need to turn diagnostics off for WASM if diff --git a/hydroflow_plus/Cargo.toml b/hydroflow_plus/Cargo.toml index 23ad3d334337..d209f43f81ac 100644 --- a/hydroflow_plus/Cargo.toml +++ b/hydroflow_plus/Cargo.toml @@ -15,7 +15,6 @@ path = "src/lib.rs" [features] default = ["deploy_runtime"] -diagnostics = [ "hydroflow_lang/diagnostics" ] stageleft_devel = [] deploy_runtime = [ "hydroflow/deploy_integration" ] deploy = [ "deploy_runtime", "dep:hydro_deploy", "dep:trybuild-internals-api", "dep:toml", "dep:prettyplease" ] From 327e19744099d7b1854ddb2cf91cb9ca7b80403a Mon Sep 17 00:00:00 2001 From: Mingwei Samuel Date: Wed, 11 Dec 2024 13:20:50 -0800 Subject: [PATCH 4/7] try_emit --- .github/workflows/ci.yml | 44 +++++++++++++++---------------- Cargo.lock | 1 + hydroflow/Cargo.toml | 3 +-- hydroflow/src/lib.rs | 6 +---- hydroflow_datalog/src/lib.rs | 14 +++++++--- hydroflow_datalog_core/src/lib.rs | 1 + hydroflow_lang/src/diagnostic.rs | 14 ++++------ hydroflow_macro/Cargo.toml | 1 + hydroflow_macro/build.rs | 9 +++++++ hydroflow_macro/src/lib.rs | 33 +++++++++-------------- 10 files changed, 64 insertions(+), 62 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82eda5e7febf..7af071b226a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,13 +36,13 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - rust_release: [pinned-nightly, latest-stable] + rust_release: [pinned-nightly, latest-nightly] exclude: # For non-pull requests, event_name != 'pull_request' will be true, and 'nothing' is # truthy, so the entire && operator will resolve to 'nothing'. Then the || operator will # resolve to 'nothing' so we will exclude 'nothing'. https://stackoverflow.com/a/73822998 - rust_release: ${{ (needs.pre_job.outputs.should_skip != 'true' && 'nothing') || 'pinned-nightly' }} - - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-stable' }} + - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-nightly' }} env: CARGO_TERM_COLOR: always @@ -55,12 +55,12 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Install toolchain + - name: Install nightly toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable - override: ${{ matrix.rust_release == 'latest-stable' }} + toolchain: nightly + override: ${{ matrix.rust_release == 'latest-nightly' }} components: rustfmt, clippy - name: Run sccache-cache @@ -96,25 +96,25 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust_release: [pinned-nightly, latest-stable] + rust_release: [pinned-nightly, latest-nightly] exclude: # For non-pull requests, event_name != 'pull_request' will be true, and 'nothing' is # truthy, so the entire && operator will resolve to 'nothing'. Then the || operator will # resolve to 'nothing' so we will exclude 'nothing'. https://stackoverflow.com/a/73822998 - rust_release: ${{ (needs.pre_job.outputs.should_skip != 'true' && 'nothing') || 'pinned-nightly' }} - - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-stable' }} + - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-nightly' }} steps: - name: Checkout sources uses: actions/checkout@v3 - - name: Install toolchain + - name: Install nightly toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: nightly target: wasm32-unknown-unknown - override: ${{ matrix.rust_release == 'latest-stable' }} + override: ${{ matrix.rust_release == 'latest-nightly' }} - name: Check hydroflow_lang uses: actions-rs/cargo@v1 @@ -132,13 +132,13 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - rust_release: [pinned-nightly, latest-stable] + rust_release: [pinned-nightly, latest-nightly] exclude: # For non-pull requests, event_name != 'pull_request' will be true, and 'nothing' is # truthy, so the entire && operator will resolve to 'nothing'. Then the || operator will # resolve to 'nothing' so we will exclude 'nothing'. https://stackoverflow.com/a/73822998 - rust_release: ${{ (needs.pre_job.outputs.should_skip != 'true' && 'nothing') || 'pinned-nightly' }} - - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-stable' }} + - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-nightly' }} - os: ${{ (github.event_name != 'pull_request' && 'nothing') || 'windows-latest' }} env: @@ -152,12 +152,12 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Install toolchain + - name: Install nightly toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable - override: ${{ matrix.rust_release == 'latest-stable' }} + toolchain: nightly + override: ${{ matrix.rust_release == 'latest-nightly' }} - name: Run sccache-cache if: matrix.rust_release == 'pinned-nightly' @@ -235,25 +235,25 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust_release: [pinned-nightly, latest-stable] + rust_release: [pinned-nightly, latest-nightly] exclude: # For non-pull requests, event_name != 'pull_request' will be true, and 'nothing' is # truthy, so the entire && operator will resolve to 'nothing'. Then the || operator will # resolve to 'nothing' so we will exclude 'nothing'. https://stackoverflow.com/a/73822998 - rust_release: ${{ (needs.pre_job.outputs.should_skip != 'true' && 'nothing') || 'pinned-nightly' }} - - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-stable' }} + - rust_release: ${{ (github.event_name != 'pull_request' && 'nothing') || 'latest-nightly' }} steps: - name: Checkout sources uses: actions/checkout@v3 - - name: Install toolchain + - name: Install nightly toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: nightly target: wasm32-unknown-unknown - override: ${{ matrix.rust_release == 'latest-stable' }} + override: ${{ matrix.rust_release == 'latest-nightly' }} - name: Get wasm-bindgen version id: wasm-bindgen-version @@ -299,7 +299,7 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Install toolchain + - name: Install nightly toolchain uses: actions-rs/toolchain@v1 with: profile: minimal @@ -366,7 +366,7 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Install toolchain + - name: Install nightly toolchain uses: actions-rs/toolchain@v1 with: profile: minimal diff --git a/Cargo.lock b/Cargo.lock index e762579e1353..d97a41f0818c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1577,6 +1577,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", + "rustc_version 0.4.1", "syn 2.0.75", ] diff --git a/hydroflow/Cargo.toml b/hydroflow/Cargo.toml index e55322b13168..e8d74c3a8a5a 100644 --- a/hydroflow/Cargo.toml +++ b/hydroflow/Cargo.toml @@ -11,9 +11,8 @@ description = "Hydro's low-level dataflow runtime and IR" workspace = true [features] -default = [ "macros", "nightly", "debugging" ] +default = [ "macros", "debugging" ] -nightly = [] macros = [ "hydroflow_macro", "hydroflow_datalog" ] hydroflow_macro = [ "dep:hydroflow_macro" ] hydroflow_datalog = [ "dep:hydroflow_datalog" ] diff --git a/hydroflow/src/lib.rs b/hydroflow/src/lib.rs index 2970b129f08d..effc596dc57b 100644 --- a/hydroflow/src/lib.rs +++ b/hydroflow/src/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(feature = "nightly", feature(never_type))] #![warn(missing_docs)] //! Hydroflow is a low-level dataflow-based runtime system for the [Hydro Project](https://hydro.run/). @@ -39,12 +38,9 @@ pub use hydroflow_macro::{ hydroflow_test as test, monotonic_fn, morphism, DemuxEnum, }; +// TODO(mingwei): Use the [nightly "never" type `!`](https://doc.rust-lang.org/std/primitive.never.html) /// Stand-in for the [nightly "never" type `!`](https://doc.rust-lang.org/std/primitive.never.html) -#[cfg(not(feature = "nightly"))] pub type Never = std::convert::Infallible; -/// The [nightly "never" type `!`](https://doc.rust-lang.org/std/primitive.never.html) -#[cfg(feature = "nightly")] -pub type Never = !; #[cfg(doctest)] mod booktest { diff --git a/hydroflow_datalog/src/lib.rs b/hydroflow_datalog/src/lib.rs index f1bd816360f9..919115bd986b 100644 --- a/hydroflow_datalog/src/lib.rs +++ b/hydroflow_datalog/src/lib.rs @@ -1,3 +1,4 @@ +use hydroflow_datalog_core::diagnostic::Diagnostic; use hydroflow_datalog_core::{gen_hydroflow_graph, hydroflow_graph_to_program}; use proc_macro2::Span; use quote::{quote, ToTokens}; @@ -31,10 +32,15 @@ pub fn datalog(item: proc_macro::TokenStream) -> proc_macro::TokenStream { program.to_token_stream().into() } Err(diagnostics) => { - for diagnostic in diagnostics { - diagnostic.emit(); - } - proc_macro::TokenStream::from(quote!(hydroflow::scheduled::graph::Hydroflow::new())) + let diagnostic_tokens = Diagnostic::try_emit_all(diagnostics.iter()) + .err() + .unwrap_or_default(); + proc_macro::TokenStream::from(quote! { + { + #diagnostic_tokens + hydroflow::scheduled::graph::Hydroflow::new() + } + }) } } } diff --git a/hydroflow_datalog_core/src/lib.rs b/hydroflow_datalog_core/src/lib.rs index 27203bdd6a3c..64835e74ab6e 100644 --- a/hydroflow_datalog_core/src/lib.rs +++ b/hydroflow_datalog_core/src/lib.rs @@ -1,6 +1,7 @@ use std::collections::{HashMap, HashSet}; use std::ops::Deref; +pub use hydroflow_lang::diagnostic; use hydroflow_lang::diagnostic::{Diagnostic, Level}; use hydroflow_lang::graph::{ eliminate_extra_unions_tees, partition_graph, FlatGraphBuilder, HydroflowGraph, diff --git a/hydroflow_lang/src/diagnostic.rs b/hydroflow_lang/src/diagnostic.rs index 0941bfc319c1..518fce44d48a 100644 --- a/hydroflow_lang/src/diagnostic.rs +++ b/hydroflow_lang/src/diagnostic.rs @@ -194,19 +194,15 @@ pub struct SerdeSpan { impl From for SerdeSpan { fn from(span: Span) -> Self { #[cfg(nightly)] - let path = span - .unwrap() - .source_file() - .path() - .display() - .to_string() - .into(); + let path = std::panic::catch_unwind(|| span.unwrap()) + .map(|span| span.source_file().path().display().to_string()) + .ok(); #[cfg(not(nightly))] - let path = "unknown".into(); + let path = None::; Self { - path, + path: path.map_or(Cow::Borrowed("unknown"), Cow::Owned), line: span.start().line, column: span.start().column, } diff --git a/hydroflow_macro/Cargo.toml b/hydroflow_macro/Cargo.toml index 16c9450b7fdd..4581adb99608 100644 --- a/hydroflow_macro/Cargo.toml +++ b/hydroflow_macro/Cargo.toml @@ -27,3 +27,4 @@ syn = { version = "2.0.46", features = [ "parsing", "extra-traits" ] } hydroflow_lang = { path = "../hydroflow_lang", version = "^0.10.0" } itertools = "0.10.0" quote = "1.0.35" +rustc_version = "0.4.0" diff --git a/hydroflow_macro/build.rs b/hydroflow_macro/build.rs index adf5e9459b2f..3fa4cb3c6f8e 100644 --- a/hydroflow_macro/build.rs +++ b/hydroflow_macro/build.rs @@ -10,6 +10,7 @@ use hydroflow_lang::graph::ops::{PortListSpec, OPERATORS}; use hydroflow_lang::graph::PortIndexValue; use itertools::Itertools; use quote::ToTokens; +use rustc_version::{version_meta, Channel}; const FILENAME: &str = "surface_ops_gen.md"; @@ -207,6 +208,14 @@ fn update_book() -> Result<()> { } fn main() { + println!("cargo::rustc-check-cfg=cfg(nightly)"); + if matches!( + version_meta().map(|meta| meta.channel), + Ok(Channel::Nightly) + ) { + println!("cargo:rustc-cfg=nightly"); + } + if Err(VarError::NotPresent) != std::env::var("CARGO_CFG_HYDROFLOW_GENERATE_DOCS") { if let Err(err) = update_book() { eprintln!("hydroflow_macro/build.rs error: {:?}", err); diff --git a/hydroflow_macro/src/lib.rs b/hydroflow_macro/src/lib.rs index 96ff839cd7d1..f03ae0dc87e0 100644 --- a/hydroflow_macro/src/lib.rs +++ b/hydroflow_macro/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr( - feature = "diagnostics", + nightly, feature(proc_macro_diagnostic, proc_macro_span, proc_macro_def_site) )] @@ -72,25 +72,16 @@ fn hydroflow_syntax_internal( .iter() .filter(|diag: &&Diagnostic| Some(diag.level) <= min_diagnostic_level); - #[cfg(feature = "diagnostics")] - { - diagnostics.for_each(Diagnostic::emit); - tokens.into() - } - - #[cfg(not(feature = "diagnostics"))] - { - let diagnostics = diagnostics.map(Diagnostic::to_tokens); - quote! { - { - #( - #diagnostics - )* - #tokens - } + let diagnostic_tokens = Diagnostic::try_emit_all(diagnostics) + .err() + .unwrap_or_default(); + quote! { + { + #diagnostic_tokens + #tokens } - .into() } + .into() } /// Parse Hydroflow "surface syntax" without emitting code. @@ -123,8 +114,10 @@ pub fn hydroflow_parser(input: proc_macro::TokenStream) -> proc_macro::TokenStre } } - diagnostics.iter().for_each(Diagnostic::emit); - quote! {}.into() + Diagnostic::try_emit_all(diagnostics.iter()) + .err() + .unwrap_or_default() + .into() } #[doc(hidden)] From 366e4029c1c76bcbefd3e9c41379b5672bd530f7 Mon Sep 17 00:00:00 2001 From: Mingwei Samuel Date: Wed, 11 Dec 2024 14:32:29 -0800 Subject: [PATCH 5/7] do not use catch_unwind unless panic=unwind --- hydroflow_lang/src/diagnostic.rs | 17 ++++++----- hydroflow_lang/src/graph/hydroflow_graph.rs | 34 ++++++++------------- hydroflow_lang/src/pretty_span.rs | 2 +- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/hydroflow_lang/src/diagnostic.rs b/hydroflow_lang/src/diagnostic.rs index 518fce44d48a..440a13e26b4f 100644 --- a/hydroflow_lang/src/diagnostic.rs +++ b/hydroflow_lang/src/diagnostic.rs @@ -71,7 +71,7 @@ impl Diagnostic { /// Emit if possible, otherwise return `Err` containing a [`TokenStream`] of a /// `compile_error!(...)` call. pub fn try_emit(&self) -> Result<(), TokenStream> { - #[cfg(nightly)] + #[cfg(all(nightly, panic = "unwind"))] { if let Ok(()) = std::panic::catch_unwind(|| { let pm_diag = match self.level { @@ -193,16 +193,17 @@ pub struct SerdeSpan { } impl From for SerdeSpan { fn from(span: Span) -> Self { - #[cfg(nightly)] - let path = std::panic::catch_unwind(|| span.unwrap()) - .map(|span| span.source_file().path().display().to_string()) - .ok(); + let path = 'a: { + #[cfg(all(nightly, panic = "unwind"))] + if let Ok(span) = std::panic::catch_unwind(|| span.unwrap()) { + break 'a span.source_file().path().display().to_string().into(); + } - #[cfg(not(nightly))] - let path = None::; + break 'a "unknown".into(); + }; Self { - path: path.map_or(Cow::Borrowed("unknown"), Cow::Owned), + path, line: span.start().line, column: span.start().column, } diff --git a/hydroflow_lang/src/graph/hydroflow_graph.rs b/hydroflow_lang/src/graph/hydroflow_graph.rs index b174393631b2..5b7114f98d87 100644 --- a/hydroflow_lang/src/graph/hydroflow_graph.rs +++ b/hydroflow_lang/src/graph/hydroflow_graph.rs @@ -1006,13 +1006,12 @@ impl HydroflowGraph { subgraph_op_iter_code.push(write_iterator); if include_type_guards { - #[cfg(not(nightly))] - let source_info = Option::::None; - - #[cfg(nightly)] - let source_info = std::panic::catch_unwind(|| op_span.unwrap()) - .map(|op_span| { - format!( + let source_info = 'a: { + #[cfg(all(nightly, panic = "unwind"))] + if let Ok(op_span) = + std::panic::catch_unwind(|| op_span.unwrap()) + { + break 'a format!( "loc_{}_{}_{}_{}_{}", op_span .source_file() @@ -1024,26 +1023,17 @@ impl HydroflowGraph { op_span.start().column(), op_span.end().line(), op_span.end().column(), - ) - }) - .ok(); - - #[cfg_attr( - not(nightly), - expect( - clippy::unnecessary_literal_unwrap, - reason = "conditional compilation" - ) - )] - let source_info = source_info.unwrap_or_else(|| { - format!( + ); + } + + break 'a format!( "loc_nopath_{}_{}_{}_{}", op_span.start().line, op_span.start().column, op_span.end().line, op_span.end().column - ) - }); + ); + }; let fn_ident = format_ident!( "{}__{}__{}", diff --git a/hydroflow_lang/src/pretty_span.rs b/hydroflow_lang/src/pretty_span.rs index 0af791ed0d94..d9af3ec320bf 100644 --- a/hydroflow_lang/src/pretty_span.rs +++ b/hydroflow_lang/src/pretty_span.rs @@ -5,7 +5,7 @@ pub struct PrettySpan(pub proc_macro2::Span); impl std::fmt::Display for PrettySpan { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - #[cfg(nightly)] + #[cfg(all(nightly, panic = "unwind"))] { if let Ok(span) = std::panic::catch_unwind(|| self.0.unwrap()) { write!( From 566c6885b3c76a61f63f7d2ea44e9491edf4b8e6 Mon Sep 17 00:00:00 2001 From: Mingwei Samuel Date: Wed, 11 Dec 2024 16:51:43 -0800 Subject: [PATCH 6/7] use proc_macro::is_available() --- hydroflow_lang/src/diagnostic.rs | 37 ++++++++++++--------- hydroflow_lang/src/graph/hydroflow_graph.rs | 9 ++--- hydroflow_lang/src/pretty_span.rs | 23 +++++++------ 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/hydroflow_lang/src/diagnostic.rs b/hydroflow_lang/src/diagnostic.rs index 440a13e26b4f..06dca5c69052 100644 --- a/hydroflow_lang/src/diagnostic.rs +++ b/hydroflow_lang/src/diagnostic.rs @@ -1,5 +1,7 @@ //! Compatibility for `proc_macro` diagnostics, which are missing from [`proc_macro2`]. +extern crate proc_macro; + use std::borrow::Cow; use std::hash::{Hash, Hasher}; @@ -71,19 +73,16 @@ impl Diagnostic { /// Emit if possible, otherwise return `Err` containing a [`TokenStream`] of a /// `compile_error!(...)` call. pub fn try_emit(&self) -> Result<(), TokenStream> { - #[cfg(all(nightly, panic = "unwind"))] - { - if let Ok(()) = std::panic::catch_unwind(|| { - let pm_diag = match self.level { - Level::Error => self.span.unwrap().error(&*self.message), - Level::Warning => self.span.unwrap().warning(&*self.message), - Level::Note => self.span.unwrap().note(&*self.message), - Level::Help => self.span.unwrap().help(&*self.message), - }; - pm_diag.emit() - }) { - return Ok(()); - } + #[cfg(nightly)] + if proc_macro::is_available() { + let pm_diag = match self.level { + Level::Error => self.span.unwrap().error(&*self.message), + Level::Warning => self.span.unwrap().warning(&*self.message), + Level::Note => self.span.unwrap().note(&*self.message), + Level::Help => self.span.unwrap().help(&*self.message), + }; + pm_diag.emit(); + return Ok(()); } Err(self.to_tokens()) } @@ -194,9 +193,15 @@ pub struct SerdeSpan { impl From for SerdeSpan { fn from(span: Span) -> Self { let path = 'a: { - #[cfg(all(nightly, panic = "unwind"))] - if let Ok(span) = std::panic::catch_unwind(|| span.unwrap()) { - break 'a span.source_file().path().display().to_string().into(); + #[cfg(nightly)] + if proc_macro::is_available() { + break 'a span + .unwrap() + .source_file() + .path() + .display() + .to_string() + .into(); } break 'a "unknown".into(); diff --git a/hydroflow_lang/src/graph/hydroflow_graph.rs b/hydroflow_lang/src/graph/hydroflow_graph.rs index 5b7114f98d87..9f964f02dd24 100644 --- a/hydroflow_lang/src/graph/hydroflow_graph.rs +++ b/hydroflow_lang/src/graph/hydroflow_graph.rs @@ -1,5 +1,7 @@ #![warn(missing_docs)] +extern crate proc_macro; + use std::collections::{BTreeMap, BTreeSet}; use std::fmt::Debug; use std::iter::FusedIterator; @@ -1007,10 +1009,9 @@ impl HydroflowGraph { if include_type_guards { let source_info = 'a: { - #[cfg(all(nightly, panic = "unwind"))] - if let Ok(op_span) = - std::panic::catch_unwind(|| op_span.unwrap()) - { + #[cfg(nightly)] + if proc_macro::is_available() { + let op_span = op_span.unwrap(); break 'a format!( "loc_{}_{}_{}_{}_{}", op_span diff --git a/hydroflow_lang/src/pretty_span.rs b/hydroflow_lang/src/pretty_span.rs index d9af3ec320bf..ba4cd54ba420 100644 --- a/hydroflow_lang/src/pretty_span.rs +++ b/hydroflow_lang/src/pretty_span.rs @@ -1,22 +1,23 @@ //! Pretty, human-readable printing of [`proc_macro2::Span`]s. +extern crate proc_macro; + /// Helper struct which displays the span as `path:row:col` for human reading/IDE linking. /// Example: `hydroflow\tests\surface_syntax.rs:42:18`. pub struct PrettySpan(pub proc_macro2::Span); impl std::fmt::Display for PrettySpan { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { #[cfg(all(nightly, panic = "unwind"))] - { - if let Ok(span) = std::panic::catch_unwind(|| self.0.unwrap()) { - write!( - f, - "{}:{}:{}", - span.source_file().path().display(), - span.start().line(), - span.start().column(), - )?; - return Ok(()); - } + if proc_macro::is_available() { + let span = self.0.unwrap(); + write!( + f, + "{}:{}:{}", + span.source_file().path().display(), + span.start().line(), + span.start().column(), + )?; + return Ok(()); } write!( From cfe554751c34753cb15ae0e95efa9dfa25cb2e25 Mon Sep 17 00:00:00 2001 From: Mingwei Samuel Date: Thu, 12 Dec 2024 09:50:27 -0800 Subject: [PATCH 7/7] fixup! use proc_macro::is_available() --- hydroflow_lang/src/pretty_span.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hydroflow_lang/src/pretty_span.rs b/hydroflow_lang/src/pretty_span.rs index ba4cd54ba420..ed4d92ba20d4 100644 --- a/hydroflow_lang/src/pretty_span.rs +++ b/hydroflow_lang/src/pretty_span.rs @@ -7,7 +7,7 @@ extern crate proc_macro; pub struct PrettySpan(pub proc_macro2::Span); impl std::fmt::Display for PrettySpan { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - #[cfg(all(nightly, panic = "unwind"))] + #[cfg(nightly)] if proc_macro::is_available() { let span = self.0.unwrap(); write!(