From 08d7fd9f5a95464bbe8b7b586496b9e34630e4c8 Mon Sep 17 00:00:00 2001 From: Matthias Kurtenacker Date: Tue, 1 Apr 2025 16:38:16 +0200 Subject: [PATCH 1/8] Support declaring external types. Syntax (for now): `type_ext = { , ... };` where the arguments are strings that are passed through to the thorin backend. The implementation of this feature depends on the backend. For now, only C supports this feature, and only a single argument is supported. `type_ext bar = { "foo" };` will cause thorin to emit `typedef foo bar;`. The type (`bar`) is opaque to artic and thorin. This feature is mainly intended to interact with external APIs, not to extend the artic programming language as a whole. --- include/artic/ast.h | 22 ++++++++++++++++++++++ include/artic/parser.h | 1 + include/artic/token.h | 1 + include/artic/types.h | 14 ++++++++++++++ src/bind.cpp | 10 ++++++++++ src/check.cpp | 5 +++++ src/emit.cpp | 12 ++++++++++++ src/lexer.cpp | 1 + src/parser.cpp | 23 +++++++++++++++++++++++ src/print.cpp | 15 +++++++++++++++ src/types.cpp | 4 ++++ 11 files changed, 108 insertions(+) diff --git a/include/artic/ast.h b/include/artic/ast.h index 401450d8..8c96fc15 100644 --- a/include/artic/ast.h +++ b/include/artic/ast.h @@ -1506,6 +1506,28 @@ struct TypeDecl : public NamedDecl { void print(Printer&) const override; }; +struct ExtTypeDecl : public NamedDecl { + Ptr type_params; + PtrVector type_args; + + ExtTypeDecl( + const Loc& loc, + Identifier&& id, + Ptr&& type_params, + PtrVector&& type_args) + : NamedDecl(loc, std::move(id)) + , type_params(std::move(type_params)) + , type_args(std::move(type_args)) + {} + + const thorin::Def* emit(Emitter&) const override; + const artic::Type* infer(TypeChecker&) override; + void bind_head(NameBinder&) override; + void bind(NameBinder&) override; + void resolve_summons(Summoner&) override {}; + void print(Printer&) const override; +}; + /// Module definition. struct ModDecl : public NamedDecl { PtrVector decls; diff --git a/include/artic/parser.h b/include/artic/parser.h index 8d5c0de1..bdf4d565 100644 --- a/include/artic/parser.h +++ b/include/artic/parser.h @@ -34,6 +34,7 @@ class Parser : public Logger { Ptr parse_implicit_decl(); Ptr parse_static_decl(); Ptr parse_type_decl(); + Ptr parse_ext_type_decl(); Ptr parse_type_param(); Ptr parse_type_params(); Ptr parse_mod_decl(); diff --git a/include/artic/token.h b/include/artic/token.h index 7d08a9a3..5f318c77 100644 --- a/include/artic/token.h +++ b/include/artic/token.h @@ -29,6 +29,7 @@ namespace artic { f(Struct, "struct") \ f(Enum, "enum") \ f(Type, "type") \ + f(TypeExt, "type_ext") \ f(Static, "static") \ f(Implicit, "implicit") \ f(Summon, "summon") \ diff --git a/include/artic/types.h b/include/artic/types.h index 3a6955ad..a97afad1 100644 --- a/include/artic/types.h +++ b/include/artic/types.h @@ -582,6 +582,19 @@ struct TypeAlias : public PolyTypeFromDecl { friend class TypeTable; }; +struct ExtType : public PolyTypeFromDecl { + void print(Printer&) const override; + +private: + ExtType(TypeTable& type_table, const ast::ExtTypeDecl& decl) + : PolyTypeFromDecl(type_table, decl) + {} + + const thorin::Type* convert(Emitter&) const override; + + friend class TypeTable; +}; + /// An application of a complex type with polymorphic parameters. struct TypeApp : public Type { const UserType* applied; @@ -684,6 +697,7 @@ class TypeTable { const EnumType* enum_type(const ast::EnumDecl&); const ModType* mod_type(const ast::ModDecl&); const TypeAlias* type_alias(const ast::TypeDecl&); + const ExtType* ext_type(const ast::ExtTypeDecl&); /// Creates a type application for structures/enumeration types, /// or returns the type alias expanded with the given type arguments. diff --git a/src/bind.cpp b/src/bind.cpp index 37c4a3f4..b0199c30 100644 --- a/src/bind.cpp +++ b/src/bind.cpp @@ -509,6 +509,10 @@ void TypeDecl::bind_head(NameBinder& binder) { binder.insert_symbol(*this); } +void ExtTypeDecl::bind_head(NameBinder& binder) { + binder.insert_symbol(*this); +} + void TypeDecl::bind(NameBinder& binder) { binder.push_scope(); if (type_params) binder.bind(*type_params); @@ -516,6 +520,12 @@ void TypeDecl::bind(NameBinder& binder) { binder.pop_scope(); } +void ExtTypeDecl::bind(NameBinder& binder) { + binder.push_scope(); + if (type_params) binder.bind(*type_params); + binder.pop_scope(); +} + void ModDecl::bind_head(NameBinder& binder) { if (id.name != "") binder.insert_symbol(*this); diff --git a/src/check.cpp b/src/check.cpp index fa6f01f9..de067da9 100644 --- a/src/check.cpp +++ b/src/check.cpp @@ -1816,6 +1816,11 @@ const artic::Type* TypeDecl::infer(TypeChecker& checker) { return type; } +const artic::Type* ExtTypeDecl::infer(TypeChecker& checker) { + const artic::Type* type = checker.type_table.ext_type(*this); + return type; +} + const artic::Type* ModDecl::infer(TypeChecker& checker) { for (auto& decl : decls) checker.infer(*decl); diff --git a/src/emit.cpp b/src/emit.cpp index fb6660a0..e4fc5ff7 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -1746,6 +1746,10 @@ const thorin::Def* TypeDecl::emit(Emitter&) const { return nullptr; } +const thorin::Def* ExtTypeDecl::emit(Emitter&) const { + return nullptr; +} + const thorin::Def* ModDecl::emit(Emitter& emitter) const { for (auto& decl : decls) { // Do not emit polymorphic functions directly: Those will be emitted from @@ -1937,6 +1941,14 @@ const thorin::Type* UserType::convert(Emitter&, const Type*) const { return nullptr; } +const thorin::Type* ExtType::convert(Emitter& emitter) const { + std::vector args; + for (auto& arg : decl.type_args) { + args.emplace_back(*arg); + } + return emitter.world.extern_type(decl.id.name, args); +} + inline std::string stringify_params( Emitter& emitter, const std::string& prefix, diff --git a/src/lexer.cpp b/src/lexer.cpp index 1f474765..c4f35ca3 100644 --- a/src/lexer.cpp +++ b/src/lexer.cpp @@ -23,6 +23,7 @@ std::unordered_map Lexer::keywords{ std::make_pair("struct", Token::Struct), std::make_pair("enum", Token::Enum), std::make_pair("type", Token::Type), + std::make_pair("type_ext", Token::TypeExt), std::make_pair("implicit", Token::Implicit), std::make_pair("summon", Token::Summon), std::make_pair("static", Token::Static), diff --git a/src/parser.cpp b/src/parser.cpp index 7ea25107..b311136a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -42,6 +42,7 @@ Ptr Parser::parse_decl(bool is_top_level) { case Token::Struct: decl = parse_struct_decl(); break; case Token::Enum: decl = parse_enum_decl(); break; case Token::Type: decl = parse_type_decl(); break; + case Token::TypeExt: decl = parse_ext_type_decl(); break; case Token::Implicit: decl = parse_implicit_decl(); break; case Token::Static: decl = parse_static_decl(); break; case Token::Mod: decl = parse_mod_decl(); break; @@ -200,6 +201,28 @@ Ptr Parser::parse_type_decl() { return make_ptr(tracker(), std::move(id), std::move(type_params), std::move(aliased_type)); } +Ptr Parser::parse_ext_type_decl() { + Tracker tracker(this); + eat(Token::TypeExt); + auto id = parse_id(); + + Ptr type_params; + if (ahead().tag() == Token::LBracket) + type_params = parse_type_params(); + + PtrVector type_args; + if (accept(Token::Eq)) { + expect(Token::LBrace); + + parse_list(Token::RBrace, Token::Comma, [&] { + type_args.emplace_back(make_ptr(parse_str())); + }); + } + + expect(Token::Semi); + return make_ptr(tracker(), std::move(id), std::move(type_params), std::move(type_args)); +} + Ptr Parser::parse_implicit_decl() { Tracker tracker(this); eat(Token::Implicit); diff --git a/src/print.cpp b/src/print.cpp index d28cc940..1414d541 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -614,6 +614,17 @@ void TypeDecl::print(Printer& p) const { p << ';'; } +void ExtTypeDecl::print(Printer& p) const { + if (attrs) attrs->print(p); + p << log::keyword_style("type_ext") << ' ' << id.name; + if (type_params) type_params->print(p); + p << " = { "; + print_list(p, ',', type_args, [&] (auto& arg) { + p << *arg; + }); + p << " };"; +} + void ModDecl::print(Printer& p) const { if (attrs) attrs->print(p); bool anon = id.name == ""; @@ -825,6 +836,10 @@ void TypeAlias::print(Printer& p) const { p << decl.id.name; } +void ExtType::print(Printer& p) const { + p << decl.id.name; +} + void TypeApp::print(Printer& p) const { applied->print(p); p << '['; diff --git a/src/types.cpp b/src/types.cpp index f7e3bf42..7055c8d5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -726,6 +726,10 @@ const TypeAlias* TypeTable::type_alias(const ast::TypeDecl& decl) { return insert(decl); } +const ExtType* TypeTable::ext_type(const ast::ExtTypeDecl& decl) { + return insert(decl); +} + const Type* TypeTable::type_app(const UserType* applied, const ArrayRef& type_args) { if (auto type_alias = applied->isa()) { assert(type_alias->type_params() && type_alias->decl.aliased_type->type); From aa2b804c9a6bf7a8afc6d1076f494b63b9c3d5b4 Mon Sep 17 00:00:00 2001 From: Matthias Kurtenacker Date: Wed, 2 Apr 2025 17:30:21 +0200 Subject: [PATCH 2/8] Bugfix: Extern Types are nominal. --- include/artic/types.h | 5 ++++- src/emit.cpp | 28 ++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/include/artic/types.h b/include/artic/types.h index a97afad1..c5e82e92 100644 --- a/include/artic/types.h +++ b/include/artic/types.h @@ -590,7 +590,10 @@ struct ExtType : public PolyTypeFromDecl { : PolyTypeFromDecl(type_table, decl) {} - const thorin::Type* convert(Emitter&) const override; + using UserType::convert; + const thorin::Type* convert(Emitter&, const Type*) const override; + + std::string stringify(Emitter&) const override; friend class TypeTable; }; diff --git a/src/emit.cpp b/src/emit.cpp index e4fc5ff7..617590ab 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -1941,14 +1941,6 @@ const thorin::Type* UserType::convert(Emitter&, const Type*) const { return nullptr; } -const thorin::Type* ExtType::convert(Emitter& emitter) const { - std::vector args; - for (auto& arg : decl.type_args) { - args.emplace_back(*arg); - } - return emitter.world.extern_type(decl.id.name, args); -} - inline std::string stringify_params( Emitter& emitter, const std::string& prefix, @@ -2025,6 +2017,26 @@ const thorin::Type* TypeApp::convert(Emitter& emitter) const { return result; } +std::string ExtType::stringify(Emitter& emitter) const { + if (!type_params()) + return decl.id.name; + return stringify_params(emitter, decl.id.name + "_", type_params()->params); +} + +const thorin::Type* ExtType::convert(Emitter& emitter, const Type* parent) const { + if (auto it = emitter.types.find(this); !type_params() && it != emitter.types.end()) + return it->second; + + std::vector args; + for (auto& arg : decl.type_args) { + args.emplace_back(*arg); + } + + auto type = emitter.world.extern_type(decl.id.name, args); + emitter.types[parent] = type; + return type; +} + // A read-only buffer from memory, not performing any copy. struct MemBuf : public std::streambuf { MemBuf(const std::string& str) { From ccbf98d9f837ed10450d09e2d530a70d982ddb0a Mon Sep 17 00:00:00 2001 From: Matthias Kurtenacker Date: Wed, 3 Sep 2025 11:58:10 +0200 Subject: [PATCH 3/8] Allow PtrType in vector expressions. --- src/check.cpp | 10 +++++----- src/emit.cpp | 13 +++++++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/check.cpp b/src/check.cpp index de067da9..b3768b5e 100644 --- a/src/check.cpp +++ b/src/check.cpp @@ -83,7 +83,7 @@ const Type* TypeChecker::invalid_cast(const Loc& loc, const Type* type, const Ty const Type* TypeChecker::invalid_simd(const Loc& loc, const Type* elem_type) { if (should_report_error(elem_type)) - error(loc, "expected primitive type for simd type component, but got '{}'", *elem_type); + error(loc, "expected primitive or pointer type for simd type component, but got '{}'", *elem_type); return type_table.type_error(); } @@ -489,7 +489,7 @@ const Type* TypeChecker::infer_array( if (elem_count == 0) return cannot_infer(loc, msg); auto elem_type = infer_elems(); - if (is_simd && !elem_type->template isa()) + if (is_simd && !(elem_type->template isa() || elem_type->template isa())) return invalid_simd(loc, elem_type); return type_table.sized_array_type(elem_type, elem_count, is_simd); } @@ -509,7 +509,7 @@ const Type* TypeChecker::check_array( if (is_simd_type(array_type) != is_simd) return incompatible_type(loc, (is_simd ? "simd " : "non-simd ") + std::string(msg), expected); auto elem_type = array_type->elem; - if (is_simd && !elem_type->isa()) + if (is_simd && !(elem_type->template isa() || elem_type->template isa())) return invalid_simd(loc, elem_type); check_elems(elem_type); if (auto sized_array_type = array_type->isa(); @@ -847,7 +847,7 @@ const artic::Type* TupleType::infer(TypeChecker& checker) { const artic::Type* SizedArrayType::infer(TypeChecker& checker) { auto elem_type = checker.infer(*elem); - if (is_simd && !elem_type->isa()) + if (is_simd && !(elem_type->template isa() || elem_type->template isa())) return checker.invalid_simd(loc, elem_type); if (std::holds_alternative(size)) { @@ -1022,7 +1022,7 @@ const artic::Type* ArrayExpr::check(TypeChecker& checker, const artic::Type* exp const artic::Type* RepeatArrayExpr::infer(TypeChecker& checker) { auto elem_type = checker.deref(elem); - if (is_simd && !elem_type->isa()) + if (is_simd && !(elem_type->template isa() || elem_type->template isa())) return checker.invalid_simd(loc, elem_type); if (std::holds_alternative(size)) { diff --git a/src/emit.cpp b/src/emit.cpp index 1806696b..7fad88c3 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -1889,8 +1889,17 @@ std::string SizedArrayType::stringify(Emitter& emitter) const { } const thorin::Type* SizedArrayType::convert(Emitter& emitter) const { - if (is_simd) - return emitter.world.prim_type(elem->convert(emitter)->as()->primtype_tag(), size); + if (is_simd) { + auto elem_type = elem->convert(emitter); + if (auto prim_type = elem_type->isa()) + return emitter.world.prim_type(prim_type->primtype_tag(), size); + else if (auto ptr_type = elem_type->isa()) + return emitter.world.ptr_type(ptr_type->pointee(), size, ptr_type->addr_space()); + + //This should be unreachable after type checking. + assert(false); + return nullptr; + } return emitter.world.definite_array_type(elem->convert(emitter), size); } From 885818bc03c2dcb8be57cd2556c4b491c6bb9ade Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Fri, 31 Oct 2025 15:09:13 +0100 Subject: [PATCH 4/8] allow values and types as operands to type_ext --- include/artic/ast.h | 11 +++++++---- include/artic/types.h | 6 ++++-- src/bind.cpp | 10 +++++++++- src/check.cpp | 12 +++++++++++- src/emit.cpp | 13 +++++++++---- src/parser.cpp | 24 +++++++++++++----------- src/print.cpp | 13 +++++++++---- src/types.cpp | 4 ++-- 8 files changed, 64 insertions(+), 29 deletions(-) diff --git a/include/artic/ast.h b/include/artic/ast.h index 8c96fc15..7380444c 100644 --- a/include/artic/ast.h +++ b/include/artic/ast.h @@ -1508,17 +1508,20 @@ struct TypeDecl : public NamedDecl { struct ExtTypeDecl : public NamedDecl { Ptr type_params; - PtrVector type_args; + std::string type_name; + std::vector, Ptr>> args_; ExtTypeDecl( const Loc& loc, Identifier&& id, + std::string&& type_name, Ptr&& type_params, - PtrVector&& type_args) + std::vector, Ptr>>&& args) : NamedDecl(loc, std::move(id)) + , type_name(type_name) , type_params(std::move(type_params)) - , type_args(std::move(type_args)) - {} + , args_(std::move(args)) { + } const thorin::Def* emit(Emitter&) const override; const artic::Type* infer(TypeChecker&) override; diff --git a/include/artic/types.h b/include/artic/types.h index c5e82e92..2b55dff1 100644 --- a/include/artic/types.h +++ b/include/artic/types.h @@ -583,11 +583,13 @@ struct TypeAlias : public PolyTypeFromDecl { }; struct ExtType : public PolyTypeFromDecl { + std::vector args_; void print(Printer&) const override; private: - ExtType(TypeTable& type_table, const ast::ExtTypeDecl& decl) + ExtType(TypeTable& type_table, const ast::ExtTypeDecl& decl, std::vector&& args) : PolyTypeFromDecl(type_table, decl) + , args_(std::move(args)) {} using UserType::convert; @@ -700,7 +702,7 @@ class TypeTable { const EnumType* enum_type(const ast::EnumDecl&); const ModType* mod_type(const ast::ModDecl&); const TypeAlias* type_alias(const ast::TypeDecl&); - const ExtType* ext_type(const ast::ExtTypeDecl&); + const ExtType* ext_type(const ast::ExtTypeDecl&, std::vector&&); /// Creates a type application for structures/enumeration types, /// or returns the type alias expanded with the given type arguments. diff --git a/src/bind.cpp b/src/bind.cpp index b0199c30..3bdc71f2 100644 --- a/src/bind.cpp +++ b/src/bind.cpp @@ -522,7 +522,15 @@ void TypeDecl::bind(NameBinder& binder) { void ExtTypeDecl::bind(NameBinder& binder) { binder.push_scope(); - if (type_params) binder.bind(*type_params); + //if (type_params) binder.bind(*type_params); + for (auto& arg : args_) { + if (auto t = std::get_if>(&arg)) + binder.bind(**t); + else if (auto e = std::get_if>(&arg)) + binder.bind(**e); + else + assert(false); + } binder.pop_scope(); } diff --git a/src/check.cpp b/src/check.cpp index b3768b5e..b85275e2 100644 --- a/src/check.cpp +++ b/src/check.cpp @@ -1817,7 +1817,17 @@ const artic::Type* TypeDecl::infer(TypeChecker& checker) { } const artic::Type* ExtTypeDecl::infer(TypeChecker& checker) { - const artic::Type* type = checker.type_table.ext_type(*this); + std::vector args; + for (auto& arg : args_) { + if (auto t = std::get_if>(&arg)) + args.emplace_back(checker.infer(**t)); + else if (auto e = std::get_if>(&arg)) { + checker.infer(**e); + args.emplace_back(nullptr); + } else + assert(false); + } + const artic::Type* type = checker.type_table.ext_type(*this, std::move(args)); return type; } diff --git a/src/emit.cpp b/src/emit.cpp index 7fad88c3..dc0ebd2b 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -2046,12 +2046,17 @@ const thorin::Type* ExtType::convert(Emitter& emitter, const Type* parent) const if (auto it = emitter.types.find(this); !type_params() && it != emitter.types.end()) return it->second; - std::vector args; - for (auto& arg : decl.type_args) { - args.emplace_back(*arg); + std::vector args; + for (size_t i = 0; i < args_.size(); i++) { + if (auto t = args_[i]) { + args.emplace_back(t->convert(emitter)); + } else if (auto e = std::get_if>(&decl.args_[i])) + args.emplace_back(emitter.emit(**e)); + else + assert(false); } - auto type = emitter.world.extern_type(decl.id.name, args); + auto type = emitter.world.extern_type(decl.type_name, args); emitter.types[parent] = type; return type; } diff --git a/src/parser.cpp b/src/parser.cpp index b311136a..1466c6d6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -207,20 +207,22 @@ Ptr Parser::parse_ext_type_decl() { auto id = parse_id(); Ptr type_params; - if (ahead().tag() == Token::LBracket) - type_params = parse_type_params(); - - PtrVector type_args; - if (accept(Token::Eq)) { - expect(Token::LBrace); + // if (ahead().tag() == Token::LBracket) + // type_params = parse_type_params(); - parse_list(Token::RBrace, Token::Comma, [&] { - type_args.emplace_back(make_ptr(parse_str())); - }); - } + std::vector, Ptr>> args; + expect(Token::Eq); + auto type_name = parse_str(); + expect(Token::LBrace); + parse_list(Token::RBrace, Token::Comma, [&] { + if (accept(Token::Type)) + args.emplace_back(parse_type()); + else + args.emplace_back(parse_expr()); + }); expect(Token::Semi); - return make_ptr(tracker(), std::move(id), std::move(type_params), std::move(type_args)); + return make_ptr(tracker(), std::move(id), std::move(type_name), std::move(type_params), std::move(args)); } Ptr Parser::parse_implicit_decl() { diff --git a/src/print.cpp b/src/print.cpp index 1414d541..49111c65 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -617,10 +617,15 @@ void TypeDecl::print(Printer& p) const { void ExtTypeDecl::print(Printer& p) const { if (attrs) attrs->print(p); p << log::keyword_style("type_ext") << ' ' << id.name; - if (type_params) type_params->print(p); - p << " = { "; - print_list(p, ',', type_args, [&] (auto& arg) { - p << *arg; + // if (type_params) type_params->print(p); + p << " = \"" << type_name << "\" { "; + print_list(p, ',', args_, [&] (auto& arg) { + if (auto t = std::get_if>(&arg)) { + p << **t; + } else if (auto e = std::get_if>(&arg)) + p << **e; + else + p << "invalid"; }); p << " };"; } diff --git a/src/types.cpp b/src/types.cpp index 7055c8d5..78dc0258 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -726,8 +726,8 @@ const TypeAlias* TypeTable::type_alias(const ast::TypeDecl& decl) { return insert(decl); } -const ExtType* TypeTable::ext_type(const ast::ExtTypeDecl& decl) { - return insert(decl); +const ExtType* TypeTable::ext_type(const ast::ExtTypeDecl& decl, std::vector&& args) { + return insert(decl, std::move(args)); } const Type* TypeTable::type_app(const UserType* applied, const ArrayRef& type_args) { From 13754c9144e436593bd85d9739434449689d04be Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Fri, 31 Oct 2025 16:01:57 +0100 Subject: [PATCH 5/8] use nominal (mutable) Thorin ext_type --- src/emit.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/emit.cpp b/src/emit.cpp index dc0ebd2b..18bb0e1e 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -2056,7 +2056,9 @@ const thorin::Type* ExtType::convert(Emitter& emitter, const Type* parent) const assert(false); } - auto type = emitter.world.extern_type(decl.type_name, args); + auto type = emitter.world.extern_type(decl.type_name, args.size()); + for (size_t i = 0; i < args.size(); i++) + type->set_op(i, args[i]); emitter.types[parent] = type; return type; } From 03b6c7dbf9fc2bed657854d3d3e58fc94748e8e3 Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Mon, 3 Nov 2025 14:35:44 +0100 Subject: [PATCH 6/8] provide debug name for extern_type --- src/emit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emit.cpp b/src/emit.cpp index 18bb0e1e..f1879a2f 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -2056,7 +2056,7 @@ const thorin::Type* ExtType::convert(Emitter& emitter, const Type* parent) const assert(false); } - auto type = emitter.world.extern_type(decl.type_name, args.size()); + auto type = emitter.world.extern_type(decl.type_name, args.size(), { decl.id.name }); for (size_t i = 0; i < args.size(); i++) type->set_op(i, args[i]); emitter.types[parent] = type; From df5ef61710245114b8aa4317838c981fea4b30ff Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Wed, 5 Nov 2025 15:55:12 +0100 Subject: [PATCH 7/8] correctly emit recursive external_types --- include/artic/ast.h | 1 + include/artic/types.h | 6 ++---- src/check.cpp | 14 +++++++++----- src/emit.cpp | 16 +++++++--------- src/types.cpp | 4 ++-- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/include/artic/ast.h b/include/artic/ast.h index 7380444c..6f175501 100644 --- a/include/artic/ast.h +++ b/include/artic/ast.h @@ -1510,6 +1510,7 @@ struct ExtTypeDecl : public NamedDecl { Ptr type_params; std::string type_name; std::vector, Ptr>> args_; + std::vector args_types_; ExtTypeDecl( const Loc& loc, diff --git a/include/artic/types.h b/include/artic/types.h index 2b55dff1..c5e82e92 100644 --- a/include/artic/types.h +++ b/include/artic/types.h @@ -583,13 +583,11 @@ struct TypeAlias : public PolyTypeFromDecl { }; struct ExtType : public PolyTypeFromDecl { - std::vector args_; void print(Printer&) const override; private: - ExtType(TypeTable& type_table, const ast::ExtTypeDecl& decl, std::vector&& args) + ExtType(TypeTable& type_table, const ast::ExtTypeDecl& decl) : PolyTypeFromDecl(type_table, decl) - , args_(std::move(args)) {} using UserType::convert; @@ -702,7 +700,7 @@ class TypeTable { const EnumType* enum_type(const ast::EnumDecl&); const ModType* mod_type(const ast::ModDecl&); const TypeAlias* type_alias(const ast::TypeDecl&); - const ExtType* ext_type(const ast::ExtTypeDecl&, std::vector&&); + const ExtType* ext_type(const ast::ExtTypeDecl&); /// Creates a type application for structures/enumeration types, /// or returns the type alias expanded with the given type arguments. diff --git a/src/check.cpp b/src/check.cpp index b85275e2..7875336c 100644 --- a/src/check.cpp +++ b/src/check.cpp @@ -1817,18 +1817,22 @@ const artic::Type* TypeDecl::infer(TypeChecker& checker) { } const artic::Type* ExtTypeDecl::infer(TypeChecker& checker) { - std::vector args; + if (!checker.enter_decl(this)) + return checker.type_table.type_error(); + const ExtType* ext_type = checker.type_table.ext_type(*this); + // Set the type before entering the args + type = ext_type; for (auto& arg : args_) { if (auto t = std::get_if>(&arg)) - args.emplace_back(checker.infer(**t)); + args_types_.emplace_back(checker.infer(**t)); else if (auto e = std::get_if>(&arg)) { checker.infer(**e); - args.emplace_back(nullptr); + args_types_.emplace_back(nullptr); } else assert(false); } - const artic::Type* type = checker.type_table.ext_type(*this, std::move(args)); - return type; + checker.exit_decl(this); + return ext_type; } const artic::Type* ModDecl::infer(TypeChecker& checker) { diff --git a/src/emit.cpp b/src/emit.cpp index f1879a2f..ab53ba5a 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -2046,20 +2046,18 @@ const thorin::Type* ExtType::convert(Emitter& emitter, const Type* parent) const if (auto it = emitter.types.find(this); !type_params() && it != emitter.types.end()) return it->second; - std::vector args; - for (size_t i = 0; i < args_.size(); i++) { - if (auto t = args_[i]) { - args.emplace_back(t->convert(emitter)); + auto type = emitter.world.extern_type(decl.type_name, decl.args_types_.size(), { decl.id.name }); + emitter.types[parent] = type; + + for (size_t i = 0; i < decl.args_types_.size(); i++) { + if (auto t = decl.args_types_[i]) { + type->set_op(i, t->convert(emitter)); } else if (auto e = std::get_if>(&decl.args_[i])) - args.emplace_back(emitter.emit(**e)); + type->set_op(i, emitter.emit(**e)); else assert(false); } - auto type = emitter.world.extern_type(decl.type_name, args.size(), { decl.id.name }); - for (size_t i = 0; i < args.size(); i++) - type->set_op(i, args[i]); - emitter.types[parent] = type; return type; } diff --git a/src/types.cpp b/src/types.cpp index 78dc0258..7055c8d5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -726,8 +726,8 @@ const TypeAlias* TypeTable::type_alias(const ast::TypeDecl& decl) { return insert(decl); } -const ExtType* TypeTable::ext_type(const ast::ExtTypeDecl& decl, std::vector&& args) { - return insert(decl, std::move(args)); +const ExtType* TypeTable::ext_type(const ast::ExtTypeDecl& decl) { + return insert(decl); } const Type* TypeTable::type_app(const UserType* applied, const ArrayRef& type_args) { From 5040b5ca7b3a38dfe2b25dd22a7a20b1cb08a2dd Mon Sep 17 00:00:00 2001 From: Matthias Kurtenacker Date: Wed, 5 Nov 2025 16:03:52 +0100 Subject: [PATCH 8/8] Do not allow non constant expressions in external types. --- src/check.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/check.cpp b/src/check.cpp index 7875336c..a0315a2d 100644 --- a/src/check.cpp +++ b/src/check.cpp @@ -1827,6 +1827,8 @@ const artic::Type* ExtTypeDecl::infer(TypeChecker& checker) { args_types_.emplace_back(checker.infer(**t)); else if (auto e = std::get_if>(&arg)) { checker.infer(**e); + if (!(*e)->is_constant()) + checker.error((*e)->loc, "only constants are allowed as external type members"); args_types_.emplace_back(nullptr); } else assert(false);