Skip to content

Commit 4b0303d

Browse files
committed
wip
1 parent 3da2382 commit 4b0303d

14 files changed

+1710
-687
lines changed

naga/src/common/diagnostic_display.rs

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//! Wrappers for displaying Naga IR terms in diagnostic output.
2+
3+
use crate::proc::GlobalCtx;
4+
use crate::{Handle, Scalar, Type, TypeInner};
5+
6+
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
7+
use crate::common::wgsl::{TryToWgsl, TypeContext};
8+
9+
use core::fmt;
10+
11+
/// A wrapper for displaying Naga IR terms in diagnostic output.
12+
///
13+
/// For some Naga IR type `T`, `DiagnosticDisplay<T>` implements
14+
/// [`core::fmt::Display`] in a way that displays values of type `T`
15+
/// appropriately for diagnostic messages presented to human readers.
16+
///
17+
/// For example, the implementation of [`Display`] for
18+
/// `DiagnosticDisplay<Scalar>` formats the type represented by the
19+
/// given [`Scalar`] appropriately for users.
20+
///
21+
/// Some types like `Handle<Type>` require contextual information like
22+
/// a type arena to be displayed. In such cases, we implement [`Display`]
23+
/// for a type like `DiagnosticDisplay<(Handle<Type>, GlobalCtx)>`, where
24+
/// the [`GlobalCtx`] type provides the necessary context.
25+
///
26+
/// [`Display`]: core::fmt::Display
27+
/// [`Scalar`]: crate::Scalar
28+
/// [`GlobalCtx`]: crate::proc::GlobalCtx
29+
///
30+
/// ## Language-sensitive diagnostics
31+
///
32+
/// As discussed in #7268, diagnostic output ought to depend on the
33+
/// source language from which the IR was produced: diagnostics
34+
/// resulting from processing GLSL code should use GLSL type syntax,
35+
/// for example. That means that `DiagnosticDisplay` ought to include
36+
/// some indication of which notation to use.
37+
///
38+
/// For the moment, only WGSL output is implemented, so
39+
/// `DiagnosticDisplay` lacks any support for this. However, the plan
40+
/// is that all language-independent code in Naga should use
41+
/// `DiagnosticDisplay` wherever appropriate, such that when its
42+
/// definition is expanded to include some indication of the right
43+
/// source language to use, any use site that does not supply this
44+
/// indication will provoke a compile-time error.
45+
pub struct DiagnosticDisplay<T>(pub T);
46+
47+
impl fmt::Display for DiagnosticDisplay<(Handle<Type>, &GlobalCtx<'_>)> {
48+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49+
let (handle, ctx) = self.0;
50+
51+
#[cfg(feature = "wgsl-in")]
52+
ctx.write_type(handle, f)?;
53+
54+
#[cfg(not(feature = "wgsl-in"))]
55+
{
56+
let _ = ctx;
57+
write!(f, "{handle:?}")?;
58+
}
59+
60+
Ok(())
61+
}
62+
}
63+
64+
impl<'m> fmt::Display for DiagnosticDisplay<(&'m TypeInner, &GlobalCtx<'m>)> {
65+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66+
let (inner, ctx) = self.0;
67+
68+
#[cfg(feature = "wgsl-in")]
69+
ctx.write_type_inner(inner, f)?;
70+
71+
#[cfg(not(feature = "wgsl-in"))]
72+
{
73+
let _ = ctx;
74+
write!(f, "{inner:?}")?;
75+
}
76+
77+
Ok(())
78+
}
79+
}
80+
81+
impl<'m> fmt::Display for DiagnosticDisplay<(&'m TypeInner, &crate::UniqueArena<Type>)> {
82+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83+
let (inner, ctx) = self.0;
84+
85+
#[cfg(feature = "wgsl-in")]
86+
ctx.write_type_inner(inner, f)?;
87+
88+
#[cfg(not(feature = "wgsl-in"))]
89+
{
90+
let _ = ctx;
91+
write!(f, "{inner:?}")?;
92+
}
93+
94+
Ok(())
95+
}
96+
}
97+
98+
impl fmt::Display for DiagnosticDisplay<Scalar> {
99+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100+
let scalar = self.0;
101+
102+
#[cfg(feature = "wgsl-in")]
103+
match scalar.try_to_wgsl() {
104+
Some(string) => f.write_str(string)?,
105+
None => crate::common::wgsl::write_scalar_for_diagnostics(scalar, f)?,
106+
}
107+
108+
#[cfg(not(feature = "wgsl-in"))]
109+
write!(f, "{scalar:?}")?;
110+
111+
Ok(())
112+
}
113+
}
114+
115+
/// A wrapper for displaying types with [`core::fmt::Debug`].
116+
///
117+
/// Since we expect this to be implemented in ad-hoc ways across Naga,
118+
/// we don't supply interesting implementations here.
119+
pub struct DiagnosticDebug<T>(pub T);

naga/src/common/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
//! Code common to the front and backends for specific languages.
22
3+
pub mod diagnostic_display;
34
pub mod wgsl;
45

6+
pub use diagnostic_display::{DiagnosticDisplay, DiagnosticDebug};
7+
58
/// Helper function that returns the string corresponding to the [`VectorSize`](crate::VectorSize)
69
pub const fn vector_size_str(size: crate::VectorSize) -> &'static str {
710
match size {

naga/src/front/wgsl/error.rs

+85-1
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,25 @@ pub(crate) enum Error<'a> {
272272
expected: Range<u32>,
273273
found: u32,
274274
},
275+
WrongArgumentCountForOverloads {
276+
function: String,
277+
call_span: Span,
278+
arg_span: Span,
279+
max_arguments: u32,
280+
overloads: Vec<String>,
281+
},
282+
WrongArgumentType {
283+
function: String,
284+
call_span: Span,
285+
arg_span: Span,
286+
arg_index: u32,
287+
found: String,
288+
allowed: Vec<String>,
289+
},
290+
AmbiguousCall {
291+
call_span: Span,
292+
alternatives: Vec<String>,
293+
},
275294
FunctionReturnsVoid(Span),
276295
FunctionMustUseUnused(Span),
277296
FunctionMustUseReturnsVoid(Span, Span),
@@ -403,7 +422,8 @@ impl<'a> Error<'a> {
403422
"workgroup size separator (`,`) or a closing parenthesis".to_string()
404423
}
405424
ExpectedToken::GlobalItem => concat!(
406-
"global item (`struct`, `const`, `var`, `alias`, `fn`, `diagnostic`, `enable`, `requires`, `;`) ",
425+
"global item (`struct`, `const`, `var`, `alias`, ",
426+
"`fn`, `diagnostic`, `enable`, `requires`, `;`) ",
407427
"or the end of the file"
408428
)
409429
.to_string(),
@@ -827,6 +847,70 @@ impl<'a> Error<'a> {
827847
labels: vec![(span, "wrong number of arguments".into())],
828848
notes: vec![],
829849
},
850+
Error::WrongArgumentCountForOverloads {
851+
ref function,
852+
call_span,
853+
arg_span,
854+
max_arguments,
855+
ref overloads,
856+
} => {
857+
let message = format!(
858+
"Given the types of arguments passed, \
859+
`{function}` accepts only {max_arguments} arguments"
860+
);
861+
let labels = vec![
862+
(call_span, "This function call has too many arguments".into()),
863+
(arg_span, "This is the first excess argument".into())
864+
];
865+
let mut notes = vec![
866+
format!("These are the only overloads of `{function}` \
867+
that accept the initial arguments:"),
868+
];
869+
notes.extend(overloads.iter().map(|o| format!("overload: {o}")));
870+
871+
ParseError { message, labels, notes }
872+
}
873+
Error::WrongArgumentType {
874+
ref function,
875+
call_span,
876+
arg_span,
877+
arg_index,
878+
ref found,
879+
ref allowed,
880+
} => {
881+
let message = format!(
882+
"This call to `{function}` cannot accept a value of type `{found}` for argument #{}",
883+
arg_index + 1,
884+
);
885+
let labels = vec![
886+
(call_span, "the function being called".into()),
887+
(arg_span, format!(
888+
"This argument has type `{found}`",
889+
).into())
890+
];
891+
892+
let mut notes = vec![];
893+
if arg_index > 0 {
894+
notes.push("Given the types of the preceding arguments,".into());
895+
notes.push(format!("the following types are allowed for argument #{}:", arg_index + 1));
896+
} else {
897+
notes.push("The following types are allowed for the first argument:".to_string());
898+
};
899+
notes.extend(allowed.iter().map(|ty| format!("allowed type: {ty}")));
900+
901+
ParseError { message, labels, notes }
902+
},
903+
Error::AmbiguousCall { call_span, ref alternatives } => {
904+
let message = "Function call is ambiguous: more than one overload could apply".into();
905+
let labels = vec![
906+
(call_span, "More than one overload of this function could apply to these arguments".into()),
907+
];
908+
let mut notes = vec![
909+
"All of the following overloads could apply, but no one overload is clearly preferable:".into()
910+
];
911+
notes.extend(alternatives.iter().map(|alt| format!("possible overload: {alt}")));
912+
ParseError { message, labels, notes }
913+
},
830914
Error::FunctionReturnsVoid(span) => ParseError {
831915
message: "function does not return any value".to_string(),
832916
labels: vec![(span, "".into())],

naga/src/front/wgsl/lower/conversion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl<'source> super::ExpressionContext<'source, '_, '_> {
7171
self.convert_leaf_scalar(expr, expr_span, goal_scalar)
7272
}
7373

74-
/// Try to convert `expr`'s leaf scalar to `goal` using automatic conversions.
74+
/// Try to convert `expr`'s leaf scalar to `goal_scalar` using automatic conversions.
7575
///
7676
/// If no conversions are necessary, return `expr` unchanged.
7777
///

0 commit comments

Comments
 (0)