tint: Remove ast::Void
WGSL does not have a void type. Functions that do not return a value simply omit the return type from the function signature. Change-Id: Id45adc008dce46115552e7dc401a2e27ae10eeb4 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/118981 Reviewed-by: James Price <jrprice@google.com> Kokoro: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
08fd42f08a
commit
1906857a50
|
@ -330,7 +330,6 @@ libtint_source_set("libtint_syntax_tree_src") {
|
|||
"ast/variable.h",
|
||||
"ast/variable_decl_statement.h",
|
||||
"ast/vector.h",
|
||||
"ast/void.h",
|
||||
"ast/while_statement.h",
|
||||
"ast/workgroup_attribute.h",
|
||||
"clone_context.cc",
|
||||
|
@ -730,8 +729,6 @@ libtint_source_set("libtint_ast_src") {
|
|||
"ast/variable_decl_statement.h",
|
||||
"ast/vector.cc",
|
||||
"ast/vector.h",
|
||||
"ast/void.cc",
|
||||
"ast/void.h",
|
||||
"ast/while_statement.cc",
|
||||
"ast/while_statement.h",
|
||||
"ast/workgroup_attribute.cc",
|
||||
|
|
|
@ -258,8 +258,6 @@ list(APPEND TINT_LIB_SRCS
|
|||
ast/variable.h
|
||||
ast/vector.cc
|
||||
ast/vector.h
|
||||
ast/void.cc
|
||||
ast/void.h
|
||||
ast/while_statement.cc
|
||||
ast/while_statement.h
|
||||
ast/workgroup_attribute.cc
|
||||
|
|
|
@ -39,13 +39,13 @@ Function::Function(ProgramID pid,
|
|||
attributes(std::move(attrs)),
|
||||
return_type_attributes(std::move(return_type_attrs)) {
|
||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
|
||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, return_ty, program_id);
|
||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
|
||||
for (auto* param : params) {
|
||||
TINT_ASSERT(AST, tint::Is<Parameter>(param));
|
||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, param, program_id);
|
||||
}
|
||||
TINT_ASSERT(AST, symbol.IsValid());
|
||||
TINT_ASSERT(AST, return_type);
|
||||
for (auto* attr : attributes) {
|
||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
|
||||
}
|
||||
|
|
|
@ -25,14 +25,26 @@ namespace {
|
|||
|
||||
using FunctionTest = TestHelper;
|
||||
|
||||
TEST_F(FunctionTest, Creation) {
|
||||
TEST_F(FunctionTest, Creation_i32ReturnType) {
|
||||
utils::Vector params{Param("var", ty.i32())};
|
||||
auto* i32 = ty.i32();
|
||||
auto* var = params[0];
|
||||
|
||||
auto* f = Func("func", params, i32, utils::Empty);
|
||||
EXPECT_EQ(f->symbol, Symbols().Get("func"));
|
||||
ASSERT_EQ(f->params.Length(), 1u);
|
||||
EXPECT_EQ(f->return_type, i32);
|
||||
EXPECT_EQ(f->params[0], var);
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, Creation_NoReturnType) {
|
||||
utils::Vector params{Param("var", ty.i32())};
|
||||
auto* var = params[0];
|
||||
|
||||
auto* f = Func("func", params, ty.void_(), utils::Empty);
|
||||
EXPECT_EQ(f->symbol, Symbols().Get("func"));
|
||||
ASSERT_EQ(f->params.Length(), 1u);
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
EXPECT_EQ(f->params[0], var);
|
||||
}
|
||||
|
||||
|
@ -54,15 +66,6 @@ TEST_F(FunctionTest, Assert_InvalidName) {
|
|||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, Assert_Null_ReturnType) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.Func("f", utils::Empty, nullptr, utils::Empty);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, Assert_Null_Param) {
|
||||
using ParamList = utils::Vector<const ast::Parameter*, 2>;
|
||||
EXPECT_FATAL_FAILURE(
|
||||
|
@ -113,6 +116,16 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_Attr) {
|
|||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, Assert_DifferentProgramID_ReturnType) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b1;
|
||||
ProgramBuilder b2;
|
||||
b1.Func("func", utils::Empty, b2.ty.i32(), utils::Empty);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, Assert_DifferentProgramID_ReturnAttr) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright 2020 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.
|
||||
|
||||
#include "src/tint/ast/void.h"
|
||||
|
||||
#include "src/tint/program_builder.h"
|
||||
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::ast::Void);
|
||||
|
||||
namespace tint::ast {
|
||||
|
||||
Void::Void(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
|
||||
|
||||
Void::Void(Void&&) = default;
|
||||
|
||||
Void::~Void() = default;
|
||||
|
||||
std::string Void::FriendlyName(const SymbolTable&) const {
|
||||
return "void";
|
||||
}
|
||||
|
||||
const Void* Void::Clone(CloneContext* ctx) const {
|
||||
auto src = ctx->Clone(source);
|
||||
return ctx->dst->create<Void>(src);
|
||||
}
|
||||
|
||||
} // namespace tint::ast
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright 2020 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.
|
||||
|
||||
#ifndef SRC_TINT_AST_VOID_H_
|
||||
#define SRC_TINT_AST_VOID_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "src/tint/ast/type.h"
|
||||
|
||||
namespace tint::ast {
|
||||
|
||||
/// A void type
|
||||
class Void final : public Castable<Void, Type> {
|
||||
public:
|
||||
/// Constructor
|
||||
/// @param pid the identifier of the program that owns this node
|
||||
/// @param nid the unique node identifier
|
||||
/// @param src the source of this node
|
||||
Void(ProgramID pid, NodeID nid, const Source& src);
|
||||
/// Move constructor
|
||||
Void(Void&&);
|
||||
~Void() override;
|
||||
|
||||
/// @param symbols the program's symbol table
|
||||
/// @returns the name for this type that closely resembles how it would be
|
||||
/// declared in WGSL.
|
||||
std::string FriendlyName(const SymbolTable& symbols) const override;
|
||||
|
||||
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned type
|
||||
const Void* Clone(CloneContext* ctx) const override;
|
||||
};
|
||||
|
||||
} // namespace tint::ast
|
||||
|
||||
#endif // SRC_TINT_AST_VOID_H_
|
|
@ -89,7 +89,6 @@
|
|||
#include "src/tint/ast/var.h"
|
||||
#include "src/tint/ast/variable_decl_statement.h"
|
||||
#include "src/tint/ast/vector.h"
|
||||
#include "src/tint/ast/void.h"
|
||||
#include "src/tint/ast/while_statement.h"
|
||||
#include "src/tint/ast/workgroup_attribute.h"
|
||||
#include "src/tint/constant/composite.h"
|
||||
|
@ -567,6 +566,9 @@ class ProgramBuilder {
|
|||
return CToAST<T>::get(this);
|
||||
}
|
||||
|
||||
/// @returns nullptr ast::Type
|
||||
const ast::Type* void_() const { return nullptr; }
|
||||
|
||||
/// @returns a boolean type
|
||||
const ast::Bool* bool_() const { return builder->create<ast::Bool>(); }
|
||||
|
||||
|
@ -612,15 +614,6 @@ class ProgramBuilder {
|
|||
return builder->create<ast::U32>(source);
|
||||
}
|
||||
|
||||
/// @returns a void type
|
||||
const ast::Void* void_() const { return builder->create<ast::Void>(); }
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @returns a void type
|
||||
const ast::Void* void_(const Source& source) const {
|
||||
return builder->create<ast::Void>(source);
|
||||
}
|
||||
|
||||
/// @param type vector subtype
|
||||
/// @param n vector width in elements
|
||||
/// @return the tint AST type for a `n`-element vector of `type`.
|
||||
|
|
|
@ -32,15 +32,13 @@ TEST_F(ParserImplTest, FunctionDecl) {
|
|||
ASSERT_NE(f.value, nullptr);
|
||||
|
||||
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
|
||||
ASSERT_NE(f->return_type, nullptr);
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
|
||||
ASSERT_EQ(f->params.Length(), 2u);
|
||||
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
|
||||
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
|
||||
|
||||
ASSERT_NE(f->return_type, nullptr);
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
|
||||
auto* body = f->body;
|
||||
ASSERT_EQ(body->statements.Length(), 1u);
|
||||
|
@ -77,15 +75,13 @@ TEST_F(ParserImplTest, FunctionDecl_Unicode) {
|
|||
ASSERT_NE(f.value, nullptr);
|
||||
|
||||
EXPECT_EQ(f->symbol, p->builder().Symbols().Get(function_ident));
|
||||
ASSERT_NE(f->return_type, nullptr);
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
|
||||
ASSERT_EQ(f->params.Length(), 2u);
|
||||
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get(param_a_ident));
|
||||
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get(param_b_ident));
|
||||
|
||||
ASSERT_NE(f->return_type, nullptr);
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
|
||||
auto* body = f->body;
|
||||
ASSERT_EQ(body->statements.Length(), 1u);
|
||||
|
@ -105,8 +101,7 @@ TEST_F(ParserImplTest, FunctionDecl_AttributeList) {
|
|||
ASSERT_NE(f.value, nullptr);
|
||||
|
||||
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
|
||||
ASSERT_NE(f->return_type, nullptr);
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
ASSERT_EQ(f->params.Length(), 0u);
|
||||
|
||||
auto& attributes = f->attributes;
|
||||
|
@ -150,8 +145,7 @@ fn main() { return; })");
|
|||
ASSERT_NE(f.value, nullptr);
|
||||
|
||||
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
|
||||
ASSERT_NE(f->return_type, nullptr);
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
ASSERT_EQ(f->params.Length(), 0u);
|
||||
|
||||
auto& attributes = f->attributes;
|
||||
|
@ -199,8 +193,7 @@ fn main() { return; })");
|
|||
ASSERT_NE(f.value, nullptr);
|
||||
|
||||
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
|
||||
ASSERT_NE(f->return_type, nullptr);
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
ASSERT_EQ(f->params.Length(), 0u);
|
||||
|
||||
auto& attrs = f->attributes;
|
||||
|
|
|
@ -28,7 +28,7 @@ TEST_F(ParserImplTest, FunctionHeader) {
|
|||
ASSERT_EQ(f->params.Length(), 2u);
|
||||
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
|
||||
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionHeader_TrailingComma) {
|
||||
|
@ -40,7 +40,7 @@ TEST_F(ParserImplTest, FunctionHeader_TrailingComma) {
|
|||
EXPECT_EQ(f->name, "main");
|
||||
ASSERT_EQ(f->params.Length(), 1u);
|
||||
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
|
||||
EXPECT_TRUE(f->return_type->Is<ast::Void>());
|
||||
EXPECT_EQ(f->return_type, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionHeader_AttributeReturnType) {
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
#include "src/tint/ast/u32.h"
|
||||
#include "src/tint/ast/variable_decl_statement.h"
|
||||
#include "src/tint/ast/vector.h"
|
||||
#include "src/tint/ast/void.h"
|
||||
#include "src/tint/ast/while_statement.h"
|
||||
#include "src/tint/ast/workgroup_attribute.h"
|
||||
#include "src/tint/scope_stack.h"
|
||||
|
@ -405,7 +404,7 @@ class DependencyScanner {
|
|||
TraverseType(tex->type);
|
||||
},
|
||||
[&](Default) {
|
||||
if (!ty->IsAnyOf<ast::Void, ast::Bool, ast::I32, ast::U32, ast::F16, ast::F32,
|
||||
if (!ty->IsAnyOf<ast::Bool, ast::I32, ast::U32, ast::F16, ast::F32,
|
||||
ast::DepthTexture, ast::DepthMultisampledTexture,
|
||||
ast::StorageTexture, ast::ExternalTexture, ast::Sampler>()) {
|
||||
UnhandledNode(diagnostics_, ty);
|
||||
|
|
|
@ -214,10 +214,13 @@ bool Resolver::ResolveInternal() {
|
|||
}
|
||||
|
||||
type::Type* Resolver::Type(const ast::Type* ty) {
|
||||
if (ty == nullptr) {
|
||||
return builder_->create<type::Void>();
|
||||
}
|
||||
|
||||
Mark(ty);
|
||||
auto* s = Switch(
|
||||
ty, //
|
||||
[&](const ast::Void*) { return builder_->create<type::Void>(); },
|
||||
[&](const ast::Bool*) { return builder_->create<type::Bool>(); },
|
||||
[&](const ast::I32*) { return builder_->create<type::I32>(); },
|
||||
[&](const ast::U32*) { return builder_->create<type::U32>(); },
|
||||
|
|
|
@ -149,10 +149,6 @@
|
|||
<DisplayString>{value}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="tint::ast::Void">
|
||||
<DisplayString>void</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="tint::ast::UnaryOpExpression">
|
||||
<DisplayString Condition="op==tint::ast::UnaryOp::kAddressOf">&({*expr})</DisplayString>
|
||||
<DisplayString Condition="op==tint::ast::UnaryOp::kComplement">~({*expr})</DisplayString>
|
||||
|
|
|
@ -154,7 +154,7 @@ class State {
|
|||
flag = b.Symbols().New("tint_return_flag");
|
||||
new_stmts[0].Push(b.Decl(b.Var(flag, b.ty.bool_())));
|
||||
|
||||
if (!function->return_type->Is<ast::Void>()) {
|
||||
if (function->return_type) {
|
||||
retval = b.Symbols().New("tint_return_value");
|
||||
new_stmts[0].Push(b.Decl(b.Var(retval, ctx.Clone(function->return_type))));
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ void Transform::RemoveStatement(CloneContext& ctx, const ast::Statement* stmt) {
|
|||
|
||||
const ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx, const type::Type* ty) {
|
||||
if (ty->Is<type::Void>()) {
|
||||
return ctx.dst->create<ast::Void>();
|
||||
return nullptr;
|
||||
}
|
||||
if (ty->Is<type::I32>()) {
|
||||
return ctx.dst->create<ast::I32>();
|
||||
|
|
|
@ -45,7 +45,7 @@ TEST_F(CreateASTTypeForTest, Basic) {
|
|||
EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<type::U32>(); })->Is<ast::U32>());
|
||||
EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<type::F32>(); })->Is<ast::F32>());
|
||||
EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<type::Bool>(); })->Is<ast::Bool>());
|
||||
EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<type::Void>(); })->Is<ast::Void>());
|
||||
EXPECT_EQ(create([](ProgramBuilder& b) { return b.create<type::Void>(); }), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(CreateASTTypeForTest, Matrix) {
|
||||
|
|
|
@ -2260,8 +2260,11 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
|
|||
// Emit original entry point signature
|
||||
{
|
||||
auto out = line();
|
||||
out << func->return_type->FriendlyName(builder_.Symbols()) << " "
|
||||
<< builder_.Symbols().NameFor(func->symbol) << "(";
|
||||
if (!EmitTypeAndName(out, func_sem->ReturnType(), type::AddressSpace::kUndefined,
|
||||
type::Access::kUndefined, builder_.Symbols().NameFor(func->symbol))) {
|
||||
return false;
|
||||
}
|
||||
out << "(";
|
||||
|
||||
bool first = true;
|
||||
|
||||
|
|
|
@ -3238,9 +3238,11 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
|
|||
out << ")]" << std::endl;
|
||||
}
|
||||
|
||||
out << func->return_type->FriendlyName(builder_.Symbols());
|
||||
|
||||
out << " " << builder_.Symbols().NameFor(func->symbol) << "(";
|
||||
if (!EmitTypeAndName(out, func_sem->ReturnType(), type::AddressSpace::kUndefined,
|
||||
type::Access::kUndefined, builder_.Symbols().NameFor(func->symbol))) {
|
||||
return false;
|
||||
}
|
||||
out << "(";
|
||||
|
||||
bool first = true;
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "src/tint/ast/interpolate_attribute.h"
|
||||
#include "src/tint/ast/module.h"
|
||||
#include "src/tint/ast/variable_decl_statement.h"
|
||||
#include "src/tint/ast/void.h"
|
||||
#include "src/tint/constant/value.h"
|
||||
#include "src/tint/sem/call.h"
|
||||
#include "src/tint/sem/function.h"
|
||||
|
@ -1974,6 +1973,8 @@ std::string GeneratorImpl::interpolation_to_attribute(ast::InterpolationType typ
|
|||
}
|
||||
|
||||
bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
|
||||
auto* func_sem = builder_.Sem().Get(func);
|
||||
|
||||
auto func_name = program_->Symbols().NameFor(func->symbol);
|
||||
|
||||
// Returns the binding index of a variable, requiring that the group
|
||||
|
@ -1999,8 +2000,11 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
|
|||
auto out = line();
|
||||
|
||||
EmitStage(out, func->PipelineStage());
|
||||
out << " " << func->return_type->FriendlyName(program_->Symbols());
|
||||
out << " " << func_name << "(";
|
||||
out << " ";
|
||||
if (!EmitTypeAndName(out, func_sem->ReturnType(), func_name)) {
|
||||
return false;
|
||||
}
|
||||
out << "(";
|
||||
|
||||
// Emit entry point parameters.
|
||||
bool first = true;
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "src/tint/ast/u32.h"
|
||||
#include "src/tint/ast/variable_decl_statement.h"
|
||||
#include "src/tint/ast/vector.h"
|
||||
#include "src/tint/ast/void.h"
|
||||
#include "src/tint/ast/workgroup_attribute.h"
|
||||
#include "src/tint/sem/struct.h"
|
||||
#include "src/tint/sem/switch_statement.h"
|
||||
|
@ -334,7 +333,7 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
|
|||
|
||||
out << ")";
|
||||
|
||||
if (!func->return_type->Is<ast::Void>() || !func->return_type_attributes.IsEmpty()) {
|
||||
if (func->return_type || !func->return_type_attributes.IsEmpty()) {
|
||||
out << " -> ";
|
||||
|
||||
if (!func->return_type_attributes.IsEmpty()) {
|
||||
|
@ -590,10 +589,6 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
|
|||
}
|
||||
return true;
|
||||
},
|
||||
[&](const ast::Void*) {
|
||||
out << "void";
|
||||
return true;
|
||||
},
|
||||
[&](const ast::TypeName* tn) {
|
||||
out << program_->Symbols().NameFor(tn->name->symbol);
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue