Skip to content

Commit

Permalink
more stuff working
Browse files Browse the repository at this point in the history
  • Loading branch information
jimblandy committed Feb 5, 2025
1 parent c504147 commit 669b817
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 23 deletions.
28 changes: 28 additions & 0 deletions naga/src/front/wgsl/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,13 @@ pub(crate) enum Error<'a> {
expected: Range<u32>,
found: u32,
},
WrongArgumentCountForOverloads {
function: String,
call_span: Span,
arg_span: Span,
max_arguments: u32,
overloads: Vec<String>,
},
WrongArgumentType {
function: String,
call_span: Span,
Expand Down Expand Up @@ -821,6 +828,27 @@ impl<'a> Error<'a> {
labels: vec![(span, "wrong number of arguments".into())],
notes: vec![],
},
Error::WrongArgumentCountForOverloads {
ref function,
call_span,
arg_span,
max_arguments,
ref overloads,
} => {
let message = format!(
"For the preceding argument types, `{function}` accepts only {max_arguments} arguments"
);
let labels = vec![
(call_span, "This function call has too many arguments".into()),
(arg_span, "This is the first excess argument".into())
];
let mut notes = vec![
format!("These are the only overloads of `{function}` that could accept the preceding arguments:"),
];
notes.extend(overloads.iter().map(|o| format!("overload: {o}")));

ParseError { message, labels, notes }
}
Error::WrongArgumentType {
ref function,
call_span,
Expand Down
48 changes: 40 additions & 8 deletions naga/src/front/wgsl/lower/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2298,20 +2298,52 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
use crate::proc::Rule as _;

let mut overloads = fun.overloads();
log::debug!("JIMB: {fun:?}");
let min_arguments = overloads.min_subexpressions();
let max_arguments = overloads.max_subexpressions();
if arguments.len() < min_arguments || max_arguments < arguments.len() {
return Err(Error::WrongArgumentCount {
span,
expected: min_arguments as u32 .. max_arguments as u32,
found: arguments.len() as u32
});
}

let mut unconverted_arguments = Vec::with_capacity(arguments.len());
for (i, &arg) in arguments.iter().enumerate() {
let lowered = self.expression_for_abstract(arg, ctx)?;
let ty = resolve_inner!(ctx, lowered);
let remaining_overloads = overloads.arg(i, ty, &ctx.module.types);
if remaining_overloads.is_empty() {
return Err(Error::WrongArgumentType {
function: fun.to_wgsl().to_string(),
call_span: span,
arg_span: ctx.ast_expressions.get_span(arg),
arg_index: i as u32,
found: crate::common::wgsl::Wgslish(ty).to_string(),
allowed: overloads.allowed_args(i),
});
// If there were other types permitted for the i'th arg, then
// this is a no-such-overload error.
//
// Otherwise, since we checked the argument count against the
// min and max earlier, it must be the case that the prior
// arguments narrowed the overloads to a subset none of which
// accept this many arguments.
let arg_span = ctx.ast_expressions.get_span(arg);
let allowed = overloads.allowed_args(i);
let function = fun.to_wgsl().to_string();
if allowed.is_empty() {
let overload_list = overloads.overload_list(&function);
return Err(Error::WrongArgumentCountForOverloads {
function,
call_span: span,
arg_span,
max_arguments: overloads.max_subexpressions() as u32,
overloads: overload_list,
});
} else {
return Err(Error::WrongArgumentType {
function,
call_span: span,
arg_span,
arg_index: i as u32,
found: crate::common::wgsl::Wgslish(ty).to_string(),
allowed,
});
}
}
overloads = remaining_overloads;
unconverted_arguments.push(lowered);
Expand Down
21 changes: 14 additions & 7 deletions naga/src/proc/builtins/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,22 @@ impl super::OverloadSet for List {
self.members == 0
}

fn min_subexpressions(&self) -> Option<usize> {
self.members().fold(None, |n, (_, rule)| {
std::cmp::min(n, Some(rule.subexpressions.len()))
})
fn min_subexpressions(&self) -> usize {
self.members().fold(None, |best, (_, rule)| {
// This is different from `max_subexpressions` because
// `<Option as PartialOrd>` doesn't work the way we'd like.
let len = rule.subexpressions.len();
Some(match best {
Some(best) => std::cmp::max(best, len),
None => len
})
}).unwrap()
}

fn max_subexpressions(&self) -> Option<usize> {
fn max_subexpressions(&self) -> usize {
self.members().fold(None, |n, (_, rule)| {
std::cmp::max(n, Some(rule.subexpressions.len()))
})
}).unwrap()
}

fn arg(&self, i: usize, ty: &crate::TypeInner, types: &crate::UniqueArena<crate::Type>) -> Self {
Expand Down Expand Up @@ -122,7 +128,8 @@ impl super::OverloadSet for List {
}

fn most_preferred(&self) -> Option<Rule> {
self.members().next().map(|(_, rule)| rule.clone())
let (_, rule) = self.members().next().unwrap();
Some(rule.clone())
}

fn overload_list(&self, name: &str) -> Vec<String> {
Expand Down
55 changes: 47 additions & 8 deletions naga/src/proc/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,20 @@ pub trait OverloadSet: Clone + std::fmt::Debug {
fn is_empty(&self) -> bool;

/// Return the smallest number of subexpressions in any type rule
/// in the set. Return `None` if `self` is empty.
fn min_subexpressions(&self) -> Option<usize>;
/// in the set.
///
/// # Panics
///
/// Panics if `self` is empty.
fn min_subexpressions(&self) -> usize;

/// Return the largest number of subexpressions in any type rule
/// in the set. Return `None` if `self` is empty.
fn max_subexpressions(&self) -> Option<usize>;
/// in the set.
///
/// # Panics
///
/// Panics if `self` is empty.
fn max_subexpressions(&self) -> usize;

/// Limit `self` to the overloads that can accept a given
/// subexpression.
Expand Down Expand Up @@ -78,12 +86,15 @@ pub trait OverloadSet: Clone + std::fmt::Debug {
/// [concretize]: https://gpuweb.github.io/gpuweb/wgsl/#concretization
fn concrete_only(self, types: &crate::UniqueArena<crate::Type>) -> Self;

/// Return the most preferred candidate, or `None` if `self` is empty.
/// Return the most preferred candidate.
///
/// Rank the candidates in `self` as described in WGSL's [overload
/// resolution algorithm][ora], and return a singleton set containing the
/// most preferred candidate.
///
/// If there is no most preferred candidate, return `None`,
/// indicating that the expression is ambiguous.
///
/// As it's described in the spec, choosing the most preferred candidate
/// depends on the ranks of the conversions being applied to each argument,
/// so it's impossible to determine the most preferred candidate from the
Expand All @@ -93,6 +104,10 @@ pub trait OverloadSet: Clone + std::fmt::Debug {
/// leaf scalar type for all its subexpressions, then the most abstract
/// overload must be the most preferred candidate.
///
/// # Panics
///
/// Panics if `self` is empty.
///
/// [ora]: https://gpuweb.github.io/gpuweb/wgsl/#overload-resolution-section
fn most_preferred(&self) -> Option<Self::Rule>;

Expand Down Expand Up @@ -139,13 +154,13 @@ impl OverloadSet for AnyOverloadSet {
}
}

fn min_subexpressions(&self) -> Option<usize> {
fn min_subexpressions(&self) -> usize {
match *self {
AnyOverloadSet::List(ref list) => list.min_subexpressions(),
}
}

fn max_subexpressions(&self) -> Option<usize> {
fn max_subexpressions(&self) -> usize {
match *self {
AnyOverloadSet::List(ref list) => list.max_subexpressions(),
}
Expand All @@ -165,7 +180,7 @@ impl OverloadSet for AnyOverloadSet {

fn most_preferred(&self) -> Option<AnyRule> {
match *self {
AnyOverloadSet::List(ref list) => list.most_preferred().map(AnyRule::List),
AnyOverloadSet::List(ref list) => list.most_preferred().map(AnyRule::List)
}
}

Expand Down Expand Up @@ -216,6 +231,10 @@ impl crate::MathFunction {
const VEC3F: Ti = Ti::Vector { size: Vs::Tri, scalar: Sc::F32 };
const VEC4F: Ti = Ti::Vector { size: Vs::Quad, scalar: Sc::F32 };

const VEC2AF: Ti = Ti::Vector { size: Vs::Bi, scalar: Sc::ABSTRACT_FLOAT };
const VEC3AF: Ti = Ti::Vector { size: Vs::Tri, scalar: Sc::ABSTRACT_FLOAT };
const VEC4AF: Ti = Ti::Vector { size: Vs::Quad, scalar: Sc::ABSTRACT_FLOAT };

const VEC2I: Ti = Ti::Vector { size: Vs::Bi, scalar: Sc::I32 };
const VEC3I: Ti = Ti::Vector { size: Vs::Tri, scalar: Sc::I32 };
const VEC4I: Ti = Ti::Vector { size: Vs::Quad, scalar: Sc::I32 };
Expand Down Expand Up @@ -266,9 +285,29 @@ impl crate::MathFunction {
},
];

static POW: &[list::Rule] = &[
list::Rule {
subexpressions: &[Ti::Scalar(Sc::F32), Ti::Scalar(Sc::F32)],
conclusion: Ti::Scalar(Sc::F32),
},
list::Rule {
subexpressions: &[Ti::Scalar(Sc::ABSTRACT_FLOAT), Ti::Scalar(Sc::ABSTRACT_FLOAT)],
conclusion: Ti::Scalar(Sc::ABSTRACT_FLOAT),
},
list::Rule {
subexpressions: &[VEC2F, VEC2F],
conclusion: VEC2F,
},
list::Rule {
subexpressions: &[VEC2AF, VEC2AF],
conclusion: VEC2AF,
},
];

match self {
Mf::Sin => AnyOverloadSet::List(list::List::from_rules(COMPONENT_WISE_FLOAT)),
Mf::Dot => AnyOverloadSet::List(list::List::from_rules(DOT_PRODUCT)),
Mf::Pow => AnyOverloadSet::List(list::List::from_rules(POW)),
_ => todo!(),
}
}
Expand Down

0 comments on commit 669b817

Please sign in to comment.