Commit 01200b96 authored by Kenton Varda's avatar Kenton Varda

Generics: Methods with implicit type parameters.

See changes to test.capnp for example.

Currently only supported through generated code, not in the dynamic API. Not exactly sure how to expose this in the dynamic API...
parent a211aa60
...@@ -796,6 +796,30 @@ TEST(Capability, Generics2) { ...@@ -796,6 +796,30 @@ TEST(Capability, Generics2) {
root.initCap().setFoo(test::TestInterface::Client(nullptr)); root.initCap().setFoo(test::TestInterface::Client(nullptr));
} }
TEST(Capability, ImplicitParams) {
kj::EventLoop loop;
kj::WaitScope waitScope(loop);
typedef test::TestImplicitMethodParams Interface;
Interface::Client client = nullptr;
capnp::Request<Interface::CallParams<Text, TestAllTypes>,
test::TestGenerics<Text, TestAllTypes>> request =
client.callRequest<Text, TestAllTypes>();
request.setFoo("hello");
initTestMessage(request.initBar());
auto promise = request.send()
.then([](capnp::Response<test::TestGenerics<Text, TestAllTypes>>&& response) {
// This doesn't actually execute; we're just checking that it compiles.
Text::Reader text = response.getFoo();
text.size();
checkTestMessage(response.getRev().getFoo());
}, [](kj::Exception&& e) {});
promise.wait(waitScope);
}
} // namespace } // namespace
} // namespace _ } // namespace _
} // namespace capnp } // namespace capnp
This diff is collapsed.
...@@ -114,7 +114,8 @@ private: ...@@ -114,7 +114,8 @@ private:
return "(?)"; return "(?)";
} }
kj::StringTree nodeName(Schema target, Schema scope, schema::Brand::Reader brand) { kj::StringTree nodeName(Schema target, Schema scope, schema::Brand::Reader brand,
kj::Maybe<InterfaceSchema::Method> method) {
kj::Vector<Schema> targetPath; kj::Vector<Schema> targetPath;
kj::Vector<Schema> scopeParts; kj::Vector<Schema> scopeParts;
...@@ -178,7 +179,7 @@ private: ...@@ -178,7 +179,7 @@ private:
case schema::Brand::Binding::UNBOUND: case schema::Brand::Binding::UNBOUND:
return kj::strTree("AnyPointer"); return kj::strTree("AnyPointer");
case schema::Brand::Binding::TYPE: case schema::Brand::Binding::TYPE:
return genType(binding.getType(), scope); return genType(binding.getType(), scope, method);
} }
return kj::strTree("<unknown binding>"); return kj::strTree("<unknown binding>");
}; };
...@@ -192,7 +193,8 @@ private: ...@@ -192,7 +193,8 @@ private:
return kj::StringTree(parts.finish(), "."); return kj::StringTree(parts.finish(), ".");
} }
kj::StringTree genType(schema::Type::Reader type, Schema scope) { kj::StringTree genType(schema::Type::Reader type, Schema scope,
kj::Maybe<InterfaceSchema::Method> method) {
switch (type.which()) { switch (type.which()) {
case schema::Type::VOID: return kj::strTree("Void"); case schema::Type::VOID: return kj::strTree("Void");
case schema::Type::BOOL: return kj::strTree("Bool"); case schema::Type::BOOL: return kj::strTree("Bool");
...@@ -209,16 +211,16 @@ private: ...@@ -209,16 +211,16 @@ private:
case schema::Type::TEXT: return kj::strTree("Text"); case schema::Type::TEXT: return kj::strTree("Text");
case schema::Type::DATA: return kj::strTree("Data"); case schema::Type::DATA: return kj::strTree("Data");
case schema::Type::LIST: case schema::Type::LIST:
return kj::strTree("List(", genType(type.getList().getElementType(), scope), ")"); return kj::strTree("List(", genType(type.getList().getElementType(), scope, method), ")");
case schema::Type::ENUM: case schema::Type::ENUM:
return nodeName(schemaLoader.get(type.getEnum().getTypeId()), scope, return nodeName(schemaLoader.get(type.getEnum().getTypeId()), scope,
type.getEnum().getBrand()); type.getEnum().getBrand(), method);
case schema::Type::STRUCT: case schema::Type::STRUCT:
return nodeName(schemaLoader.get(type.getStruct().getTypeId()), scope, return nodeName(schemaLoader.get(type.getStruct().getTypeId()), scope,
type.getStruct().getBrand()); type.getStruct().getBrand(), method);
case schema::Type::INTERFACE: case schema::Type::INTERFACE:
return nodeName(schemaLoader.get(type.getInterface().getTypeId()), scope, return nodeName(schemaLoader.get(type.getInterface().getTypeId()), scope,
type.getInterface().getBrand()); type.getInterface().getBrand(), method);
case schema::Type::ANY_POINTER: { case schema::Type::ANY_POINTER: {
auto anyPointer = type.getAnyPointer(); auto anyPointer = type.getAnyPointer();
switch (anyPointer.which()) { switch (anyPointer.which()) {
...@@ -235,6 +237,12 @@ private: ...@@ -235,6 +237,12 @@ private:
KJ_REQUIRE(param.getParameterIndex() < params.size()); KJ_REQUIRE(param.getParameterIndex() < params.size());
return kj::strTree(params[param.getParameterIndex()].getName()); return kj::strTree(params[param.getParameterIndex()].getName());
} }
case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER: {
auto params = KJ_REQUIRE_NONNULL(method).getProto().getImplicitParameters();
uint index = anyPointer.getImplicitMethodParameter().getParameterIndex();
KJ_REQUIRE(index < params.size());
return kj::strTree(params[index].getName());
}
} }
KJ_UNREACHABLE; KJ_UNREACHABLE;
} }
...@@ -361,10 +369,10 @@ private: ...@@ -361,10 +369,10 @@ private:
auto value = genValue(schemaLoader.getType(annDecl.getType(), decl), auto value = genValue(schemaLoader.getType(annDecl.getType(), decl),
annotation.getValue()).flatten(); annotation.getValue()).flatten();
if (value.startsWith("(")) { if (value.startsWith("(")) {
return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getBrand()), return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getBrand(), nullptr),
value, suffix); value, suffix);
} else { } else {
return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getBrand()), return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getBrand(), nullptr),
"(", value, ")", suffix); "(", value, ")", suffix);
} }
} }
...@@ -443,7 +451,7 @@ private: ...@@ -443,7 +451,7 @@ private:
int size = typeSizeBits(slot.getType()); int size = typeSizeBits(slot.getType());
return kj::strTree( return kj::strTree(
indent, proto.getName(), " @", proto.getOrdinal().getExplicit(), indent, proto.getName(), " @", proto.getOrdinal().getExplicit(),
" :", genType(slot.getType(), scope), " :", genType(slot.getType(), scope, nullptr),
isEmptyValue(slot.getDefaultValue()) ? kj::strTree("") : isEmptyValue(slot.getDefaultValue()) ? kj::strTree("") :
kj::strTree(" = ", genValue(field.getType(), slot.getDefaultValue())), kj::strTree(" = ", genValue(field.getType(), slot.getDefaultValue())),
genAnnotations(proto.getAnnotations(), scope), genAnnotations(proto.getAnnotations(), scope),
...@@ -470,7 +478,7 @@ private: ...@@ -470,7 +478,7 @@ private:
} }
kj::StringTree genParamList(InterfaceSchema interface, StructSchema schema, kj::StringTree genParamList(InterfaceSchema interface, StructSchema schema,
schema::Brand::Reader brand) { schema::Brand::Reader brand, InterfaceSchema::Method method) {
if (schema.getProto().getScopeId() == 0) { if (schema.getProto().getScopeId() == 0) {
// A named parameter list. // A named parameter list.
return kj::strTree("(", kj::StringTree( return kj::strTree("(", kj::StringTree(
...@@ -479,13 +487,13 @@ private: ...@@ -479,13 +487,13 @@ private:
auto slot = proto.getSlot(); auto slot = proto.getSlot();
return kj::strTree( return kj::strTree(
proto.getName(), " :", genType(slot.getType(), interface), proto.getName(), " :", genType(slot.getType(), interface, nullptr),
isEmptyValue(slot.getDefaultValue()) ? kj::strTree("") : isEmptyValue(slot.getDefaultValue()) ? kj::strTree("") :
kj::strTree(" = ", genValue(field.getType(), slot.getDefaultValue())), kj::strTree(" = ", genValue(field.getType(), slot.getDefaultValue())),
genAnnotations(proto.getAnnotations(), interface)); genAnnotations(proto.getAnnotations(), interface));
}, ", "), ")"); }, ", "), ")");
} else { } else {
return nodeName(schema, interface, brand); return nodeName(schema, interface, brand, method);
} }
} }
...@@ -496,7 +504,8 @@ private: ...@@ -496,7 +504,8 @@ private:
} else { } else {
return kj::strTree(" superclasses(", kj::StringTree( return kj::strTree(" superclasses(", kj::StringTree(
KJ_MAP(superclass, superclasses) { KJ_MAP(superclass, superclasses) {
return nodeName(schemaLoader.get(superclass.getId()), interface, superclass.getBrand()); return nodeName(schemaLoader.get(superclass.getId()), interface,
superclass.getBrand(), nullptr);
}, ", "), ")"); }, ", "), ")");
} }
} }
...@@ -549,12 +558,23 @@ private: ...@@ -549,12 +558,23 @@ private:
genAnnotations(schema), " {\n", genAnnotations(schema), " {\n",
KJ_MAP(method, sortByCodeOrder(interface.getMethods())) { KJ_MAP(method, sortByCodeOrder(interface.getMethods())) {
auto methodProto = method.getProto(); auto methodProto = method.getProto();
auto implicits = methodProto.getImplicitParameters();
kj::StringTree implicitsStr;
if (implicits.size() > 0) {
implicitsStr = kj::strTree(
"[", kj::StringTree(KJ_MAP(implicit, implicits) {
return kj::strTree(implicit.getName());
}, ", "), "] ");
}
auto params = schemaLoader.get(methodProto.getParamStructType()).asStruct(); auto params = schemaLoader.get(methodProto.getParamStructType()).asStruct();
auto results = schemaLoader.get(methodProto.getResultStructType()).asStruct(); auto results = schemaLoader.get(methodProto.getResultStructType()).asStruct();
return kj::strTree( return kj::strTree(
indent.next(), methodProto.getName(), " @", method.getIndex(), " ", indent.next(), methodProto.getName(),
genParamList(interface, params, methodProto.getParamBrand()), " -> ", " @", method.getIndex(), " ", kj::mv(implicitsStr),
genParamList(interface, results, methodProto.getResultBrand()), genParamList(interface, params, methodProto.getParamBrand(), method), " -> ",
genParamList(interface, results, methodProto.getResultBrand(), method),
genAnnotations(methodProto.getAnnotations(), interface), ";\n"); genAnnotations(methodProto.getAnnotations(), interface), ";\n");
}, },
genNestedDecls(schema, indent.next()), genNestedDecls(schema, indent.next()),
...@@ -564,7 +584,7 @@ private: ...@@ -564,7 +584,7 @@ private:
auto constProto = proto.getConst(); auto constProto = proto.getConst();
return kj::strTree( return kj::strTree(
indent, "const ", name, " @0x", kj::hex(proto.getId()), " :", indent, "const ", name, " @0x", kj::hex(proto.getId()), " :",
genType(constProto.getType(), schema), " = ", genType(constProto.getType(), schema, nullptr), " = ",
genValue(schema.asConst().getType(), constProto.getValue()), genValue(schema.asConst().getType(), constProto.getValue()),
genAnnotations(schema), ";\n"); genAnnotations(schema), ";\n");
} }
...@@ -596,7 +616,7 @@ private: ...@@ -596,7 +616,7 @@ private:
return kj::strTree( return kj::strTree(
indent, "annotation ", name, " @0x", kj::hex(proto.getId()), indent, "annotation ", name, " @0x", kj::hex(proto.getId()),
" (", strArray(targets, ", "), ") :", " (", strArray(targets, ", "), ") :",
genType(annotationProto.getType(), schema), genAnnotations(schema), ";\n"); genType(annotationProto.getType(), schema, nullptr), genAnnotations(schema), ";\n");
} }
} }
......
This diff is collapsed.
...@@ -133,11 +133,11 @@ public: ...@@ -133,11 +133,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -224,7 +224,7 @@ public: ...@@ -224,7 +224,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -239,7 +239,7 @@ public: ...@@ -239,7 +239,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
...@@ -278,11 +278,11 @@ public: ...@@ -278,11 +278,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -337,7 +337,7 @@ public: ...@@ -337,7 +337,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -352,7 +352,7 @@ public: ...@@ -352,7 +352,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
...@@ -376,11 +376,11 @@ public: ...@@ -376,11 +376,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -409,7 +409,7 @@ public: ...@@ -409,7 +409,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -424,7 +424,7 @@ public: ...@@ -424,7 +424,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
...@@ -448,11 +448,11 @@ public: ...@@ -448,11 +448,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -481,7 +481,7 @@ public: ...@@ -481,7 +481,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -496,7 +496,7 @@ public: ...@@ -496,7 +496,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
......
This diff is collapsed.
...@@ -207,16 +207,34 @@ private: ...@@ -207,16 +207,34 @@ private:
// The `members` arrays contain only members with ordinal numbers, in code order. Other members // The `members` arrays contain only members with ordinal numbers, in code order. Other members
// are handled elsewhere. // are handled elsewhere.
struct ImplicitParams {
// Represents a set of implicit parameters visible in the current context.
uint64_t scopeId;
// If zero, then any reference to an implciit param in this context should be compiled to a
// `implicitMethodParam` AnyPointer. If non-zero, it should be complied to a `parameter`
// AnyPointer.
List<Declaration::BrandParameter>::Reader params;
};
static inline ImplicitParams noImplicitParams() {
return { 0, List<Declaration::BrandParameter>::Reader() };
}
template <typename InitBrandFunc> template <typename InitBrandFunc>
uint64_t compileParamList(kj::StringPtr methodName, uint16_t ordinal, bool isResults, uint64_t compileParamList(kj::StringPtr methodName, uint16_t ordinal, bool isResults,
Declaration::ParamList::Reader paramList, Declaration::ParamList::Reader paramList,
List<Declaration::BrandParameter>::Reader implicitParams,
InitBrandFunc&& initBrand); InitBrandFunc&& initBrand);
// 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, ImplicitParams implicitMethodParams);
// 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,
ImplicitParams implicitMethodParams);
// 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.
......
...@@ -344,16 +344,8 @@ Orphan<List<T>> arrayToList(Orphanage& orphanage, kj::Array<Orphan<T>>&& element ...@@ -344,16 +344,8 @@ Orphan<List<T>> arrayToList(Orphanage& orphanage, kj::Array<Orphan<T>>&& element
return kj::mv(result); return kj::mv(result);
} }
inline Declaration::Builder initDecl( static void initGenericParams(Declaration::Builder builder,
Declaration::Builder builder, Located<Text::Reader>&& name, kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>>&& genericParameters) {
kj::Maybe<Orphan<LocatedInteger>>&& id,
kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>>&& genericParameters,
kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations) {
name.copyTo(builder.initName());
KJ_IF_MAYBE(i, id) {
builder.getId().adoptUid(kj::mv(*i));
}
KJ_IF_MAYBE(p, genericParameters) { KJ_IF_MAYBE(p, genericParameters) {
auto params = builder.initParameters(p->value.size()); auto params = builder.initParameters(p->value.size());
for (uint i: kj::indices(p->value)) { for (uint i: kj::indices(p->value)) {
...@@ -364,6 +356,19 @@ inline Declaration::Builder initDecl( ...@@ -364,6 +356,19 @@ inline Declaration::Builder initDecl(
} }
} }
} }
}
static Declaration::Builder initDecl(
Declaration::Builder builder, Located<Text::Reader>&& name,
kj::Maybe<Orphan<LocatedInteger>>&& id,
kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>>&& genericParameters,
kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations) {
name.copyTo(builder.initName());
KJ_IF_MAYBE(i, id) {
builder.getId().adoptUid(kj::mv(*i));
}
initGenericParams(builder, kj::mv(genericParameters));
auto list = builder.initAnnotations(annotations.size()); auto list = builder.initAnnotations(annotations.size());
for (uint i = 0; i < annotations.size(); i++) { for (uint i = 0; i < annotations.size(); i++) {
...@@ -372,7 +377,7 @@ inline Declaration::Builder initDecl( ...@@ -372,7 +377,7 @@ inline Declaration::Builder initDecl(
return builder; return builder;
} }
inline Declaration::Builder initMemberDecl( static Declaration::Builder initMemberDecl(
Declaration::Builder builder, Located<Text::Reader>&& name, Declaration::Builder builder, Located<Text::Reader>&& name,
Orphan<LocatedInteger>&& ordinal, Orphan<LocatedInteger>&& ordinal,
kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations) { kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations) {
...@@ -902,18 +907,24 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP ...@@ -902,18 +907,24 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterP
}))); })));
parsers.methodDecl = arena.copy(p::transform( parsers.methodDecl = arena.copy(p::transform(
p::sequence(identifier, parsers.ordinal, paramList, p::sequence(identifier, parsers.ordinal,
p::optional(bracketedList(identifier, errorReporter)),
paramList,
p::optional(p::sequence(op("->"), paramList)), p::optional(p::sequence(op("->"), paramList)),
p::many(parsers.annotation)), p::many(parsers.annotation)),
[this](Located<Text::Reader>&& name, Orphan<LocatedInteger>&& ordinal, [this](Located<Text::Reader>&& name, Orphan<LocatedInteger>&& ordinal,
kj::Maybe<Located<kj::Array<kj::Maybe<Located<Text::Reader>>>>>&& genericParams,
Orphan<Declaration::ParamList>&& params, Orphan<Declaration::ParamList>&& params,
kj::Maybe<Orphan<Declaration::ParamList>>&& results, kj::Maybe<Orphan<Declaration::ParamList>>&& results,
kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations) kj::Array<Orphan<Declaration::AnnotationApplication>>&& annotations)
-> DeclParserResult { -> DeclParserResult {
auto decl = orphanage.newOrphan<Declaration>(); auto decl = orphanage.newOrphan<Declaration>();
auto builder = auto nodeBuilder = initMemberDecl(
initMemberDecl(decl.get(), kj::mv(name), kj::mv(ordinal), kj::mv(annotations)) decl.get(), kj::mv(name), kj::mv(ordinal), kj::mv(annotations));
.initMethod();
initGenericParams(nodeBuilder, kj::mv(genericParams));
auto builder = nodeBuilder.initMethod();
builder.adoptParams(kj::mv(params)); builder.adoptParams(kj::mv(params));
......
...@@ -57,9 +57,13 @@ struct RawBrandedSchema { ...@@ -57,9 +57,13 @@ struct RawBrandedSchema {
struct Binding { struct Binding {
uint8_t which; // Numeric value of one of schema::Type::Which. uint8_t which; // Numeric value of one of schema::Type::Which.
bool isImplicitParameter;
// For AnyPointer, true if it's an implicit method parameter.
uint16_t listDepth; // Number of times to wrap the base type in List(). uint16_t listDepth; // Number of times to wrap the base type in List().
uint32_t paramIndex; // for AnyPointer, if it's a type parameter. uint16_t paramIndex; // for AnyPointer, if it's a type parameter.
union { union {
const RawBrandedSchema* schema; // for struct, enum, interface const RawBrandedSchema* schema; // for struct, enum, interface
...@@ -68,10 +72,15 @@ struct RawBrandedSchema { ...@@ -68,10 +72,15 @@ struct RawBrandedSchema {
Binding() = default; Binding() = default;
inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema) inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema)
: which(which), listDepth(listDepth), paramIndex(0), schema(schema) {} : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0),
schema(schema) {}
inline constexpr Binding(uint8_t which, uint16_t listDepth, inline constexpr Binding(uint8_t which, uint16_t listDepth,
uint64_t scopeId, uint32_t paramIndex) uint64_t scopeId, uint16_t paramIndex)
: which(which), listDepth(listDepth), paramIndex(paramIndex), scopeId(scopeId) {} : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex),
scopeId(scopeId) {}
inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex)
: which(which), isImplicitParameter(true), listDepth(listDepth),
paramIndex(implicitParamIndex), scopeId(0) {}
}; };
struct Scope { struct Scope {
...@@ -264,7 +273,7 @@ struct BrandBindingFor_; ...@@ -264,7 +273,7 @@ struct BrandBindingFor_;
template <> \ template <> \
struct BrandBindingFor_<Type, Kind::PRIMITIVE> { \ struct BrandBindingFor_<Type, Kind::PRIMITIVE> { \
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { \ static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { \
return { which, listDepth, 0 }; \ return { which, listDepth, nullptr }; \
} \ } \
} }
HANDLE_TYPE(Void, 0); HANDLE_TYPE(Void, 0);
......
...@@ -117,11 +117,11 @@ public: ...@@ -117,11 +117,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -146,7 +146,7 @@ public: ...@@ -146,7 +146,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -161,7 +161,7 @@ public: ...@@ -161,7 +161,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
...@@ -184,11 +184,11 @@ public: ...@@ -184,11 +184,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -213,7 +213,7 @@ public: ...@@ -213,7 +213,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -228,7 +228,7 @@ public: ...@@ -228,7 +228,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
...@@ -249,11 +249,11 @@ public: ...@@ -249,11 +249,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -275,7 +275,7 @@ public: ...@@ -275,7 +275,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -290,7 +290,7 @@ public: ...@@ -290,7 +290,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
...@@ -311,11 +311,11 @@ public: ...@@ -311,11 +311,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -337,7 +337,7 @@ public: ...@@ -337,7 +337,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -352,7 +352,7 @@ public: ...@@ -352,7 +352,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
...@@ -379,11 +379,11 @@ public: ...@@ -379,11 +379,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -414,7 +414,7 @@ public: ...@@ -414,7 +414,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -429,7 +429,7 @@ public: ...@@ -429,7 +429,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
...@@ -457,11 +457,11 @@ public: ...@@ -457,11 +457,11 @@ public:
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::_::PointerHelpers; friend struct ::capnp::_::PointerHelpers;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::List; friend struct ::capnp::List;
friend class ::capnp::MessageBuilder; friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
...@@ -493,7 +493,7 @@ public: ...@@ -493,7 +493,7 @@ public:
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage; friend class ::capnp::Orphanage;
}; };
...@@ -508,7 +508,7 @@ public: ...@@ -508,7 +508,7 @@ public:
private: private:
::capnp::AnyPointer::Pipeline _typeless; ::capnp::AnyPointer::Pipeline _typeless;
template <typename T, ::capnp::Kind k> template <typename, ::capnp::Kind>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
}; };
......
This diff is collapsed.
...@@ -1714,7 +1714,7 @@ _::RawBrandedSchema::Binding SchemaLoader::Impl::makeDep( ...@@ -1714,7 +1714,7 @@ _::RawBrandedSchema::Binding SchemaLoader::Impl::makeDep(
case schema::Type::AnyPointer::PARAMETER: { case schema::Type::AnyPointer::PARAMETER: {
auto param = anyPointer.getParameter(); auto param = anyPointer.getParameter();
uint64_t id = param.getScopeId(); uint64_t id = param.getScopeId();
uint index = param.getParameterIndex(); uint16_t index = param.getParameterIndex();
KJ_IF_MAYBE(b, brandBindings) { KJ_IF_MAYBE(b, brandBindings) {
// TODO(perf): We could binary search here, but... bleh. // TODO(perf): We could binary search here, but... bleh.
...@@ -1739,6 +1739,9 @@ _::RawBrandedSchema::Binding SchemaLoader::Impl::makeDep( ...@@ -1739,6 +1739,9 @@ _::RawBrandedSchema::Binding SchemaLoader::Impl::makeDep(
return { static_cast<uint8_t>(schema::Type::ANY_POINTER), 0, id, index }; return { static_cast<uint8_t>(schema::Type::ANY_POINTER), 0, id, index };
} }
} }
case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER:
return { static_cast<uint8_t>(schema::Type::ANY_POINTER), 0,
anyPointer.getImplicitMethodParameter().getParameterIndex() };
} }
KJ_UNREACHABLE; KJ_UNREACHABLE;
} }
...@@ -2061,6 +2064,9 @@ Type SchemaLoader::getType(schema::Type::Reader proto, Schema scope) const { ...@@ -2061,6 +2064,9 @@ Type SchemaLoader::getType(schema::Type::Reader proto, Schema scope) const {
auto param = anyPointer.getParameter(); auto param = anyPointer.getParameter();
return scope.getBrandBinding(param.getScopeId(), param.getParameterIndex()); return scope.getBrandBinding(param.getScopeId(), param.getParameterIndex());
} }
case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER:
// We don't support binding implicit method params here.
return schema::Type::ANY_POINTER;
} }
KJ_UNREACHABLE; KJ_UNREACHABLE;
......
...@@ -377,6 +377,9 @@ Type Schema::interpretType(schema::Type::Reader proto, uint location) const { ...@@ -377,6 +377,9 @@ Type Schema::interpretType(schema::Type::Reader proto, uint location) const {
auto param = anyPointer.getParameter(); auto param = anyPointer.getParameter();
return getBrandBinding(param.getScopeId(), param.getParameterIndex()); return getBrandBinding(param.getScopeId(), param.getParameterIndex());
} }
case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER:
return Type(Type::ImplicitParameter {
anyPointer.getImplicitMethodParameter().getParameterIndex() });
} }
KJ_UNREACHABLE; KJ_UNREACHABLE;
...@@ -400,10 +403,12 @@ Type Schema::BrandArgumentList::operator[](uint index) const { ...@@ -400,10 +403,12 @@ Type Schema::BrandArgumentList::operator[](uint index) const {
auto& binding = bindings[index]; auto& binding = bindings[index];
if (binding.which == (uint)schema::Type::ANY_POINTER) { if (binding.which == (uint)schema::Type::ANY_POINTER) {
if (binding.scopeId == 0) { if (binding.scopeId != 0) {
return Type(schema::Type::ANY_POINTER, binding.listDepth, nullptr);
} else {
return Type::BrandParameter { binding.scopeId, binding.paramIndex }; return Type::BrandParameter { binding.scopeId, binding.paramIndex };
} else if (binding.isImplicitParameter) {
return Type::ImplicitParameter { binding.paramIndex };
} else {
return Type(schema::Type::ANY_POINTER, binding.listDepth, nullptr);
} }
} else if (binding.schema == nullptr) { } else if (binding.schema == nullptr) {
// Builtin / primitive type. // Builtin / primitive type.
...@@ -798,6 +803,17 @@ kj::Maybe<Type::BrandParameter> Type::getBrandParameter() const { ...@@ -798,6 +803,17 @@ kj::Maybe<Type::BrandParameter> Type::getBrandParameter() const {
} }
} }
kj::Maybe<Type::ImplicitParameter> Type::getImplicitParameter() const {
KJ_REQUIRE(isAnyPointer(),
"Type::getImplicitParameter() can only be called on AnyPointer types.");
if (isImplicitParam) {
return ImplicitParameter { paramIndex };
} else {
return nullptr;
}
}
bool Type::operator==(const Type& other) const { bool Type::operator==(const Type& other) const {
if (baseType != other.baseType || listDepth != other.listDepth) { if (baseType != other.baseType || listDepth != other.listDepth) {
return false; return false;
......
...@@ -255,6 +255,10 @@ struct Method { ...@@ -255,6 +255,10 @@ struct Method {
# Specifies order in which the methods were declared in the code. # Specifies order in which the methods were declared in the code.
# Like Struct.Field.codeOrder. # Like Struct.Field.codeOrder.
implicitParameters @7 :List(Node.Parameter);
# The parameters listed in [] (typically, type / generic parameters), whose bindings are intended
# to be inferred rather than specified explicitly, although not all languages support this.
paramStructType @2 :Id; paramStructType @2 :Id;
# ID of the parameter struct type. If a named parameter list was specified in the method # ID of the parameter struct type. If a named parameter list was specified in the method
# declaration (rather than a single struct parameter type) then a corresponding struct type is # declaration (rather than a single struct parameter type) then a corresponding struct type is
...@@ -328,6 +332,13 @@ struct Type { ...@@ -328,6 +332,13 @@ struct Type {
parameterIndex @20 :UInt16; parameterIndex @20 :UInt16;
# Index of the parameter within the generic type's parameter list. # Index of the parameter within the generic type's parameter list.
} }
implicitMethodParameter :group {
# This is actually a reference to an implicit (generic) parameter of a method. The only
# legal context for this type to appear is inside Method.paramBrand or Method.resultBrand.
parameterIndex @24 :UInt16;
}
} }
} }
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -570,6 +570,9 @@ public: ...@@ -570,6 +570,9 @@ public:
uint64_t scopeId; uint64_t scopeId;
uint index; uint index;
}; };
struct ImplicitParameter {
uint index;
};
inline Type(); inline Type();
inline Type(schema::Type::Which primitive); inline Type(schema::Type::Which primitive);
...@@ -578,6 +581,7 @@ public: ...@@ -578,6 +581,7 @@ public:
inline Type(InterfaceSchema schema); inline Type(InterfaceSchema schema);
inline Type(ListSchema schema); inline Type(ListSchema schema);
inline Type(BrandParameter param); inline Type(BrandParameter param);
inline Type(ImplicitParameter param);
template <typename T> template <typename T>
inline static Type from(); inline static Type from();
...@@ -594,6 +598,10 @@ public: ...@@ -594,6 +598,10 @@ public:
// Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular
// AnyPointer and not a parameter. // AnyPointer and not a parameter.
kj::Maybe<ImplicitParameter> getImplicitParameter() const;
// Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular
// AnyPointer and not a parameter. "Implicit parameters" refer to type parameters on methods.
inline bool isVoid() const; inline bool isVoid() const;
inline bool isBool() const; inline bool isBool() const;
inline bool isInt8() const; inline bool isInt8() const;
...@@ -621,7 +629,11 @@ private: ...@@ -621,7 +629,11 @@ private:
schema::Type::Which baseType; // type not including applications of List() schema::Type::Which baseType; // type not including applications of List()
uint8_t listDepth; // 0 for T, 1 for List(T), 2 for List(List(T)), ... uint8_t listDepth; // 0 for T, 1 for List(T), 2 for List(List(T)), ...
uint32_t paramIndex; bool isImplicitParam;
// If true, this refers to an implicit method parameter. baseType must be ANY_POINTER, scopeId
// must be zero, and paramIndex indicates the parameter index.
uint16_t paramIndex;
// If baseType is ANY_POINTER but this Type actually refers to a type parameter, this is the // If baseType is ANY_POINTER but this Type actually refers to a type parameter, this is the
// index of the parameter among the parameters at its scope, and `scopeId` below is the type ID // index of the parameter among the parameters at its scope, and `scopeId` below is the type ID
// of the scope where the parameter was defined. // of the scope where the parameter was defined.
...@@ -806,7 +818,7 @@ struct ListSchema::FromImpl<List<T>> { ...@@ -806,7 +818,7 @@ struct ListSchema::FromImpl<List<T>> {
inline Type::Type(): baseType(schema::Type::VOID), listDepth(0), schema(nullptr) {} inline Type::Type(): baseType(schema::Type::VOID), listDepth(0), schema(nullptr) {}
inline Type::Type(schema::Type::Which primitive) inline Type::Type(schema::Type::Which primitive)
: baseType(primitive), listDepth(0), schema(nullptr) { : baseType(primitive), listDepth(0), isImplicitParam(false), scopeId(0) {
KJ_IREQUIRE(primitive != schema::Type::STRUCT && KJ_IREQUIRE(primitive != schema::Type::STRUCT &&
primitive != schema::Type::ENUM && primitive != schema::Type::ENUM &&
primitive != schema::Type::INTERFACE && primitive != schema::Type::INTERFACE &&
...@@ -822,8 +834,11 @@ inline Type::Type(InterfaceSchema schema) ...@@ -822,8 +834,11 @@ inline Type::Type(InterfaceSchema schema)
inline Type::Type(ListSchema schema) inline Type::Type(ListSchema schema)
: Type(schema.getElementType()) { ++listDepth; } : Type(schema.getElementType()) { ++listDepth; }
inline Type::Type(BrandParameter param) inline Type::Type(BrandParameter param)
: baseType(schema::Type::ANY_POINTER), listDepth(0), paramIndex(param.index), : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false),
scopeId(param.scopeId) {} paramIndex(param.index), scopeId(param.scopeId) {}
inline Type::Type(ImplicitParameter param)
: baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(true),
paramIndex(param.index), scopeId(0) {}
inline schema::Type::Which Type::which() const { inline schema::Type::Which Type::which() const {
return listDepth > 0 ? schema::Type::LIST : baseType; return listDepth > 0 ? schema::Type::LIST : baseType;
......
...@@ -556,6 +556,10 @@ struct TestGenericsWrapper2 { ...@@ -556,6 +556,10 @@ struct TestGenericsWrapper2 {
value @0 :TestGenericsWrapper(Text, TestAllTypes); value @0 :TestGenericsWrapper(Text, TestAllTypes);
} }
interface TestImplicitMethodParams {
call @0 [T, U] (foo :T, bar :U) -> TestGenerics(T, U);
}
struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") { struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") {
basic @0 :TestGenerics(TestAllTypes, TestAnyPointer); basic @0 :TestGenerics(TestAllTypes, TestAnyPointer);
inner @1 :TestGenerics(TestAllTypes, TestAnyPointer).Inner; inner @1 :TestGenerics(TestAllTypes, TestAnyPointer).Inner;
......
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