#![feature(rustc_private)]
extern crate rustc_driver;
extern crate rustc_error_messages;
extern crate rustc_errors;
extern crate rustc_session;
extern crate rustc_span;
use colored::Colorize;
use rustc_error_messages::MultiSpan;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub trait SessionExtTrait {
fn span_hax_err<S: Into<MultiSpan> + Clone>(&self, diag: Diagnostics<S>);
}
impl SessionExtTrait for rustc_session::Session {
fn span_hax_err<S: Into<MultiSpan> + Clone>(&self, diag: Diagnostics<S>) {
let span: MultiSpan = diag.span.clone().into();
let diag = diag.set_span(span.clone());
self.span_err_with_code(
span,
format!("{}", diag),
rustc_errors::DiagnosticId::Error(diag.kind.code().into()),
);
}
}
pub mod error;
#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize)]
pub struct Diagnostics<S> {
pub kind: Kind,
pub span: S,
pub context: String,
}
impl<S> Diagnostics<S> {
pub fn set_span<T>(&self, span: T) -> Diagnostics<T> {
Diagnostics {
kind: self.kind.clone(),
context: self.context.clone(),
span,
}
}
}
impl<S: PartialEq + Clone, I: IntoIterator<Item = S> + Clone> Diagnostics<I> {
pub fn convert<T: Clone + Ord>(
&self,
mapping: &Vec<(S, T)>,
) -> Diagnostics<Vec<T>>
where
for<'b> &'b S: PartialEq,
{
self.set_span(
self.span
.clone()
.into_iter()
.map(|span| {
mapping
.iter()
.filter(|(candidate, _)| candidate == &span)
.map(|(_, span)| span)
.max()
})
.flatten()
.cloned()
.collect(),
)
}
}
impl<S> std::fmt::Display for Diagnostics<S> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "({}) ", self.context)?;
match &self.kind {
Kind::Unimplemented { issue_id, details } => write!(
f,
"something is not implemented yet.{}{}",
match issue_id {
Some(id) => format!("This is discussed in issue https://github.com/hacspec/hacspec-v2/issues/{id}.\nPlease upvote or comment this issue if you see this error message."),
_ => "".to_string(),
},
match details {
Some(details) => format!("\n{}", details),
_ => "".to_string(),
}
),
Kind::UnsupportedMacro { id } => write!(
f,
"The unexpanded macro {} it is not supported by this backend. Please verify the option you passed the {} (or {}) option.",
id.bold(),
"--inline-macro-call".bold(), "-i".bold()
),
Kind::UnsafeBlock => write!(f, "Unsafe blocks are not allowed."),
Kind::AssertionFailure {details} => write!(
f,
"Fatal error: something we considered as impossible occurred! {}\nDetails: {}",
"Please report this by submitting an issue on GitHub!".bold(),
details
),
Kind::UnallowedMutRef => write!(
f,
"The mutation of this {} is not allowed here.",
"&mut".bold()
),
Kind::ExpectedMutRef => write!(
f,
"At this position, Hax was expecting an expression of the shape `&mut _`. Hax forbids `f(x)` (where `f` expects a mutable reference as input) when `x` is not a {}{} or when it is a dereference expression.
{}
",
"place expression".bold(),
"[1]".bright_black(),
"[1]: https://doc.rust-lang.org/reference/expressions.html#place-expressions-and-value-expressions"
),
Kind::ClosureMutatesParentBindings {bindings} => write!(
f,
"The bindings {:?} cannot be mutated here: they don't belong to the closure scope, and this is not allowed.",
bindings
),
Kind::ArbitraryLHS => write!(f, "Assignation of an arbitrary left-hand side is not supported. [lhs = e] is fine only when [lhs] is a combination of local identifiers, field accessors and index accessors."),
_ => write!(f, "{:?}", self.kind),
}
}
}
#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize)]
#[repr(u16)]
pub enum Kind {
UnsafeBlock = 0,
Unimplemented {
issue_id: Option<u32>,
details: Option<String>,
} = 1,
AssertionFailure {
details: String,
} = 2,
UnallowedMutRef = 3,
UnsupportedMacro {
id: String,
} = 4,
ErrorParsingMacroInvocation {
macro_id: String,
details: String,
} = 5,
ClosureMutatesParentBindings {
bindings: Vec<String>,
} = 6,
ArbitraryLHS = 7,
ExplicitRejection {
reason: String,
} = 8,
UnsupportedTupleSize {
tuple_size: u32,
reason: String,
} = 9,
ExpectedMutRef = 10,
}
impl Kind {
pub fn discriminant(&self) -> u16 {
unsafe { *(self as *const Self as *const u16) }
}
pub fn code(&self) -> String {
format!("HAX{:0>4}", self.discriminant())
}
}