Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: use cfg(nightly) instead of feature, remove -Z flag, use Diagnostic::try_emit #1606

Merged
merged 7 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(all(nightly, panic = "unwind"))]
MingweiSamuel marked this conversation as resolved.
Show resolved Hide resolved
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
Loading