-
Notifications
You must be signed in to change notification settings - Fork 979
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
1,185 additions
and
583 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
//! An overload set represented as a static list. | ||
#![allow(dead_code, unused_variables)] | ||
|
||
/// A simple list of overloads. | ||
/// | ||
/// Note that this type is not quite as general as it looks, in that | ||
/// the implementation of `most_preferred` doesn't work for arbitrary | ||
/// lists of overloads. See the documentation for [`List::rules`] for | ||
/// details. | ||
pub struct List { | ||
/// A bitmask of which elements of `rules` are included in the set. | ||
members: u64, | ||
|
||
/// A list of type rules that are members of the set. | ||
/// | ||
/// These must be listed in order such that the first rule in the | ||
/// list is always more preferred than any other rule in the list. | ||
/// If there is no such arrangement, then you cannot use `List` to | ||
/// represent the overload set. | ||
rules: &'static [Rule], | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct Rule { | ||
pub subexpressions: &'static [crate::TypeInner], | ||
pub conclusion: crate::TypeInner, | ||
} | ||
|
||
impl List { | ||
pub const fn from_rules(rules: &'static [Rule]) -> List { | ||
List { | ||
members: len_to_full_mask(rules.len()), | ||
rules, | ||
} | ||
} | ||
|
||
fn members(&self) -> impl Iterator<Item = (u64, &Rule)> { | ||
OneBitsIter(self.members).map(|mask| { | ||
let index = mask.trailing_zeros() as usize; | ||
(mask, &self.rules[index]) | ||
}) | ||
} | ||
|
||
fn filter<F>(&self, mut pred: F) -> List | ||
where | ||
F: FnMut(&Rule) -> bool, | ||
{ | ||
let mut filtered_members = 0; | ||
for (mask, rule) in self.members() { | ||
if pred(rule) { | ||
filtered_members |= mask; | ||
} | ||
} | ||
|
||
List { | ||
members: filtered_members, | ||
rules: self.rules, | ||
} | ||
} | ||
} | ||
|
||
impl super::OverloadSet for List { | ||
type Rule = Rule; | ||
|
||
fn is_empty(&self) -> bool { | ||
self.members == 0 | ||
} | ||
|
||
fn max_subexpressions(&self) -> Option<usize> { | ||
self.members().fold(None, |n, (_, rule)| { | ||
std::cmp::max(n, Some(rule.subexpressions.len())) | ||
}) | ||
} | ||
|
||
fn arg(self, i: usize, ty: &crate::TypeInner, types: &crate::UniqueArena<crate::Type>) -> Self { | ||
use crate::common::wgsl::Wgslish; | ||
self.filter(|rule| { | ||
log::debug!("JIMB: arg {i} of type {} in rule {rule:?}", Wgslish(ty)); | ||
if let Some(rule_ty) = rule.subexpressions.get(i) { | ||
log::debug!("JIMB: converts automatically: {:?}", | ||
ty.automatically_converts_to(rule_ty, types)); | ||
} | ||
rule.subexpressions | ||
.get(i) | ||
.and_then(|rule_ty| ty.automatically_converts_to(rule_ty, types)) | ||
.is_some() | ||
}) | ||
} | ||
|
||
fn concrete_only(self, types: &crate::UniqueArena<crate::Type>) -> Self { | ||
self.filter(|rule| { | ||
rule.subexpressions | ||
.iter() | ||
.all(|arg_ty| !arg_ty.is_abstract(types)) | ||
}) | ||
} | ||
|
||
fn most_preferred(self) -> Option<Rule> { | ||
self.members().next().map(|(_, rule)| rule.clone()) | ||
} | ||
} | ||
|
||
impl super::Rule for Rule { | ||
fn leaf_scalar(&self, i: usize) -> Option<crate::Scalar> { | ||
// TODO: This is wrong for arrays | ||
self.subexpressions[i].scalar() | ||
} | ||
|
||
fn conclusion_type(&self) -> crate::TypeInner { | ||
self.conclusion.clone() | ||
} | ||
} | ||
|
||
const fn len_to_full_mask(n: usize) -> u64 { | ||
if n >= 64 { | ||
panic!("List::rules can only hold up to 63 rules"); | ||
} | ||
|
||
(1_u64 << n) - 1 | ||
} | ||
|
||
impl std::fmt::Debug for List { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
f.debug_map() | ||
.entries( | ||
self.members() | ||
.map(|(mask, rule)| (rule, self.members & mask != 0)), | ||
) | ||
.finish() | ||
} | ||
} | ||
|
||
impl std::fmt::Debug for Rule { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
use crate::common::wgsl::Wgslish; | ||
|
||
f.write_str("(")?; | ||
for (i, subexpression) in self.subexpressions.iter().enumerate() { | ||
if i > 0 { | ||
f.write_str(", ")?; | ||
} | ||
write!(f, "{}", Wgslish(subexpression))?; | ||
} | ||
write!(f, ") -> {}", Wgslish(&self.conclusion)) | ||
} | ||
} | ||
|
||
/// An iterator that produces the set bits in the given `u64`. | ||
/// | ||
/// The values produced are masks, not bit numbers. Use | ||
/// `u64::trailing_zeros` if you need bit numbers. | ||
struct OneBitsIter(u64); | ||
|
||
impl Iterator for OneBitsIter { | ||
type Item = u64; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
if self.0 == 0 { | ||
return None; | ||
} | ||
|
||
// Return the lowest `1` bit, and remove it. | ||
let mask = self.0 - 1; | ||
let item = self.0 & !mask; | ||
self.0 &= mask; | ||
Some(item) | ||
} | ||
} |
Oops, something went wrong.