Skip to content

Commit

Permalink
refactor!: use cfg(nightly) instead of feature, remove -Z flag, u…
Browse files Browse the repository at this point in the history
…se `Diagnostic::try_emit` (#1606)

Previous PR (#1587) website build did not work because `panic = "abort"`
is set on wasm, leading to aborts for `proc_macro2::Span::unwrap()`
calls.

All tests except trybuild seem to pass on stable, WIP #1587 next

BREAKING CHANGE: replaces `hydroflow_lang::diagnostic::Diagnostic::emit`
with `try_emit`
BREAKING CHANGE: removes features: `hydroflow/nightly`,
`hydroflow_datalog/diagnostics`, `hydroflow_datalog_core/diagnostics`,
`hydroflow_lang/diagnostics`, `hydroflow_macro/diagnostics`,
`hydroflow_plus/diagnostics`.
  • Loading branch information
MingweiSamuel authored Dec 12, 2024
1 parent f2a4bee commit 251b103
Show file tree
Hide file tree
Showing 18 changed files with 133 additions and 107 deletions.
4 changes: 0 additions & 4 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -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]
Expand Down
13 changes: 12 additions & 1 deletion Cargo.lock

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

3 changes: 1 addition & 2 deletions hydroflow/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ description = "Hydro's low-level dataflow runtime and IR"
workspace = true

[features]
default = [ "macros", "nightly", "debugging" ]
default = [ "macros", "debugging" ]

nightly = [ "hydroflow_macro", "hydroflow_macro/diagnostics" ]
macros = [ "hydroflow_macro", "hydroflow_datalog" ]
hydroflow_macro = [ "dep:hydroflow_macro" ]
hydroflow_datalog = [ "dep:hydroflow_datalog" ]
Expand Down
6 changes: 1 addition & 5 deletions hydroflow/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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/).
Expand Down Expand Up @@ -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 {
Expand Down
3 changes: 0 additions & 3 deletions hydroflow_datalog/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" ] }
Expand Down
14 changes: 10 additions & 4 deletions hydroflow_datalog/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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()
}
})
}
}
}
4 changes: 0 additions & 4 deletions hydroflow_datalog_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions hydroflow_datalog_core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
2 changes: 1 addition & 1 deletion hydroflow_lang/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ workspace = true

[features]
default = []
diagnostics = []
debugging = [ "dep:data-encoding", "dep:webbrowser", "clap-derive" ]
clap-derive = [ "dep:clap" ]

Expand All @@ -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"
10 changes: 10 additions & 0 deletions hydroflow_lang/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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);
Expand Down
66 changes: 46 additions & 20 deletions hydroflow_lang/src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -40,8 +42,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<S = Span> {
/// Span (source code location).
Expand All @@ -68,23 +70,44 @@ 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)]
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())
}

/// Used to emulate [`Diagnostic::emit`] by turning this diagnostic into a properly spanned [`TokenStream`]
/// that emits an error with this diagnostic's message.
/// Emits all if possible, otherwise returns `Err` containing a [`TokenStream`] of
/// `compile_error!(...)` calls.
pub fn try_emit_all<'a>(
diagnostics: impl IntoIterator<Item = &'a Self>,
) -> 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 `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 = {
Expand All @@ -98,7 +121,7 @@ impl Diagnostic {
if Level::Error == self.level {
quote_spanned! {self.span=>
{
::std::compile_error!(#msg_lit);
::core::compile_error!(#msg_lit);
}
}
} else {
Expand Down Expand Up @@ -169,17 +192,20 @@ pub struct SerdeSpan {
}
impl From<Span> for SerdeSpan {
fn from(span: Span) -> Self {
#[cfg(feature = "diagnostics")]
let path = span
.unwrap()
.source_file()
.path()
.display()
.to_string()
.into();
let path = 'a: {
#[cfg(nightly)]
if proc_macro::is_available() {
break 'a span
.unwrap()
.source_file()
.path()
.display()
.to_string()
.into();
}

#[cfg(not(feature = "diagnostics"))]
let path = "unknown".into();
break 'a "unknown".into();
};

Self {
path,
Expand Down
35 changes: 13 additions & 22 deletions hydroflow_lang/src/graph/hydroflow_graph.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![warn(missing_docs)]

extern crate proc_macro;

use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Debug;
use std::iter::FusedIterator;
Expand Down Expand Up @@ -1006,13 +1008,11 @@ impl HydroflowGraph {
subgraph_op_iter_code.push(write_iterator);

if include_type_guards {
#[cfg(not(feature = "diagnostics"))]
let source_info = Option::<String>::None;

#[cfg(feature = "diagnostics")]
let source_info = std::panic::catch_unwind(|| op_span.unwrap())
.map(|op_span| {
format!(
let source_info = 'a: {
#[cfg(nightly)]
if proc_macro::is_available() {
let op_span = op_span.unwrap();
break 'a format!(
"loc_{}_{}_{}_{}_{}",
op_span
.source_file()
Expand All @@ -1024,26 +1024,17 @@ impl HydroflowGraph {
op_span.start().column(),
op_span.end().line(),
op_span.end().column(),
)
})
.ok();

#[cfg_attr(
not(feature = "diagnostics"),
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!(
"{}__{}__{}",
Expand Down
5 changes: 1 addition & 4 deletions hydroflow_lang/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
27 changes: 14 additions & 13 deletions hydroflow_lang/src/pretty_span.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
//! 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(feature = "diagnostics")]
{
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(());
}
#[cfg(nightly)]
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!(
f,
"nopath:{}:{}",
"unknown:{}:{}",
self.0.start().line,
self.0.start().column
)
Expand Down
Loading

0 comments on commit 251b103

Please sign in to comment.