Commit 1d9a5d88 authored by Georg Schmid's avatar Georg Schmid Committed by Commit Bot

[torque] Add Generic Structs

This CL introduces generic Torque structs. Generics are grounded early in the Torque compilation pipeline, meaning that every instantiation of a generic struct with concrete types will be turned into a distinct StructType.

As an example, consider a Tuple of types T1, T2:

  struct Tuple<T1: type, T2: type> {
    const fst: T1;
    const snd: T2;
  }

which can be manipulated using generic macros, such as

  macro Swap<T1: type, T2: type>(tuple: Tuple<T1, T2>): Tuple<T2, T1> {
    return Tuple<T2, T1>{fst: tuple.snd, snd: tuple.fst};
  }

Currently there is no type inference for struct instantiation sites, so type arguments have to be provided explicitly:

  const intptrAndSmi = Tuple<intptr, Smi>{fst: 1, snd: 2};

R=sigurds@chromium.org, tebbi@chromium.org

Change-Id: I43111561cbe53144db473dc844a478045644ef6c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1714868
Commit-Queue: Georg Schmid <gsps@google.com>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62878}
parent bbb833c9
......@@ -586,14 +586,17 @@ struct BasicTypeExpression : TypeExpression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(BasicTypeExpression)
BasicTypeExpression(SourcePosition pos,
std::vector<std::string> namespace_qualification,
std::string name)
std::string name,
std::vector<TypeExpression*> generic_arguments)
: TypeExpression(kKind, pos),
namespace_qualification(std::move(namespace_qualification)),
is_constexpr(IsConstexprName(name)),
name(std::move(name)) {}
name(std::move(name)),
generic_arguments(std::move(generic_arguments)) {}
std::vector<std::string> namespace_qualification;
bool is_constexpr;
std::string name;
std::vector<TypeExpression*> generic_arguments;
};
struct FunctionTypeExpression : TypeExpression {
......@@ -1070,12 +1073,17 @@ struct StructDeclaration : TypeDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(StructDeclaration)
StructDeclaration(SourcePosition pos, Identifier* name,
std::vector<Declaration*> methods,
std::vector<StructFieldExpression> fields)
std::vector<StructFieldExpression> fields,
std::vector<Identifier*> generic_parameters)
: TypeDeclaration(kKind, pos, name),
methods(std::move(methods)),
fields(std::move(fields)) {}
fields(std::move(fields)),
generic_parameters(std::move(generic_parameters)) {}
std::vector<Declaration*> methods;
std::vector<StructFieldExpression> fields;
std::vector<Identifier*> generic_parameters;
bool IsGeneric() const { return !generic_parameters.empty(); }
};
struct ClassDeclaration : TypeDeclaration {
......
......@@ -50,6 +50,7 @@ class Declarable {
kRuntimeFunction,
kIntrinsic,
kGeneric,
kGenericStructType,
kTypeAlias,
kExternConstant,
kNamespaceConstant
......@@ -64,6 +65,7 @@ class Declarable {
bool IsBuiltin() const { return kind() == kBuiltin; }
bool IsRuntimeFunction() const { return kind() == kRuntimeFunction; }
bool IsGeneric() const { return kind() == kGeneric; }
bool IsGenericStructType() const { return kind() == kGenericStructType; }
bool IsTypeAlias() const { return kind() == kTypeAlias; }
bool IsExternConstant() const { return kind() == kExternConstant; }
bool IsNamespaceConstant() const { return kind() == kNamespaceConstant; }
......@@ -450,26 +452,43 @@ class Intrinsic : public Callable {
}
};
class Generic : public Declarable {
template <class T>
class SpecializationMap {
private:
using Map = std::unordered_map<TypeVector, T*, base::hash<TypeVector>>;
public:
DECLARE_DECLARABLE_BOILERPLATE(Generic, generic)
SpecializationMap() {}
GenericDeclaration* declaration() const { return declaration_; }
const std::vector<Identifier*> generic_parameters() const {
return declaration()->generic_parameters;
}
const std::string& name() const { return name_; }
void AddSpecialization(const TypeVector& type_arguments,
Callable* specialization) {
void Add(const TypeVector& type_arguments, T* specialization) {
DCHECK_EQ(0, specializations_.count(type_arguments));
specializations_[type_arguments] = specialization;
}
base::Optional<Callable*> GetSpecialization(
const TypeVector& type_arguments) const {
base::Optional<T*> Get(const TypeVector& type_arguments) const {
auto it = specializations_.find(type_arguments);
if (it != specializations_.end()) return it->second;
return base::nullopt;
}
using iterator = typename Map::const_iterator;
iterator begin() const { return specializations_.begin(); }
iterator end() const { return specializations_.end(); }
private:
Map specializations_;
};
class Generic : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(Generic, generic)
const std::string& name() const { return name_; }
GenericDeclaration* declaration() const { return declaration_; }
const std::vector<Identifier*> generic_parameters() const {
return declaration()->generic_parameters;
}
SpecializationMap<Callable>& specializations() { return specializations_; }
base::Optional<TypeVector> InferSpecializationTypes(
const TypeVector& explicit_specialization_types,
const TypeVector& arguments);
......@@ -482,9 +501,8 @@ class Generic : public Declarable {
declaration_(declaration) {}
std::string name_;
std::unordered_map<TypeVector, Callable*, base::hash<TypeVector>>
specializations_;
GenericDeclaration* declaration_;
SpecializationMap<Callable> specializations_;
};
struct SpecializationKey {
......@@ -492,6 +510,32 @@ struct SpecializationKey {
TypeVector specialized_types;
};
class GenericStructType : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(GenericStructType, generic_type)
const std::string& name() const { return name_; }
StructDeclaration* declaration() const { return declaration_; }
const std::vector<Identifier*>& generic_parameters() const {
return declaration_->generic_parameters;
}
SpecializationMap<const StructType>& specializations() {
return specializations_;
}
private:
friend class Declarations;
GenericStructType(const std::string& name, StructDeclaration* declaration)
: Declarable(Declarable::kGenericStructType),
name_(name),
declaration_(declaration) {
DCHECK_GT(declaration->generic_parameters.size(), 0);
}
std::string name_;
StructDeclaration* declaration_;
SpecializationMap<const StructType> specializations_;
};
class TypeAlias : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(TypeAlias, type_alias)
......
......@@ -333,7 +333,7 @@ Callable* DeclarationVisitor::Specialize(
<< std::to_string(generic_parameter_count) << ")";
ReportError(stream.str());
}
if (key.generic->GetSpecialization(key.specialized_types)) {
if (key.generic->specializations().Get(key.specialized_types)) {
ReportError("cannot redeclare specialization of ", key.generic->name(),
" with types <", key.specialized_types, ">");
}
......@@ -364,7 +364,7 @@ Callable* DeclarationVisitor::Specialize(
callable = CreateBuiltin(builtin, generated_name, readable_name.str(),
type_signature, *body);
}
key.generic->AddSpecialization(key.specialized_types, callable);
key.generic->specializations().Add(key.specialized_types, callable);
return callable;
}
......
......@@ -37,6 +37,13 @@ class PredeclarationVisitor {
static void Predeclare(TypeDeclaration* decl) {
Declarations::PredeclareTypeAlias(decl->name, decl, false);
}
static void Predeclare(StructDeclaration* decl) {
if (decl->IsGeneric()) {
Declarations::DeclareGenericStructType(decl->name->value, decl);
} else {
Declarations::PredeclareTypeAlias(decl->name, decl, false);
}
}
static void Predeclare(GenericDeclaration* decl) {
Declarations::DeclareGeneric(decl->callable->name, decl);
}
......@@ -59,6 +66,11 @@ class DeclarationVisitor {
// are reported even if the type is unused.
Declarations::LookupType(decl->name);
}
static void Visit(StructDeclaration* decl) {
if (!decl->IsGeneric()) {
Declarations::LookupType(decl->name);
}
}
static Builtin* CreateBuiltin(BuiltinDeclaration* decl,
std::string external_name,
......
......@@ -133,6 +133,12 @@ Generic* Declarations::LookupUniqueGeneric(const QualifiedName& name) {
"generic");
}
GenericStructType* Declarations::LookupUniqueGenericStructType(
const QualifiedName& name) {
return EnsureUnique(FilterDeclarables<GenericStructType>(Lookup(name)), name,
"generic struct");
}
Namespace* Declarations::DeclareNamespace(const std::string& name) {
return Declare(name, std::unique_ptr<Namespace>(new Namespace(name)));
}
......@@ -278,6 +284,12 @@ Generic* Declarations::DeclareGeneric(const std::string& name,
return Declare(name, std::unique_ptr<Generic>(new Generic(name, generic)));
}
GenericStructType* Declarations::DeclareGenericStructType(
const std::string& name, StructDeclaration* decl) {
return Declare(name, std::unique_ptr<GenericStructType>(
new GenericStructType(name, decl)));
}
std::string Declarations::GetGeneratedCallableName(
const std::string& name, const TypeVector& specialized_types) {
std::string result = name;
......
......@@ -76,6 +76,9 @@ class Declarations {
static std::vector<Generic*> LookupGeneric(const std::string& name);
static Generic* LookupUniqueGeneric(const QualifiedName& name);
static GenericStructType* LookupUniqueGenericStructType(
const QualifiedName& name);
static Namespace* DeclareNamespace(const std::string& name);
static TypeAlias* DeclareType(const Identifier* name, const Type* type);
......@@ -129,6 +132,8 @@ class Declarations {
static Generic* DeclareGeneric(const std::string& name,
GenericDeclaration* generic);
static GenericStructType* DeclareGenericStructType(const std::string& name,
StructDeclaration* decl);
template <class T>
static T* Declare(const std::string& name, T* d) {
......
......@@ -1601,7 +1601,7 @@ void FailCallableLookup(const std::string& reason, const QualifiedName& name,
Callable* GetOrCreateSpecialization(const SpecializationKey& key) {
if (base::Optional<Callable*> specialization =
key.generic->GetSpecialization(key.specialized_types)) {
key.generic->specializations().Get(key.specialized_types)) {
return *specialization;
}
return DeclarationVisitor::SpecializeImplicit(key);
......@@ -2658,6 +2658,7 @@ void ImplementationVisitor::Visit(Declarable* declarable) {
case Declarable::kExternConstant:
case Declarable::kNamespace:
case Declarable::kGeneric:
case Declarable::kGenericStructType:
return;
}
}
......@@ -3671,13 +3672,13 @@ void ImplementationVisitor::GenerateCSATypes(
NamespaceScope h_namespaces(h_contents, {"v8", "internal"});
for (auto& declarable : GlobalContext::AllDeclarables()) {
TypeAlias* alias = TypeAlias::DynamicCast(declarable.get());
if (!alias || alias->IsRedeclaration()) continue;
const StructType* struct_type = StructType::DynamicCast(alias->type());
// Generates headers for all structs in a topologically-sorted order, since
// TypeOracle keeps them in the order of their resolution
for (auto& type : *TypeOracle::GetAggregateTypes()) {
const StructType* struct_type = StructType::DynamicCast(type.get());
if (!struct_type) continue;
const std::string& name = struct_type->name();
h_contents << "struct TorqueStruct" << name << " {\n";
h_contents << "struct " << struct_type->GetGeneratedTypeNameImpl()
<< " {\n";
for (auto& field : struct_type->fields()) {
h_contents << " " << field.name_and_type.type->GetGeneratedTypeName();
h_contents << " " << field.name_and_type.name << ";\n";
......
......@@ -65,7 +65,7 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
// A class types' fields are resolved here, which allows two class fields to
// mutually refer to each others.
TypeOracle::FinalizeClassTypes();
TypeOracle::FinalizeAggregateTypes();
std::string output_directory = options.output_directory;
......
......@@ -461,8 +461,8 @@ base::Optional<ParseResult> MakeDebugStatement(
}
base::Optional<ParseResult> MakeVoidType(ParseResultIterator* child_results) {
TypeExpression* result =
MakeNode<BasicTypeExpression>(std::vector<std::string>{}, "void");
TypeExpression* result = MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, "void", std::vector<TypeExpression*>{});
return ParseResult{result};
}
......@@ -776,10 +776,13 @@ base::Optional<ParseResult> MakeStructDeclaration(
if (!IsValidTypeName(name->value)) {
NamingConventionError("Struct", name, "UpperCamelCase");
}
auto generic_parameters = child_results->NextAs<GenericParameters>();
LintGenericParameters(generic_parameters);
auto methods = child_results->NextAs<std::vector<Declaration*>>();
auto fields = child_results->NextAs<std::vector<StructFieldExpression>>();
Declaration* result =
MakeNode<StructDeclaration>(name, std::move(methods), std::move(fields));
MakeNode<StructDeclaration>(name, std::move(methods), std::move(fields),
std::move(generic_parameters));
return ParseResult{result};
}
......@@ -855,9 +858,12 @@ base::Optional<ParseResult> MakeBasicTypeExpression(
child_results->NextAs<std::vector<std::string>>();
auto is_constexpr = child_results->NextAs<bool>();
auto name = child_results->NextAs<std::string>();
auto generic_arguments =
child_results->NextAs<std::vector<TypeExpression*>>();
TypeExpression* result = MakeNode<BasicTypeExpression>(
std::move(namespace_qualification),
is_constexpr ? GetConstexprName(name) : std::move(name));
is_constexpr ? GetConstexprName(name) : std::move(name),
std::move(generic_arguments));
return ParseResult{result};
}
......@@ -1134,8 +1140,8 @@ base::Optional<ParseResult> MakeCatchBlock(ParseResultIterator* child_results) {
}
ParameterList parameters;
parameters.names.push_back(MakeNode<Identifier>(variable));
parameters.types.push_back(
MakeNode<BasicTypeExpression>(std::vector<std::string>{}, "Object"));
parameters.types.push_back(MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, "Object", std::vector<TypeExpression*>{}));
parameters.has_varargs = false;
LabelBlock* result = MakeNode<LabelBlock>(
MakeNode<Identifier>(kCatchLabelName), std::move(parameters), body);
......@@ -1161,6 +1167,17 @@ base::Optional<ParseResult> MakeIdentifierFromMatchedInput(
MakeNode<Identifier>(child_results->matched_input().ToString())};
}
base::Optional<ParseResult> MakeRightShiftIdentifier(
ParseResultIterator* child_results) {
std::string str = child_results->matched_input().ToString();
for (auto character : str) {
if (character != '>') {
ReportError("right-shift operators may not contain any whitespace");
}
}
return ParseResult{MakeNode<Identifier>(str)};
}
base::Optional<ParseResult> MakeIdentifierExpression(
ParseResultIterator* child_results) {
auto namespace_qualification =
......@@ -1491,7 +1508,9 @@ struct TorqueGrammar : Grammar {
Symbol simpleType = {
Rule({Token("("), &type, Token(")")}),
Rule({List<std::string>(Sequence({&identifier, Token("::")})),
CheckIf(Token("constexpr")), &identifier},
CheckIf(Token("constexpr")), &identifier,
TryOrDefault<std::vector<TypeExpression*>>(
&genericSpecializationTypeList)},
MakeBasicTypeExpression),
Rule({Token("builtin"), Token("("), typeList, Token(")"), Token("=>"),
&simpleType},
......@@ -1689,9 +1708,14 @@ struct TorqueGrammar : Grammar {
Symbol* additiveExpression =
BinaryOperator(multiplicativeExpression, OneOf({"+", "-"}));
// Result: Identifier*
Symbol shiftOperator = {
Rule({Token("<<")}, MakeIdentifierFromMatchedInput),
Rule({Token(">"), Token(">")}, MakeRightShiftIdentifier),
Rule({Token(">"), Token(">"), Token(">")}, MakeRightShiftIdentifier)};
// Result: Expression*
Symbol* shiftExpression =
BinaryOperator(additiveExpression, OneOf({"<<", ">>", ">>>"}));
Symbol* shiftExpression = BinaryOperator(additiveExpression, &shiftOperator);
// Do not allow expressions like a < b > c because this is never
// useful and ambiguous with template parameters.
......@@ -1853,7 +1877,9 @@ struct TorqueGrammar : Grammar {
Token("{"), List<Declaration*>(&method),
List<ClassFieldExpression>(&classField), Token("}")},
AsSingletonVector<Declaration*, MakeClassDeclaration>()),
Rule({Token("struct"), &name, Token("{"), List<Declaration*>(&method),
Rule({Token("struct"), &name,
TryOrDefault<GenericParameters>(&genericParameters), Token("{"),
List<Declaration*>(&method),
List<StructFieldExpression>(&structField), Token("}")},
AsSingletonVector<Declaration*, MakeStructDeclaration>()),
Rule({CheckIf(Token("transient")), Token("type"), &name,
......
......@@ -11,8 +11,14 @@ namespace torque {
DEFINE_CONTEXTUAL_VARIABLE(TypeOracle)
// static
void TypeOracle::FinalizeClassTypes() {
for (const std::unique_ptr<AggregateType>& p : Get().struct_types_) {
const std::vector<std::unique_ptr<AggregateType>>*
TypeOracle::GetAggregateTypes() {
return &Get().aggregate_types_;
}
// static
void TypeOracle::FinalizeAggregateTypes() {
for (const std::unique_ptr<AggregateType>& p : Get().aggregate_types_) {
p->Finalize();
}
}
......
......@@ -32,7 +32,7 @@ class TypeOracle : public ContextualClass<TypeOracle> {
static StructType* GetStructType(const std::string& name) {
StructType* result = new StructType(CurrentNamespace(), name);
Get().struct_types_.push_back(std::unique_ptr<StructType>(result));
Get().aggregate_types_.push_back(std::unique_ptr<StructType>(result));
return result;
}
......@@ -42,7 +42,7 @@ class TypeOracle : public ContextualClass<TypeOracle> {
const TypeAlias* alias) {
ClassType* result = new ClassType(parent, CurrentNamespace(), name, flags,
generates, decl, alias);
Get().struct_types_.push_back(std::unique_ptr<ClassType>(result));
Get().aggregate_types_.push_back(std::unique_ptr<ClassType>(result));
return result;
}
......@@ -222,8 +222,8 @@ class TypeOracle : public ContextualClass<TypeOracle> {
static bool IsImplicitlyConvertableFrom(const Type* to, const Type* from) {
for (Generic* from_constexpr :
Declarations::LookupGeneric(kFromConstexprMacroName)) {
if (base::Optional<Callable*> specialization =
from_constexpr->GetSpecialization({to, from})) {
if (base::Optional<const Callable*> specialization =
from_constexpr->specializations().Get({to, from})) {
if ((*specialization)->signature().GetExplicitTypes() ==
TypeVector{from}) {
return true;
......@@ -233,7 +233,9 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return false;
}
static void FinalizeClassTypes();
static const std::vector<std::unique_ptr<AggregateType>>* GetAggregateTypes();
static void FinalizeAggregateTypes();
private:
const Type* GetBuiltinType(const std::string& name) {
......@@ -245,7 +247,7 @@ class TypeOracle : public ContextualClass<TypeOracle> {
Deduplicator<UnionType> union_types_;
Deduplicator<ReferenceType> reference_types_;
std::vector<std::unique_ptr<Type>> nominal_types_;
std::vector<std::unique_ptr<AggregateType>> struct_types_;
std::vector<std::unique_ptr<AggregateType>> aggregate_types_;
std::vector<std::unique_ptr<Type>> top_types_;
};
......
......@@ -110,9 +110,25 @@ void DeclareMethods(AggregateType* container_type,
}
}
namespace {
std::string ComputeStructName(StructDeclaration* decl) {
TypeVector args;
if (decl->IsGeneric()) {
args.resize(decl->generic_parameters.size());
std::transform(
decl->generic_parameters.begin(), decl->generic_parameters.end(),
args.begin(), [](Identifier* parameter) {
return Declarations::LookupTypeAlias(QualifiedName(parameter->value))
->type();
});
}
return StructType::ComputeName(decl->name->value, args);
}
} // namespace
const StructType* TypeVisitor::ComputeType(StructDeclaration* decl) {
CurrentSourcePosition::Scope position_activator(decl->pos);
StructType* struct_type = TypeOracle::GetStructType(decl->name->value);
StructType* struct_type = TypeOracle::GetStructType(ComputeStructName(decl));
size_t offset = 0;
for (auto& field : decl->fields) {
CurrentSourcePosition::Scope position_activator(
......@@ -186,13 +202,54 @@ const ClassType* TypeVisitor::ComputeType(ClassDeclaration* decl) {
const Type* TypeVisitor::ComputeType(TypeExpression* type_expression) {
if (auto* basic = BasicTypeExpression::DynamicCast(type_expression)) {
const TypeAlias* alias = Declarations::LookupTypeAlias(
QualifiedName{basic->namespace_qualification, basic->name});
QualifiedName qualified_name{basic->namespace_qualification, basic->name};
auto& args = basic->generic_arguments;
const Type* type;
SourcePosition pos = SourcePosition::Invalid();
if (args.empty()) {
auto* alias = Declarations::LookupTypeAlias(qualified_name);
type = alias->type();
pos = alias->GetDeclarationPosition();
} else {
auto* generic_struct =
Declarations::LookupUniqueGenericStructType(qualified_name);
auto& params = generic_struct->generic_parameters();
auto& specializations = generic_struct->specializations();
if (params.size() != args.size()) {
ReportError("Generic struct takes ", params.size(),
" parameters, but only ", args.size(), " were given");
}
std::vector<const Type*> arg_types = ComputeTypeVector(args);
if (auto specialization = specializations.Get(arg_types)) {
type = *specialization;
} else {
CurrentScope::Scope generic_scope(generic_struct->ParentScope());
// Create a temporary fake-namespace just to temporarily declare the
// specialization aliases for the generic types to create a signature.
Namespace tmp_namespace("_tmp");
CurrentScope::Scope tmp_namespace_scope(&tmp_namespace);
auto arg_types_iterator = arg_types.begin();
for (auto param : params) {
TypeAlias* alias =
Declarations::DeclareType(param, *arg_types_iterator);
alias->SetIsUserDefined(false);
arg_types_iterator++;
}
auto struct_type = ComputeType(generic_struct->declaration());
specializations.Add(arg_types, struct_type);
type = struct_type;
}
pos = generic_struct->declaration()->name->pos;
}
if (GlobalContext::collect_language_server_data()) {
LanguageServerData::AddDefinition(type_expression->pos,
alias->GetDeclarationPosition());
LanguageServerData::AddDefinition(type_expression->pos, pos);
}
return alias->type();
return type;
} else if (auto* union_type =
UnionTypeExpression::DynamicCast(type_expression)) {
return TypeOracle::GetUnionType(ComputeType(union_type->a),
......
......@@ -272,7 +272,25 @@ const Field& AggregateType::LookupField(const std::string& name) const {
}
std::string StructType::GetGeneratedTypeNameImpl() const {
return "TorqueStruct" + name();
return "TorqueStruct" + MangledName();
}
// static
std::string StructType::ComputeName(const std::string& basename,
const std::vector<const Type*>& args) {
if (args.size() == 0) return basename;
std::stringstream s;
s << basename << "<";
bool first = true;
for (auto t : args) {
if (!first) {
s << ", ";
}
s << t->ToString();
first = false;
}
s << ">";
return s.str();
}
std::vector<Method*> AggregateType::Methods(const std::string& name) const {
......
......@@ -502,6 +502,18 @@ class StructType final : public AggregateType {
DECLARE_TYPE_BOILERPLATE(StructType)
std::string ToExplicitString() const override;
std::string GetGeneratedTypeNameImpl() const override;
std::string MangledName() const override {
// TODO(gsps): Generate more readable mangled names
std::string str(name());
std::replace(str.begin(), str.end(), ',', '_');
std::replace(str.begin(), str.end(), ' ', '_');
std::replace(str.begin(), str.end(), '<', '_');
std::replace(str.begin(), str.end(), '>', '_');
return str;
}
static std::string ComputeName(const std::string& basename,
const std::vector<const Type*>& args);
private:
friend class TypeOracle;
......
......@@ -560,6 +560,31 @@ TEST(TestRedundantSmiCheck) {
asm_tester.GenerateCode();
}
TEST(TestGenericStruct1) {
CcTest::InitializeVM();
Isolate* isolate(CcTest::i_isolate());
i::HandleScope scope(isolate);
CodeAssemblerTester asm_tester(isolate);
TestTorqueAssembler m(asm_tester.state());
{
m.TestGenericStruct1();
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.Call();
}
TEST(TestGenericStruct2) {
CcTest::InitializeVM();
Isolate* isolate(CcTest::i_isolate());
i::HandleScope scope(isolate);
CodeAssemblerTester asm_tester(isolate);
TestTorqueAssembler m(asm_tester.state());
{ m.Return(m.TestGenericStruct2().fst); }
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.Call();
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -973,4 +973,38 @@ namespace test {
return 1;
}
struct SBox<T: type> {
value: T;
}
@export
macro TestGenericStruct1(): intptr {
const i: intptr = 123;
let box = SBox<intptr>{value: i};
let boxbox = SBox<SBox<intptr>>{value: box};
check(box.value == 123);
boxbox.value.value *= 2;
check(boxbox.value.value == 246);
return boxbox.value.value;
}
struct TestTuple<T1: type, T2: type> {
const fst: T1;
const snd: T2;
}
macro Swap<T1: type, T2: type>(tuple: TestTuple<T1, T2>):
TestTuple<T2, T1> {
return TestTuple<T2, T1>{fst: tuple.snd, snd: tuple.fst};
}
@export
macro TestGenericStruct2(): TestTuple<Smi, intptr> {
const intptrAndSmi = TestTuple<intptr, Smi>{fst: 1, snd: 2};
const smiAndIntptr = Swap<intptr, Smi>(intptrAndSmi);
check(intptrAndSmi.fst == smiAndIntptr.snd);
check(intptrAndSmi.snd == smiAndIntptr.fst);
return smiAndIntptr;
}
}
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