Commit 9a0fced2 authored by Kenton Varda's avatar Kenton Varda

Generics: Refactor NodeTranslator and fix alias evaluation.

More refactoring is needed, but this at least makes "using" aliases work correctly with generics.
parent a19956a6
...@@ -37,13 +37,18 @@ namespace compiler { ...@@ -37,13 +37,18 @@ namespace compiler {
class Compiler::Alias { class Compiler::Alias {
public: public:
Alias(Node& parent, const Expression::Reader& targetName) Alias(CompiledModule& module, Node& parent, const Expression::Reader& targetName)
: targetName(targetName) {} : module(module), parent(parent), targetName(targetName) {}
Expression::Reader getTarget() { return targetName; } kj::Maybe<NodeTranslator::Resolver::ResolveResult> compile();
private: private:
CompiledModule& module;
Node& parent;
Expression::Reader targetName; Expression::Reader targetName;
kj::Maybe<NodeTranslator::Resolver::ResolveResult> target;
Orphan<schema::Brand> brandOrphan;
bool initialized = false;
}; };
class Compiler::Node: public NodeTranslator::Resolver { class Compiler::Node: public NodeTranslator::Resolver {
...@@ -68,6 +73,7 @@ public: ...@@ -68,6 +73,7 @@ public:
// Create a dummy node representing a built-in declaration, like "Int32" or "true". // Create a dummy node representing a built-in declaration, like "Int32" or "true".
uint64_t getId() { return id; } uint64_t getId() { return id; }
uint getParameterCount() { return genericParamCount; }
Declaration::Which getKind() { return kind; } Declaration::Which getKind() { return kind; }
kj::Maybe<Schema> getBootstrapSchema(); kj::Maybe<Schema> getBootstrapSchema();
...@@ -83,9 +89,10 @@ public: ...@@ -83,9 +89,10 @@ public:
// Report an error on this Node. // Report an error on this Node.
// implements NodeTranslator::Resolver ----------------------------- // implements NodeTranslator::Resolver -----------------------------
kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedParameter, ResolvedAlias>> kj::Maybe<ResolveResult> resolve(kj::StringPtr name) override;
resolve(kj::StringPtr name) override; kj::Maybe<ResolveResult> resolveMember(kj::StringPtr name) override;
kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedAlias>> resolveMember(kj::StringPtr name) override; ResolvedDecl resolveBuiltin(Declaration::Which which) override;
ResolvedDecl resolveId(uint64_t id) override;
kj::Maybe<ResolvedDecl> getParent() override; kj::Maybe<ResolvedDecl> getParent() override;
ResolvedDecl getTopScope() override; ResolvedDecl getTopScope() override;
kj::Maybe<Schema> resolveBootstrapSchema( kj::Maybe<Schema> resolveBootstrapSchema(
...@@ -297,6 +304,7 @@ public: ...@@ -297,6 +304,7 @@ public:
kj::Maybe<Node&> findNode(uint64_t id); kj::Maybe<Node&> findNode(uint64_t id);
kj::Maybe<Node&> lookupBuiltin(kj::StringPtr name); kj::Maybe<Node&> lookupBuiltin(kj::StringPtr name);
Node& getBuiltin(Declaration::Which which);
void load(const SchemaLoader& loader, uint64_t id) const override; void load(const SchemaLoader& loader, uint64_t id) const override;
// SchemaLoader callback for the bootstrap loader. // SchemaLoader callback for the bootstrap loader.
...@@ -320,6 +328,7 @@ private: ...@@ -320,6 +328,7 @@ private:
// Map of nodes by ID. // Map of nodes by ID.
std::map<kj::StringPtr, kj::Own<Node>> builtinDecls; std::map<kj::StringPtr, kj::Own<Node>> builtinDecls;
std::map<Declaration::Which, Node*> builtinDeclsByKind;
// Map of built-in declarations, like "Int32" and "List", which make up the global scope. // Map of built-in declarations, like "Int32" and "List", which make up the global scope.
uint64_t nextBogusId = 1000; uint64_t nextBogusId = 1000;
...@@ -328,6 +337,30 @@ private: ...@@ -328,6 +337,30 @@ private:
// ======================================================================================= // =======================================================================================
kj::Maybe<NodeTranslator::Resolver::ResolveResult> Compiler::Alias::compile() {
if (!initialized) {
initialized = true;
auto& workspace = module.getCompiler().getWorkspace();
brandOrphan = workspace.orphanage.newOrphan<schema::Brand>();
// If the Workspace is destroyed, revert the alias to the uninitialized state, because the
// orphan we created is no longer valid in this case.
workspace.arena.copy(kj::defer([this]() {
initialized = false;
brandOrphan = Orphan<schema::Brand>();
}));
target = NodeTranslator::compileDecl(
parent.getId(), parent.getParameterCount(), parent,
module.getErrorReporter(), targetName, brandOrphan.get());
}
return target;
}
// =======================================================================================
Compiler::Node::Node(CompiledModule& module) Compiler::Node::Node(CompiledModule& module)
: module(&module), : module(&module),
parent(nullptr), parent(nullptr),
...@@ -447,7 +480,7 @@ kj::Maybe<Compiler::Node::Content&> Compiler::Node::getContent(Content::State mi ...@@ -447,7 +480,7 @@ kj::Maybe<Compiler::Node::Content&> Compiler::Node::getContent(Content::State mi
case Declaration::USING: { case Declaration::USING: {
kj::Own<Alias> alias = arena.allocateOwn<Alias>( kj::Own<Alias> alias = arena.allocateOwn<Alias>(
*this, nestedDecl.getUsing().getTarget()); *module, *this, nestedDecl.getUsing().getTarget());
kj::StringPtr name = nestedDecl.getName().getValue(); kj::StringPtr name = nestedDecl.getName().getValue();
content.aliases.insert(std::make_pair(name, kj::mv(alias))); content.aliases.insert(std::make_pair(name, kj::mv(alias)));
break; break;
...@@ -780,21 +813,11 @@ void Compiler::Node::addError(kj::StringPtr error) { ...@@ -780,21 +813,11 @@ void Compiler::Node::addError(kj::StringPtr error) {
module->getErrorReporter().addError(startByte, endByte, error); module->getErrorReporter().addError(startByte, endByte, error);
} }
kj::Maybe<kj::OneOf<NodeTranslator::Resolver::ResolvedDecl, kj::Maybe<NodeTranslator::Resolver::ResolveResult>
NodeTranslator::Resolver::ResolvedParameter,
NodeTranslator::Resolver::ResolvedAlias>>
Compiler::Node::resolve(kj::StringPtr name) { Compiler::Node::resolve(kj::StringPtr name) {
typedef kj::OneOf<ResolvedDecl, ResolvedParameter, ResolvedAlias> Result;
// Check members. // Check members.
KJ_IF_MAYBE(member, resolveMember(name)) { KJ_IF_MAYBE(member, resolveMember(name)) {
Result result; return *member;
if (member->is<ResolvedDecl>()) {
result.init<ResolvedDecl>(kj::mv(member->get<ResolvedDecl>()));
} else {
result.init<ResolvedAlias>(kj::mv(member->get<ResolvedAlias>()));
}
return result;
} }
// Check parameters. // Check parameters.
...@@ -802,7 +825,7 @@ Compiler::Node::resolve(kj::StringPtr name) { ...@@ -802,7 +825,7 @@ Compiler::Node::resolve(kj::StringPtr name) {
auto params = declaration.getParameters(); auto params = declaration.getParameters();
for (uint i: kj::indices(params)) { for (uint i: kj::indices(params)) {
if (params[i].getName() == name) { if (params[i].getName() == name) {
Result result; ResolveResult result;
result.init<ResolvedParameter>(ResolvedParameter {id, i}); result.init<ResolvedParameter>(ResolvedParameter {id, i});
return result; return result;
} }
...@@ -812,7 +835,7 @@ Compiler::Node::resolve(kj::StringPtr name) { ...@@ -812,7 +835,7 @@ Compiler::Node::resolve(kj::StringPtr name) {
KJ_IF_MAYBE(p, parent) { KJ_IF_MAYBE(p, parent) {
return p->resolve(name); return p->resolve(name);
} else KJ_IF_MAYBE(b, module->getCompiler().lookupBuiltin(name)) { } else KJ_IF_MAYBE(b, module->getCompiler().lookupBuiltin(name)) {
Result result; ResolveResult result;
result.init<ResolvedDecl>(ResolvedDecl { b->id, b->genericParamCount, 0, b->kind, b }); result.init<ResolvedDecl>(ResolvedDecl { b->id, b->genericParamCount, 0, b->kind, b });
return result; return result;
} else { } else {
...@@ -820,19 +843,16 @@ Compiler::Node::resolve(kj::StringPtr name) { ...@@ -820,19 +843,16 @@ Compiler::Node::resolve(kj::StringPtr name) {
} }
} }
kj::Maybe<kj::OneOf<NodeTranslator::Resolver::ResolvedDecl, kj::Maybe<NodeTranslator::Resolver::ResolveResult>
NodeTranslator::Resolver::ResolvedAlias>>
Compiler::Node::resolveMember(kj::StringPtr name) { Compiler::Node::resolveMember(kj::StringPtr name) {
if (isBuiltin) return nullptr; if (isBuiltin) return nullptr;
typedef kj::OneOf<ResolvedDecl, ResolvedAlias> Result;
KJ_IF_MAYBE(content, getContent(Content::EXPANDED)) { KJ_IF_MAYBE(content, getContent(Content::EXPANDED)) {
{ {
auto iter = content->nestedNodes.find(name); auto iter = content->nestedNodes.find(name);
if (iter != content->nestedNodes.end()) { if (iter != content->nestedNodes.end()) {
Node* node = iter->second; Node* node = iter->second;
Result result; ResolveResult result;
result.init<ResolvedDecl>(ResolvedDecl { result.init<ResolvedDecl>(ResolvedDecl {
node->id, node->genericParamCount, id, node->kind, node }); node->id, node->genericParamCount, id, node->kind, node });
return result; return result;
...@@ -841,15 +861,24 @@ Compiler::Node::resolveMember(kj::StringPtr name) { ...@@ -841,15 +861,24 @@ Compiler::Node::resolveMember(kj::StringPtr name) {
{ {
auto iter = content->aliases.find(name); auto iter = content->aliases.find(name);
if (iter != content->aliases.end()) { if (iter != content->aliases.end()) {
Result result; return iter->second->compile();
result.init<ResolvedAlias>(ResolvedAlias { iter->second->getTarget(), id, this });
return result;
} }
} }
} }
return nullptr; return nullptr;
} }
NodeTranslator::Resolver::ResolvedDecl Compiler::Node::resolveBuiltin(Declaration::Which which) {
auto& b = module->getCompiler().getBuiltin(which);
return { b.id, b.genericParamCount, 0, b.kind, &b };
}
NodeTranslator::Resolver::ResolvedDecl Compiler::Node::resolveId(uint64_t id) {
auto& n = KJ_ASSERT_NONNULL(module->getCompiler().findNode(id));
uint64_t parentId = n.parent.map([](Node& n) { return n.id; }).orDefault(0);
return { n.id, n.genericParamCount, parentId, n.kind, &n };
}
kj::Maybe<NodeTranslator::Resolver::ResolvedDecl> Compiler::Node::getParent() { kj::Maybe<NodeTranslator::Resolver::ResolvedDecl> Compiler::Node::getParent() {
return parent.map([](Node& parent) { return parent.map([](Node& parent) {
uint64_t scopeId = parent.parent.map([](Node& gp) { return gp.id; }).orDefault(0); uint64_t scopeId = parent.parent.map([](Node& gp) { return gp.id; }).orDefault(0);
...@@ -1072,8 +1101,11 @@ Compiler::Impl::Impl(AnnotationFlag annotationFlag) ...@@ -1072,8 +1101,11 @@ Compiler::Impl::Impl(AnnotationFlag annotationFlag)
} }
} }
builtinDecls[symbolName] = nodeArena.allocateOwn<Node>( Declaration::Which which =
symbolName, static_cast<Declaration::Which>(fieldProto.getDiscriminantValue()), params); static_cast<Declaration::Which>(fieldProto.getDiscriminantValue());
kj::Own<Node> newNode = nodeArena.allocateOwn<Node>(symbolName, which, params);
builtinDeclsByKind[which] = newNode;
builtinDecls[symbolName] = kj::mv(newNode);
} }
} }
} }
...@@ -1135,6 +1167,12 @@ kj::Maybe<Compiler::Node&> Compiler::Impl::lookupBuiltin(kj::StringPtr name) { ...@@ -1135,6 +1167,12 @@ kj::Maybe<Compiler::Node&> Compiler::Impl::lookupBuiltin(kj::StringPtr name) {
} }
} }
Compiler::Node& Compiler::Impl::getBuiltin(Declaration::Which which) {
auto iter = builtinDeclsByKind.find(which);
KJ_REQUIRE(iter != builtinDeclsByKind.end(), "invalid builtin", (uint)which);
return *iter->second;
}
uint64_t Compiler::Impl::add(Module& module) { uint64_t Compiler::Impl::add(Module& module) {
return addInternal(module).getRootNode().getId(); return addInternal(module).getRootNode().getId();
} }
......
This diff is collapsed.
...@@ -41,6 +41,10 @@ class NodeTranslator { ...@@ -41,6 +41,10 @@ class NodeTranslator {
public: public:
class Resolver { class Resolver {
// Callback class used to find other nodes relative to this one. // Callback class used to find other nodes relative to this one.
//
// TODO(cleanup): This has evolved into being a full interface for traversing the node tree.
// Maybe we should rename it as such, and move it out of NodeTranslator. See also
// TODO(cleanup) on NodeTranslator::BrandedDecl.
public: public:
struct ResolvedDecl { struct ResolvedDecl {
...@@ -49,6 +53,12 @@ public: ...@@ -49,6 +53,12 @@ public:
uint64_t scopeId; uint64_t scopeId;
Declaration::Which kind; Declaration::Which kind;
Resolver* resolver; Resolver* resolver;
kj::Maybe<schema::Brand::Reader> brand;
// If present, then it is necessary to replace the brand scope with the given brand before
// using the target type. This happens when the decl resolved to an alias; all other fields
// of `ResolvedDecl` refer to the target of the alias, except for `scopeId` which is the
// scope that contained the alias.
}; };
struct ResolvedParameter { struct ResolvedParameter {
...@@ -56,23 +66,18 @@ public: ...@@ -56,23 +66,18 @@ public:
uint index; // Index of the parameter. uint index; // Index of the parameter.
}; };
struct ResolvedAlias { typedef kj::OneOf<ResolvedDecl, ResolvedParameter> ResolveResult;
Expression::Reader value;
uint64_t scopeId;
Resolver* scope;
// TODO(now): Returning an Expression from some other file is wrong wrong wrong. We need
// to compile the alias down to an id + brand.
};
virtual kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedParameter, ResolvedAlias>> virtual kj::Maybe<ResolveResult> resolve(kj::StringPtr name) = 0;
resolve(kj::StringPtr name) = 0;
// Look up the given name, relative to this node, and return basic information about the // Look up the given name, relative to this node, and return basic information about the
// target. // target.
virtual kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedAlias>> resolveMember(kj::StringPtr name) = 0; virtual kj::Maybe<ResolveResult> resolveMember(kj::StringPtr name) = 0;
// Look up a member of this node. // Look up a member of this node.
virtual ResolvedDecl resolveBuiltin(Declaration::Which which) = 0;
virtual ResolvedDecl resolveId(uint64_t id) = 0;
virtual kj::Maybe<ResolvedDecl> getParent() = 0; virtual kj::Maybe<ResolvedDecl> getParent() = 0;
// Returns the parent of this scope, or null if this is the top scope. // Returns the parent of this scope, or null if this is the top scope.
...@@ -141,6 +146,15 @@ public: ...@@ -141,6 +146,15 @@ public:
// Finish translating the node (including filling in all the pieces that are missing from the // Finish translating the node (including filling in all the pieces that are missing from the
// bootstrap node) and return it. // bootstrap node) and return it.
static kj::Maybe<Resolver::ResolveResult> compileDecl(
uint64_t scopeId, uint scopeParameterCount, Resolver& resolver, ErrorReporter& errorReporter,
Expression::Reader expression, schema::Brand::Builder brandBuilder);
// Compile a one-off declaration expression without building a NodeTranslator. Used for
// evaluating aliases.
//
// `brandBuilder` may be used to construct a message which will fill in ResolvedDecl::brand in
// the result.
private: private:
class DuplicateNameDetector; class DuplicateNameDetector;
class DuplicateOrdinalDetector; class DuplicateOrdinalDetector;
...@@ -200,12 +214,9 @@ private: ...@@ -200,12 +214,9 @@ private:
// Compile a param (or result) list and return the type ID of the struct type. // Compile a param (or result) list and return the type ID of the struct type.
kj::Maybe<BrandedDecl> compileDeclExpression(Expression::Reader source); kj::Maybe<BrandedDecl> compileDeclExpression(Expression::Reader source);
kj::Maybe<BrandedDecl> compileDeclExpression(
Expression::Reader source, kj::Own<BrandScope> brand, Resolver& resolver);
// Compile an expression which is expected to resolve to a declaration or type expression. // Compile an expression which is expected to resolve to a declaration or type expression.
bool compileType(Expression::Reader source, schema::Type::Builder target); bool compileType(Expression::Reader source, schema::Type::Builder target);
bool compileType(BrandedDecl& decl, schema::Type::Builder target);
// Returns false if there was a problem, in which case value expressions of this type should // Returns false if there was a problem, in which case value expressions of this type should
// not be parsed. // not be parsed.
......
...@@ -524,6 +524,21 @@ struct TestGenerics(Foo, Bar) { ...@@ -524,6 +524,21 @@ struct TestGenerics(Foo, Bar) {
} }
annotation ann(struct) :Foo; annotation ann(struct) :Foo;
using AliasFoo = Foo;
using AliasInner = Inner;
using AliasInner2 = Inner2;
using AliasInner2Text = Inner2(Text);
using AliasRev = TestGenerics(Bar, Foo);
struct UseAliases {
foo @0 :AliasFoo;
inner @1 :AliasInner;
inner2 @2 :AliasInner2;
inner2Bind @3 :AliasInner2(Text);
inner2Text @4 :AliasInner2Text;
revFoo @5 :AliasRev.AliasFoo;
}
} }
struct TestGenericsWrapper(Foo, Bar) { struct TestGenericsWrapper(Foo, Bar) {
...@@ -551,6 +566,25 @@ struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") { ...@@ -551,6 +566,25 @@ struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") {
(value = (foo = "text", rev = (foo = (int16Field = 321)))); (value = (foo = "text", rev = (foo = (int16Field = 321))));
defaultWrapper2 @10 :TestGenericsWrapper2 = defaultWrapper2 @10 :TestGenericsWrapper2 =
(value = (value = (foo = "text", rev = (foo = (int16Field = 321))))); (value = (value = (foo = "text", rev = (foo = (int16Field = 321)))));
aliasFoo @11 :TestGenerics(TestAllTypes, TestAnyPointer).AliasFoo = (int16Field = 123);
aliasInner @12 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner
= (foo = (int16Field = 123));
aliasInner2 @13 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2
= (innerBound = (foo = (int16Field = 123)));
aliasInner2Bind @14 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2(List(UInt32))
= (baz = [12, 34], innerBound = (foo = (int16Field = 123)));
aliasInner2Text @15 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2Text
= (baz = "text", innerBound = (foo = (int16Field = 123)));
aliasRev @16 :TestGenerics(TestAnyPointer, Text).AliasRev.AliasFoo = "text";
useAliases @17 :TestGenerics(TestAllTypes, List(UInt32)).UseAliases = (
foo = (int16Field = 123),
inner = (foo = (int16Field = 123)),
inner2 = (innerBound = (foo = (int16Field = 123))),
inner2Bind = (baz = "text", innerBound = (foo = (int16Field = 123))),
inner2Text = (baz = "text", innerBound = (foo = (int16Field = 123))),
revFoo = [12, 34, 56]);
} }
struct TestEmptyStruct {} struct TestEmptyStruct {}
......
...@@ -614,16 +614,19 @@ struct CopyConstructArray_<T, Iterator, false> { ...@@ -614,16 +614,19 @@ struct CopyConstructArray_<T, Iterator, false> {
}; };
static T* apply(T* __restrict__ pos, Iterator start, Iterator end) { static T* apply(T* __restrict__ pos, Iterator start, Iterator end) {
if (noexcept(T(instance<const T&>()))) { // Verify that T can be *implicitly* constructed from the source values.
if (false) implicitCast<T>(*start);
if (noexcept(T(*start))) {
while (start != end) { while (start != end) {
ctor(*pos++, implicitCast<const T&>(*start++)); ctor(*pos++, *start++);
} }
return pos; return pos;
} else { } else {
// Crap. This is complicated. // Crap. This is complicated.
ExceptionGuard guard(pos); ExceptionGuard guard(pos);
while (start != end) { while (start != end) {
ctor(*guard.pos, implicitCast<const T&>(*start++)); ctor(*guard.pos, *start++);
++guard.pos; ++guard.pos;
} }
guard.start = guard.pos; guard.start = guard.pos;
...@@ -652,6 +655,13 @@ Array<T> heapArray(const T* content, size_t size) { ...@@ -652,6 +655,13 @@ Array<T> heapArray(const T* content, size_t size) {
return builder.finish(); return builder.finish();
} }
template <typename T>
Array<T> heapArray(T* content, size_t size) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(size);
builder.addAll(content, content + size);
return builder.finish();
}
template <typename T> template <typename T>
Array<T> heapArray(ArrayPtr<T> content) { Array<T> heapArray(ArrayPtr<T> content) {
ArrayBuilder<T> builder = heapArrayBuilder<T>(content.size()); ArrayBuilder<T> builder = heapArrayBuilder<T>(content.size());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment