tint: IntrinsicTable: Rename open/closed -> template
The concept of 'closing' an open type or number made sense when these were immutable once the first type/number had been matched during overload resolution. In order to support abstract numerics, these template parameters need to be constrained as the arguments are evaluated, so there's no longer a binary open / closed state. Give up on this concept, and rename everything to 'template type' and 'template number'. This is likely easier for people to understand anyway. Also fix a small typo in the ICE message printed when there's an ambiguous overload resolution (should never happen with the current entries in the table). Bug: tint:1504 Change-Id: I2bf043c71e5afa757259968eae4af830c50f38e0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/90662 Commit-Queue: Ben Clayton <bclayton@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
parent
d968e28a9a
commit
4c9ed74b5e
|
@ -154,7 +154,7 @@ match workgroup_or_storage: workgroup | storage
|
|||
// functions supported by the WGSL language. This builtin definition //
|
||||
// language supports simple static-type function declarations, as well as //
|
||||
// single overload declarations that can match a number of different //
|
||||
// argument types via the use of 'open-types' and 'open-numbers'. //
|
||||
// argument types via the use of template types and template numbers //
|
||||
// //
|
||||
// * Basic example: //
|
||||
// //
|
||||
|
@ -163,10 +163,9 @@ match workgroup_or_storage: workgroup | storage
|
|||
// Declares an overload of the function 'isInf' that accepts a single //
|
||||
// parameter of type 'f32' and returns a 'bool'. //
|
||||
// //
|
||||
// An 'open-type' can be thought as a template type that is determined by the //
|
||||
// arguments to the builtin. //
|
||||
// A template type is a type determined by the arguments to the builtin. //
|
||||
// //
|
||||
// * Open-type example without constraint: //
|
||||
// * Template type example without constraint: //
|
||||
// //
|
||||
// fn arrayLength<T>(array<T>) -> u32 //
|
||||
// //
|
||||
|
@ -175,7 +174,7 @@ match workgroup_or_storage: workgroup | storage
|
|||
// element type. This overload will always return a value of the same type //
|
||||
// as its single argument. //
|
||||
// //
|
||||
// * Open-type example with constraint: //
|
||||
// * Template type example with constraint: //
|
||||
// //
|
||||
// fn abs<T: fiu32>(T) -> T //
|
||||
// //
|
||||
|
@ -183,10 +182,10 @@ match workgroup_or_storage: workgroup | storage
|
|||
// argument of type 'f32', 'i32' or 'u32', which returns a value of the //
|
||||
// same argument type. //
|
||||
// //
|
||||
// Similarly an 'open-number' can be thought as a template number or //
|
||||
// enumerator that is determined by the arguments to the builtin. //
|
||||
// Similarly a template number is a number or enumerator that is determined //
|
||||
// by the arguments to the builtin. //
|
||||
// //
|
||||
// * Open-number example: //
|
||||
// * Template number example: //
|
||||
// //
|
||||
// fn dpdx<N: num>(vec<N, f32>) -> vec<N, f32> //
|
||||
// //
|
||||
|
@ -198,51 +197,50 @@ match workgroup_or_storage: workgroup | storage
|
|||
// Matching algorithm: //
|
||||
// ------------------- //
|
||||
// //
|
||||
// Prior to matching an overload, all open-types are undefined. //
|
||||
// Prior to matching an overload, all template types are undefined. //
|
||||
// //
|
||||
// Open-types become closed-types (pinned to a fixed type) on the first //
|
||||
// attempt to match an argument to that open-type. //
|
||||
// Once open-types are closed, they remain that type for the rest of the //
|
||||
// overload evaluation. //
|
||||
// Template types become defined on the first attempt to match an argument to //
|
||||
// that template type. Once template types are defined, they remain that type //
|
||||
// for the rest of the overload evaluation. //
|
||||
// //
|
||||
// To better understand, let's consider the following hypothetical overload //
|
||||
// declaration: //
|
||||
// //
|
||||
// fn foo<T: scalar>(T, T); //
|
||||
// //
|
||||
// T - is the open-type //
|
||||
// T - is the template type name //
|
||||
// scalar - is a matcher for the types 'f32', 'i32', 'u32' or 'bool' //
|
||||
// (declared above) //
|
||||
// <T: scalar> - declares the open-type T, with the constraint that T must //
|
||||
// match one of 'f32', 'i32', 'u32' or 'bool'. //
|
||||
// <T: scalar> - declares the template type T, with the constraint that T //
|
||||
// must match one of 'f32', 'i32', 'u32' or 'bool'. //
|
||||
// //
|
||||
// The process for resolving this overload is as follows: //
|
||||
// //
|
||||
// (1) The overload resolver begins by attempting to match the argument //
|
||||
// types from left to right. //
|
||||
// The first parameter type is compared against the argument type. //
|
||||
// As the open-type T has not been closed yet, T is closed as the type //
|
||||
// of the first argument. //
|
||||
// The first parameter type is compared against the argument type T. //
|
||||
// As the template type T has not been defined yet, T is defined as the //
|
||||
// type of the first argument. //
|
||||
// There's no verification that the T type is a scalar at this stage. //
|
||||
// (2) The second parameter is then compared against the second argument. //
|
||||
// As the open-type T is now closed, the argument type is compared //
|
||||
// against the value of the closed-type of T. If the types match, then //
|
||||
// As the template type T is now defined the argument type is compared //
|
||||
// against the value of the defined type of T. If the types match, then //
|
||||
// the overload is still a candidate for matching, otherwise the //
|
||||
// overload is no longer considered. //
|
||||
// (3) If all the parameters matched, constraints on the open-types need //
|
||||
// to be checked next. If the closed-type does not match the 'match' //
|
||||
// constraint, then the overload is no longer considered. //
|
||||
// (3) If all the parameters matched, constraints on the template types //
|
||||
// need to be checked next. If the defined type does not match the //
|
||||
// 'match' constraint, then the overload is no longer considered. //
|
||||
// //
|
||||
// The algorithm for matching open-numbers is almost identical to open-types, //
|
||||
// except of course, they match against integer numbers or enumerators //
|
||||
// instead of types. //
|
||||
// The algorithm for matching template numbers is almost identical to //
|
||||
// matching template types, except of course, they match against integer //
|
||||
// numbers or enumerators instead of types. //
|
||||
// //
|
||||
// //
|
||||
// * More examples: //
|
||||
// //
|
||||
// fn F() //
|
||||
// - Function called F. //
|
||||
// No open types or numbers, no parameters, no return value //
|
||||
// No template types or numbers, no parameters, no return value //
|
||||
// //
|
||||
// fn F() -> RETURN_TYPE //
|
||||
// - Function with RETURN_TYPE as the return type value //
|
||||
|
@ -256,21 +254,21 @@ match workgroup_or_storage: workgroup | storage
|
|||
// some builtin functions //
|
||||
// //
|
||||
// fn F<T>(T) //
|
||||
// - Single parameter of unconstrained open-type T (any type) //
|
||||
// - Single parameter of unconstrained template type T (any type) //
|
||||
// //
|
||||
// fn F<T: scalar>(T) //
|
||||
// - Single parameter of constrained open-type T (must be a scalar) //
|
||||
// - Single parameter of constrained template type T (must be a scalar) //
|
||||
// //
|
||||
// fn F<T: fiu32>(T) -> T //
|
||||
// - Single parameter of constrained open-type T (must be a one of fiu32) //
|
||||
// Return type matches parameter type //
|
||||
// - Single parameter of constrained template type T (must be a one of //
|
||||
// fiu32) Return type matches parameter type //
|
||||
// //
|
||||
// fn F<T, N: num>(vec<N, T>) //
|
||||
// - Single parameter of vector type with open-number size N and element //
|
||||
// open-type T //
|
||||
// - Single parameter of vector type with template number size N and //
|
||||
// element template type T //
|
||||
// //
|
||||
// fn F<A: access>(texture_storage_1d<f32_texel_format, A>) //
|
||||
// - Single parameter of texture_storage_1d type with open-number //
|
||||
// - Single parameter of texture_storage_1d type with template number //
|
||||
// access-control C, and of a texel format that is listed in //
|
||||
// f32_texel_format //
|
||||
// //
|
||||
|
|
|
@ -100,34 +100,33 @@ struct Number {
|
|||
const Number Number::any{Number::kAny};
|
||||
const Number Number::invalid{Number::kInvalid};
|
||||
|
||||
/// ClosedState holds the state of the open / closed numbers and types.
|
||||
/// TemplateState holds the state of the template numbers and types.
|
||||
/// Used by the MatchState.
|
||||
class ClosedState {
|
||||
class TemplateState {
|
||||
public:
|
||||
/// If the type with index `idx` is open, then it is closed with type `ty` and
|
||||
/// Type() returns true. If the type is closed, then `Type()` returns true iff
|
||||
/// it is equal to `ty`.
|
||||
/// If the type with index `idx` is undefined, then it is defined with type `ty` and Type()
|
||||
/// returns true. If the template type is defined, then `Type()` returns true iff it is equal to
|
||||
/// `ty`.
|
||||
bool Type(size_t idx, const sem::Type* ty) {
|
||||
auto res = types_.emplace(idx, ty);
|
||||
return res.second || res.first->second == ty;
|
||||
}
|
||||
|
||||
/// If the number with index `idx` is open, then it is closed with number
|
||||
/// `number` and Num() returns true. If the number is closed, then `Num()`
|
||||
/// returns true iff it is equal to `ty`.
|
||||
/// If the number with index `idx` is undefined, then it is defined with the number `number` and
|
||||
/// Num() returns true. If the number is defined, then `Num()` returns true iff it is equal to
|
||||
/// `ty`.
|
||||
bool Num(size_t idx, Number number) {
|
||||
auto res = numbers_.emplace(idx, number.Value());
|
||||
return res.second || res.first->second == number.Value();
|
||||
}
|
||||
|
||||
/// Type returns the closed type with index `idx`, or nullptr if the type was not closed.
|
||||
/// Type returns the template type with index `idx`, or nullptr if the type was not defined.
|
||||
const sem::Type* Type(size_t idx) const {
|
||||
auto it = types_.find(idx);
|
||||
return (it != types_.end()) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
/// Type returns the number type with index `idx`.
|
||||
/// An ICE is raised if the number is not closed.
|
||||
Number Num(size_t idx) const {
|
||||
auto it = numbers_.find(idx);
|
||||
return (it != numbers_.end()) ? Number(it->second) : Number::invalid;
|
||||
|
@ -141,23 +140,23 @@ class ClosedState {
|
|||
/// Index type used for matcher indices
|
||||
using MatcherIndex = uint8_t;
|
||||
|
||||
/// Index value used for open types / numbers that do not have a constraint
|
||||
/// Index value used for template types / numbers that do not have a constraint
|
||||
constexpr MatcherIndex kNoMatcher = std::numeric_limits<MatcherIndex>::max();
|
||||
|
||||
/// MatchState holds the state used to match an overload.
|
||||
class MatchState {
|
||||
public:
|
||||
MatchState(ProgramBuilder& b,
|
||||
ClosedState& c,
|
||||
TemplateState& t,
|
||||
const Matchers& m,
|
||||
const OverloadInfo* o,
|
||||
MatcherIndex const* matcher_indices)
|
||||
: builder(b), closed(c), matchers(m), overload(o), matcher_indices_(matcher_indices) {}
|
||||
: builder(b), templates(t), matchers(m), overload(o), matcher_indices_(matcher_indices) {}
|
||||
|
||||
/// The program builder
|
||||
ProgramBuilder& builder;
|
||||
/// The open / closed types and numbers
|
||||
ClosedState& closed;
|
||||
/// The template types and numbers
|
||||
TemplateState& templates;
|
||||
/// The type and number matchers
|
||||
Matchers const& matchers;
|
||||
/// The current overload being evaluated
|
||||
|
@ -198,7 +197,7 @@ class TypeMatcher {
|
|||
|
||||
/// Checks whether the given type matches the matcher rules, and returns the
|
||||
/// expected, canonicalized type on success.
|
||||
/// Match may close open types and numbers in state.
|
||||
/// Match may define template types and numbers in state.
|
||||
/// @param type the type to match
|
||||
/// @returns the canonicalized type on match, otherwise nullptr
|
||||
virtual const sem::Type* Match(MatchState& state, const sem::Type* type) const = 0;
|
||||
|
@ -216,7 +215,7 @@ class NumberMatcher {
|
|||
virtual ~NumberMatcher() = default;
|
||||
|
||||
/// Checks whether the given number matches the matcher rules.
|
||||
/// Match may close open numbers in state.
|
||||
/// Match may define template numbers in state.
|
||||
/// @param number the number to match
|
||||
/// @returns true if the argument type is as expected.
|
||||
virtual Number Match(MatchState& state, Number number) const = 0;
|
||||
|
@ -226,19 +225,19 @@ class NumberMatcher {
|
|||
virtual std::string String(MatchState& state) const = 0;
|
||||
};
|
||||
|
||||
/// OpenTypeMatcher is a Matcher for an open type.
|
||||
/// The OpenTypeMatcher will match against any type (so long as it is consistent
|
||||
/// across all uses in the overload)
|
||||
class OpenTypeMatcher : public TypeMatcher {
|
||||
/// TemplateTypeMatcher is a Matcher for a template type.
|
||||
/// The TemplateTypeMatcher will initially match against any type (so long as it is
|
||||
/// consistent for all uses in the overload)
|
||||
class TemplateTypeMatcher : public TypeMatcher {
|
||||
public:
|
||||
/// Constructor
|
||||
explicit OpenTypeMatcher(size_t index) : index_(index) {}
|
||||
explicit TemplateTypeMatcher(size_t index) : index_(index) {}
|
||||
|
||||
const sem::Type* Match(MatchState& state, const sem::Type* type) const override {
|
||||
if (type->Is<Any>()) {
|
||||
return state.closed.Type(index_);
|
||||
return state.templates.Type(index_);
|
||||
}
|
||||
return state.closed.Type(index_, type) ? type : nullptr;
|
||||
return state.templates.Type(index_, type) ? type : nullptr;
|
||||
}
|
||||
|
||||
std::string String(MatchState& state) const override;
|
||||
|
@ -247,18 +246,18 @@ class OpenTypeMatcher : public TypeMatcher {
|
|||
size_t index_;
|
||||
};
|
||||
|
||||
/// OpenNumberMatcher is a Matcher for an open number.
|
||||
/// The OpenNumberMatcher will match against any number (so long as it is
|
||||
/// consistent for the overload)
|
||||
class OpenNumberMatcher : public NumberMatcher {
|
||||
/// TemplateNumberMatcher is a Matcher for a template number.
|
||||
/// The TemplateNumberMatcher will match against any number (so long as it is
|
||||
/// consistent for all uses in the overload)
|
||||
class TemplateNumberMatcher : public NumberMatcher {
|
||||
public:
|
||||
explicit OpenNumberMatcher(size_t index) : index_(index) {}
|
||||
explicit TemplateNumberMatcher(size_t index) : index_(index) {}
|
||||
|
||||
Number Match(MatchState& state, Number number) const override {
|
||||
if (number.IsAny()) {
|
||||
return state.closed.Num(index_);
|
||||
return state.templates.Num(index_);
|
||||
}
|
||||
return state.closed.Num(index_, number) ? number : Number::invalid;
|
||||
return state.templates.Num(index_, number) ? number : Number::invalid;
|
||||
}
|
||||
|
||||
std::string String(MatchState& state) const override;
|
||||
|
@ -301,6 +300,10 @@ const sem::Bool* build_bool(MatchState& state) {
|
|||
return state.builder.create<sem::Bool>();
|
||||
}
|
||||
|
||||
const sem::F32* build_f32(MatchState& state) {
|
||||
return state.builder.create<sem::F32>();
|
||||
}
|
||||
|
||||
bool match_f32(const sem::Type* ty) {
|
||||
return ty->IsAnyOf<Any, sem::F32>();
|
||||
}
|
||||
|
@ -321,10 +324,6 @@ bool match_u32(const sem::Type* ty) {
|
|||
return ty->IsAnyOf<Any, sem::U32>();
|
||||
}
|
||||
|
||||
const sem::F32* build_f32(MatchState& state) {
|
||||
return state.builder.create<sem::F32>();
|
||||
}
|
||||
|
||||
bool match_vec(const sem::Type* ty, Number& N, const sem::Type*& T) {
|
||||
if (ty->Is<Any>()) {
|
||||
N = Number::any;
|
||||
|
@ -751,18 +750,18 @@ struct ParameterInfo {
|
|||
MatcherIndex const* const matcher_indices;
|
||||
};
|
||||
|
||||
/// OpenTypeInfo describes an open type
|
||||
struct OpenTypeInfo {
|
||||
/// Name of the open type (e.g. 'T')
|
||||
/// TemplateTypeInfo describes an template type
|
||||
struct TemplateTypeInfo {
|
||||
/// Name of the template type (e.g. 'T')
|
||||
const char* name;
|
||||
/// Optional type matcher constraint.
|
||||
/// Either an index in Matchers::type, or kNoMatcher
|
||||
const MatcherIndex matcher_index;
|
||||
};
|
||||
|
||||
/// OpenNumberInfo describes an open number
|
||||
struct OpenNumberInfo {
|
||||
/// Name of the open number (e.g. 'N')
|
||||
/// TemplateNumberInfo describes a template number
|
||||
struct TemplateNumberInfo {
|
||||
/// Name of the template number (e.g. 'N')
|
||||
const char* name;
|
||||
/// Optional number matcher constraint.
|
||||
/// Either an index in Matchers::number, or kNoMatcher
|
||||
|
@ -773,14 +772,14 @@ struct OpenNumberInfo {
|
|||
struct OverloadInfo {
|
||||
/// Total number of parameters for the overload
|
||||
const uint8_t num_parameters;
|
||||
/// Total number of open types for the overload
|
||||
const uint8_t num_open_types;
|
||||
/// Total number of open numbers for the overload
|
||||
const uint8_t num_open_numbers;
|
||||
/// Pointer to the first open type
|
||||
OpenTypeInfo const* const open_types;
|
||||
/// Pointer to the first open number
|
||||
OpenNumberInfo const* const open_numbers;
|
||||
/// Total number of template types for the overload
|
||||
const uint8_t num_template_types;
|
||||
/// Total number of template numbers for the overload
|
||||
const uint8_t num_template_numbers;
|
||||
/// Pointer to the first template type
|
||||
TemplateTypeInfo const* const template_types;
|
||||
/// Pointer to the first template number
|
||||
TemplateNumberInfo const* const template_numbers;
|
||||
/// Pointer to the first parameter
|
||||
ParameterInfo const* const parameters;
|
||||
/// Pointer to a list of matcher indices that index on Matchers::type and
|
||||
|
@ -872,8 +871,8 @@ class Impl : public IntrinsicTable {
|
|||
struct Candidate {
|
||||
/// The candidate overload
|
||||
const OverloadInfo* overload;
|
||||
/// The closed types and numbers
|
||||
ClosedState closed;
|
||||
/// The template types and numbers
|
||||
TemplateState templates;
|
||||
/// The parameter types for the candidate overload
|
||||
std::vector<IntrinsicPrototype::Parameter> parameters;
|
||||
/// The match-score of the candidate overload.
|
||||
|
@ -893,9 +892,9 @@ class Impl : public IntrinsicTable {
|
|||
/// @param intrinsic the intrinsic being called
|
||||
/// @param intrinsic_name the name of the intrinsic
|
||||
/// @param args the argument types
|
||||
/// @param closed initial closed state. This may contain explicitly specified template
|
||||
/// arguments. For example `vec3<f32>()` would have the first template-type closed
|
||||
/// as `f32`.
|
||||
/// @param templates initial template state. This may contain explicitly specified template
|
||||
/// arguments. For example `vec3<f32>()` would have the first template-type
|
||||
/// defined as `f32`.
|
||||
/// @param on_no_match an error callback when no intrinsic overloads matched the provided
|
||||
/// arguments.
|
||||
/// @returns the matched intrinsic. If no intrinsic could be matched then IntrinsicPrototype
|
||||
|
@ -904,25 +903,25 @@ class Impl : public IntrinsicTable {
|
|||
IntrinsicPrototype MatchIntrinsic(const IntrinsicInfo& intrinsic,
|
||||
const char* intrinsic_name,
|
||||
const std::vector<const sem::Type*>& args,
|
||||
ClosedState closed,
|
||||
TemplateState templates,
|
||||
OnNoMatch on_no_match) const;
|
||||
|
||||
/// Evaluates the overload for the provided argument types.
|
||||
/// @param overload the overload being considered
|
||||
/// @param args the argument types
|
||||
/// @param closed initial closed state. This may contain explicitly specified template
|
||||
/// arguments. For example `vec3<f32>()` would have the first template-type closed
|
||||
/// as `f32`.
|
||||
/// @param templates initial template state. This may contain explicitly specified template
|
||||
/// arguments. For example `vec3<f32>()` would have the first template-type
|
||||
/// template as `f32`.
|
||||
/// @returns the evaluated Candidate information.
|
||||
Candidate ScoreOverload(const OverloadInfo* overload,
|
||||
const std::vector<const sem::Type*>& args,
|
||||
ClosedState closed) const;
|
||||
TemplateState templates) const;
|
||||
|
||||
/// Match constructs a new MatchState
|
||||
/// @param closed the open / closed numbers and types used for matcher evaluation
|
||||
/// @param templates the template state used for matcher evaluation
|
||||
/// @param overload the overload being evaluated
|
||||
/// @param matcher_indices pointer to a list of matcher indices
|
||||
MatchState Match(ClosedState& closed,
|
||||
MatchState Match(TemplateState& templates,
|
||||
const OverloadInfo* overload,
|
||||
MatcherIndex const* matcher_indices) const;
|
||||
|
||||
|
@ -940,7 +939,7 @@ class Impl : public IntrinsicTable {
|
|||
void ErrMultipleOverloadsMatched(size_t num_matched,
|
||||
const char* intrinsic_name,
|
||||
const std::vector<const sem::Type*>& args,
|
||||
ClosedState closed,
|
||||
TemplateState templates,
|
||||
Candidates candidates) const;
|
||||
|
||||
ProgramBuilder& builder;
|
||||
|
@ -979,12 +978,12 @@ std::string CallSignature(ProgramBuilder& builder,
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
std::string OpenTypeMatcher::String(MatchState& state) const {
|
||||
return state.overload->open_types[index_].name;
|
||||
std::string TemplateTypeMatcher::String(MatchState& state) const {
|
||||
return state.overload->template_types[index_].name;
|
||||
}
|
||||
|
||||
std::string OpenNumberMatcher::String(MatchState& state) const {
|
||||
return state.overload->open_numbers[index_].name;
|
||||
std::string TemplateNumberMatcher::String(MatchState& state) const {
|
||||
return state.overload->template_numbers[index_].name;
|
||||
}
|
||||
|
||||
Impl::Impl(ProgramBuilder& b) : builder(b) {}
|
||||
|
@ -1009,7 +1008,7 @@ const sem::Builtin* Impl::Lookup(sem::BuiltinType builtin_type,
|
|||
|
||||
// Resolve the intrinsic overload
|
||||
auto match = MatchIntrinsic(kBuiltins[static_cast<size_t>(builtin_type)], intrinsic_name, args,
|
||||
ClosedState{}, on_no_match);
|
||||
TemplateState{}, on_no_match);
|
||||
if (!match.overload) {
|
||||
return {};
|
||||
}
|
||||
|
@ -1070,7 +1069,7 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
|
|||
|
||||
// Resolve the intrinsic overload
|
||||
auto match = MatchIntrinsic(kUnaryOperators[intrinsic_index], intrinsic_name, {arg},
|
||||
ClosedState{}, on_no_match);
|
||||
TemplateState{}, on_no_match);
|
||||
if (!match.overload) {
|
||||
return {};
|
||||
}
|
||||
|
@ -1141,7 +1140,7 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
|
|||
|
||||
// Resolve the intrinsic overload
|
||||
auto match = MatchIntrinsic(kBinaryOperators[intrinsic_index], intrinsic_name, {lhs, rhs},
|
||||
ClosedState{}, on_no_match);
|
||||
TemplateState{}, on_no_match);
|
||||
if (!match.overload) {
|
||||
return {};
|
||||
}
|
||||
|
@ -1184,14 +1183,14 @@ const sem::CallTarget* Impl::Lookup(CtorConvIntrinsic type,
|
|||
};
|
||||
|
||||
// If a template type was provided, then close the 0'th type with this.
|
||||
ClosedState closed;
|
||||
TemplateState templates;
|
||||
if (template_arg) {
|
||||
closed.Type(0, template_arg);
|
||||
templates.Type(0, template_arg);
|
||||
}
|
||||
|
||||
// Resolve the intrinsic overload
|
||||
auto match = MatchIntrinsic(kConstructorsAndConverters[static_cast<size_t>(type)], name, args,
|
||||
closed, on_no_match);
|
||||
templates, on_no_match);
|
||||
if (!match.overload) {
|
||||
return {};
|
||||
}
|
||||
|
@ -1222,14 +1221,14 @@ const sem::CallTarget* Impl::Lookup(CtorConvIntrinsic type,
|
|||
IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
|
||||
const char* intrinsic_name,
|
||||
const std::vector<const sem::Type*>& args,
|
||||
ClosedState closed,
|
||||
TemplateState templates,
|
||||
OnNoMatch on_no_match) const {
|
||||
size_t num_matched = 0;
|
||||
Candidates candidates;
|
||||
candidates.reserve(intrinsic.num_overloads);
|
||||
for (size_t overload_idx = 0; overload_idx < static_cast<size_t>(intrinsic.num_overloads);
|
||||
overload_idx++) {
|
||||
auto candidate = ScoreOverload(&intrinsic.overloads[overload_idx], args, closed);
|
||||
auto candidate = ScoreOverload(&intrinsic.overloads[overload_idx], args, templates);
|
||||
if (candidate.score == 0) {
|
||||
num_matched++;
|
||||
}
|
||||
|
@ -1248,7 +1247,7 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
|
|||
case 1:
|
||||
break;
|
||||
default:
|
||||
ErrMultipleOverloadsMatched(num_matched, intrinsic_name, args, closed, candidates);
|
||||
ErrMultipleOverloadsMatched(num_matched, intrinsic_name, args, templates, candidates);
|
||||
}
|
||||
|
||||
auto match = candidates[0];
|
||||
|
@ -1257,7 +1256,7 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
|
|||
const sem::Type* return_type = nullptr;
|
||||
if (auto* indices = match.overload->return_matcher_indices) {
|
||||
Any any;
|
||||
return_type = Match(match.closed, match.overload, indices).Type(&any);
|
||||
return_type = Match(match.templates, match.overload, indices).Type(&any);
|
||||
if (!return_type) {
|
||||
TINT_ICE(Resolver, builder.Diagnostics()) << "MatchState.Match() returned null";
|
||||
return {};
|
||||
|
@ -1271,15 +1270,15 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
|
|||
|
||||
Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
|
||||
const std::vector<const sem::Type*>& args,
|
||||
ClosedState closed) const {
|
||||
TemplateState templates) const {
|
||||
// Penalty weights for overload mismatching.
|
||||
// This scoring is used to order the suggested overloads in diagnostic on overload mismatch, and
|
||||
// has no impact for a correct program.
|
||||
// The overloads with the lowest score will be displayed first (top-most).
|
||||
constexpr int kMismatchedParamCountPenalty = 3;
|
||||
constexpr int kMismatchedParamTypePenalty = 2;
|
||||
constexpr int kMismatchedOpenTypePenalty = 1;
|
||||
constexpr int kMismatchedOpenNumberPenalty = 1;
|
||||
constexpr int kMismatchedTemplateTypePenalty = 1;
|
||||
constexpr int kMismatchedTemplateNumberPenalty = 1;
|
||||
|
||||
size_t num_parameters = static_cast<size_t>(overload->num_parameters);
|
||||
size_t num_arguments = static_cast<size_t>(args.size());
|
||||
|
@ -1297,7 +1296,7 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
|
|||
for (size_t p = 0; p < num_params; p++) {
|
||||
auto& parameter = overload->parameters[p];
|
||||
auto* indices = parameter.matcher_indices;
|
||||
auto* type = Match(closed, overload, indices).Type(args[p]->UnwrapRef());
|
||||
auto* type = Match(templates, overload, indices).Type(args[p]->UnwrapRef());
|
||||
if (type) {
|
||||
parameters.emplace_back(IntrinsicPrototype::Parameter{type, parameter.usage});
|
||||
} else {
|
||||
|
@ -1306,14 +1305,14 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
|
|||
}
|
||||
|
||||
if (score == 0) {
|
||||
// Check all constrained open types matched
|
||||
for (size_t ot = 0; ot < overload->num_open_types; ot++) {
|
||||
auto& open_type = overload->open_types[ot];
|
||||
if (open_type.matcher_index != kNoMatcher) {
|
||||
auto* closed_type = closed.Type(ot);
|
||||
auto* matcher_index = &open_type.matcher_index;
|
||||
if (!closed_type || !Match(closed, overload, matcher_index).Type(closed_type)) {
|
||||
score += kMismatchedOpenTypePenalty;
|
||||
// Check all constrained template types matched
|
||||
for (size_t ot = 0; ot < overload->num_template_types; ot++) {
|
||||
auto* matcher_index = &overload->template_types[ot].matcher_index;
|
||||
if (*matcher_index != kNoMatcher) {
|
||||
auto* template_type = templates.Type(ot);
|
||||
if (!template_type ||
|
||||
!Match(templates, overload, matcher_index).Type(template_type)) {
|
||||
score += kMismatchedTemplateTypePenalty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1321,32 +1320,31 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
|
|||
|
||||
if (score == 0) {
|
||||
// Check all constrained open numbers matched
|
||||
for (size_t on = 0; on < overload->num_open_numbers; on++) {
|
||||
auto& open_number = overload->open_numbers[on];
|
||||
if (open_number.matcher_index != kNoMatcher) {
|
||||
auto closed_num = closed.Num(on);
|
||||
auto* index = &open_number.matcher_index;
|
||||
if (!closed_num.IsValid() ||
|
||||
!Match(closed, overload, index).Num(closed_num).IsValid()) {
|
||||
score += kMismatchedOpenNumberPenalty;
|
||||
for (size_t on = 0; on < overload->num_template_numbers; on++) {
|
||||
auto* matcher_index = &overload->template_numbers[on].matcher_index;
|
||||
if (*matcher_index != kNoMatcher) {
|
||||
auto template_num = templates.Num(on);
|
||||
if (!template_num.IsValid() ||
|
||||
!Match(templates, overload, matcher_index).Num(template_num).IsValid()) {
|
||||
score += kMismatchedTemplateNumberPenalty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Candidate{overload, closed, parameters, score};
|
||||
return Candidate{overload, templates, parameters, score};
|
||||
}
|
||||
|
||||
MatchState Impl::Match(ClosedState& closed,
|
||||
MatchState Impl::Match(TemplateState& templates,
|
||||
const OverloadInfo* overload,
|
||||
MatcherIndex const* matcher_indices) const {
|
||||
return MatchState(builder, closed, matchers, overload, matcher_indices);
|
||||
return MatchState(builder, templates, matchers, overload, matcher_indices);
|
||||
}
|
||||
|
||||
void Impl::PrintOverload(std::ostream& ss,
|
||||
const OverloadInfo* overload,
|
||||
const char* intrinsic_name) const {
|
||||
ClosedState closed;
|
||||
TemplateState templates;
|
||||
|
||||
ss << intrinsic_name << "(";
|
||||
for (size_t p = 0; p < overload->num_parameters; p++) {
|
||||
|
@ -1358,13 +1356,13 @@ void Impl::PrintOverload(std::ostream& ss,
|
|||
ss << sem::str(parameter.usage) << ": ";
|
||||
}
|
||||
auto* indices = parameter.matcher_indices;
|
||||
ss << Match(closed, overload, indices).TypeName();
|
||||
ss << Match(templates, overload, indices).TypeName();
|
||||
}
|
||||
ss << ")";
|
||||
if (overload->return_matcher_indices) {
|
||||
ss << " -> ";
|
||||
auto* indices = overload->return_matcher_indices;
|
||||
ss << Match(closed, overload, indices).TypeName();
|
||||
ss << Match(templates, overload, indices).TypeName();
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
|
@ -1372,22 +1370,22 @@ void Impl::PrintOverload(std::ostream& ss,
|
|||
ss << (first ? " where: " : ", ");
|
||||
first = false;
|
||||
};
|
||||
for (size_t i = 0; i < overload->num_open_types; i++) {
|
||||
auto& open_type = overload->open_types[i];
|
||||
if (open_type.matcher_index != kNoMatcher) {
|
||||
for (size_t i = 0; i < overload->num_template_types; i++) {
|
||||
auto& template_type = overload->template_types[i];
|
||||
if (template_type.matcher_index != kNoMatcher) {
|
||||
separator();
|
||||
ss << open_type.name;
|
||||
auto* index = &open_type.matcher_index;
|
||||
ss << " is " << Match(closed, overload, index).TypeName();
|
||||
ss << template_type.name;
|
||||
auto* index = &template_type.matcher_index;
|
||||
ss << " is " << Match(templates, overload, index).TypeName();
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < overload->num_open_numbers; i++) {
|
||||
auto& open_number = overload->open_numbers[i];
|
||||
if (open_number.matcher_index != kNoMatcher) {
|
||||
for (size_t i = 0; i < overload->num_template_numbers; i++) {
|
||||
auto& template_number = overload->template_numbers[i];
|
||||
if (template_number.matcher_index != kNoMatcher) {
|
||||
separator();
|
||||
ss << open_number.name;
|
||||
auto* index = &open_number.matcher_index;
|
||||
ss << " is " << Match(closed, overload, index).NumName();
|
||||
ss << template_number.name;
|
||||
auto* index = &template_number.matcher_index;
|
||||
ss << " is " << Match(templates, overload, index).NumName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1429,15 +1427,17 @@ std::string MatchState::NumName() {
|
|||
void Impl::ErrMultipleOverloadsMatched(size_t num_matched,
|
||||
const char* intrinsic_name,
|
||||
const std::vector<const sem::Type*>& args,
|
||||
ClosedState closed,
|
||||
TemplateState templates,
|
||||
Candidates candidates) const {
|
||||
std::stringstream ss;
|
||||
ss << num_matched << " overloads matched " << intrinsic_name;
|
||||
for (size_t i = 0; i < std::numeric_limits<size_t>::max(); i++) {
|
||||
if (auto* ty = closed.Type(i)) {
|
||||
if (auto* ty = templates.Type(i)) {
|
||||
ss << ((i == 0) ? "<" : ", ") << ty->FriendlyName(builder.Symbols());
|
||||
} else if (i > 0) {
|
||||
ss << ">";
|
||||
} else {
|
||||
if (i > 0) {
|
||||
ss << ">";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -51,8 +51,8 @@ constexpr ParameterInfo kParameters[] = {
|
|||
{{- end }}
|
||||
};
|
||||
|
||||
constexpr OpenTypeInfo kOpenTypes[] = {
|
||||
{{- range $i, $o := .OpenTypes }}
|
||||
constexpr TemplateTypeInfo kTemplateTypes[] = {
|
||||
{{- range $i, $o := .TemplateTypes }}
|
||||
{
|
||||
/* [{{$i}}] */
|
||||
/* name */ "{{$o.Name}}",
|
||||
|
@ -64,8 +64,8 @@ constexpr OpenTypeInfo kOpenTypes[] = {
|
|||
{{- end }}
|
||||
};
|
||||
|
||||
constexpr OpenNumberInfo kOpenNumbers[] = {
|
||||
{{- range $i, $o := .OpenNumbers }}
|
||||
constexpr TemplateNumberInfo kTemplateNumbers[] = {
|
||||
{{- range $i, $o := .TemplateNumbers }}
|
||||
{
|
||||
/* [{{$i}}] */
|
||||
/* name */ "{{$o.Name}}",
|
||||
|
@ -82,14 +82,14 @@ constexpr OverloadInfo kOverloads[] = {
|
|||
{
|
||||
/* [{{$i}}] */
|
||||
/* num parameters */ {{$o.NumParameters}},
|
||||
/* num open types */ {{$o.NumOpenTypes}},
|
||||
/* num open numbers */ {{$o.NumOpenNumbers}},
|
||||
/* open types */
|
||||
{{- if $o.OpenTypesOffset }} &kOpenTypes[{{$o.OpenTypesOffset}}],
|
||||
/* num template types */ {{$o.NumTemplateTypes}},
|
||||
/* num template numbers */ {{$o.NumTemplateNumbers}},
|
||||
/* template types */
|
||||
{{- if $o.TemplateTypesOffset }} &kTemplateTypes[{{$o.TemplateTypesOffset}}],
|
||||
{{- else }} nullptr,
|
||||
{{- end }}
|
||||
/* open numbers */
|
||||
{{- if $o.OpenNumbersOffset }} &kOpenNumbers[{{$o.OpenNumbersOffset}}]
|
||||
/* template numbers */
|
||||
{{- if $o.TemplateNumbersOffset }} &kTemplateNumbers[{{$o.TemplateNumbersOffset}}]
|
||||
{{- else }} nullptr
|
||||
{{- end }},
|
||||
/* parameters */ &kParameters[{{$o.ParametersOffset}}],
|
||||
|
@ -180,7 +180,7 @@ constexpr IntrinsicInfo kConstructorsAndConverters[] = {
|
|||
class {{$class}} : public TypeMatcher {
|
||||
public:
|
||||
/// Checks whether the given type matches the matcher rules.
|
||||
/// Match may close open types and numbers in state.
|
||||
/// Match may define template types and numbers in state.
|
||||
/// @param state the MatchState
|
||||
/// @param type the type to match
|
||||
/// @returns the canonicalized type on match, otherwise nullptr
|
||||
|
@ -236,7 +236,7 @@ class {{$class}} : public TypeMatcher {
|
|||
public:
|
||||
/// Checks whether the given type matches the matcher rules, and returns the
|
||||
/// expected, canonicalized type on success.
|
||||
/// Match may close open types and numbers in state.
|
||||
/// Match may define template types and numbers in state.
|
||||
/// @param state the MatchState
|
||||
/// @param type the type to match
|
||||
/// @returns the canonicalized type on match, otherwise nullptr
|
||||
|
@ -280,7 +280,7 @@ std::string {{$class}}::String(MatchState&) const {
|
|||
class {{$class}} : public NumberMatcher {
|
||||
public:
|
||||
/// Checks whether the given number matches the enum matcher rules.
|
||||
/// Match may close open types and numbers in state.
|
||||
/// Match may define template types and numbers in state.
|
||||
/// @param state the MatchState
|
||||
/// @param number the enum value as a Number
|
||||
/// @return true if the enum value matches the set
|
||||
|
@ -332,15 +332,15 @@ class Matchers {
|
|||
private:
|
||||
{{- $t_names := Map -}}
|
||||
{{- $n_names := Map -}}
|
||||
{{- range Iterate .Sem.MaxOpenTypes -}}
|
||||
{{- $name := printf "open_type_%v" . -}}
|
||||
{{- range Iterate .Sem.MaxTemplateTypes -}}
|
||||
{{- $name := printf "template_type_%v" . -}}
|
||||
{{- $t_names.Put . $name }}
|
||||
OpenTypeMatcher {{$name}}_{ {{- . -}} };
|
||||
TemplateTypeMatcher {{$name}}_{ {{- . -}} };
|
||||
{{- end }}
|
||||
{{- range Iterate .Sem.MaxOpenNumbers -}}
|
||||
{{- $name := printf "open_number_%v" . -}}
|
||||
{{- range Iterate .Sem.MaxTemplateNumbers -}}
|
||||
{{- $name := printf "template_number_%v" . -}}
|
||||
{{- $n_names.Put . $name }}
|
||||
OpenNumberMatcher {{$name}}_{ {{- . -}} };
|
||||
TemplateNumberMatcher {{$name}}_{ {{- . -}} };
|
||||
{{- end }}
|
||||
{{- range .Sem.Types -}}
|
||||
{{- $name := PascalCase .Name -}}
|
||||
|
@ -364,7 +364,7 @@ class Matchers {
|
|||
/// Destructor
|
||||
~Matchers();
|
||||
|
||||
/// The open-types, types, and type matchers
|
||||
/// The template types, types, and type matchers
|
||||
TypeMatcher const* const type[{{len .TMatchers}}] = {
|
||||
{{- range $i, $m := .TMatchers }}
|
||||
/* [{{$i}}] */
|
||||
|
@ -374,7 +374,7 @@ class Matchers {
|
|||
{{- end }}
|
||||
};
|
||||
|
||||
/// The open-numbers, and number matchers
|
||||
/// The template numbers, and number matchers
|
||||
NumberMatcher const* const number[{{len .NMatchers}}] = {
|
||||
{{- range $i, $m := .NMatchers }}
|
||||
/* [{{$i}}] */
|
||||
|
|
|
@ -27,39 +27,39 @@ type IntrinsicTable struct {
|
|||
// The semantic info
|
||||
Sem *sem.Sem
|
||||
|
||||
// TMatchers are all the sem.OpenType, sem.Type and sem.TypeMatchers.
|
||||
// TMatchers are all the sem.TemplateType, sem.Type and sem.TypeMatchers.
|
||||
// These are all implemented by classes deriving from tint::TypeMatcher
|
||||
TMatchers []sem.Named
|
||||
TMatcherIndex map[sem.Named]int // [object -> index] in TMatcher
|
||||
|
||||
// NMatchers are all the sem.OpenNumber and sem.EnumMatchers.
|
||||
// NMatchers are all the sem.TemplateNumber and sem.EnumMatchers.
|
||||
// These are all implemented by classes deriving from tint::NumberMatcher
|
||||
NMatchers []sem.Named
|
||||
NMatcherIndex map[sem.Named]int // [object -> index] in NMatchers
|
||||
|
||||
MatcherIndices []int // kMatcherIndices table content
|
||||
OpenTypes []OpenType // kOpenTypes table content
|
||||
OpenNumbers []OpenNumber // kOpenNumbers table content
|
||||
Parameters []Parameter // kParameters table content
|
||||
Overloads []Overload // kOverloads table content
|
||||
Builtins []Intrinsic // kBuiltins table content
|
||||
UnaryOperators []Intrinsic // kUnaryOperators table content
|
||||
BinaryOperators []Intrinsic // kBinaryOperators table content
|
||||
ConstructorsAndConverters []Intrinsic // kConstructorsAndConverters table content
|
||||
MatcherIndices []int // kMatcherIndices table content
|
||||
TemplateTypes []TemplateType // kTemplateTypes table content
|
||||
TemplateNumbers []TemplateNumber // kTemplateNumbers table content
|
||||
Parameters []Parameter // kParameters table content
|
||||
Overloads []Overload // kOverloads table content
|
||||
Builtins []Intrinsic // kBuiltins table content
|
||||
UnaryOperators []Intrinsic // kUnaryOperators table content
|
||||
BinaryOperators []Intrinsic // kBinaryOperators table content
|
||||
ConstructorsAndConverters []Intrinsic // kConstructorsAndConverters table content
|
||||
}
|
||||
|
||||
// OpenType is used to create the C++ OpenTypeInfo structure
|
||||
type OpenType struct {
|
||||
// Name of the open type (e.g. 'T')
|
||||
// TemplateType is used to create the C++ TemplateTypeInfo structure
|
||||
type TemplateType struct {
|
||||
// Name of the template type (e.g. 'T')
|
||||
Name string
|
||||
// Optional type matcher constraint.
|
||||
// Either an index in Matchers::type, or -1
|
||||
MatcherIndex int
|
||||
}
|
||||
|
||||
// OpenNumber is used to create the C++ OpenNumberInfo structure
|
||||
type OpenNumber struct {
|
||||
// Name of the open number (e.g. 'N')
|
||||
// TemplateNumber is used to create the C++ TemplateNumberInfo structure
|
||||
type TemplateNumber struct {
|
||||
// Name of the template number (e.g. 'N')
|
||||
Name string
|
||||
// Optional type matcher constraint.
|
||||
// Either an index in Matchers::type, or -1
|
||||
|
@ -83,14 +83,14 @@ type Parameter struct {
|
|||
type Overload struct {
|
||||
// Total number of parameters for the overload
|
||||
NumParameters int
|
||||
// Total number of open types for the overload
|
||||
NumOpenTypes int
|
||||
// Total number of open numbers for the overload
|
||||
NumOpenNumbers int
|
||||
// Index to the first open type in IntrinsicTable.OpenTypes
|
||||
OpenTypesOffset *int
|
||||
// Index to the first open number in IntrinsicTable.OpenNumbers
|
||||
OpenNumbersOffset *int
|
||||
// Total number of template types for the overload
|
||||
NumTemplateTypes int
|
||||
// Total number of template numbers for the overload
|
||||
NumTemplateNumbers int
|
||||
// Index to the first template type in IntrinsicTable.TemplateTypes
|
||||
TemplateTypesOffset *int
|
||||
// Index to the first template number in IntrinsicTable.TemplateNumbers
|
||||
TemplateNumbersOffset *int
|
||||
// Index to the first parameter in IntrinsicTable.Parameters
|
||||
ParametersOffset *int
|
||||
// Index into IntrinsicTable.MatcherIndices, beginning the list of matchers
|
||||
|
@ -123,25 +123,25 @@ type IntrinsicTableBuilder struct {
|
|||
// Lookup tables.
|
||||
// These are packed (compressed) once all the entries have been added.
|
||||
lut struct {
|
||||
matcherIndices lut.LUT
|
||||
openTypes lut.LUT
|
||||
openNumbers lut.LUT
|
||||
parameters lut.LUT
|
||||
overloads lut.LUT
|
||||
matcherIndices lut.LUT
|
||||
templateTypes lut.LUT
|
||||
templateNumbers lut.LUT
|
||||
parameters lut.LUT
|
||||
overloads lut.LUT
|
||||
}
|
||||
}
|
||||
|
||||
// Helper for building a single overload
|
||||
type overloadBuilder struct {
|
||||
*IntrinsicTableBuilder
|
||||
// Maps TemplateParam to index in openTypes
|
||||
openTypeIndex map[sem.TemplateParam]int
|
||||
// Maps TemplateParam to index in openNumbers
|
||||
openNumberIndex map[sem.TemplateParam]int
|
||||
// Open types used by the overload
|
||||
openTypes []OpenType
|
||||
// Open numbers used by the overload
|
||||
openNumbers []OpenNumber
|
||||
// Maps TemplateParam to index in templateTypes
|
||||
templateTypeIndex map[sem.TemplateParam]int
|
||||
// Maps TemplateParam to index in templateNumbers
|
||||
templateNumberIndex map[sem.TemplateParam]int
|
||||
// Template types used by the overload
|
||||
templateTypes []TemplateType
|
||||
// Template numbers used by the overload
|
||||
templateNumbers []TemplateNumber
|
||||
// All parameters declared by the overload
|
||||
parameters []Parameter
|
||||
// Index into IntrinsicTable.MatcherIndices, beginning the list of matchers
|
||||
|
@ -155,8 +155,8 @@ type overloadBuilder struct {
|
|||
// layoutMatchers assigns each of the TMatchers and NMatchers a unique index
|
||||
// in the C++ Matchers::type and Matchers::number arrays, respectively.
|
||||
func (b *IntrinsicTableBuilder) layoutMatchers(s *sem.Sem) {
|
||||
// First MaxOpenTypes of TMatchers are open types
|
||||
b.TMatchers = make([]sem.Named, s.MaxOpenTypes)
|
||||
// First MaxTemplateTypes of TMatchers are template types
|
||||
b.TMatchers = make([]sem.Named, s.MaxTemplateTypes)
|
||||
for _, m := range s.Types {
|
||||
b.TMatcherIndex[m] = len(b.TMatchers)
|
||||
b.TMatchers = append(b.TMatchers, m)
|
||||
|
@ -166,8 +166,8 @@ func (b *IntrinsicTableBuilder) layoutMatchers(s *sem.Sem) {
|
|||
b.TMatchers = append(b.TMatchers, m)
|
||||
}
|
||||
|
||||
// First MaxOpenNumbers of NMatchers are open numbers
|
||||
b.NMatchers = make([]sem.Named, s.MaxOpenNumbers)
|
||||
// First MaxTemplateNumbers of NMatchers are template numbers
|
||||
b.NMatchers = make([]sem.Named, s.MaxTemplateNumbers)
|
||||
for _, m := range s.EnumMatchers {
|
||||
b.NMatcherIndex[m] = len(b.NMatchers)
|
||||
b.NMatchers = append(b.NMatchers, m)
|
||||
|
@ -178,14 +178,14 @@ func (b *IntrinsicTableBuilder) layoutMatchers(s *sem.Sem) {
|
|||
func (b *IntrinsicTableBuilder) buildOverload(o *sem.Overload) (Overload, error) {
|
||||
ob := overloadBuilder{
|
||||
IntrinsicTableBuilder: b,
|
||||
openTypeIndex: map[sem.TemplateParam]int{},
|
||||
openNumberIndex: map[sem.TemplateParam]int{},
|
||||
templateTypeIndex: map[sem.TemplateParam]int{},
|
||||
templateNumberIndex: map[sem.TemplateParam]int{},
|
||||
}
|
||||
|
||||
if err := ob.buildOpenTypes(o); err != nil {
|
||||
if err := ob.buildTemplateTypes(o); err != nil {
|
||||
return Overload{}, err
|
||||
}
|
||||
if err := ob.buildOpenNumbers(o); err != nil {
|
||||
if err := ob.buildTemplateNumbers(o); err != nil {
|
||||
return Overload{}, err
|
||||
}
|
||||
if err := ob.buildParameters(o); err != nil {
|
||||
|
@ -197,10 +197,10 @@ func (b *IntrinsicTableBuilder) buildOverload(o *sem.Overload) (Overload, error)
|
|||
|
||||
return Overload{
|
||||
NumParameters: len(ob.parameters),
|
||||
NumOpenTypes: len(ob.openTypes),
|
||||
NumOpenNumbers: len(ob.openNumbers),
|
||||
OpenTypesOffset: b.lut.openTypes.Add(ob.openTypes),
|
||||
OpenNumbersOffset: b.lut.openNumbers.Add(ob.openNumbers),
|
||||
NumTemplateTypes: len(ob.templateTypes),
|
||||
NumTemplateNumbers: len(ob.templateNumbers),
|
||||
TemplateTypesOffset: b.lut.templateTypes.Add(ob.templateTypes),
|
||||
TemplateNumbersOffset: b.lut.templateNumbers.Add(ob.templateNumbers),
|
||||
ParametersOffset: b.lut.parameters.Add(ob.parameters),
|
||||
ReturnMatcherIndicesOffset: ob.returnTypeMatcherIndicesOffset,
|
||||
CanBeUsedInStage: o.CanBeUsedInStage,
|
||||
|
@ -209,12 +209,12 @@ func (b *IntrinsicTableBuilder) buildOverload(o *sem.Overload) (Overload, error)
|
|||
}, nil
|
||||
}
|
||||
|
||||
// buildOpenTypes constructs the OpenTypes used by the overload, populating
|
||||
// b.openTypes
|
||||
func (b *overloadBuilder) buildOpenTypes(o *sem.Overload) error {
|
||||
b.openTypes = make([]OpenType, len(o.OpenTypes))
|
||||
for i, t := range o.OpenTypes {
|
||||
b.openTypeIndex[t] = i
|
||||
// buildTemplateTypes constructs the TemplateTypes used by the overload, populating
|
||||
// b.templateTypes
|
||||
func (b *overloadBuilder) buildTemplateTypes(o *sem.Overload) error {
|
||||
b.templateTypes = make([]TemplateType, len(o.TemplateTypes))
|
||||
for i, t := range o.TemplateTypes {
|
||||
b.templateTypeIndex[t] = i
|
||||
matcherIndex := -1
|
||||
if t.Type != nil {
|
||||
var err error
|
||||
|
@ -223,7 +223,7 @@ func (b *overloadBuilder) buildOpenTypes(o *sem.Overload) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
b.openTypes[i] = OpenType{
|
||||
b.templateTypes[i] = TemplateType{
|
||||
Name: t.Name,
|
||||
MatcherIndex: matcherIndex,
|
||||
}
|
||||
|
@ -231,12 +231,12 @@ func (b *overloadBuilder) buildOpenTypes(o *sem.Overload) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// buildOpenNumbers constructs the OpenNumbers used by the overload, populating
|
||||
// b.openNumbers
|
||||
func (b *overloadBuilder) buildOpenNumbers(o *sem.Overload) error {
|
||||
b.openNumbers = make([]OpenNumber, len(o.OpenNumbers))
|
||||
for i, t := range o.OpenNumbers {
|
||||
b.openNumberIndex[t] = i
|
||||
// buildTemplateNumbers constructs the TemplateNumbers used by the overload, populating
|
||||
// b.templateNumbers
|
||||
func (b *overloadBuilder) buildTemplateNumbers(o *sem.Overload) error {
|
||||
b.templateNumbers = make([]TemplateNumber, len(o.TemplateNumbers))
|
||||
for i, t := range o.TemplateNumbers {
|
||||
b.templateNumberIndex[t] = i
|
||||
matcherIndex := -1
|
||||
if e, ok := t.(*sem.TemplateEnumParam); ok && e.Matcher != nil {
|
||||
var err error
|
||||
|
@ -245,7 +245,7 @@ func (b *overloadBuilder) buildOpenNumbers(o *sem.Overload) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
b.openNumbers[i] = OpenNumber{
|
||||
b.templateNumbers[i] = TemplateNumber{
|
||||
Name: t.GetName(),
|
||||
MatcherIndex: matcherIndex,
|
||||
}
|
||||
|
@ -295,25 +295,25 @@ func (b *overloadBuilder) matcherIndex(n sem.Named) (int, error) {
|
|||
}
|
||||
return 0, fmt.Errorf("matcherIndex missing entry for %v %T", n.GetName(), n)
|
||||
case *sem.TemplateTypeParam:
|
||||
if i, ok := b.openTypeIndex[n]; ok {
|
||||
if i, ok := b.templateTypeIndex[n]; ok {
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("openTypeIndex missing entry for %v %T", n.Name, n)
|
||||
return 0, fmt.Errorf("templateTypeIndex missing entry for %v %T", n.Name, n)
|
||||
case *sem.EnumMatcher:
|
||||
if i, ok := b.NMatcherIndex[n]; ok {
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("matcherIndex missing entry for %v %T", n.GetName(), n)
|
||||
case *sem.TemplateEnumParam:
|
||||
if i, ok := b.openNumberIndex[n]; ok {
|
||||
if i, ok := b.templateNumberIndex[n]; ok {
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("openNumberIndex missing entry for %v %T", n, n)
|
||||
return 0, fmt.Errorf("templateNumberIndex missing entry for %v %T", n, n)
|
||||
case *sem.TemplateNumberParam:
|
||||
if i, ok := b.openNumberIndex[n]; ok {
|
||||
if i, ok := b.templateNumberIndex[n]; ok {
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("openNumberIndex missing entry for %v %T", n, n)
|
||||
return 0, fmt.Errorf("templateNumberIndex missing entry for %v %T", n, n)
|
||||
default:
|
||||
return 0, fmt.Errorf("overload.matcherIndex() does not handle %v %T", n, n)
|
||||
}
|
||||
|
@ -359,8 +359,8 @@ func buildIntrinsicTable(s *sem.Sem) (*IntrinsicTable, error) {
|
|||
},
|
||||
}
|
||||
b.lut.matcherIndices = lut.New(list.Wrap(&b.MatcherIndices))
|
||||
b.lut.openTypes = lut.New(list.Wrap(&b.OpenTypes))
|
||||
b.lut.openNumbers = lut.New(list.Wrap(&b.OpenNumbers))
|
||||
b.lut.templateTypes = lut.New(list.Wrap(&b.TemplateTypes))
|
||||
b.lut.templateNumbers = lut.New(list.Wrap(&b.TemplateNumbers))
|
||||
b.lut.parameters = lut.New(list.Wrap(&b.Parameters))
|
||||
b.lut.overloads = lut.New(list.Wrap(&b.Overloads))
|
||||
|
||||
|
@ -397,8 +397,8 @@ func buildIntrinsicTable(s *sem.Sem) (*IntrinsicTable, error) {
|
|||
}
|
||||
|
||||
b.lut.matcherIndices.Compact()
|
||||
b.lut.openTypes.Compact()
|
||||
b.lut.openNumbers.Compact()
|
||||
b.lut.templateTypes.Compact()
|
||||
b.lut.templateNumbers.Compact()
|
||||
b.lut.parameters.Compact()
|
||||
b.lut.overloads.Compact()
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ type Permuter struct {
|
|||
|
||||
// buildPermuter returns a new initialized Permuter
|
||||
func buildPermuter(s *sem.Sem) (*Permuter, error) {
|
||||
// allTypes are the list of FQNs that are used for open, unconstrained types
|
||||
// allTypes are the list of FQNs that are used for unconstrained types
|
||||
allTypes := []sem.FullyQualifiedName{}
|
||||
for _, ty := range s.Types {
|
||||
if len(ty.TemplateParams) > 0 {
|
||||
|
@ -58,10 +58,10 @@ type Permutation struct {
|
|||
// Permute generates a set of permutations for the given intrinsic overload
|
||||
func (p *Permuter) Permute(overload *sem.Overload) ([]Permutation, error) {
|
||||
state := permutationState{
|
||||
Permuter: p,
|
||||
closedTypes: map[sem.TemplateParam]sem.FullyQualifiedName{},
|
||||
closedNumbers: map[sem.TemplateParam]interface{}{},
|
||||
parameters: map[int]sem.FullyQualifiedName{},
|
||||
Permuter: p,
|
||||
templateTypes: map[sem.TemplateParam]sem.FullyQualifiedName{},
|
||||
templateNumbers: map[sem.TemplateParam]interface{}{},
|
||||
parameters: map[int]sem.FullyQualifiedName{},
|
||||
}
|
||||
|
||||
out := []Permutation{}
|
||||
|
@ -144,15 +144,15 @@ func (p *Permuter) Permute(overload *sem.Overload) ([]Permutation, error) {
|
|||
var err error
|
||||
types, err = state.permutateFQN(sem.FullyQualifiedName{Target: t.Type})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("while permutating open types: %w", err)
|
||||
return nil, fmt.Errorf("while permutating template types: %w", err)
|
||||
}
|
||||
}
|
||||
if len(types) == 0 {
|
||||
return nil, fmt.Errorf("open type %v has no permutations", t.Name)
|
||||
return nil, fmt.Errorf("template type %v has no permutations", t.Name)
|
||||
}
|
||||
permutate = func() error {
|
||||
for _, ty := range types {
|
||||
state.closedTypes[t] = ty
|
||||
state.templateTypes[t] = ty
|
||||
if err := next(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -168,14 +168,14 @@ func (p *Permuter) Permute(overload *sem.Overload) ([]Permutation, error) {
|
|||
permutations, err = state.permutateFQN(sem.FullyQualifiedName{Target: t.Enum})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("while permutating open numbers: %w", err)
|
||||
return nil, fmt.Errorf("while permutating template numbers: %w", err)
|
||||
}
|
||||
if len(permutations) == 0 {
|
||||
return nil, fmt.Errorf("open type %v has no permutations", t.Name)
|
||||
return nil, fmt.Errorf("template type %v has no permutations", t.Name)
|
||||
}
|
||||
permutate = func() error {
|
||||
for _, n := range permutations {
|
||||
state.closedNumbers[t] = n
|
||||
state.templateNumbers[t] = n
|
||||
if err := next(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ func (p *Permuter) Permute(overload *sem.Overload) ([]Permutation, error) {
|
|||
permutations := []int{2, 3, 4}
|
||||
permutate = func() error {
|
||||
for _, n := range permutations {
|
||||
state.closedNumbers[t] = n
|
||||
state.templateNumbers[t] = n
|
||||
if err := next(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -206,19 +206,19 @@ func (p *Permuter) Permute(overload *sem.Overload) ([]Permutation, error) {
|
|||
|
||||
type permutationState struct {
|
||||
*Permuter
|
||||
closedTypes map[sem.TemplateParam]sem.FullyQualifiedName
|
||||
closedNumbers map[sem.TemplateParam]interface{}
|
||||
parameters map[int]sem.FullyQualifiedName
|
||||
templateTypes map[sem.TemplateParam]sem.FullyQualifiedName
|
||||
templateNumbers map[sem.TemplateParam]interface{}
|
||||
parameters map[int]sem.FullyQualifiedName
|
||||
}
|
||||
|
||||
func (s permutationState) String() string {
|
||||
sb := &strings.Builder{}
|
||||
sb.WriteString("Closed types:\n")
|
||||
for ct, ty := range s.closedTypes {
|
||||
sb.WriteString("Template types:\n")
|
||||
for ct, ty := range s.templateTypes {
|
||||
fmt.Fprintf(sb, " %v: %v\n", ct.GetName(), ty)
|
||||
}
|
||||
sb.WriteString("Closed numbers:\n")
|
||||
for cn, v := range s.closedNumbers {
|
||||
sb.WriteString("Template numbers:\n")
|
||||
for cn, v := range s.templateNumbers {
|
||||
fmt.Fprintf(sb, " %v: %v\n", cn.GetName(), v)
|
||||
}
|
||||
return sb.String()
|
||||
|
@ -240,13 +240,13 @@ func (s *permutationState) permutateFQN(in sem.FullyQualifiedName) ([]sem.FullyQ
|
|||
return nil
|
||||
}
|
||||
case sem.TemplateParam:
|
||||
if ty, ok := s.closedTypes[target]; ok {
|
||||
if ty, ok := s.templateTypes[target]; ok {
|
||||
permutate = func() error {
|
||||
out = append(out, ty)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("'%v' was not found in closedTypes", target.GetName())
|
||||
return nil, fmt.Errorf("'%v' was not found in templateTypes", target.GetName())
|
||||
}
|
||||
case *sem.TypeMatcher:
|
||||
permutate = func() error {
|
||||
|
@ -284,12 +284,12 @@ func (s *permutationState) permutateFQN(in sem.FullyQualifiedName) ([]sem.FullyQ
|
|||
case sem.FullyQualifiedName:
|
||||
switch target := arg.Target.(type) {
|
||||
case sem.TemplateParam:
|
||||
if ty, ok := s.closedTypes[target]; ok {
|
||||
if ty, ok := s.templateTypes[target]; ok {
|
||||
args[i] = ty
|
||||
} else if num, ok := s.closedNumbers[target]; ok {
|
||||
} else if num, ok := s.templateNumbers[target]; ok {
|
||||
args[i] = num
|
||||
} else {
|
||||
return nil, fmt.Errorf("'%v' was not found in closedTypes or closedNumbers", target.GetName())
|
||||
return nil, fmt.Errorf("'%v' was not found in templateTypes or templateNumbers", target.GetName())
|
||||
}
|
||||
default:
|
||||
perms, err := s.permutateFQN(arg)
|
||||
|
|
|
@ -328,22 +328,22 @@ func (r *resolver) intrinsic(
|
|||
intrinsic.Overloads = append(intrinsic.Overloads, overload)
|
||||
|
||||
// Sort the template parameters by resolved type. Append these to
|
||||
// sem.Overload.OpenTypes or sem.Overload.OpenNumbers based on their kind.
|
||||
// sem.Overload.TemplateTypes or sem.Overload.TemplateNumbers based on their kind.
|
||||
for _, param := range templateParams {
|
||||
switch param := param.(type) {
|
||||
case *sem.TemplateTypeParam:
|
||||
overload.OpenTypes = append(overload.OpenTypes, param)
|
||||
overload.TemplateTypes = append(overload.TemplateTypes, param)
|
||||
case *sem.TemplateEnumParam, *sem.TemplateNumberParam:
|
||||
overload.OpenNumbers = append(overload.OpenNumbers, param)
|
||||
overload.TemplateNumbers = append(overload.TemplateNumbers, param)
|
||||
}
|
||||
}
|
||||
|
||||
// Update high-water marks of open types / numbers
|
||||
if r.s.MaxOpenTypes < len(overload.OpenTypes) {
|
||||
r.s.MaxOpenTypes = len(overload.OpenTypes)
|
||||
// Update high-water marks of template types and numbers
|
||||
if r.s.MaxTemplateTypes < len(overload.TemplateTypes) {
|
||||
r.s.MaxTemplateTypes = len(overload.TemplateTypes)
|
||||
}
|
||||
if r.s.MaxOpenNumbers < len(overload.OpenNumbers) {
|
||||
r.s.MaxOpenNumbers = len(overload.OpenNumbers)
|
||||
if r.s.MaxTemplateNumbers < len(overload.TemplateNumbers) {
|
||||
r.s.MaxTemplateNumbers = len(overload.TemplateNumbers)
|
||||
}
|
||||
|
||||
// Resolve the parameters
|
||||
|
|
|
@ -30,10 +30,10 @@ type Sem struct {
|
|||
UnaryOperators []*Intrinsic
|
||||
BinaryOperators []*Intrinsic
|
||||
ConstructorsAndConverters []*Intrinsic
|
||||
// Maximum number of open-types used across all builtins
|
||||
MaxOpenTypes int
|
||||
// Maximum number of open-numbers used across all builtins
|
||||
MaxOpenNumbers int
|
||||
// Maximum number of template types used across all builtins
|
||||
MaxTemplateTypes int
|
||||
// Maximum number of template numbers used across all builtins
|
||||
MaxTemplateNumbers int
|
||||
// The alphabetically sorted list of unique parameter names
|
||||
UniqueParameterNames []string
|
||||
}
|
||||
|
@ -137,8 +137,8 @@ type Overload struct {
|
|||
Decl ast.IntrinsicDecl
|
||||
Intrinsic *Intrinsic
|
||||
TemplateParams []TemplateParam
|
||||
OpenTypes []*TemplateTypeParam
|
||||
OpenNumbers []TemplateParam
|
||||
TemplateTypes []*TemplateTypeParam
|
||||
TemplateNumbers []TemplateParam
|
||||
ReturnType *FullyQualifiedName
|
||||
Parameters []Parameter
|
||||
CanBeUsedInStage StageUses
|
||||
|
|
Loading…
Reference in New Issue