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 {
class Compiler::Alias {
public:
Alias(Node& parent, const Expression::Reader& targetName)
: targetName(targetName) {}
Alias(CompiledModule& module, Node& parent, const Expression::Reader& targetName)
: module(module), parent(parent), targetName(targetName) {}
Expression::Reader getTarget() { return targetName; }
kj::Maybe<NodeTranslator::Resolver::ResolveResult> compile();
private:
CompiledModule& module;
Node& parent;
Expression::Reader targetName;
kj::Maybe<NodeTranslator::Resolver::ResolveResult> target;
Orphan<schema::Brand> brandOrphan;
bool initialized = false;
};
class Compiler::Node: public NodeTranslator::Resolver {
......@@ -68,6 +73,7 @@ public:
// Create a dummy node representing a built-in declaration, like "Int32" or "true".
uint64_t getId() { return id; }
uint getParameterCount() { return genericParamCount; }
Declaration::Which getKind() { return kind; }
kj::Maybe<Schema> getBootstrapSchema();
......@@ -83,9 +89,10 @@ public:
// Report an error on this Node.
// implements NodeTranslator::Resolver -----------------------------
kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedParameter, ResolvedAlias>>
resolve(kj::StringPtr name) override;
kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedAlias>> resolveMember(kj::StringPtr name) override;
kj::Maybe<ResolveResult> resolve(kj::StringPtr name) override;
kj::Maybe<ResolveResult> resolveMember(kj::StringPtr name) override;
ResolvedDecl resolveBuiltin(Declaration::Which which) override;
ResolvedDecl resolveId(uint64_t id) override;
kj::Maybe<ResolvedDecl> getParent() override;
ResolvedDecl getTopScope() override;
kj::Maybe<Schema> resolveBootstrapSchema(
......@@ -297,6 +304,7 @@ public:
kj::Maybe<Node&> findNode(uint64_t id);
kj::Maybe<Node&> lookupBuiltin(kj::StringPtr name);
Node& getBuiltin(Declaration::Which which);
void load(const SchemaLoader& loader, uint64_t id) const override;
// SchemaLoader callback for the bootstrap loader.
......@@ -320,6 +328,7 @@ private:
// Map of nodes by ID.
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.
uint64_t nextBogusId = 1000;
......@@ -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)
: module(&module),
parent(nullptr),
......@@ -447,7 +480,7 @@ kj::Maybe<Compiler::Node::Content&> Compiler::Node::getContent(Content::State mi
case Declaration::USING: {
kj::Own<Alias> alias = arena.allocateOwn<Alias>(
*this, nestedDecl.getUsing().getTarget());
*module, *this, nestedDecl.getUsing().getTarget());
kj::StringPtr name = nestedDecl.getName().getValue();
content.aliases.insert(std::make_pair(name, kj::mv(alias)));
break;
......@@ -780,21 +813,11 @@ void Compiler::Node::addError(kj::StringPtr error) {
module->getErrorReporter().addError(startByte, endByte, error);
}
kj::Maybe<kj::OneOf<NodeTranslator::Resolver::ResolvedDecl,
NodeTranslator::Resolver::ResolvedParameter,
NodeTranslator::Resolver::ResolvedAlias>>
kj::Maybe<NodeTranslator::Resolver::ResolveResult>
Compiler::Node::resolve(kj::StringPtr name) {
typedef kj::OneOf<ResolvedDecl, ResolvedParameter, ResolvedAlias> Result;
// Check members.
KJ_IF_MAYBE(member, resolveMember(name)) {
Result result;
if (member->is<ResolvedDecl>()) {
result.init<ResolvedDecl>(kj::mv(member->get<ResolvedDecl>()));
} else {
result.init<ResolvedAlias>(kj::mv(member->get<ResolvedAlias>()));
}
return result;
return *member;
}
// Check parameters.
......@@ -802,7 +825,7 @@ Compiler::Node::resolve(kj::StringPtr name) {
auto params = declaration.getParameters();
for (uint i: kj::indices(params)) {
if (params[i].getName() == name) {
Result result;
ResolveResult result;
result.init<ResolvedParameter>(ResolvedParameter {id, i});
return result;
}
......@@ -812,7 +835,7 @@ Compiler::Node::resolve(kj::StringPtr name) {
KJ_IF_MAYBE(p, parent) {
return p->resolve(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 });
return result;
} else {
......@@ -820,19 +843,16 @@ Compiler::Node::resolve(kj::StringPtr name) {
}
}
kj::Maybe<kj::OneOf<NodeTranslator::Resolver::ResolvedDecl,
NodeTranslator::Resolver::ResolvedAlias>>
kj::Maybe<NodeTranslator::Resolver::ResolveResult>
Compiler::Node::resolveMember(kj::StringPtr name) {
if (isBuiltin) return nullptr;
typedef kj::OneOf<ResolvedDecl, ResolvedAlias> Result;
KJ_IF_MAYBE(content, getContent(Content::EXPANDED)) {
{
auto iter = content->nestedNodes.find(name);
if (iter != content->nestedNodes.end()) {
Node* node = iter->second;
Result result;
ResolveResult result;
result.init<ResolvedDecl>(ResolvedDecl {
node->id, node->genericParamCount, id, node->kind, node });
return result;
......@@ -841,15 +861,24 @@ Compiler::Node::resolveMember(kj::StringPtr name) {
{
auto iter = content->aliases.find(name);
if (iter != content->aliases.end()) {
Result result;
result.init<ResolvedAlias>(ResolvedAlias { iter->second->getTarget(), id, this });
return result;
return iter->second->compile();
}
}
}
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() {
return parent.map([](Node& parent) {
uint64_t scopeId = parent.parent.map([](Node& gp) { return gp.id; }).orDefault(0);
......@@ -1072,8 +1101,11 @@ Compiler::Impl::Impl(AnnotationFlag annotationFlag)
}
}
builtinDecls[symbolName] = nodeArena.allocateOwn<Node>(
symbolName, static_cast<Declaration::Which>(fieldProto.getDiscriminantValue()), params);
Declaration::Which which =
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) {
}
}
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) {
return addInternal(module).getRootNode().getId();
}
......
This diff is collapsed.
......@@ -41,6 +41,10 @@ class NodeTranslator {
public:
class Resolver {
// 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:
struct ResolvedDecl {
......@@ -49,6 +53,12 @@ public:
uint64_t scopeId;
Declaration::Which kind;
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 {
......@@ -56,23 +66,18 @@ public:
uint index; // Index of the parameter.
};
struct ResolvedAlias {
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.
};
typedef kj::OneOf<ResolvedDecl, ResolvedParameter> ResolveResult;
virtual kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedParameter, ResolvedAlias>>
resolve(kj::StringPtr name) = 0;
virtual kj::Maybe<ResolveResult> resolve(kj::StringPtr name) = 0;
// Look up the given name, relative to this node, and return basic information about the
// 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.
virtual ResolvedDecl resolveBuiltin(Declaration::Which which) = 0;
virtual ResolvedDecl resolveId(uint64_t id) = 0;
virtual kj::Maybe<ResolvedDecl> getParent() = 0;
// Returns the parent of this scope, or null if this is the top scope.
......@@ -141,6 +146,15 @@ public:
// Finish translating the node (including filling in all the pieces that are missing from the
// 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:
class DuplicateNameDetector;
class DuplicateOrdinalDetector;
......@@ -200,12 +214,9 @@ private:
// 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::Own<BrandScope> brand, Resolver& resolver);
// 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(BrandedDecl& decl, schema::Type::Builder target);
// Returns false if there was a problem, in which case value expressions of this type should
// not be parsed.
......
......@@ -524,6 +524,21 @@ struct TestGenerics(Foo, Bar) {
}
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) {
......@@ -551,6 +566,25 @@ struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") {
(value = (foo = "text", rev = (foo = (int16Field = 321))));
defaultWrapper2 @10 :TestGenericsWrapper2 =
(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 {}
......
......@@ -614,16 +614,19 @@ struct CopyConstructArray_<T, Iterator, false> {
};
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) {
ctor(*pos++, implicitCast<const T&>(*start++));
ctor(*pos++, *start++);
}
return pos;
} else {
// Crap. This is complicated.
ExceptionGuard guard(pos);
while (start != end) {
ctor(*guard.pos, implicitCast<const T&>(*start++));
ctor(*guard.pos, *start++);
++guard.pos;
}
guard.start = guard.pos;
......@@ -652,6 +655,13 @@ Array<T> heapArray(const T* content, size_t size) {
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>
Array<T> heapArray(ArrayPtr<T> content) {
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