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:
Ben Clayton 2022-05-17 22:42:32 +00:00 committed by Dawn LUCI CQ
parent d968e28a9a
commit 4c9ed74b5e
8 changed files with 2139 additions and 2141 deletions

View File

@ -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 //
// //

View File

@ -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

View File

@ -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}}] */

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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