tint: Add builtin type aliases (vec3f, etc)
Fixed: tint:1772 Change-Id: I4bed36ded91ca5288875ed6ea819ff4bbb432186 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112340 Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
parent
5798f2d021
commit
d5d207ba9f
|
@ -408,6 +408,8 @@ libtint_source_set("libtint_core_all_src") {
|
|||
"resolver/resolver.h",
|
||||
"resolver/sem_helper.cc",
|
||||
"resolver/sem_helper.h",
|
||||
"resolver/type_alias.cc",
|
||||
"resolver/type_alias.h",
|
||||
"resolver/uniformity.cc",
|
||||
"resolver/uniformity.h",
|
||||
"resolver/validator.cc",
|
||||
|
|
|
@ -542,6 +542,7 @@ tint_generated(ast/extension BENCH TEST)
|
|||
tint_generated(ast/interpolate_attribute BENCH TEST)
|
||||
tint_generated(ast/texel_format BENCH TEST)
|
||||
tint_generated(resolver/init_conv_intrinsic)
|
||||
tint_generated(resolver/type_alias BENCH TEST)
|
||||
tint_generated(sem/builtin_type)
|
||||
tint_generated(sem/parameter_usage)
|
||||
|
||||
|
|
|
@ -111,6 +111,22 @@ enum interpolation_sampling {
|
|||
sample
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/WGSL/#vector-types
|
||||
enum type_alias {
|
||||
vec2f
|
||||
vec2h
|
||||
vec2i
|
||||
vec2u
|
||||
vec3f
|
||||
vec3h
|
||||
vec3i
|
||||
vec3u
|
||||
vec4f
|
||||
vec4h
|
||||
vec4i
|
||||
vec4u
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WGSL primitive types //
|
||||
// Types may be decorated with @precedence(N) to prioritize which type //
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#include "src/tint/ast/void.h"
|
||||
#include "src/tint/ast/while_statement.h"
|
||||
#include "src/tint/ast/workgroup_attribute.h"
|
||||
#include "src/tint/resolver/type_alias.h"
|
||||
#include "src/tint/scope_stack.h"
|
||||
#include "src/tint/sem/builtin.h"
|
||||
#include "src/tint/symbol_table.h"
|
||||
|
@ -481,9 +482,14 @@ class DependencyScanner {
|
|||
graph_.resolved_symbols.Add(from, resolved);
|
||||
}
|
||||
|
||||
/// @returns true if `name` is the name of a builtin function
|
||||
/// @returns true if `name` is the name of a builtin function, or builtin type alias
|
||||
bool IsBuiltin(Symbol name) const {
|
||||
return sem::ParseBuiltinType(symbols_.NameFor(name)) != sem::BuiltinType::kNone;
|
||||
auto s = symbols_.NameFor(name);
|
||||
if (sem::ParseBuiltinType(s) != sem::BuiltinType::kNone ||
|
||||
ParseTypeAlias(s) != TypeAlias::kUndefined) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Appends an error to the diagnostics that the given symbol cannot be
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "src/tint/ast/vector.h"
|
||||
#include "src/tint/ast/while_statement.h"
|
||||
#include "src/tint/ast/workgroup_attribute.h"
|
||||
#include "src/tint/resolver/type_alias.h"
|
||||
#include "src/tint/resolver/uniformity.h"
|
||||
#include "src/tint/sem/abstract_float.h"
|
||||
#include "src/tint/sem/abstract_int.h"
|
||||
|
@ -329,13 +330,16 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
|
|||
AddNote("'" + name + "' declared here", func->Declaration()->source);
|
||||
return nullptr;
|
||||
},
|
||||
[&](Default) {
|
||||
[&](Default) -> sem::Type* {
|
||||
if (auto* tn = ty->As<ast::TypeName>()) {
|
||||
if (IsBuiltin(tn->name)) {
|
||||
auto name = builder_->Symbols().NameFor(tn->name);
|
||||
AddError("cannot use builtin '" + name + "' as type", ty->source);
|
||||
return nullptr;
|
||||
}
|
||||
if (auto* t = BuiltinTypeAlias(tn->name)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
TINT_UNREACHABLE(Resolver, diagnostics_)
|
||||
<< "Unhandled resolved type '"
|
||||
|
@ -2228,11 +2232,13 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
|||
},
|
||||
[&](Default) -> sem::Call* {
|
||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||
auto builtin_type = sem::ParseBuiltinType(name);
|
||||
if (builtin_type != sem::BuiltinType::kNone) {
|
||||
if (auto* alias = BuiltinTypeAlias(ident->symbol)) {
|
||||
return ty_init_or_conv(alias);
|
||||
}
|
||||
if (auto builtin_type = sem::ParseBuiltinType(name);
|
||||
builtin_type != sem::BuiltinType::kNone) {
|
||||
return BuiltinCall(expr, builtin_type, args);
|
||||
}
|
||||
|
||||
TINT_ICE(Resolver, diagnostics_)
|
||||
<< expr->source << " unhandled CallExpression target:\n"
|
||||
<< "resolved: " << (resolved ? resolved->TypeInfo().name : "<null>") << "\n"
|
||||
|
@ -2328,6 +2334,40 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
|
|||
return call;
|
||||
}
|
||||
|
||||
sem::Type* Resolver::BuiltinTypeAlias(Symbol sym) const {
|
||||
auto name = builder_->Symbols().NameFor(sym);
|
||||
auto& b = *builder_;
|
||||
switch (ParseTypeAlias(name)) {
|
||||
case TypeAlias::kVec2F:
|
||||
return b.create<sem::Vector>(b.create<sem::F32>(), 2u);
|
||||
case TypeAlias::kVec3F:
|
||||
return b.create<sem::Vector>(b.create<sem::F32>(), 3u);
|
||||
case TypeAlias::kVec4F:
|
||||
return b.create<sem::Vector>(b.create<sem::F32>(), 4u);
|
||||
case TypeAlias::kVec2H:
|
||||
return b.create<sem::Vector>(b.create<sem::F16>(), 2u);
|
||||
case TypeAlias::kVec3H:
|
||||
return b.create<sem::Vector>(b.create<sem::F16>(), 3u);
|
||||
case TypeAlias::kVec4H:
|
||||
return b.create<sem::Vector>(b.create<sem::F16>(), 4u);
|
||||
case TypeAlias::kVec2I:
|
||||
return b.create<sem::Vector>(b.create<sem::I32>(), 2u);
|
||||
case TypeAlias::kVec3I:
|
||||
return b.create<sem::Vector>(b.create<sem::I32>(), 3u);
|
||||
case TypeAlias::kVec4I:
|
||||
return b.create<sem::Vector>(b.create<sem::I32>(), 4u);
|
||||
case TypeAlias::kVec2U:
|
||||
return b.create<sem::Vector>(b.create<sem::U32>(), 2u);
|
||||
case TypeAlias::kVec3U:
|
||||
return b.create<sem::Vector>(b.create<sem::U32>(), 3u);
|
||||
case TypeAlias::kVec4U:
|
||||
return b.create<sem::Vector>(b.create<sem::U32>(), 4u);
|
||||
case TypeAlias::kUndefined:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Resolver::CollectTextureSamplerPairs(const sem::Builtin* builtin,
|
||||
utils::VectorRef<const sem::Expression*> args) const {
|
||||
// Collect a texture/sampler pair for this builtin.
|
||||
|
@ -2550,7 +2590,7 @@ sem::Expression* Resolver::Identifier(const ast::IdentifierExpression* expr) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (resolved->Is<sem::Type>()) {
|
||||
if (resolved->Is<sem::Type>() || BuiltinTypeAlias(symbol)) {
|
||||
AddError("missing '(' for type initializer or cast", expr->source.End());
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -384,6 +384,7 @@ class Resolver {
|
|||
/// Set the shadowing information on variable declarations.
|
||||
/// @note this method must only be called after all semantic nodes are built.
|
||||
void SetShadows();
|
||||
|
||||
/// StatementScope() does the following:
|
||||
/// * Creates the AST -> SEM mapping.
|
||||
/// * Assigns `sem` to #current_statement_
|
||||
|
@ -415,6 +416,9 @@ class Resolver {
|
|||
/// @returns true if the symbol is the name of a builtin function.
|
||||
bool IsBuiltin(Symbol) const;
|
||||
|
||||
/// @returns the builtin type alias for the given symbol
|
||||
sem::Type* BuiltinTypeAlias(Symbol) const;
|
||||
|
||||
// ArrayInitializerSig represents a unique array initializer signature.
|
||||
// It is a tuple of the array type, number of arguments provided and earliest evaluation stage.
|
||||
using ArrayInitializerSig =
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2022 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// File generated by tools/src/cmd/gen
|
||||
// using the template:
|
||||
// src/tint/resolver/type_alias.cc.tmpl
|
||||
//
|
||||
// Do not modify this file directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "src/tint/resolver/type_alias.h"
|
||||
|
||||
namespace tint::resolver {
|
||||
|
||||
/// ParseTypeAlias parses a TypeAlias from a string.
|
||||
/// @param str the string to parse
|
||||
/// @returns the parsed enum, or TypeAlias::kUndefined if the string could not be parsed.
|
||||
TypeAlias ParseTypeAlias(std::string_view str) {
|
||||
if (str == "vec2f") {
|
||||
return TypeAlias::kVec2F;
|
||||
}
|
||||
if (str == "vec2h") {
|
||||
return TypeAlias::kVec2H;
|
||||
}
|
||||
if (str == "vec2i") {
|
||||
return TypeAlias::kVec2I;
|
||||
}
|
||||
if (str == "vec2u") {
|
||||
return TypeAlias::kVec2U;
|
||||
}
|
||||
if (str == "vec3f") {
|
||||
return TypeAlias::kVec3F;
|
||||
}
|
||||
if (str == "vec3h") {
|
||||
return TypeAlias::kVec3H;
|
||||
}
|
||||
if (str == "vec3i") {
|
||||
return TypeAlias::kVec3I;
|
||||
}
|
||||
if (str == "vec3u") {
|
||||
return TypeAlias::kVec3U;
|
||||
}
|
||||
if (str == "vec4f") {
|
||||
return TypeAlias::kVec4F;
|
||||
}
|
||||
if (str == "vec4h") {
|
||||
return TypeAlias::kVec4H;
|
||||
}
|
||||
if (str == "vec4i") {
|
||||
return TypeAlias::kVec4I;
|
||||
}
|
||||
if (str == "vec4u") {
|
||||
return TypeAlias::kVec4U;
|
||||
}
|
||||
return TypeAlias::kUndefined;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, TypeAlias value) {
|
||||
switch (value) {
|
||||
case TypeAlias::kUndefined:
|
||||
return out << "undefined";
|
||||
case TypeAlias::kVec2F:
|
||||
return out << "vec2f";
|
||||
case TypeAlias::kVec2H:
|
||||
return out << "vec2h";
|
||||
case TypeAlias::kVec2I:
|
||||
return out << "vec2i";
|
||||
case TypeAlias::kVec2U:
|
||||
return out << "vec2u";
|
||||
case TypeAlias::kVec3F:
|
||||
return out << "vec3f";
|
||||
case TypeAlias::kVec3H:
|
||||
return out << "vec3h";
|
||||
case TypeAlias::kVec3I:
|
||||
return out << "vec3i";
|
||||
case TypeAlias::kVec3U:
|
||||
return out << "vec3u";
|
||||
case TypeAlias::kVec4F:
|
||||
return out << "vec4f";
|
||||
case TypeAlias::kVec4H:
|
||||
return out << "vec4h";
|
||||
case TypeAlias::kVec4I:
|
||||
return out << "vec4i";
|
||||
case TypeAlias::kVec4U:
|
||||
return out << "vec4u";
|
||||
}
|
||||
return out << "<unknown>";
|
||||
}
|
||||
|
||||
} // namespace tint::resolver
|
|
@ -0,0 +1,25 @@
|
|||
{{- /*
|
||||
--------------------------------------------------------------------------------
|
||||
Template file for use with tools/src/cmd/gen to generate type_alias.cc
|
||||
|
||||
To update the generated file, run:
|
||||
./tools/run gen
|
||||
|
||||
See:
|
||||
* tools/src/cmd/gen for structures used by this template
|
||||
* https://golang.org/pkg/text/template/ for documentation on the template syntax
|
||||
--------------------------------------------------------------------------------
|
||||
*/ -}}
|
||||
|
||||
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||
{{- $enum := (Sem.Enum "type_alias") -}}
|
||||
|
||||
#include "src/tint/resolver/type_alias.h"
|
||||
|
||||
namespace tint::resolver {
|
||||
|
||||
{{ Eval "ParseEnum" $enum}}
|
||||
|
||||
{{ Eval "EnumOStream" $enum}}
|
||||
|
||||
} // namespace tint::resolver
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2022 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// File generated by tools/src/cmd/gen
|
||||
// using the template:
|
||||
// src/tint/resolver/type_alias.h.tmpl
|
||||
//
|
||||
// Do not modify this file directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SRC_TINT_RESOLVER_TYPE_ALIAS_H_
|
||||
#define SRC_TINT_RESOLVER_TYPE_ALIAS_H_
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace tint::resolver {
|
||||
|
||||
/// An enumerator of builtin type aliases.
|
||||
enum class TypeAlias {
|
||||
kUndefined,
|
||||
kVec2F,
|
||||
kVec2H,
|
||||
kVec2I,
|
||||
kVec2U,
|
||||
kVec3F,
|
||||
kVec3H,
|
||||
kVec3I,
|
||||
kVec3U,
|
||||
kVec4F,
|
||||
kVec4H,
|
||||
kVec4I,
|
||||
kVec4U,
|
||||
};
|
||||
|
||||
/// @param out the std::ostream to write to
|
||||
/// @param value the TypeAlias
|
||||
/// @returns `out` so calls can be chained
|
||||
std::ostream& operator<<(std::ostream& out, TypeAlias value);
|
||||
|
||||
/// ParseTypeAlias parses a TypeAlias from a string.
|
||||
/// @param str the string to parse
|
||||
/// @returns the parsed enum, or TypeAlias::kUndefined if the string could not be parsed.
|
||||
TypeAlias ParseTypeAlias(std::string_view str);
|
||||
|
||||
constexpr const char* kTypeAliasStrings[] = {
|
||||
"vec2f", "vec2h", "vec2i", "vec2u", "vec3f", "vec3h",
|
||||
"vec3i", "vec3u", "vec4f", "vec4h", "vec4i", "vec4u",
|
||||
};
|
||||
|
||||
} // namespace tint::resolver
|
||||
|
||||
#endif // SRC_TINT_RESOLVER_TYPE_ALIAS_H_
|
|
@ -0,0 +1,29 @@
|
|||
{{- /*
|
||||
--------------------------------------------------------------------------------
|
||||
Template file for use with tools/src/cmd/gen to generate type_alias.h
|
||||
|
||||
To update the generated file, run:
|
||||
./tools/run gen
|
||||
|
||||
See:
|
||||
* tools/src/cmd/gen for structures used by this template
|
||||
* https://golang.org/pkg/text/template/ for documentation on the template syntax
|
||||
--------------------------------------------------------------------------------
|
||||
*/ -}}
|
||||
|
||||
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||
{{- $enum := (Sem.Enum "type_alias") -}}
|
||||
|
||||
#ifndef SRC_TINT_RESOLVER_TYPE_ALIAS_H_
|
||||
#define SRC_TINT_RESOLVER_TYPE_ALIAS_H_
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace tint::resolver {
|
||||
|
||||
/// An enumerator of builtin type aliases.
|
||||
{{ Eval "DeclareEnum" $enum}}
|
||||
|
||||
} // namespace tint::resolver
|
||||
|
||||
#endif // SRC_TINT_RESOLVER_TYPE_ALIAS_H_
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2022 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// File generated by tools/src/cmd/gen
|
||||
// using the template:
|
||||
// src/tint/resolver/type_alias_bench.cc.tmpl
|
||||
//
|
||||
// Do not modify this file directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "src/tint/resolver/type_alias.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
namespace tint::resolver {
|
||||
namespace {
|
||||
|
||||
void TypeAliasParser(::benchmark::State& state) {
|
||||
std::array kStrings{
|
||||
"veccf", "32", "vVc2f", "vec2f", "vec21", "qqeJf", "vecll7f", "veqH2pp",
|
||||
"vh", "Gebh", "vec2h", "vevi2h", "ve8WWh", "Mxxc2", "vgg2i", "V2X",
|
||||
"vec23", "vec2i", "vec2E", "TTeP2i", "vxxcdd", "v44c2u", "veVVSSu", "22RRu",
|
||||
"vec2u", "vF2u", "vecu", "ROOHVu", "ecyf", "n77rrlcGf", "vec340", "vec3f",
|
||||
"oof", "vezz", "1ipp3f", "XXec3h", "ve9IInn5h", "HHreSSaYh", "vec3h", "kk3",
|
||||
"jgRR", "veb", "vjc3i", "vc3i", "vcq", "vec3i", "Nec3i", "vcvv",
|
||||
"ve3QQ", "vrcf", "vecju", "NNew23", "vec3u", "ve3u", "vrrc3u", "Gec3u",
|
||||
"veFF4f", "vE", "verrf", "vec4f", "vef", "veJJD", "v4", "e4k",
|
||||
"vech", "Jech", "vec4h", "ec4h", "_KKttcH", "vexxh", "__qcF", "vc4qq",
|
||||
"33e64i", "vec4i", "6QQott4i", "v6c4i", "zzc4O6", "vyyc4u", "vcZZ", "ecWq4u",
|
||||
"vec4u", "vOO4u", "oYe4", "v4",
|
||||
};
|
||||
for (auto _ : state) {
|
||||
for (auto& str : kStrings) {
|
||||
auto result = ParseTypeAlias(str);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(TypeAliasParser);
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::resolver
|
|
@ -0,0 +1,29 @@
|
|||
{{- /*
|
||||
--------------------------------------------------------------------------------
|
||||
Template file for use with tools/src/cmd/gen to generate type_alias_bench.cc
|
||||
|
||||
To update the generated file, run:
|
||||
./tools/run gen
|
||||
|
||||
See:
|
||||
* tools/src/cmd/gen for structures used by this template
|
||||
* https://golang.org/pkg/text/template/ for documentation on the template syntax
|
||||
--------------------------------------------------------------------------------
|
||||
*/ -}}
|
||||
|
||||
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||
{{- $enum := (Sem.Enum "type_alias") -}}
|
||||
|
||||
#include "src/tint/resolver/type_alias.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
namespace tint::resolver {
|
||||
namespace {
|
||||
|
||||
{{ Eval "BenchmarkParseEnum" $enum }}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::resolver
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright 2022 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// File generated by tools/src/cmd/gen
|
||||
// using the template:
|
||||
// src/tint/resolver/type_alias_test.cc.tmpl
|
||||
//
|
||||
// Do not modify this file directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "src/tint/resolver/type_alias.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "src/tint/utils/string.h"
|
||||
|
||||
namespace tint::resolver {
|
||||
namespace {
|
||||
|
||||
namespace parse_print_tests {
|
||||
|
||||
struct Case {
|
||||
const char* string;
|
||||
TypeAlias value;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, Case c) {
|
||||
return out << "'" << std::string(c.string) << "'";
|
||||
}
|
||||
|
||||
static constexpr Case kValidCases[] = {
|
||||
{"vec2f", TypeAlias::kVec2F}, {"vec2h", TypeAlias::kVec2H}, {"vec2i", TypeAlias::kVec2I},
|
||||
{"vec2u", TypeAlias::kVec2U}, {"vec3f", TypeAlias::kVec3F}, {"vec3h", TypeAlias::kVec3H},
|
||||
{"vec3i", TypeAlias::kVec3I}, {"vec3u", TypeAlias::kVec3U}, {"vec4f", TypeAlias::kVec4F},
|
||||
{"vec4h", TypeAlias::kVec4H}, {"vec4i", TypeAlias::kVec4I}, {"vec4u", TypeAlias::kVec4U},
|
||||
};
|
||||
|
||||
static constexpr Case kInvalidCases[] = {
|
||||
{"veccf", TypeAlias::kUndefined}, {"32", TypeAlias::kUndefined},
|
||||
{"vVc2f", TypeAlias::kUndefined}, {"vec21", TypeAlias::kUndefined},
|
||||
{"qqeJh", TypeAlias::kUndefined}, {"vecll7h", TypeAlias::kUndefined},
|
||||
{"veqH2pp", TypeAlias::kUndefined}, {"vi", TypeAlias::kUndefined},
|
||||
{"Gebi", TypeAlias::kUndefined}, {"vevi2u", TypeAlias::kUndefined},
|
||||
{"ve8WWu", TypeAlias::kUndefined}, {"Mxxc2", TypeAlias::kUndefined},
|
||||
{"vgg3f", TypeAlias::kUndefined}, {"V3X", TypeAlias::kUndefined},
|
||||
{"vec33", TypeAlias::kUndefined}, {"vec3E", TypeAlias::kUndefined},
|
||||
{"TTeP3h", TypeAlias::kUndefined}, {"vxxcdd", TypeAlias::kUndefined},
|
||||
{"v44c3i", TypeAlias::kUndefined}, {"veVVSSi", TypeAlias::kUndefined},
|
||||
{"22RRi", TypeAlias::kUndefined}, {"vF3u", TypeAlias::kUndefined},
|
||||
{"vecu", TypeAlias::kUndefined}, {"ROOHVu", TypeAlias::kUndefined},
|
||||
{"ecyf", TypeAlias::kUndefined}, {"n77rrlcGf", TypeAlias::kUndefined},
|
||||
{"vec440", TypeAlias::kUndefined}, {"ooh", TypeAlias::kUndefined},
|
||||
{"vezz", TypeAlias::kUndefined}, {"1ipp4h", TypeAlias::kUndefined},
|
||||
{"XXec4i", TypeAlias::kUndefined}, {"ve9IInn5i", TypeAlias::kUndefined},
|
||||
{"HHreSSaYi", TypeAlias::kUndefined}, {"kk4", TypeAlias::kUndefined},
|
||||
{"jgRR", TypeAlias::kUndefined}, {"veb", TypeAlias::kUndefined},
|
||||
};
|
||||
|
||||
using TypeAliasParseTest = testing::TestWithParam<Case>;
|
||||
|
||||
TEST_P(TypeAliasParseTest, Parse) {
|
||||
const char* string = GetParam().string;
|
||||
TypeAlias expect = GetParam().value;
|
||||
EXPECT_EQ(expect, ParseTypeAlias(string));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ValidCases, TypeAliasParseTest, testing::ValuesIn(kValidCases));
|
||||
INSTANTIATE_TEST_SUITE_P(InvalidCases, TypeAliasParseTest, testing::ValuesIn(kInvalidCases));
|
||||
|
||||
using TypeAliasPrintTest = testing::TestWithParam<Case>;
|
||||
|
||||
TEST_P(TypeAliasPrintTest, Print) {
|
||||
TypeAlias value = GetParam().value;
|
||||
const char* expect = GetParam().string;
|
||||
EXPECT_EQ(expect, utils::ToString(value));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ValidCases, TypeAliasPrintTest, testing::ValuesIn(kValidCases));
|
||||
|
||||
} // namespace parse_print_tests
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::resolver
|
|
@ -0,0 +1,31 @@
|
|||
{{- /*
|
||||
--------------------------------------------------------------------------------
|
||||
Template file for use with tools/src/cmd/gen to generate type_alias_test.cc
|
||||
|
||||
To update the generated file, run:
|
||||
./tools/run gen
|
||||
|
||||
See:
|
||||
* tools/src/cmd/gen for structures used by this template
|
||||
* https://golang.org/pkg/text/template/ for documentation on the template syntax
|
||||
--------------------------------------------------------------------------------
|
||||
*/ -}}
|
||||
|
||||
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||
{{- $enum := (Sem.Enum "type_alias") -}}
|
||||
|
||||
#include "src/tint/resolver/type_alias.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "src/tint/utils/string.h"
|
||||
|
||||
namespace tint::resolver {
|
||||
namespace {
|
||||
|
||||
{{ Eval "TestParsePrintEnum" $enum}}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::resolver
|
|
@ -1395,5 +1395,56 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
|
|||
ParamsFor<array<2, f32>>(2)));
|
||||
} // namespace VectorTests
|
||||
|
||||
namespace BuiltinTypeAliasTests {
|
||||
struct Params {
|
||||
const char* alias;
|
||||
builder::ast_type_func_ptr type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr Params Case(const char* alias) {
|
||||
return Params{alias, DataType<T>::AST};
|
||||
}
|
||||
|
||||
using BuiltinTypeAliasTest = ResolverTestWithParam<Params>;
|
||||
TEST_P(BuiltinTypeAliasTest, CheckEquivalent) {
|
||||
// var aliased : vecTN;
|
||||
// var explicit : vecN<T>;
|
||||
// explicit = aliased;
|
||||
auto& params = GetParam();
|
||||
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
WrapInFunction(Decl(Var("aliased", ty.type_name(params.alias))),
|
||||
Decl(Var("explicit", params.type(*this))), //
|
||||
Assign("explicit", "aliased"));
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
TEST_P(BuiltinTypeAliasTest, Construct) {
|
||||
// var v : vecN<T> = vecTN();
|
||||
auto& params = GetParam();
|
||||
|
||||
Enable(ast::Extension::kF16);
|
||||
|
||||
WrapInFunction(Decl(Var("v", params.type(*this), Construct(ty.type_name(params.alias)))));
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
|
||||
BuiltinTypeAliasTest,
|
||||
testing::Values(Case<vec2<f32>>("vec2f"),
|
||||
Case<vec3<f32>>("vec3f"),
|
||||
Case<vec4<f32>>("vec4f"),
|
||||
Case<vec2<f16>>("vec2h"),
|
||||
Case<vec3<f16>>("vec3h"),
|
||||
Case<vec4<f16>>("vec4h"),
|
||||
Case<vec2<i32>>("vec2i"),
|
||||
Case<vec3<i32>>("vec3i"),
|
||||
Case<vec4<i32>>("vec4i"),
|
||||
Case<vec2<u32>>("vec2u"),
|
||||
Case<vec3<u32>>("vec3u"),
|
||||
Case<vec4<u32>>("vec4u")));
|
||||
|
||||
} // namespace BuiltinTypeAliasTests
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::resolver
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
#define SRC_TINT_RESOLVER_UNIFORMITY_H_
|
||||
|
||||
// Forward declarations.
|
||||
namespace tint {
|
||||
namespace resolver {
|
||||
namespace tint::resolver {
|
||||
struct DependencyGraph;
|
||||
} // namespace resolver
|
||||
} // namespace tint::resolver
|
||||
namespace tint {
|
||||
class ProgramBuilder;
|
||||
} // namespace tint
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
type a = vec3f;
|
||||
|
||||
fn f() {
|
||||
{
|
||||
const vec3f = 1;
|
||||
const b = vec3f;
|
||||
}
|
||||
const c = a();
|
||||
const d = vec3f();
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
type a = vec3f;
|
||||
|
||||
fn f() {
|
||||
{
|
||||
const vec3f = 1;
|
||||
const b = vec3f;
|
||||
}
|
||||
const c = a();
|
||||
const d = vec3f();
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
type a = vec3f;
|
||||
|
||||
fn f() {
|
||||
{
|
||||
let vec3f = 1;
|
||||
let b = vec3f;
|
||||
}
|
||||
let c = a();
|
||||
let d = vec3f();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
[numthreads(1, 1, 1)]
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
|
||||
void f() {
|
||||
{
|
||||
const int vec3f = 1;
|
||||
const int b = vec3f;
|
||||
}
|
||||
const float3 c = (0.0f).xxx;
|
||||
const float3 d = (0.0f).xxx;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
[numthreads(1, 1, 1)]
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
|
||||
void f() {
|
||||
{
|
||||
const int vec3f = 1;
|
||||
const int b = vec3f;
|
||||
}
|
||||
const float3 c = (0.0f).xxx;
|
||||
const float3 d = (0.0f).xxx;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#version 310 es
|
||||
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
void f() {
|
||||
{
|
||||
int vec3f = 1;
|
||||
int b = vec3f;
|
||||
}
|
||||
vec3 c = vec3(0.0f);
|
||||
vec3 d = vec3(0.0f);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
void f() {
|
||||
{
|
||||
int const vec3f = 1;
|
||||
int const b = vec3f;
|
||||
}
|
||||
float3 const c = float3(0.0f);
|
||||
float3 const d = float3(0.0f);
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
; SPIR-V
|
||||
; Version: 1.3
|
||||
; Generator: Google Tint Compiler; 0
|
||||
; Bound: 12
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
|
||||
OpExecutionMode %unused_entry_point LocalSize 1 1 1
|
||||
OpName %unused_entry_point "unused_entry_point"
|
||||
OpName %f "f"
|
||||
%void = OpTypeVoid
|
||||
%1 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%int_1 = OpConstant %int 1
|
||||
%float = OpTypeFloat 32
|
||||
%v3float = OpTypeVector %float 3
|
||||
%11 = OpConstantNull %v3float
|
||||
%unused_entry_point = OpFunction %void None %1
|
||||
%4 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%f = OpFunction %void None %1
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
|
@ -0,0 +1,10 @@
|
|||
type a = vec3f;
|
||||
|
||||
fn f() {
|
||||
{
|
||||
let vec3f = 1;
|
||||
let b = vec3f;
|
||||
}
|
||||
let c = a();
|
||||
let d = vec3f();
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fn f(vec3f : vec3f) {
|
||||
let b = vec3f;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
[numthreads(1, 1, 1)]
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
|
||||
void f(float3 vec3f) {
|
||||
const float3 b = vec3f;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
[numthreads(1, 1, 1)]
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
|
||||
void f(float3 vec3f) {
|
||||
const float3 b = vec3f;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#version 310 es
|
||||
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
void f(vec3 vec3f) {
|
||||
vec3 b = vec3f;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
void f(float3 vec3f) {
|
||||
float3 const b = vec3f;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
; SPIR-V
|
||||
; Version: 1.3
|
||||
; Generator: Google Tint Compiler; 0
|
||||
; Bound: 11
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
|
||||
OpExecutionMode %unused_entry_point LocalSize 1 1 1
|
||||
OpName %unused_entry_point "unused_entry_point"
|
||||
OpName %f "f"
|
||||
OpName %vec3f "vec3f"
|
||||
%void = OpTypeVoid
|
||||
%1 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v3float = OpTypeVector %float 3
|
||||
%5 = OpTypeFunction %void %v3float
|
||||
%unused_entry_point = OpFunction %void None %1
|
||||
%4 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%f = OpFunction %void None %5
|
||||
%vec3f = OpFunctionParameter %v3float
|
||||
%10 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
|
@ -0,0 +1,3 @@
|
|||
fn f(vec3f : vec3f) {
|
||||
let b = vec3f;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
type a = vec3f;
|
||||
|
||||
fn f() {
|
||||
{
|
||||
var vec3f = 1;
|
||||
var b = vec3f;
|
||||
}
|
||||
var c = a();
|
||||
var d = vec3f();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
[numthreads(1, 1, 1)]
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
|
||||
void f() {
|
||||
{
|
||||
int vec3f = 1;
|
||||
int b = vec3f;
|
||||
}
|
||||
float3 c = (0.0f).xxx;
|
||||
float3 d = (0.0f).xxx;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
[numthreads(1, 1, 1)]
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
|
||||
void f() {
|
||||
{
|
||||
int vec3f = 1;
|
||||
int b = vec3f;
|
||||
}
|
||||
float3 c = (0.0f).xxx;
|
||||
float3 d = (0.0f).xxx;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#version 310 es
|
||||
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
void f() {
|
||||
{
|
||||
int vec3f = 1;
|
||||
int b = vec3f;
|
||||
}
|
||||
vec3 c = vec3(0.0f);
|
||||
vec3 d = vec3(0.0f);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
void f() {
|
||||
{
|
||||
int vec3f = 1;
|
||||
int b = vec3f;
|
||||
}
|
||||
float3 c = float3(0.0f);
|
||||
float3 d = float3(0.0f);
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
; SPIR-V
|
||||
; Version: 1.3
|
||||
; Generator: Google Tint Compiler; 0
|
||||
; Bound: 20
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
|
||||
OpExecutionMode %unused_entry_point LocalSize 1 1 1
|
||||
OpName %unused_entry_point "unused_entry_point"
|
||||
OpName %f "f"
|
||||
OpName %vec3f "vec3f"
|
||||
OpName %b "b"
|
||||
OpName %c "c"
|
||||
OpName %d "d"
|
||||
%void = OpTypeVoid
|
||||
%1 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%int_1 = OpConstant %int 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%11 = OpConstantNull %int
|
||||
%float = OpTypeFloat 32
|
||||
%v3float = OpTypeVector %float 3
|
||||
%16 = OpConstantNull %v3float
|
||||
%_ptr_Function_v3float = OpTypePointer Function %v3float
|
||||
%unused_entry_point = OpFunction %void None %1
|
||||
%4 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%f = OpFunction %void None %1
|
||||
%6 = OpLabel
|
||||
%vec3f = OpVariable %_ptr_Function_int Function %11
|
||||
%b = OpVariable %_ptr_Function_int Function %11
|
||||
%c = OpVariable %_ptr_Function_v3float Function %16
|
||||
%d = OpVariable %_ptr_Function_v3float Function %16
|
||||
OpStore %vec3f %int_1
|
||||
%12 = OpLoad %int %vec3f
|
||||
OpStore %b %12
|
||||
OpStore %c %16
|
||||
OpStore %d %16
|
||||
OpReturn
|
||||
OpFunctionEnd
|
|
@ -0,0 +1,10 @@
|
|||
type a = vec3f;
|
||||
|
||||
fn f() {
|
||||
{
|
||||
var vec3f = 1;
|
||||
var b = vec3f;
|
||||
}
|
||||
var c = a();
|
||||
var d = vec3f();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
[numthreads(1, 1, 1)]
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
|
||||
void f() {
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
[numthreads(1, 1, 1)]
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
|
||||
void f() {
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#version 310 es
|
||||
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
void unused_entry_point() {
|
||||
return;
|
||||
}
|
||||
void f() {
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
void f() {
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
; SPIR-V
|
||||
; Version: 1.3
|
||||
; Generator: Google Tint Compiler; 0
|
||||
; Bound: 7
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
|
||||
OpExecutionMode %unused_entry_point LocalSize 1 1 1
|
||||
OpName %unused_entry_point "unused_entry_point"
|
||||
OpName %f "f"
|
||||
%void = OpTypeVoid
|
||||
%1 = OpTypeFunction %void
|
||||
%unused_entry_point = OpFunction %void None %1
|
||||
%4 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%f = OpFunction %void None %1
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
|
@ -93,15 +93,26 @@ func (l *lexer) lex() error {
|
|||
case l.match("/", tok.Divide):
|
||||
case l.match(".", tok.Dot):
|
||||
case l.match("->", tok.Arrow):
|
||||
case l.match("fn", tok.Function):
|
||||
case l.match("op", tok.Operator):
|
||||
case l.match("enum", tok.Enum):
|
||||
case l.match("type", tok.Type):
|
||||
case l.match("init", tok.Initializer):
|
||||
case l.match("conv", tok.Converter):
|
||||
case l.match("match", tok.Match):
|
||||
case unicode.IsLetter(l.peek(0)) || l.peek(0) == '_':
|
||||
l.tok(l.count(alphaNumericOrUnderscore), tok.Identifier)
|
||||
n := l.count(alphaNumericOrUnderscore)
|
||||
switch string(l.runes[:n]) {
|
||||
case "fn":
|
||||
l.tok(n, tok.Function)
|
||||
case "op":
|
||||
l.tok(n, tok.Operator)
|
||||
case "enum":
|
||||
l.tok(n, tok.Enum)
|
||||
case "type":
|
||||
l.tok(n, tok.Type)
|
||||
case "init":
|
||||
l.tok(n, tok.Initializer)
|
||||
case "conv":
|
||||
l.tok(n, tok.Converter)
|
||||
case "match":
|
||||
l.tok(n, tok.Match)
|
||||
default:
|
||||
l.tok(n, tok.Identifier)
|
||||
}
|
||||
case unicode.IsNumber(l.peek(0)) || l.peek(0) == '-':
|
||||
isFloat := false
|
||||
isNegative := false
|
||||
|
|
|
@ -84,6 +84,9 @@ func TestLexTokens(t *testing.T) {
|
|||
{"op", []tok.Token{{Kind: tok.Operator, Runes: []rune("op"), Source: tok.Source{
|
||||
S: loc(1, 1, 0), E: loc(1, 3, 2),
|
||||
}}}},
|
||||
{"operation", []tok.Token{{Kind: tok.Identifier, Runes: []rune("operation"), Source: tok.Source{
|
||||
S: loc(1, 1, 0), E: loc(1, 10, 9),
|
||||
}}}},
|
||||
{"type", []tok.Token{{Kind: tok.Type, Runes: []rune("type"), Source: tok.Source{
|
||||
S: loc(1, 1, 0), E: loc(1, 5, 4),
|
||||
}}}},
|
||||
|
|
Loading…
Reference in New Issue