Commit 87ea5bdb authored by Kenton Varda's avatar Kenton Varda

Generics: Schema/dynamic API support.

parent d7b612a1
......@@ -30,7 +30,7 @@ static const ::capnp::_::AlignedData<21> b_b9c6f99ebf805f2c = {
};
const ::capnp::_::RawSchema s_b9c6f99ebf805f2c = {
0xb9c6f99ebf805f2c, b_b9c6f99ebf805f2c.words, 21, nullptr, nullptr,
0, 0, nullptr, nullptr, nullptr
0, 0, nullptr, nullptr, nullptr, { &s_b9c6f99ebf805f2c, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<20> b_f264a779fef191ce = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -56,7 +56,7 @@ static const ::capnp::_::AlignedData<20> b_f264a779fef191ce = {
};
const ::capnp::_::RawSchema s_f264a779fef191ce = {
0xf264a779fef191ce, b_f264a779fef191ce.words, 20, nullptr, nullptr,
0, 0, nullptr, nullptr, nullptr
0, 0, nullptr, nullptr, nullptr, { &s_f264a779fef191ce, nullptr, nullptr, 0, 0, nullptr }
};
} // namespace schemas
namespace _ { // private
......
......@@ -1005,8 +1005,6 @@ public:
// Set up stuff for the ValueTranslator.
ValueResolverGlue resolver(compiler->getLoader(), errorReporter);
auto type = arena.getOrphanage().newOrphan<schema::Type>();
type.get().initStruct().setTypeId(rootType.getProto().getId());
// Set up output stream.
kj::FdOutputStream rawOutput(STDOUT_FILENO);
......@@ -1019,7 +1017,7 @@ public:
segmentSize == 0 ? SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy::FIXED_SIZE);
ValueTranslator translator(resolver, errorReporter, item.getOrphanage());
KJ_IF_MAYBE(value, translator.compileValue(expression->getReader(), type.getReader())) {
KJ_IF_MAYBE(value, translator.compileValue(expression->getReader(), rootType)) {
if (segmentSize == 0) {
writeFlat(value->getReader().as<DynamicStruct>(), output);
} else {
......
......@@ -1679,7 +1679,7 @@ private:
membersByName.size() == 0 ? kj::strTree("nullptr") : kj::strTree("m_", hexId), ",\n",
" ", deps.size(), ", ", membersByName.size(), ", ",
membersByDiscrim.size() == 0 ? kj::strTree("nullptr") : kj::strTree("i_", hexId),
", nullptr, nullptr\n"
", nullptr, nullptr, { &s_", hexId, ", nullptr, nullptr, 0, 0, nullptr }\n"
"};\n");
NodeTextNoSchema top = makeNodeTextWithoutNested(
......
......@@ -122,7 +122,16 @@ private:
std::map<uint64_t, List<schema::TypeEnvironment::Binding>::Reader> scopeBindings;
for (auto scopeEnv: env.getScopes()) {
scopeBindings[scopeEnv.getScopeId()] = scopeEnv.getBindings();
switch (scopeEnv.which()) {
case schema::TypeEnvironment::Scope::BIND:
scopeBindings[scopeEnv.getScopeId()] = scopeEnv.getBind();
break;
case schema::TypeEnvironment::Scope::INHERIT:
// TODO(someday): We need to pay attention to INHERIT and be sure to explicitly override
// any bindings that are not inherited. This requires a way to determine which of our
// parent scopes have a non-empty parameter list.
break;
}
}
{
......@@ -283,7 +292,7 @@ private:
return true;
}
kj::StringTree genValue(schema::Type::Reader type, schema::Value::Reader value, Schema scope) {
kj::StringTree genValue(Type type, schema::Value::Reader value) {
switch (value.which()) {
case schema::Value::VOID: return kj::strTree("void");
case schema::Value::BOOL:
......@@ -303,23 +312,19 @@ private:
case schema::Value::DATA:
return kj::strTree(DynamicValue::Reader(value.getData()));
case schema::Value::LIST: {
KJ_REQUIRE(type.isList(), "type/value mismatch");
auto listValue = value.getList().getAs<DynamicList>(
ListSchema::of(type.getList().getElementType(), scope));
auto listValue = value.getList().getAs<DynamicList>(type.asList());
return kj::strTree(listValue);
}
case schema::Value::ENUM: {
KJ_REQUIRE(type.isEnum(), "type/value mismatch");
auto enumNode = schemaLoader.get(type.getEnum().getTypeId()).asEnum().getProto();
auto enumNode = type.asEnum().getProto();
auto enumerants = enumNode.getEnum().getEnumerants();
KJ_REQUIRE(value.getEnum() < enumerants.size(),
"Enum value out-of-range.", value.getEnum(), enumNode.getDisplayName());
return kj::strTree(enumerants[value.getEnum()].getName());
}
case schema::Value::STRUCT: {
KJ_REQUIRE(type.isStruct(), "type/value mismatch");
auto structValue = value.getStruct().getAs<DynamicStruct>(
schemaLoader.get(type.getStruct().getTypeId()).asStruct());
KJ_REQUIRE(type.which() == schema::Type::STRUCT, "type/value mismatch");
auto structValue = value.getStruct().getAs<DynamicStruct>(type.asStruct());
return kj::strTree(structValue);
}
case schema::Value::INTERFACE: {
......@@ -348,12 +353,13 @@ private:
kj::StringTree genAnnotation(schema::Annotation::Reader annotation,
Schema scope,
const char* prefix = " ", const char* suffix = "") {
auto decl = schemaLoader.get(annotation.getId());
auto decl = schemaLoader.get(annotation.getId(), annotation.getTypeEnvironment(), scope);
auto proto = decl.getProto();
KJ_REQUIRE(proto.isAnnotation());
auto annDecl = proto.getAnnotation();
auto value = genValue(annDecl.getType(), annotation.getValue(), decl).flatten();
auto value = genValue(schemaLoader.getType(annDecl.getType(), decl),
annotation.getValue()).flatten();
if (value.startsWith("(")) {
return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getTypeEnvironment()),
value, suffix);
......@@ -419,42 +425,42 @@ private:
return kj::strTree(
indent, "union { # tag bits [", offset * 16, ", ", offset * 16 + 16, ")\n",
KJ_MAP(uField, unionFields) {
return genStructField(uField.getProto(), schema, indent.next());
return genStructField(uField, schema, indent.next());
},
indent, "}\n");
}
} else {
return genStructField(field.getProto(), schema, indent);
return genStructField(field, schema, indent);
}
};
}
kj::StringTree genStructField(schema::Field::Reader field, Schema scope, Indent indent) {
switch (field.which()) {
kj::StringTree genStructField(StructSchema::Field field, Schema scope, Indent indent) {
auto proto = field.getProto();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = field.getSlot();
auto slot = proto.getSlot();
int size = typeSizeBits(slot.getType());
return kj::strTree(
indent, field.getName(), " @", field.getOrdinal().getExplicit(),
indent, proto.getName(), " @", proto.getOrdinal().getExplicit(),
" :", genType(slot.getType(), scope),
isEmptyValue(slot.getDefaultValue()) ? kj::strTree("") :
kj::strTree(" = ", genValue(
slot.getType(), slot.getDefaultValue(), scope)),
genAnnotations(field.getAnnotations(), scope),
kj::strTree(" = ", genValue(field.getType(), slot.getDefaultValue())),
genAnnotations(proto.getAnnotations(), scope),
"; # ", size == -1 ? kj::strTree("ptr[", slot.getOffset(), "]")
: kj::strTree("bits[", slot.getOffset() * size, ", ",
(slot.getOffset() + 1) * size, ")"),
hasDiscriminantValue(field)
? kj::strTree(", union tag = ", field.getDiscriminantValue()) : kj::strTree(),
hasDiscriminantValue(proto)
? kj::strTree(", union tag = ", proto.getDiscriminantValue()) : kj::strTree(),
"\n");
}
case schema::Field::GROUP: {
auto group = schemaLoader.get(field.getGroup().getTypeId()).asStruct();
auto group = field.getType().asStruct();
return kj::strTree(
indent, field.getName(),
" :group", genAnnotations(field.getAnnotations(), scope), " {",
hasDiscriminantValue(field)
? kj::strTree(" # union tag = ", field.getDiscriminantValue()) : kj::strTree(),
indent, proto.getName(),
" :group", genAnnotations(proto.getAnnotations(), scope), " {",
hasDiscriminantValue(proto)
? kj::strTree(" # union tag = ", proto.getDiscriminantValue()) : kj::strTree(),
"\n",
genStructFields(group, indent.next()),
indent, "}\n");
......@@ -475,8 +481,7 @@ private:
return kj::strTree(
proto.getName(), " :", genType(slot.getType(), interface),
isEmptyValue(slot.getDefaultValue()) ? kj::strTree("") :
kj::strTree(" = ", genValue(
slot.getType(), slot.getDefaultValue(), interface)),
kj::strTree(" = ", genValue(field.getType(), slot.getDefaultValue())),
genAnnotations(proto.getAnnotations(), interface));
}, ", "), ")");
} else {
......@@ -518,7 +523,8 @@ private:
structProto.getPointerCount(), " ptrs",
structProto.getPreferredListEncoding() == schema::ElementSize::INLINE_COMPOSITE
? kj::strTree()
: kj::strTree(", packed as ", elementSizeName(structProto.getPreferredListEncoding())),
: kj::strTree(", packed as ",
elementSizeName(structProto.getPreferredListEncoding())),
"\n",
genStructFields(schema.asStruct(), indent.next()),
genNestedDecls(schema, indent.next()),
......@@ -560,7 +566,7 @@ private:
return kj::strTree(
indent, "const ", name, " @0x", kj::hex(proto.getId()), " :",
genType(constProto.getType(), schema), " = ",
genValue(constProto.getType(), constProto.getValue(), schema),
genValue(schema.asConst().getType(), constProto.getValue()),
genAnnotations(schema), ";\n");
}
case schema::Node::ANNOTATION: {
......
......@@ -86,10 +86,13 @@ public:
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<ResolvedDecl> getParent() override;
ResolvedDecl getTopScope() override;
kj::Maybe<Schema> resolveBootstrapSchema(uint64_t id) override;
kj::Maybe<Schema> resolveBootstrapSchema(
uint64_t id, schema::TypeEnvironment::Reader environment) override;
kj::Maybe<schema::Node::Reader> resolveFinalSchema(uint64_t id) override;
kj::Maybe<ResolvedDecl> resolveImport(kj::StringPtr name) override;
kj::Maybe<Type> resolveBootstrapType(schema::Type::Reader type, Schema scope) override;
private:
CompiledModule* module; // null iff isBuiltin is true
......@@ -732,7 +735,9 @@ void Compiler::Node::traverseEnvironment(
std::unordered_map<Node*, uint>& seen,
const SchemaLoader& finalLoader) {
for (auto scope: env.getScopes()) {
for (auto binding: scope.getBindings()) {
switch (scope.which()) {
case schema::TypeEnvironment::Scope::BIND:
for (auto binding: scope.getBind()) {
switch (binding.which()) {
case schema::TypeEnvironment::Binding::UNBOUND:
break;
......@@ -741,6 +746,10 @@ void Compiler::Node::traverseEnvironment(
break;
}
}
break;
case schema::TypeEnvironment::Scope::INHERIT:
break;
}
}
}
......@@ -841,14 +850,28 @@ Compiler::Node::resolveMember(kj::StringPtr name) {
return nullptr;
}
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);
return ResolvedDecl { parent.id, parent.genericParamCount, scopeId, parent.kind, &parent };
});
}
NodeTranslator::Resolver::ResolvedDecl Compiler::Node::getTopScope() {
Node& node = module->getRootNode();
return ResolvedDecl { node.id, 0, 0, node.kind, &node };
}
kj::Maybe<Schema> Compiler::Node::resolveBootstrapSchema(uint64_t id) {
kj::Maybe<Schema> Compiler::Node::resolveBootstrapSchema(
uint64_t id, schema::TypeEnvironment::Reader environment) {
KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) {
return node->getBootstrapSchema();
// Make sure the bootstrap schema is loaded into the SchemaLoader.
if (node->getBootstrapSchema() == nullptr) {
return nullptr;
}
// Now we actually invoke get() to evaluate the environment.
return module->getCompiler().getWorkspace().bootstrapLoader.get(id, environment);
} else {
KJ_FAIL_REQUIRE("Tried to get schema for ID we haven't seen before.");
}
......@@ -872,6 +895,22 @@ Compiler::Node::resolveImport(kj::StringPtr name) {
}
}
kj::Maybe<Type> Compiler::Node::resolveBootstrapType(schema::Type::Reader type, Schema scope) {
// TODO(someday): Arguably should return null if the type or its dependencies are placeholders.
kj::Maybe<Type> result;
KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
result = module->getCompiler().getWorkspace().bootstrapLoader.getType(type, scope);
})) {
result = nullptr;
if (!module->getErrorReporter().hadErrors()) {
addError(kj::str("Internal compiler bug: Bootstrap schema failed to load:\n",
*exception));
}
}
return result;
}
// =======================================================================================
Compiler::CompiledModule::CompiledModule(Compiler::Impl& compiler, Module& parserModule)
......
This diff is collapsed.
......@@ -209,7 +209,7 @@ static const uint16_t m_91cc55cd57de5419[] = {9, 6, 8, 3, 0, 2, 4, 5, 7, 1};
static const uint16_t i_91cc55cd57de5419[] = {0, 1, 2, 3, 4, 5, 6, 9, 7, 8};
const ::capnp::_::RawSchema s_91cc55cd57de5419 = {
0x91cc55cd57de5419, b_91cc55cd57de5419.words, 195, d_91cc55cd57de5419, m_91cc55cd57de5419,
1, 10, i_91cc55cd57de5419, nullptr, nullptr
1, 10, i_91cc55cd57de5419, nullptr, nullptr, { &s_91cc55cd57de5419, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<119> b_c6725e678d60fa37 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -340,7 +340,7 @@ static const uint16_t m_c6725e678d60fa37[] = {2, 3, 5, 1, 4, 0};
static const uint16_t i_c6725e678d60fa37[] = {1, 2, 0, 3, 4, 5};
const ::capnp::_::RawSchema s_c6725e678d60fa37 = {
0xc6725e678d60fa37, b_c6725e678d60fa37.words, 119, d_c6725e678d60fa37, m_c6725e678d60fa37,
2, 6, i_c6725e678d60fa37, nullptr, nullptr
2, 6, i_c6725e678d60fa37, nullptr, nullptr, { &s_c6725e678d60fa37, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<38> b_9e69a92512b19d18 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -389,7 +389,7 @@ static const uint16_t m_9e69a92512b19d18[] = {0};
static const uint16_t i_9e69a92512b19d18[] = {0};
const ::capnp::_::RawSchema s_9e69a92512b19d18 = {
0x9e69a92512b19d18, b_9e69a92512b19d18.words, 38, d_9e69a92512b19d18, m_9e69a92512b19d18,
1, 1, i_9e69a92512b19d18, nullptr, nullptr
1, 1, i_9e69a92512b19d18, nullptr, nullptr, { &s_9e69a92512b19d18, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<40> b_a11f97b9d6c73dd4 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -440,7 +440,7 @@ static const uint16_t m_a11f97b9d6c73dd4[] = {0};
static const uint16_t i_a11f97b9d6c73dd4[] = {0};
const ::capnp::_::RawSchema s_a11f97b9d6c73dd4 = {
0xa11f97b9d6c73dd4, b_a11f97b9d6c73dd4.words, 40, d_a11f97b9d6c73dd4, m_a11f97b9d6c73dd4,
1, 1, i_a11f97b9d6c73dd4, nullptr, nullptr
1, 1, i_a11f97b9d6c73dd4, nullptr, nullptr, { &s_a11f97b9d6c73dd4, nullptr, nullptr, 0, 0, nullptr }
};
} // namespace schemas
namespace _ { // private
......
This diff is collapsed.
......@@ -73,13 +73,17 @@ public:
virtual kj::Maybe<kj::OneOf<ResolvedDecl, ResolvedAlias>> resolveMember(kj::StringPtr name) = 0;
// Look up a member of this node.
virtual kj::Maybe<ResolvedDecl> getParent() = 0;
// Returns the parent of this scope, or null if this is the top scope.
virtual ResolvedDecl getTopScope() = 0;
// Get the top-level scope containing this node.
virtual kj::Maybe<Schema> resolveBootstrapSchema(uint64_t id) = 0;
virtual kj::Maybe<Schema> resolveBootstrapSchema(uint64_t id,
schema::TypeEnvironment::Reader environment) = 0;
// Get the schema for the given ID. If a schema is returned, it must be safe to traverse its
// dependencies using Schema::getDependency(). A schema that is only at the bootstrap stage
// is acceptable.
// dependencies via the Schema API. A schema that is only at the bootstrap stage is
// acceptable.
//
// Throws an exception if the id is not one that was found by calling resolve() or by
// traversing other schemas. Returns null if the ID is recognized, but the corresponding
......@@ -97,6 +101,13 @@ public:
virtual kj::Maybe<ResolvedDecl> resolveImport(kj::StringPtr name) = 0;
// Get the ID of an imported file given the import path.
virtual kj::Maybe<Type> resolveBootstrapType(schema::Type::Reader type, Schema scope) = 0;
// Compile a schema::Type into a Type whose dependencies may safely be traversed via the schema
// API. These dependencies may have only bootstrap schemas. Returns null if the type could not
// be constructed due to already-reported errors.
//
// `scope` is the schema
};
NodeTranslator(Resolver& resolver, ErrorReporter& errorReporter,
......@@ -106,6 +117,8 @@ public:
// `displayName`, `id`, `scopeId`, and `nestedNodes` already initialized. The `NodeTranslator`
// fills in the rest.
~NodeTranslator();
struct NodeSet {
schema::Node::Reader node;
// The main node.
......@@ -130,10 +143,18 @@ public:
// bootstrap node) and return it.
private:
class DuplicateNameDetector;
class DuplicateOrdinalDetector;
class StructLayout;
class StructTranslator;
class DeclInstance;
class TypeEnvironment;
Resolver& resolver;
ErrorReporter& errorReporter;
Orphanage orphanage;
bool compileAnnotations;
kj::Own<TypeEnvironment> baseEnvironment;
Orphan<schema::Node> wipNode;
// The work-in-progress schema node.
......@@ -148,6 +169,7 @@ private:
struct UnfinishedValue {
Expression::Reader source;
schema::Type::Reader type;
Schema typeScope;
schema::Value::Builder target;
};
kj::Vector<UnfinishedValue> unfinishedValues;
......@@ -162,13 +184,6 @@ private:
void compileAnnotation(Declaration::Annotation::Reader decl,
schema::Node::Annotation::Builder builder);
class DuplicateNameDetector;
class DuplicateOrdinalDetector;
class StructLayout;
class StructTranslator;
class DeclInstance;
class TypeEnvironment;
void compileEnum(Void decl, List<Declaration>::Reader members,
schema::Node::Builder builder);
void compileStruct(Void decl, List<Declaration>::Reader members,
......@@ -198,23 +213,26 @@ private:
void compileDefaultDefaultValue(schema::Type::Reader type, schema::Value::Builder target);
// Initializes `target` to contain the "default default" value for `type`.
void compileBootstrapValue(Expression::Reader source, schema::Type::Reader type,
schema::Value::Builder target);
void compileBootstrapValue(
Expression::Reader source, schema::Type::Reader type, schema::Value::Builder target,
Schema typeScope = Schema());
// Calls compileValue() if this value should be interpreted at bootstrap time. Otheriwse,
// adds the value to `unfinishedValues` for later evaluation.
//
// If `type` comes from some other node, `typeScope` is the schema for that node. This is only
// really needed for looking up generic parameter bindings, therefore if the type comes from
// the node being built, an empty "Schema" (the default) works here because the node being built
// is of course being built for all possible bindings and thus none of its generic parameters are
// bound.
void compileValue(Expression::Reader source, schema::Type::Reader type,
schema::Value::Builder target, bool isBootstrap);
Schema typeScope, schema::Value::Builder target, bool isBootstrap);
// Interprets the value expression and initializes `target` with the result.
kj::Maybe<DynamicValue::Reader> readConstant(Expression::Reader name, bool isBootstrap);
// Get the value of the given constant. May return null if some error occurs, which will already
// have been reported.
kj::Maybe<ListSchema> makeListSchemaOf(schema::Type::Reader elementType);
// Construct a list schema representing a list of elements of the given type. May return null if
// some error occurs, which will already have been reported.
Orphan<List<schema::Annotation>> compileAnnotationApplications(
List<Declaration::AnnotationApplication>::Reader annotations,
kj::StringPtr targetsFlagName);
......@@ -224,29 +242,28 @@ class ValueTranslator {
public:
class Resolver {
public:
virtual kj::Maybe<Schema> resolveType(uint64_t id) = 0;
virtual kj::Maybe<DynamicValue::Reader> resolveConstant(Expression::Reader name) = 0;
};
ValueTranslator(Resolver& resolver, ErrorReporter& errorReporter, Orphanage orphanage)
: resolver(resolver), errorReporter(errorReporter), orphanage(orphanage) {}
kj::Maybe<Orphan<DynamicValue>> compileValue(Expression::Reader src, schema::Type::Reader type);
kj::Maybe<Orphan<DynamicValue>> compileValue(Expression::Reader src, Type type);
private:
Resolver& resolver;
ErrorReporter& errorReporter;
Orphanage orphanage;
Orphan<DynamicValue> compileValueInner(Expression::Reader src, schema::Type::Reader type);
Orphan<DynamicValue> compileValueInner(Expression::Reader src, Type type);
// Helper for compileValue().
void fillStructValue(DynamicStruct::Builder builder,
List<Expression::Param>::Reader assignments);
// Interprets the given assignments and uses them to fill in the given struct builder.
kj::String makeNodeName(uint64_t id);
kj::String makeTypeName(schema::Type::Reader type);
kj::String makeNodeName(Schema node);
kj::String makeTypeName(Type type);
kj::Maybe<ListSchema> makeListSchemaOf(schema::Type::Reader elementType);
};
......
This diff is collapsed.
......@@ -208,7 +208,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend kj::StringTree _::structString(
_::StructReader reader, const _::RawSchema& schema);
_::StructReader reader, const _::RawBrandedSchema& schema);
friend class Orphanage;
friend class Orphan<DynamicStruct>;
friend class Orphan<DynamicValue>;
......
......@@ -43,6 +43,97 @@ struct DynamicStruct; // So that it can be declared a friend.
namespace _ { // private
struct RawSchema;
struct RawBrandedSchema {
// Represents a combination of a schema and bindings for its generic parameters.
//
// Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for
// every _instance_ of a generic type -- or, at least, every instance that is actually used. For
// generated-code types, we use template magic to initialize these.
const RawSchema* generic = nullptr;
// Generic type which we're branding.
struct Binding {
uint8_t which; // Numeric value of one of schema::Type::Which.
uint16_t listDepth; // Number of times to wrap the base type in List().
const RawBrandedSchema* schema; // may be null
};
struct Scope {
uint64_t typeId;
// Type ID whose parameters are being bound.
const Binding* bindings;
uint bindingCount;
// Bindings for those parameters.
};
const Scope* scopes = nullptr;
// Array of enclosing scopes for which generic variables have been bound, sorted by type ID.
struct Dependency {
uint location;
const RawBrandedSchema* schema;
};
const Dependency* dependencies = nullptr;
// Map of branded schemas for dependencies of this type, given our brand. Only dependencies that
// are branded are included in this map; if a dependency is missing, use its `defaultBrand`.
uint32_t scopeCount = 0;
uint32_t dependencyCount = 0;
enum class DepKind {
// Component of a Dependency::location. Specifies what sort of dependency this is.
INVALID,
// Mostly defined to ensure that zero is not a valid location.
FIELD,
// Binding needed for a field's type. The index is the field index (NOT ordinal!).
METHOD_PARAMS,
// Bindings needed for a method's params type. The index is the method number.
METHOD_RESULTS,
// Bindings needed for a method's results type. The index is the method ordinal.
SUPERCLASS,
// Bindings needed for a superclass type. The index is the superclass's index in the
// "extends" list.
CONST_TYPE
// Bindings needed for the type of a constant. The index is zero.
};
static inline uint makeDepLocation(DepKind kind, uint index) {
// Make a number representing the location of a particular dependency within its parent
// schema.
return (static_cast<uint>(kind) << 24) | index;
}
class Initializer {
public:
virtual void init(const RawBrandedSchema* generic) const = 0;
};
const Initializer* lazyInitializer = nullptr;
// Lazy initializer, invoked by ensureInitialized().
inline void ensureInitialized() const {
// Lazy initialization support. Invoke to ensure that initialization has taken place. This
// is required in particular when traversing the dependency list. RawSchemas for compiled-in
// types are always initialized; only dynamically-loaded schemas may be lazy.
const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
if (i != nullptr) i->init(this);
}
};
struct RawSchema {
// The generated code defines a constant RawSchema for every compiled declaration.
//
......@@ -96,6 +187,13 @@ struct RawSchema {
const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
if (i != nullptr) i->init(this);
}
RawBrandedSchema defaultBrand;
// Specifies the brand to use for this schema if no generic parameters have been bound to
// anything. Generally, in the default brand, all generic parameters are treated as if they were
// bound to `AnyPointer`.
//
// TODO(now): Remove initializer; it's just to assist incremental changes.
};
template <typename T>
......@@ -106,6 +204,12 @@ inline const RawSchema& rawSchema() {
return RawSchema_<T>::get();
}
template <typename T>
inline const RawBrandedSchema& rawBrandedSchema() {
// TODO(now): implement properly
return rawSchema<T>().defaultBrand;
}
template <typename T> struct TypeId_;
extern const RawSchema NULL_INTERFACE_SCHEMA; // defined in schema.c++
......@@ -124,13 +228,15 @@ struct UnionParentType_;
template <typename T>
using UnionParentType = typename UnionParentType_<T>::Type;
kj::StringTree structString(StructReader reader, const RawSchema& schema);
kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema);
// Declared here so that we can declare inline stringify methods on generated types.
// Defined in stringify.c++, which depends on dynamic.c++, which is allowed not to be linked in.
//
// TODO(now): No default for env.
template <typename T>
inline kj::StringTree structString(StructReader reader) {
return structString(reader, rawSchema<T>());
return structString(reader, rawBrandedSchema<T>());
}
// TODO(cleanup): Unify ConstStruct and ConstList.
......
......@@ -36,7 +36,7 @@ static const ::capnp::_::AlignedData<26> b_9fd69ebc87b9719c = {
static const uint16_t m_9fd69ebc87b9719c[] = {1, 0};
const ::capnp::_::RawSchema s_9fd69ebc87b9719c = {
0x9fd69ebc87b9719c, b_9fd69ebc87b9719c.words, 26, nullptr, m_9fd69ebc87b9719c,
0, 2, nullptr, nullptr, nullptr
0, 2, nullptr, nullptr, nullptr, { &s_9fd69ebc87b9719c, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<35> b_e615e371b1036508 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -82,7 +82,7 @@ static const uint16_t m_e615e371b1036508[] = {0};
static const uint16_t i_e615e371b1036508[] = {0};
const ::capnp::_::RawSchema s_e615e371b1036508 = {
0xe615e371b1036508, b_e615e371b1036508.words, 35, d_e615e371b1036508, m_e615e371b1036508,
1, 1, i_e615e371b1036508, nullptr, nullptr
1, 1, i_e615e371b1036508, nullptr, nullptr, { &s_e615e371b1036508, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<34> b_b88d09a9c5f39817 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -124,7 +124,7 @@ static const uint16_t m_b88d09a9c5f39817[] = {0};
static const uint16_t i_b88d09a9c5f39817[] = {0};
const ::capnp::_::RawSchema s_b88d09a9c5f39817 = {
0xb88d09a9c5f39817, b_b88d09a9c5f39817.words, 34, nullptr, m_b88d09a9c5f39817,
0, 1, i_b88d09a9c5f39817, nullptr, nullptr
0, 1, i_b88d09a9c5f39817, nullptr, nullptr, { &s_b88d09a9c5f39817, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<18> b_89f389b6fd4082c1 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -148,7 +148,7 @@ static const ::capnp::_::AlignedData<18> b_89f389b6fd4082c1 = {
};
const ::capnp::_::RawSchema s_89f389b6fd4082c1 = {
0x89f389b6fd4082c1, b_89f389b6fd4082c1.words, 18, nullptr, nullptr,
0, 0, nullptr, nullptr, nullptr
0, 0, nullptr, nullptr, nullptr, { &s_89f389b6fd4082c1, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<19> b_b47f4979672cb59d = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -173,7 +173,7 @@ static const ::capnp::_::AlignedData<19> b_b47f4979672cb59d = {
};
const ::capnp::_::RawSchema s_b47f4979672cb59d = {
0xb47f4979672cb59d, b_b47f4979672cb59d.words, 19, nullptr, nullptr,
0, 0, nullptr, nullptr, nullptr
0, 0, nullptr, nullptr, nullptr, { &s_b47f4979672cb59d, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<65> b_95b29059097fca83 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -246,7 +246,7 @@ static const uint16_t m_95b29059097fca83[] = {0, 1, 2};
static const uint16_t i_95b29059097fca83[] = {0, 1, 2};
const ::capnp::_::RawSchema s_95b29059097fca83 = {
0x95b29059097fca83, b_95b29059097fca83.words, 65, nullptr, m_95b29059097fca83,
0, 3, i_95b29059097fca83, nullptr, nullptr
0, 3, i_95b29059097fca83, nullptr, nullptr, { &s_95b29059097fca83, nullptr, nullptr, 0, 0, nullptr }
};
static const ::capnp::_::AlignedData<65> b_9d263a3630b7ebee = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
......@@ -319,7 +319,7 @@ static const uint16_t m_9d263a3630b7ebee[] = {2, 0, 1};
static const uint16_t i_9d263a3630b7ebee[] = {0, 1, 2};
const ::capnp::_::RawSchema s_9d263a3630b7ebee = {
0x9d263a3630b7ebee, b_9d263a3630b7ebee.words, 65, nullptr, m_9d263a3630b7ebee,
0, 3, i_9d263a3630b7ebee, nullptr, nullptr
0, 3, i_9d263a3630b7ebee, nullptr, nullptr, { &s_9d263a3630b7ebee, nullptr, nullptr, 0, 0, nullptr }
};
} // namespace schemas
namespace _ { // private
......
This diff is collapsed.
......@@ -328,6 +328,45 @@ TEST(SchemaLoader, LazyLoadGetDependency) {
EXPECT_EQ(dep, loader.get(typeId<TestAllTypes>()));
}
TEST(SchemaLoader, Generics) {
SchemaLoader loader;
StructSchema allTypes = loader.load(Schema::from<TestAllTypes>().getProto()).asStruct();
StructSchema tap = loader.load(Schema::from<test::TestAnyPointer>().getProto()).asStruct();
loader.load(Schema::from<test::TestGenerics::Inner>().getProto());
loader.load(Schema::from<test::TestGenerics::Inner2>().getProto());
loader.load(Schema::from<test::TestGenerics::Interface>().getProto());
loader.load(Schema::from<test::TestGenerics>().getProto());
StructSchema schema = loader.load(Schema::from<test::TestUseGenerics>().getProto()).asStruct();
{
StructSchema::Field basic = schema.getFieldByName("basic");
StructSchema instance = basic.getType().asStruct();
StructSchema::Field foo = instance.getFieldByName("foo");
EXPECT_TRUE(foo.getType().asStruct() == allTypes);
EXPECT_TRUE(foo.getType().asStruct() != tap);
StructSchema instance2 = instance.getFieldByName("rev").getType().asStruct();
StructSchema::Field foo2 = instance2.getFieldByName("foo");
EXPECT_TRUE(foo2.getType().asStruct() == tap);
EXPECT_TRUE(foo2.getType().asStruct() != allTypes);
}
{
StructSchema inner2 = schema.getFieldByName("inner2").getType().asStruct();
StructSchema bound = inner2.getFieldByName("innerBound").getType().asStruct();
Type boundFoo = bound.getFieldByName("foo").getType();
EXPECT_FALSE(boundFoo.isAnyPointer());
EXPECT_TRUE(boundFoo.asStruct() == allTypes);
StructSchema unbound = inner2.getFieldByName("innerUnbound").getType().asStruct();
Type unboundFoo = unbound.getFieldByName("foo").getType();
EXPECT_TRUE(unboundFoo.isAnyPointer());
}
}
} // namespace
} // namespace _ (private)
} // namespace capnp
This diff is collapsed.
......@@ -65,15 +65,30 @@ public:
~SchemaLoader() noexcept(false);
KJ_DISALLOW_COPY(SchemaLoader);
Schema get(uint64_t id) const;
typedef schema::TypeEnvironment::Reader GenericBindings;
Schema get(uint64_t id, GenericBindings bindings = GenericBindings(),
Schema scope = Schema()) const;
// Gets the schema for the given ID, throwing an exception if it isn't present.
//
// The returned schema may be invalidated if load() is called with a new schema for the same ID.
// In general, you should not call load() while a schema from this loader is in-use.
kj::Maybe<Schema> tryGet(uint64_t id) const;
//
// `bindings` and `scope` are used to determine generic parameter bindings where relevant.
// `bindings` gives parameter bindings for the target type's generic parameters that were
// specified at the reference site. `scope` specifies the scope in which the type ID appeared --
// if the target type and the scope share some common super-scope which is parameterized,
// and bindings for those parameters weren't specified in `bindings`, they will be carried over
// from the scope.
kj::Maybe<Schema> tryGet(uint64_t id, GenericBindings bindings = GenericBindings(),
Schema scope = Schema()) const;
// Like get() but doesn't throw.
Type getType(schema::Type::Reader type, Schema scope = Schema()) const;
// Convenience method which interprets a schema::Type to produce a Type object. Implemented in
// terms of get().
Schema load(const schema::Node::Reader& reader);
// Loads the given schema node. Validates the node and throws an exception if invalid. This
// makes a copy of the schema, so the object passed in can be destroyed after this returns.
......@@ -134,6 +149,7 @@ private:
class CompatibilityChecker;
class Impl;
class InitializerImpl;
class BrandedInitializerImpl;
kj::MutexGuarded<kj::Own<Impl>> impl;
void loadNative(const _::RawSchema* nativeSchema);
......
......@@ -156,22 +156,29 @@ TEST(SchemaParser, Constants) {
"struct Foo {\n"
" bar @0 :Int16;\n"
" baz @1 :Text;\n"
"}\n"
"const genericConst :TestGeneric(Text) = (value = \"text\");\n"
"struct TestGeneric(T) {\n"
" value @0 :T;\n"
"}\n");
ParsedSchema barSchema = parser.parseFile(SchemaFile::newDiskFile(
ParsedSchema fileSchema = parser.parseFile(SchemaFile::newDiskFile(
"const.capnp", "const.capnp", nullptr, reader));
EXPECT_EQ(1234, barSchema.getNested("uint32Const").asConst().as<uint32_t>());
EXPECT_EQ(1234, fileSchema.getNested("uint32Const").asConst().as<uint32_t>());
auto list = barSchema.getNested("listConst").asConst().as<DynamicList>();
auto list = fileSchema.getNested("listConst").asConst().as<DynamicList>();
ASSERT_EQ(3u, list.size());
EXPECT_EQ(1.25, list[0].as<float>());
EXPECT_EQ(2.5, list[1].as<float>());
EXPECT_EQ(3e4f, list[2].as<float>());
auto structConst = barSchema.getNested("structConst").asConst().as<DynamicStruct>();
auto structConst = fileSchema.getNested("structConst").asConst().as<DynamicStruct>();
EXPECT_EQ(123, structConst.get("bar").as<int16_t>());
EXPECT_EQ("qux", structConst.get("baz").as<Text>());
auto genericConst = fileSchema.getNested("genericConst").asConst().as<DynamicStruct>();
EXPECT_EQ("text", genericConst.get("value").as<Text>());
}
} // namespace
......
This diff is collapsed.
......@@ -342,8 +342,14 @@ struct TypeEnvironment {
scopeId @0 :Id;
# ID of the scope to which these params apply.
bindings @1 :List(Binding);
union {
bind @1 :List(Binding);
# List of parameter bindings.
inherit @2 :Void;
# The place where this TypeEnivornment appears is actually within this scope or a sub-scope,
# and the bindings for this scope should be inherited from the reference point.
}
}
struct Binding {
......
This diff is collapsed.
......@@ -265,6 +265,10 @@ struct TypeEnvironment::Scope {
class Reader;
class Builder;
class Pipeline;
enum Which: uint16_t {
BIND,
INHERIT,
};
};
struct TypeEnvironment::Binding {
......@@ -468,7 +472,7 @@ CAPNP_DECLARE_STRUCT(
0, 1, POINTER);
CAPNP_DECLARE_STRUCT(
::capnp::schema::TypeEnvironment::Scope, 8343d91197413c18,
1, 1, INLINE_COMPOSITE);
2, 1, INLINE_COMPOSITE);
CAPNP_DECLARE_STRUCT(
::capnp::schema::TypeEnvironment::Binding, f5b4269b6dd5cd38,
1, 1, INLINE_COMPOSITE);
......@@ -2770,10 +2774,15 @@ public:
return _reader.totalSize().asPublic();
}
inline Which which() const;
inline ::uint64_t getScopeId() const;
inline bool hasBindings() const;
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Reader getBindings() const;
inline bool isBind() const;
inline bool hasBind() const;
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Reader getBind() const;
inline bool isInherit() const;
inline ::capnp::Void getInherit() const;
private:
::capnp::_::StructReader _reader;
......@@ -2805,15 +2814,21 @@ public:
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
inline Which which();
inline ::uint64_t getScopeId();
inline void setScopeId( ::uint64_t value);
inline bool hasBindings();
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Builder getBindings();
inline void setBindings( ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Reader value);
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Builder initBindings(unsigned int size);
inline void adoptBindings(::capnp::Orphan< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>>&& value);
inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>> disownBindings();
inline bool isBind();
inline bool hasBind();
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Builder getBind();
inline void setBind( ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Reader value);
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Builder initBind(unsigned int size);
inline void adoptBind(::capnp::Orphan< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>>&& value);
inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>> disownBind();
inline bool isInherit();
inline ::capnp::Void getInherit();
inline void setInherit( ::capnp::Void value = ::capnp::VOID);
private:
::capnp::_::StructBuilder _builder;
......@@ -5818,6 +5833,13 @@ inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::TypeEnvironment::Scope>>
_builder.getPointerField(0 * ::capnp::POINTERS));
}
inline TypeEnvironment::Scope::Which TypeEnvironment::Scope::Reader::which() const {
return _reader.getDataField<Which>(4 * ::capnp::ELEMENTS);
}
inline TypeEnvironment::Scope::Which TypeEnvironment::Scope::Builder::which() {
return _builder.getDataField<Which>(4 * ::capnp::ELEMENTS);
}
inline ::uint64_t TypeEnvironment::Scope::Reader::getScopeId() const {
return _reader.getDataField< ::uint64_t>(
0 * ::capnp::ELEMENTS);
......@@ -5832,38 +5854,84 @@ inline void TypeEnvironment::Scope::Builder::setScopeId( ::uint64_t value) {
0 * ::capnp::ELEMENTS, value);
}
inline bool TypeEnvironment::Scope::Reader::hasBindings() const {
inline bool TypeEnvironment::Scope::Reader::isBind() const {
return which() == TypeEnvironment::Scope::BIND;
}
inline bool TypeEnvironment::Scope::Builder::isBind() {
return which() == TypeEnvironment::Scope::BIND;
}
inline bool TypeEnvironment::Scope::Reader::hasBind() const {
if (which() != TypeEnvironment::Scope::BIND) return false;
return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull();
}
inline bool TypeEnvironment::Scope::Builder::hasBindings() {
inline bool TypeEnvironment::Scope::Builder::hasBind() {
if (which() != TypeEnvironment::Scope::BIND) return false;
return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull();
}
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Reader TypeEnvironment::Scope::Reader::getBindings() const {
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Reader TypeEnvironment::Scope::Reader::getBind() const {
KJ_IREQUIRE(which() == TypeEnvironment::Scope::BIND,
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>>::get(
_reader.getPointerField(0 * ::capnp::POINTERS));
}
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Builder TypeEnvironment::Scope::Builder::getBindings() {
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Builder TypeEnvironment::Scope::Builder::getBind() {
KJ_IREQUIRE(which() == TypeEnvironment::Scope::BIND,
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>>::get(
_builder.getPointerField(0 * ::capnp::POINTERS));
}
inline void TypeEnvironment::Scope::Builder::setBindings( ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Reader value) {
inline void TypeEnvironment::Scope::Builder::setBind( ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Reader value) {
_builder.setDataField<TypeEnvironment::Scope::Which>(
4 * ::capnp::ELEMENTS, TypeEnvironment::Scope::BIND);
::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>>::set(
_builder.getPointerField(0 * ::capnp::POINTERS), value);
}
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Builder TypeEnvironment::Scope::Builder::initBindings(unsigned int size) {
inline ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>::Builder TypeEnvironment::Scope::Builder::initBind(unsigned int size) {
_builder.setDataField<TypeEnvironment::Scope::Which>(
4 * ::capnp::ELEMENTS, TypeEnvironment::Scope::BIND);
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>>::init(
_builder.getPointerField(0 * ::capnp::POINTERS), size);
}
inline void TypeEnvironment::Scope::Builder::adoptBindings(
inline void TypeEnvironment::Scope::Builder::adoptBind(
::capnp::Orphan< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>>&& value) {
_builder.setDataField<TypeEnvironment::Scope::Which>(
4 * ::capnp::ELEMENTS, TypeEnvironment::Scope::BIND);
::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>>::adopt(
_builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>> TypeEnvironment::Scope::Builder::disownBindings() {
inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>> TypeEnvironment::Scope::Builder::disownBind() {
KJ_IREQUIRE(which() == TypeEnvironment::Scope::BIND,
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::TypeEnvironment::Binding>>::disown(
_builder.getPointerField(0 * ::capnp::POINTERS));
}
inline bool TypeEnvironment::Scope::Reader::isInherit() const {
return which() == TypeEnvironment::Scope::INHERIT;
}
inline bool TypeEnvironment::Scope::Builder::isInherit() {
return which() == TypeEnvironment::Scope::INHERIT;
}
inline ::capnp::Void TypeEnvironment::Scope::Reader::getInherit() const {
KJ_IREQUIRE(which() == TypeEnvironment::Scope::INHERIT,
"Must check which() before get()ing a union member.");
return _reader.getDataField< ::capnp::Void>(
0 * ::capnp::ELEMENTS);
}
inline ::capnp::Void TypeEnvironment::Scope::Builder::getInherit() {
KJ_IREQUIRE(which() == TypeEnvironment::Scope::INHERIT,
"Must check which() before get()ing a union member.");
return _builder.getDataField< ::capnp::Void>(
0 * ::capnp::ELEMENTS);
}
inline void TypeEnvironment::Scope::Builder::setInherit( ::capnp::Void value) {
_builder.setDataField<TypeEnvironment::Scope::Which>(
4 * ::capnp::ELEMENTS, TypeEnvironment::Scope::INHERIT);
_builder.setDataField< ::capnp::Void>(
0 * ::capnp::ELEMENTS, value);
}
inline TypeEnvironment::Binding::Which TypeEnvironment::Binding::Reader::which() const {
return _reader.getDataField<Which>(0 * ::capnp::ELEMENTS);
}
......
This diff is collapsed.
......@@ -282,8 +282,8 @@ kj::StringTree KJ_STRINGIFY(const DynamicList::Builder& value) { return stringif
namespace _ { // private
kj::StringTree structString(StructReader reader, const RawSchema& schema) {
return stringify(DynamicStruct::Reader(StructSchema(&schema), reader));
kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema) {
return stringify(DynamicStruct::Reader(Schema(&schema).asStruct(), reader));
}
} // namespace _ (private)
......
......@@ -515,19 +515,42 @@ struct TestGenerics(Foo, Bar) {
struct Inner2(Baz) {
bar @0 :Bar;
baz @1 :Baz;
innerBound @2 :Inner;
innerUnbound @3 :TestGenerics.Inner;
}
interface Interface(Qux) {
call @0 Inner2(Text) -> (qux :Qux, gen :TestGenerics(TestAllTypes, TestDefaults));
}
annotation ann(struct) :Foo;
}
struct TestGenericsWrapper(Foo, Bar) {
value @0 :TestGenerics(Foo, Bar);
}
struct TestUseGenerics {
basic @0 :TestGenerics(TestAllTypes, TestDefaults);
inner @1 :TestGenerics(TestAllTypes, TestDefaults).Inner;
inner2 @2 :TestGenerics(TestAllTypes, TestDefaults).Inner2(Text);
struct TestGenericsWrapper2 {
value @0 :TestGenericsWrapper(Text, TestAllTypes);
}
struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") {
basic @0 :TestGenerics(TestAllTypes, TestAnyPointer);
inner @1 :TestGenerics(TestAllTypes, TestAnyPointer).Inner;
inner2 @2 :TestGenerics(TestAllTypes, TestAnyPointer).Inner2(Text);
unspecified @3 :TestGenerics;
unspecifiedInner @4 :TestGenerics.Inner2(Text);
wrapper @8 :TestGenericsWrapper(TestAllTypes, TestAnyPointer);
default @5 :TestGenerics(TestAllTypes, Text) =
(foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321))));
defaultInner @6 :TestGenerics(TestAllTypes, Text).Inner =
(foo = (int16Field = 123), bar = "text");
defaultUser @7 :TestUseGenerics = (basic = (foo = (int16Field = 123)));
defaultWrapper @9 :TestGenericsWrapper(Text, TestAllTypes) =
(value = (foo = "text", rev = (foo = (int16Field = 321))));
defaultWrapper2 @10 :TestGenericsWrapper2 =
(value = (value = (foo = "text", rev = (foo = (int16Field = 321)))));
}
struct TestEmptyStruct {}
......@@ -623,6 +646,9 @@ const derivedConstant :TestAllTypes = (
int16List = TestConstants.int16ListConst,
structList = TestConstants.structListConst);
const genericConstant :TestGenerics(TestAllTypes, Text) =
(foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321))));
interface TestInterface {
foo @0 (i :UInt32, j :Bool) -> (x :Text);
bar @1 () -> ();
......
......@@ -143,6 +143,14 @@ typedef unsigned char byte;
#define KJ_UNUSED_MEMBER
#endif
#if __clang__
#define KJ_DEPRECATED(reason) \
__attribute__((deprecated(reason)))
#else
#define KJ_DEPRECATED(reason) \
__attribute__((deprecated))
#endif
namespace _ { // private
void inlineRequireFailure(
......
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