Skip to content

Commit

Permalink
move the is_value logic out of Path::infer
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugobros3 committed Jul 5, 2024
1 parent 590131a commit e3c60f4
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 76 deletions.
5 changes: 3 additions & 2 deletions include/artic/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,10 @@ struct Path : public Node {
: Node(loc), elems(std::move(elems))
{}

const artic::Type* infer(TypeChecker&, std::optional<bool>, Ptr<Expr>* = nullptr);
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, std::nullopt, nullptr);
return infer(checker, nullptr);
}

const thorin::Def* emit(Emitter&) const override;
Expand Down
97 changes: 49 additions & 48 deletions src/bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,55 +69,56 @@ void Path::bind(NameBinder& binder) {
decl = binder.cur_mod;
for (auto& elem : elems) {
assert(decl);
//while (auto use = decl->isa<UseDecl>()) {
// decl = use.decl;
//}

if (elem.id.name[0] == '_')
binder.error(elem.id.loc, "identifiers beginning with '_' cannot be referenced");
else if (elem.is_super()) {
if (auto mod = decl->isa<ModDecl>()) {
if (!mod->super)
binder.error(elem.id.loc, "top-level module has no super-module");
else
decl = mod->super;
} else
binder.error(elem.id.loc, "''super' can only be used on modules");
} else if (elem.is_wildcard()) {
if (!start_decl) {
binder.error(elem.loc, "wildcards cannot appear at the start of a path!");
return;
}
decl = nullptr;
} else if (decl == binder.cur_mod) {
auto symbol = binder.find_symbol(elem.id.name);
if (!symbol) {
binder.error(elem.id.loc, "unknown identifier '{}'", elem.id.name);
if (auto similar = binder.find_similar_symbol(elem.id.name))
binder.note("did you mean '{}'?", similar->decl->id.name);
} else
decl = symbol->decl;
} else if (auto mod = decl->isa<ModDecl>()) {
auto member = mod->find_member(elem.id.name);
if (!member) {
binder.unknown_member(elem.loc, mod, elem.id.name);
return;
}
decl = *member;
} else if (auto use = decl->isa<UseDecl>()) {
binder.bind(*use);
assert(use->bound_to);
decl = use->bound_to;
} else if (auto enu = decl->isa<EnumDecl>()) {
auto found = enu->find_member(elem.id.name);
if (!found) {
binder.unknown_member(elem.loc, mod, elem.id.name);
return;

while (true) {
if (elem.id.name[0] == '_')
binder.error(elem.id.loc, "identifiers beginning with '_' cannot be referenced");
else if (elem.is_super()) {
if (auto mod = decl->isa<ModDecl>()) {
if (!mod->super)
binder.error(elem.id.loc, "top-level module has no super-module");
else
decl = mod->super;
} else
binder.error(elem.id.loc, "''super' can only be used on modules");
} else if (elem.is_wildcard()) {
if (!start_decl) {
binder.error(elem.loc, "wildcards cannot appear at the start of a path!");
return;
}
decl = nullptr;
} else if (decl == binder.cur_mod) {
auto symbol = binder.find_symbol(elem.id.name);
if (!symbol) {
binder.error(elem.id.loc, "unknown identifier '{}'", elem.id.name);
if (auto similar = binder.find_similar_symbol(elem.id.name))
binder.note("did you mean '{}'?", similar->decl->id.name);
} else
decl = symbol->decl;
} else if (auto mod = decl->isa<ModDecl>()) {
auto member = mod->find_member(elem.id.name);
if (!member) {
binder.unknown_member(elem.loc, mod, elem.id.name);
return;
}
decl = *member;
} else if (auto use = decl->isa<UseDecl>()) {
binder.bind(*use);
assert(use->bound_to);
decl = use->bound_to;
continue;
} else if (auto enu = decl->isa<EnumDecl>()) {
auto found = enu->find_member(elem.id.name);
if (!found) {
binder.unknown_member(elem.loc, mod, elem.id.name);
return;
}
decl = *found;
} else {
// ...
assert(false);
}
decl = *found;
} else {
// ...
assert(false);
break;
}

if (!start_decl)
Expand Down
54 changes: 31 additions & 23 deletions src/check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,11 +625,11 @@ const artic::Type* Ptrn::check(TypeChecker& checker, const artic::Type* expected

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

const artic::Type* Path::infer(TypeChecker& checker, std::optional<bool> value_expected, Ptr<Expr>* arg) {
if (!start_decl)
return checker.type_table.type_error();
if (elems.back().id.name == "*")
const artic::Type* Path::infer(TypeChecker& checker, Ptr<Expr>* arg) {
if (elems.back().is_wildcard())
return nullptr;
if (!decl)
return checker.type_table.type_error();

type = elems[0].is_super()
? checker.type_table.mod_type(*start_decl->as<ModDecl>())
Expand Down Expand Up @@ -673,21 +673,6 @@ const artic::Type* Path::infer(TypeChecker& checker, std::optional<bool> value_e
}
elem.type = type;

// Treat tuple-like structure constructors as functions
if (auto [type_app, struct_type] = match_app<StructType>(type);
is_ctor && (*value_expected && value_expected) && struct_type && struct_type->is_tuple_like()) {
if (struct_type->member_count() > 0) {
SmallArray<const artic::Type*> tuple_args(struct_type->member_count());
for (size_t i = 0, n = struct_type->member_count(); i < n; ++i)
tuple_args[i] = member_type(type_app, struct_type, i);
auto dom = struct_type->member_count() == 1
? tuple_args.front()
: checker.type_table.tuple_type(tuple_args);
type = checker.type_table.fn_type(dom, type);
}
is_value = true;
}

// Perform a lookup inside the current object if the path is not finished
if (i != n - 1) {
if (elems[i + 1].is_super()) {
Expand Down Expand Up @@ -730,10 +715,32 @@ const artic::Type* Path::infer(TypeChecker& checker, std::optional<bool> value_e
}
}

if (value_expected && is_value != *value_expected) {
checker.error(loc, "{} expected, but got '{}'", *value_expected ? "value" : "type", *this);
return type;
}

const artic::Type* Path::infer(artic::TypeChecker& checker, bool value_expected, Ptr<artic::ast::Expr>* arg) {
infer(checker, arg);

// Treat tuple-like structure constructors as functions
if (auto [type_app, struct_type] = match_app<StructType>(type);
is_ctor && value_expected && struct_type && struct_type->is_tuple_like()) {
if (struct_type->member_count() > 0) {
SmallArray<const artic::Type*> tuple_args(struct_type->member_count());
for (size_t i = 0, n = struct_type->member_count(); i < n; ++i)
tuple_args[i] = member_type(type_app, struct_type, i);
auto dom = struct_type->member_count() == 1
? tuple_args.front()
: checker.type_table.tuple_type(tuple_args);
type = checker.type_table.fn_type(dom, type);
}
is_value = true;
}

if (is_value != value_expected) {
checker.error(loc, "{} expected, but got '{}'", value_expected ? "value" : "type", *this);
return checker.type_table.type_error();
}

return type;
}

Expand Down Expand Up @@ -1732,7 +1739,8 @@ const artic::Type* UseDecl::infer(TypeChecker& checker) {
if (!checker.enter_decl(this))
return checker.type_table.type_error();
auto path_type = checker.infer(path);
is_value_ = path.is_value;
if (path.decl)
is_value_ = path.decl->is_value();
checker.exit_decl(this);
return path_type;
}
Expand Down Expand Up @@ -1798,7 +1806,7 @@ const artic::Type* RecordPtrn::infer(TypeChecker& checker) {

const artic::Type* CtorPtrn::infer(TypeChecker& checker) {
auto path_type = path.infer(checker, true);
if (!path.is_ctor) {
if (!path.decl->isa<CtorDecl>()) {
checker.error(path.loc, "structure or enumeration constructor expected");
return checker.type_table.type_error();
}
Expand Down
11 changes: 8 additions & 3 deletions src/emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1071,10 +1071,12 @@ const thorin::Def* Path::emit(Emitter& emitter) const {
for (size_t i = 0, n = elems.size(); i < n; ++i) {
if (elems[i].is_super())
decl = i == 0 ? start_decl : decl->as<ModDecl>()->super;
if (elems[i].is_wildcard())
return nullptr;

if (auto mod_type = elems[i].type->isa<ModType>()) {
decl = &mod_type->member(elems[i + 1].index);
} else if (!is_ctor) {
} else if (!elems[i].decl->isa<CtorDecl>()) {
// If type arguments are present, this is a polymorphic application
std::unordered_map<const artic::TypeVar*, const artic::Type*> map;
if (!elems[i].inferred_args.empty()) {
Expand Down Expand Up @@ -1756,14 +1758,17 @@ const thorin::Def* ModDecl::emit(Emitter& emitter) const {
// Likewise, we do not emit implicit declarations
if (auto implicit = decl->isa<ImplicitDecl>())
continue;
// Don't emit use declarations: they might point to modules. When used in expressions we'll emit them.
if (auto implicit = decl->isa<UseDecl>())
continue;
emitter.emit(*decl);
}
return nullptr;
}

const thorin::Def* UseDecl::emit(Emitter& emitter) const {
if (path.is_value)
return path.emit(emitter);
if (path.decl)
return emitter.emit(*path.decl);
return nullptr;
}

Expand Down

0 comments on commit e3c60f4

Please sign in to comment.