mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
feat(wgsl-in): detect conflicting diag. filters
This commit is contained in:
parent
44b8e38fd8
commit
7a5d505896
@ -1,5 +1,11 @@
|
|||||||
//! [`DiagnosticFilter`]s and supporting functionality.
|
//! [`DiagnosticFilter`]s and supporting functionality.
|
||||||
|
|
||||||
|
use crate::Handle;
|
||||||
|
#[cfg(feature = "wgsl-in")]
|
||||||
|
use crate::Span;
|
||||||
|
#[cfg(feature = "wgsl-in")]
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
/// A severity set on a [`DiagnosticFilter`].
|
/// A severity set on a [`DiagnosticFilter`].
|
||||||
///
|
///
|
||||||
/// <https://www.w3.org/TR/WGSL/#diagnostic-severity>
|
/// <https://www.w3.org/TR/WGSL/#diagnostic-severity>
|
||||||
@ -95,3 +101,88 @@ pub struct DiagnosticFilter {
|
|||||||
pub new_severity: Severity,
|
pub new_severity: Severity,
|
||||||
pub triggering_rule: FilterableTriggeringRule,
|
pub triggering_rule: FilterableTriggeringRule,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A map of diagnostic filters to their severity and first occurrence's span.
|
||||||
|
///
|
||||||
|
/// Intended for front ends' first step into storing parsed [`DiagnosticFilter`]s.
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
#[cfg(feature = "wgsl-in")]
|
||||||
|
pub(crate) struct DiagnosticFilterMap(IndexMap<FilterableTriggeringRule, (Severity, Span)>);
|
||||||
|
|
||||||
|
#[cfg(feature = "wgsl-in")]
|
||||||
|
impl DiagnosticFilterMap {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add the given `diagnostic_filter` parsed at the given `span` to this map.
|
||||||
|
pub(crate) fn add(
|
||||||
|
&mut self,
|
||||||
|
diagnostic_filter: DiagnosticFilter,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<(), ConflictingDiagnosticRuleError> {
|
||||||
|
use indexmap::map::Entry;
|
||||||
|
|
||||||
|
let &mut Self(ref mut diagnostic_filters) = self;
|
||||||
|
let DiagnosticFilter {
|
||||||
|
new_severity,
|
||||||
|
triggering_rule,
|
||||||
|
} = diagnostic_filter;
|
||||||
|
|
||||||
|
match diagnostic_filters.entry(triggering_rule) {
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
entry.insert((new_severity, span));
|
||||||
|
}
|
||||||
|
Entry::Occupied(entry) => {
|
||||||
|
let &(first_severity, first_span) = entry.get();
|
||||||
|
if first_severity != new_severity {
|
||||||
|
return Err(ConflictingDiagnosticRuleError {
|
||||||
|
triggering_rule,
|
||||||
|
triggering_rule_spans: [first_span, span],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An error returned by [`DiagnosticFilterMap::add`] when it encounters conflicting rules.
|
||||||
|
#[cfg(feature = "wgsl-in")]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(crate) struct ConflictingDiagnosticRuleError {
|
||||||
|
pub triggering_rule: FilterableTriggeringRule,
|
||||||
|
pub triggering_rule_spans: [Span; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a single parent-linking node in a tree of [`DiagnosticFilter`]s backed by a
|
||||||
|
/// [`crate::Arena`].
|
||||||
|
///
|
||||||
|
/// A single element of a _tree_ of diagnostic filter rules stored in
|
||||||
|
/// [`crate::Module::diagnostic_filters`]. When nodes are built by a front-end, module-applicable
|
||||||
|
/// filter rules are chained together in runs based on parse site. For instance, given the
|
||||||
|
/// following:
|
||||||
|
///
|
||||||
|
/// - Module-applicable rules `a` and `b`.
|
||||||
|
/// - Rules `c` and `d`, applicable to an entry point called `c_and_d_func`.
|
||||||
|
/// - Rule `e`, applicable to an entry point called `e_func`.
|
||||||
|
///
|
||||||
|
/// The tree would be represented as follows:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// a <- b
|
||||||
|
/// ^
|
||||||
|
/// |- c <- d
|
||||||
|
/// |
|
||||||
|
/// \- e
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ...where:
|
||||||
|
///
|
||||||
|
/// - `d` is the first leaf consulted by validation in `c_and_d_func`.
|
||||||
|
/// - `e` is the first leaf consulted by validation in `e_func`.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DiagnosticFilterNode {
|
||||||
|
pub inner: DiagnosticFilter,
|
||||||
|
pub parent: Option<Handle<DiagnosticFilterNode>>,
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::diagnostic_filter::FilterableTriggeringRule;
|
use crate::diagnostic_filter::ConflictingDiagnosticRuleError;
|
||||||
use crate::front::wgsl::parse::directive::enable_extension::{
|
use crate::front::wgsl::parse::directive::enable_extension::{
|
||||||
EnableExtension, UnimplementedEnableExtension,
|
EnableExtension, UnimplementedEnableExtension,
|
||||||
};
|
};
|
||||||
@ -295,12 +295,19 @@ pub(crate) enum Error<'a> {
|
|||||||
DiagnosticInvalidSeverity {
|
DiagnosticInvalidSeverity {
|
||||||
severity_control_name_span: Span,
|
severity_control_name_span: Span,
|
||||||
},
|
},
|
||||||
|
DiagnosticDuplicateTriggeringRule(ConflictingDiagnosticRuleError),
|
||||||
DiagnosticNotYetImplemented {
|
DiagnosticNotYetImplemented {
|
||||||
triggering_rule: FilterableTriggeringRule,
|
triggering_rule: FilterableTriggeringRule,
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<ConflictingDiagnosticRuleError> for Error<'a> {
|
||||||
|
fn from(value: ConflictingDiagnosticRuleError) -> Self {
|
||||||
|
Self::DiagnosticDuplicateTriggeringRule(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct AutoConversionError {
|
pub(crate) struct AutoConversionError {
|
||||||
pub dest_span: Span,
|
pub dest_span: Span,
|
||||||
@ -1017,6 +1024,29 @@ impl<'a> Error<'a> {
|
|||||||
)
|
)
|
||||||
.into()],
|
.into()],
|
||||||
},
|
},
|
||||||
|
Error::DiagnosticDuplicateTriggeringRule(ConflictingDiagnosticRuleError {
|
||||||
|
triggering_rule,
|
||||||
|
triggering_rule_spans,
|
||||||
|
}) => {
|
||||||
|
let [first_span, second_span] = triggering_rule_spans;
|
||||||
|
ParseError {
|
||||||
|
message: format!(
|
||||||
|
"found conflicting `diagnostic(…)` rule(s) for `{}`",
|
||||||
|
triggering_rule.to_ident()
|
||||||
|
),
|
||||||
|
labels: vec![
|
||||||
|
(first_span, "first rule".into()),
|
||||||
|
(second_span, "second rule".into()),
|
||||||
|
],
|
||||||
|
notes: vec![concat!(
|
||||||
|
"multiple `diagnostic(…)` rules with the same rule name ",
|
||||||
|
"conflict unless the severity is the same; ",
|
||||||
|
"delete the rule you don't want, or ",
|
||||||
|
"ensure that all severities with the same rule name match"
|
||||||
|
)
|
||||||
|
.into()],
|
||||||
|
}
|
||||||
|
}
|
||||||
Error::DiagnosticNotYetImplemented {
|
Error::DiagnosticNotYetImplemented {
|
||||||
triggering_rule,
|
triggering_rule,
|
||||||
span,
|
span,
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use crate::diagnostic_filter::{self, DiagnosticFilter, FilterableTriggeringRule};
|
use crate::diagnostic_filter::{
|
||||||
|
self, DiagnosticFilter, DiagnosticFilterMap, FilterableTriggeringRule,
|
||||||
|
};
|
||||||
use crate::front::wgsl::error::{Error, ExpectedToken};
|
use crate::front::wgsl::error::{Error, ExpectedToken};
|
||||||
use crate::front::wgsl::parse::directive::enable_extension::{
|
use crate::front::wgsl::parse::directive::enable_extension::{
|
||||||
EnableExtension, EnableExtensions, UnimplementedEnableExtension,
|
EnableExtension, EnableExtensions, UnimplementedEnableExtension,
|
||||||
@ -2522,6 +2524,7 @@ impl Parser {
|
|||||||
let mut lexer = Lexer::new(source);
|
let mut lexer = Lexer::new(source);
|
||||||
let mut tu = ast::TranslationUnit::default();
|
let mut tu = ast::TranslationUnit::default();
|
||||||
let mut enable_extensions = EnableExtensions::empty();
|
let mut enable_extensions = EnableExtensions::empty();
|
||||||
|
let mut diagnostic_filters = DiagnosticFilterMap::new();
|
||||||
|
|
||||||
// Parse directives.
|
// Parse directives.
|
||||||
while let Ok((ident, _directive_ident_span)) = lexer.peek_ident_with_span() {
|
while let Ok((ident, _directive_ident_span)) = lexer.peek_ident_with_span() {
|
||||||
@ -2533,6 +2536,7 @@ impl Parser {
|
|||||||
if let Some(diagnostic_filter) = self.diagnostic_filter(&mut lexer)? {
|
if let Some(diagnostic_filter) = self.diagnostic_filter(&mut lexer)? {
|
||||||
let triggering_rule = diagnostic_filter.triggering_rule;
|
let triggering_rule = diagnostic_filter.triggering_rule;
|
||||||
let span = self.peek_rule_span(&lexer);
|
let span = self.peek_rule_span(&lexer);
|
||||||
|
diagnostic_filters.add(diagnostic_filter, span)?;
|
||||||
Err(Error::DiagnosticNotYetImplemented {
|
Err(Error::DiagnosticNotYetImplemented {
|
||||||
triggering_rule,
|
triggering_rule,
|
||||||
span,
|
span,
|
||||||
|
Loading…
Reference in New Issue
Block a user