Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e16442d
Allow `use` of non-module declarations
Hugobros3 Jul 4, 2024
a82a3fc
remove 'allow_type' from parse_path as it's always true
Hugobros3 Jul 4, 2024
4f15a45
remove dead field in UseDecl
Hugobros3 Jul 4, 2024
48eacc8
add find_member helper method on ModDecl
Hugobros3 Jul 4, 2024
232a92f
parser: added wildcard support to Path
Hugobros3 Jul 4, 2024
f6ca46f
hacky support for wildcard binders in 'use' declarations
Hugobros3 Jul 4, 2024
0badd8f
added a simple test for wildcard uses
Hugobros3 Jul 4, 2024
b6f4035
document the new use capabilities in the README
Hugobros3 Jul 4, 2024
a54b74f
bind Path during NameBinding
Hugobros3 Jul 5, 2024
673aa3c
move the is_value logic out of Path::infer
Hugobros3 Jul 5, 2024
0c861b6
use new Path::bind capability to resolve wildcards
Hugobros3 Jul 5, 2024
7d44e9b
naming
Hugobros3 Jul 5, 2024
a2a0c7c
don't pre-resolve intermediary UseDecls in Path::bind
Hugobros3 Jul 9, 2024
a51f8be
removed is_ctor member from Path
Hugobros3 Jul 9, 2024
80abb6b
Merge branch 'master' into rust-like-use
Hugobros3 Jan 6, 2026
3551b5e
allow importing definitions with type params
Hugobros3 Jan 7, 2026
99b89a8
fix wildcard uses not allowing unspecialized polymorphic defs
Hugobros3 Jan 7, 2026
3c8fd85
minor cleanup
Hugobros3 Jan 7, 2026
b1df0e8
add support for emitting empty tuple-like structs from a non-trivial …
Hugobros3 Jan 8, 2026
e4ad8d6
add test to validate we can emit polymorphic fns from paths with uses
Hugobros3 Jan 8, 2026
73be375
allow arbitrary long paths for constant static expressions
Hugobros3 Jan 8, 2026
f4cfc53
cleanup/improve support for static values as array sizes
Hugobros3 Jan 8, 2026
9e33f89
fix broken check for static array sizes
Hugobros3 Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ mod A {
```rust
mod A {
use super::C;
fn foo() { C::baz() }
fn foo() { baz() }
mod B {
fn bar() { super::foo() }
}
Expand All @@ -135,6 +135,17 @@ mod C {
fn baz() { D::bar }
}
```
- Wildcard imports are now supported:
```rust
mod A {
fn f() -> i32 = 42;
fn g() -> i32 = 69;
}
use A::*;

fn main() = f() + g();
```

- Tuples cannot be indexed with constant integers anymore:
```rust
let t = (1, 2);
Expand Down
41 changes: 35 additions & 6 deletions include/artic/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <memory>
#include <vector>
#include <variant>
#include <optional>

#include "artic/arena.h"
#include "artic/loc.h"
Expand Down Expand Up @@ -47,6 +48,7 @@ struct Node : public Cast<Node> {
/// Location of the node in the source file.
Loc loc;

mutable bool bound = false;
/// Type assigned after type inference. Not all nodes are typeable.
mutable const artic::Type* type = nullptr;
/// IR definition assigned after IR emission.
Expand Down Expand Up @@ -161,43 +163,56 @@ struct Ptrn : public Node {

// Path ----------------------------------------------------------------------------

struct StaticDecl;

/// A path of the form A[T1, ..., TN]:: ... ::Z[U1, ..., UN]
struct Path : public Node {
struct Elem {
Loc loc;
Identifier id;
PtrVector<Type> args;

// Set during name-binding
NamedDecl* decl = nullptr;

// These members are set during type-checking
const artic::Type* type = nullptr;
size_t index = 0;
std::vector<const artic::Type*> inferred_args;

bool is_super() const { return id.name == "super"; }
bool is_wildcard() const { return id.name == "*"; }

Elem(const Loc& loc, Identifier&& id, PtrVector<Type>&& args)
: loc(loc), id(std::move(id)), args(std::move(args))
{}

const artic::Type* infer(TypeChecker& checker, const artic::Type* prev_elem_type, Path& path);
};

std::vector<Elem> elems;
// use paths are allowed to have un-instantiated type params
bool is_use_path_ = false;

// Set during name-binding, corresponds to the declaration that
// is associated with the _first_ element of the path.
// The rest of the path is resolved during type-checking.
ast::NamedDecl* start_decl;
ast::NamedDecl* start_decl = nullptr;
ast::NamedDecl* decl = nullptr;

// Set during type-checking
bool is_value = false;
// represents tuple-like enum options, or tuple-like structs
bool is_ctor = false;

Path(const Loc& loc, std::vector<Elem>&& elems)
: Node(loc), elems(std::move(elems))
Path(const Loc& loc, bool is_use_path, std::vector<Elem>&& elems)
: Node(loc), is_use_path_(is_use_path), elems(std::move(elems))
{}

const artic::Type* infer(TypeChecker&, Ptr<Expr>*);
const artic::Type* infer(TypeChecker&, bool, Ptr<Expr>* = nullptr);
const artic::Type* infer(TypeChecker& checker) override {
return infer(checker, false, nullptr);
return infer(checker, nullptr);
}

const thorin::Def* emit(Emitter&) const override;
Expand Down Expand Up @@ -1472,6 +1487,8 @@ struct EnumDecl : public CtorDecl {
, options(std::move(options))
{}

std::optional<OptionDecl*> find_member(const std::string_view&) const;

const thorin::Def* emit(Emitter&) const override;
const artic::Type* infer(TypeChecker&) override;
void bind_head(NameBinder&) override;
Expand Down Expand Up @@ -1508,8 +1525,6 @@ struct ModDecl : public NamedDecl {
PtrVector<Decl> decls;
ModDecl* super = nullptr;

std::vector<const NamedDecl*> members;

/// Constructor for the implicitly defined global module.
/// When using this constructor, the user is responsible for calling
/// `set_super()` once the declarations have been added to the module.
Expand All @@ -1525,6 +1540,7 @@ struct ModDecl : public NamedDecl {
}

void set_super();
std::optional<NamedDecl*> find_member(const std::string_view& name) const;

const thorin::Def* emit(Emitter&) const override;
const artic::Type* infer(TypeChecker&) override;
Expand All @@ -1538,6 +1554,9 @@ struct ModDecl : public NamedDecl {
struct UseDecl : public NamedDecl {
Path path;

NamedDecl* bound_to;
PtrVector<UseDecl> wildcard_imports;

UseDecl(const Loc& loc, Path&& path, Identifier&& id)
: NamedDecl(loc, std::move(id)), path(std::move(path))
{}
Expand All @@ -1548,8 +1567,18 @@ struct UseDecl : public NamedDecl {
void bind(NameBinder&) override;
void resolve_summons(Summoner&) override {};
void print(Printer&) const override;

void bind_wildcard(NameBinder&);
};

static inline NamedDecl* resolve_use_decl(NamedDecl* decl) {
while (auto use_decl = decl->isa<UseDecl>()) {
assert(use_decl->bound_to && "run binding first");
decl = use_decl->bound_to;
}
return decl;
}

/// Incorrect declaration, coming from parsing.
struct ErrorDecl : public Decl {
ErrorDecl(const Loc& loc) : Decl(loc) {}
Expand Down
6 changes: 5 additions & 1 deletion include/artic/bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ namespace artic {
/// Binds identifiers to the nodes of the AST.
class NameBinder : public Logger {
public:
NameBinder(Log& log)
NameBinder(Log& log, Arena& arena)
: Logger(log)
, cur_fn(nullptr)
, cur_loop(nullptr)
, cur_mod(nullptr)
, arena_(arena)
{
push_scope(true);
}
Expand All @@ -35,6 +36,7 @@ class NameBinder : public Logger {
ast::FnExpr* cur_fn;
ast::LoopExpr* cur_loop;
ast::ModDecl* cur_mod;
Arena& arena_;

void bind_head(ast::Decl&);
void bind(ast::Node&);
Expand Down Expand Up @@ -73,6 +75,8 @@ class NameBinder : public Logger {
return best;
}

void unknown_member(const Loc&, const ast::NamedDecl*, const std::string_view&);

private:
// Levenshtein distance is used to suggest similar identifiers to the user
static constexpr size_t levenshtein_threshold() { return 3; }
Expand Down
2 changes: 2 additions & 0 deletions include/artic/check.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ class TypeChecker : public Logger {
bool infer_type_args(const Loc&, const ForallType*, const Type*, std::vector<const Type*>&);
const Type* infer_record_type(const TypeApp*, const StructType*, size_t&);

size_t path_to_size(ast::Path& path, const std::string_view&);

private:
std::unordered_set<const ast::Decl*> decls_;
Arena& _arena;
Expand Down
6 changes: 3 additions & 3 deletions include/artic/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ class Parser : public Logger {
Ptr<ast::AttrList> parse_attr_list();
Ptr<ast::Attr> parse_attr();

ast::Path parse_path(ast::Identifier&&, bool);
ast::Path parse_path(bool allow_types = true) { return parse_path(parse_path_elem(), allow_types); }
ast::Identifier parse_path_elem();
ast::Path parse_path(ast::Identifier&&, bool is_use_path);
ast::Path parse_path(bool is_use_path = false) { return parse_path(parse_path_elem(), is_use_path); }
ast::Identifier parse_path_elem(bool allow_wildcard = false);
ast::Identifier parse_id();
ast::AsmExpr::Constr parse_constr();
Literal parse_lit();
Expand Down
8 changes: 5 additions & 3 deletions src/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,9 +593,9 @@ bool ImplicitCastExpr::has_side_effect() const {
bool ImplicitCastExpr::is_constant() const {
assert(expr->type);
if (auto path_expr = expr->isa<PathExpr>();
path_expr && path_expr->path.elems.size() == 1 && path_expr->path.start_decl)
path_expr && path_expr->path.elems.back().decl)
{
if (auto static_decl = path_expr->path.start_decl->isa<StaticDecl>()) {
if (auto static_decl = path_expr->path.elems.back().decl->isa<StaticDecl>()) {
// Allow using other constant static declarations as constants
return !static_decl->is_mut;
}
Expand All @@ -607,6 +607,8 @@ bool AsmExpr::has_side_effect() const {
return !outs.empty() || std::find(opts.begin(), opts.end(), "volatile") != opts.end();
}

// Decls ---------------------------------------------------------------------------

// Patterns ------------------------------------------------------------------------

void Ptrn::collect_bound_ptrns(std::vector<const IdPtrn*>&) const {}
Expand Down Expand Up @@ -641,7 +643,7 @@ const Expr* IdPtrn::to_expr(Arena& arena) {
Identifier id = decl->id;
std::vector<Path::Elem> elems;
elems.push_back(Path::Elem( loc, std::move(id), {} ));
Path path = Path(loc, std::move(elems));
Path path = Path(loc, false, std::move(elems));
path.start_decl = decl.get();
path.is_value = true;
as_expr = arena.make_ptr<PathExpr>(std::move(path));
Expand Down
Loading