/// Overload sets represented as sets of scalars and constructors. /// /// This type represents an [`OverloadSet`] using a bitset of scalar /// types and a bitset of type constructors that might be applied to /// those scalars. The overload set contains a rule for every possible /// combination of scalars and constructors, essentially the cartesian /// product of the two sets. /// /// For example, if the arity is 2, set of scalars is { AbstractFloat, /// `f32` }, and the set of constructors is { `vec2`, `vec3` }, then /// that represents the set of overloads: /// /// - (`vec2<AbstractFloat>`, `vec2<AbstractFloat>`) -> `vec2<AbstractFloat>` /// - (`vec2<f32>`, `vec2<f32>`) -> `vec2<f32>` /// - (`vec3<AbstractFloat>`, `vec3<AbstractFloat>`) -> `vec3<AbstractFloat>` /// - (`vec3<f32>`, `vec3<f32>`) -> `vec3<f32>` /// /// The `conclude` value says how to determine the return type from /// the argument type. /// /// Restrictions: /// /// - All overloads must take the same number of arguments. /// /// - For any given overload, all its arguments must have the same /// type. #[derive(Clone)] pub(incrate::proc::overloads) struct Regular { /// The number of arguments in the rules. pub arity: usize,
/// The set of type constructors to apply. pub constructors: ConstructorSet,
/// The set of scalars to apply them to. pub scalars: ScalarSet,
/// How to determine a member rule's return type given the type of /// its arguments. pub conclude: ConclusionRule,
}
/// Return an iterator over all the argument types allowed by `self`. /// /// Return an iterator that produces, for each overload in `self`, the /// constructor and scalar of its argument types and return type. /// /// A [`Regular`] value can only represent overload sets where, in /// each overload, all the arguments have the same type, and the /// return type is always going to be a determined by the argument /// types, so giving the constructor and scalar is sufficient to /// characterize the entire rule. fn members(&self) -> impl Iterator<Item = (ConstructorSize, ir::Scalar)> { let scalars = self.scalars; self.constructors.members().flat_map(move |constructor| { let size = constructor.size(); // Technically, we don't need the "most general" `TypeInner` here, // but since `ScalarSet::members` only produces singletons anyway, // the effect is the same.
scalars
.members()
.map(move |singleton| (size, singleton.most_general_scalar()))
})
}
// If there is more than one constructor allowed, then we must // not have had any arguments supplied at all. In any case, we // don't have any unambiguously preferred candidate.
assert!(self.constructors.is_singleton());
let size = self.constructors.size(); let scalar = self.scalars.most_general_scalar();
make_rule(self.arity, size, scalar, self.conclude)
}
/// Construct a [`Regular`] member [`Rule`] for the given arity and type. /// /// [`Regular`] can only represent rules where all the argument types and the /// return type are the same, so just knowing `arity` and `inner` is sufficient. /// /// [`Rule`]: crate::proc::overloads::Rule fn make_rule(
arity: usize,
size: ConstructorSize,
scalar: ir::Scalar,
conclusion_rule: ConclusionRule,
) -> Rule { let inner = size.to_inner(scalar); let arg = TypeResolution::Value(inner.clone());
Rule {
arguments: core::iter::repeat_n(arg.clone(), arity).collect(),
conclusion: conclusion_rule.conclude(size, scalar),
}
}
/// Construct a [`Regular`] [`OverloadSet`]. /// /// Examples: /// /// - `regular!(2, SCALAR|VECN of FLOAT)`: An overload set whose rules take two /// arguments of the same type: a floating-point scalar (possibly abstract) or /// a vector of such. The return type is the same as the argument type. /// /// - `regular!(1, VECN of FLOAT -> Scalar)`: An overload set whose rules take /// one argument that is a vector of floats, and whose return type is the leaf /// scalar type of the argument type. /// /// The constructor values (before the `<` angle brackets `>`) are /// constants from [`ConstructorSet`]. /// /// The scalar values (inside the `<` angle brackets `>`) are /// constants from [`ScalarSet`]. /// /// When a return type identifier is given, it is treated as a variant /// of the the [`ConclusionRule`] enum.
macro_rules! regular { // regular!(ARITY, CONSTRUCTOR of SCALAR)
( $arity:literal , $( $constr:ident )|* of $( $scalar:ident )|*) => {
{ use $crate::proc::overloads; use overloads::constructor_set::constructor_set; use overloads::regular::{Regular, ConclusionRule}; use overloads::scalar_set::scalar_set;
Regular {
arity: $arity,
constructors: constructor_set!( $( $constr )|* ),
scalars: scalar_set!( $( $scalar )|* ),
conclude: ConclusionRule::ArgumentType,
}
}
};
// regular!(ARITY, CONSTRUCTOR of SCALAR -> CONCLUSION_RULE)
( $arity:literal , $( $constr:ident )|* of $( $scalar:ident )|* -> $conclude:ident) => {
{ use $crate::proc::overloads; use overloads::constructor_set::constructor_set; use overloads::regular::{Regular, ConclusionRule}; use overloads::scalar_set::scalar_set;
Regular {
arity: $arity,
constructors:constructor_set!( $( $constr )|* ),
scalars: scalar_set!( $( $scalar )|* ),
conclude: ConclusionRule::$conclude,
}
}
};
}
pub(incrate::proc::overloads) use regular;
#[cfg(test)] mod test { usesuper::*; usecrate::ir;
/// Assert that `set` has a most preferred candidate whose type /// conclusion is `expected`. #[track_caller] fn check_return_type(set: &Regular, expected: &ir::TypeInner, arena: &UniqueArena<ir::Type>) {
assert!(!set.is_empty());
let special_types = ir::SpecialTypes::default();
let preferred = set.most_preferred(); let conclusion = preferred.conclusion; let resolution = conclusion
.into_resolution(&special_types)
.expect("special types should have been pre-registered"); let inner = resolution.inner_with(arena);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.