Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions xls/dslx/frontend/ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -405,15 +405,7 @@ AnyNameDef TypeDefinitionGetNameDef(const TypeDefinition& td) {
}

AstNode* TypeDefinitionToAstNode(const TypeDefinition& td) {
return absl::visit(Visitor{
[](TypeAlias* n) -> AstNode* { return n; },
[](StructDef* n) -> AstNode* { return n; },
[](ProcDef* n) -> AstNode* { return n; },
[](EnumDef* n) -> AstNode* { return n; },
[](ColonRef* n) -> AstNode* { return n; },
[](UseTreeEntry* n) -> AstNode* { return n; },
},
td);
return absl::visit(Visitor{[](auto* n) -> AstNode* { return n; }}, td);
}

absl::StatusOr<TypeDefinition> ToTypeDefinition(AstNode* node) {
Expand Down
7 changes: 1 addition & 6 deletions xls/dslx/frontend/ast_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,7 @@ absl::StatusOr<StructDef*> ResolveLocalStructDef(TypeDefinition td) {
return ResolveLocalStructDef(&n->type_annotation(), td);
},
[&](StructDef* n) -> absl::StatusOr<StructDef*> { return n; },
[&](ProcDef* n) -> absl::StatusOr<StructDef*> { return error(n); },
[&](EnumDef* n) -> absl::StatusOr<StructDef*> { return error(n); },
[&](ColonRef* n) -> absl::StatusOr<StructDef*> { return error(n); },
[&](UseTreeEntry* n) -> absl::StatusOr<StructDef*> {
return error(n);
},
[&](auto* n) -> absl::StatusOr<StructDef*> { return error(n); },
},
td);
}
Expand Down
10 changes: 10 additions & 0 deletions xls/dslx/frontend/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,16 @@ class Bindings {
if (!bn) {
return false;
}
// A `NameDef` is a type definition if its definer is a
// `GenericTypeAnnotation`.
if (std::holds_alternative<NameDef*>(*bn)) {
auto nd = std::get<NameDef*>(*bn);
if (nd->definer() != nullptr) {
if (auto* ta = dynamic_cast<TypeAnnotation*>(nd->definer())) {
return ta->IsAnnotation<GenericTypeAnnotation>();
}
}
}
return std::holds_alternative<EnumDef*>(*bn) ||
std::holds_alternative<TypeAlias*>(*bn) ||
std::holds_alternative<StructDef*>(*bn) ||
Expand Down
33 changes: 24 additions & 9 deletions xls/dslx/type_system_v2/import_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ namespace {
// can be obtained by calling `GetStructOrProcRef` or `GetEnumDef`.
class TypeRefUnwrapper : public AstNodeVisitorWithDefault {
public:
explicit TypeRefUnwrapper(const ImportData& import_data)
: import_data_(import_data) {}
explicit TypeRefUnwrapper(const ImportData& import_data,
bool include_generic = false)
: import_data_(import_data), include_generic_(include_generic) {}

absl::Status HandleColonRef(const ColonRef* colon_ref) override {
XLS_ASSIGN_OR_RETURN(std::optional<ModuleInfo*> import_module,
Expand Down Expand Up @@ -101,6 +102,12 @@ class TypeRefUnwrapper : public AstNodeVisitorWithDefault {
return ToAstNode(annotation->type_ref()->type_definition())->Accept(this);
}

absl::Status HandleGenericTypeAnnotation(
const GenericTypeAnnotation* annotation) override {
is_generic_ = true;
return absl::OkStatus();
}

absl::Status HandleProcDef(const ProcDef* def) override {
type_def_ = const_cast<ProcDef*>(def);
return absl::OkStatus();
Expand Down Expand Up @@ -128,16 +135,21 @@ class TypeRefUnwrapper : public AstNodeVisitorWithDefault {
}

std::optional<StructOrProcRef> GetStructOrProcRef() {
if (!type_def_.has_value() ||
(!std::holds_alternative<StructDef*>(*type_def_) &&
!std::holds_alternative<ProcDef*>(*type_def_))) {
if (!(include_generic_ && is_generic_) &&
(!type_def_.has_value() ||
(!std::holds_alternative<StructDef*>(*type_def_) &&
!std::holds_alternative<ProcDef*>(*type_def_)))) {
return std::nullopt;
}
return StructOrProcRef{
.def = absl::down_cast<StructDefBase*>(ToAstNode(*type_def_)),
.def = type_def_.has_value()
? absl::down_cast<StructDefBase*>(ToAstNode(*type_def_))
: nullptr,
.parametrics = parametrics_,
.instantiator = instantiator_,
.type_ref_type_annotation = type_ref_type_annotation_};
.type_ref_type_annotation = type_ref_type_annotation_,
.is_generic = is_generic_,
};
}

std::optional<const EnumDef*> GetEnumDef() {
Expand All @@ -148,23 +160,26 @@ class TypeRefUnwrapper : public AstNodeVisitorWithDefault {

private:
const ImportData& import_data_;
bool include_generic_;

// These fields get populated as we visit nodes.
std::vector<ExprOrType> parametrics_;
std::optional<TypeDefinition> type_def_;
std::optional<const TypeRefTypeAnnotation*> type_ref_type_annotation_;
std::optional<const StructInstanceBase*> instantiator_;
bool is_generic_ = false;
};

} // namespace

absl::StatusOr<std::optional<StructOrProcRef>> GetStructOrProcRef(
const TypeAnnotation* annotation, const ImportData& import_data) {
const TypeAnnotation* annotation, const ImportData& import_data,
bool include_generic) {
if (!annotation->IsAnnotation<TypeRefTypeAnnotation>() &&
!annotation->IsAnnotation<TypeVariableTypeAnnotation>()) {
return std::nullopt;
}
TypeRefUnwrapper unwrapper(import_data);
TypeRefUnwrapper unwrapper(import_data, include_generic);
XLS_RETURN_IF_ERROR(annotation->Accept(&unwrapper));
return unwrapper.GetStructOrProcRef();
}
Expand Down
6 changes: 5 additions & 1 deletion xls/dslx/type_system_v2/import_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@ namespace xls::dslx {

// Resolves the definition and parametrics for the struct or proc type referred
// to by `annotation`.
// If `include_generic` is true, annotations that resolve to
// `GenericTypeAnnotation` will return a `StructOrProcRef`, but with
// `.def=nullptr` and `.is_generic=true`.
absl::StatusOr<std::optional<StructOrProcRef>> GetStructOrProcRef(
const TypeAnnotation* annotation, const ImportData& import_data);
const TypeAnnotation* annotation, const ImportData& import_data,
bool include_generic = false);

// Variant that takes a `ColonRef`. This will only yield a struct ref if the
// `ColonRef` itself refers to an actual struct or alias of one. It will yield
Expand Down
90 changes: 55 additions & 35 deletions xls/dslx/type_system_v2/populate_table_visitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2278,8 +2278,14 @@ class PopulateInferenceTableVisitor : public PopulateTableVisitor,
// creates additional pitfalls, like erroneously naming two different
// arguments the same thing.
XLS_RETURN_IF_ERROR(node->struct_ref()->Accept(this));
XLS_ASSIGN_OR_RETURN(std::optional<StructOrProcRef> struct_or_proc_ref,
GetStructOrProcRef(node->struct_ref(), import_data_));
const NameRef* type_variable = *table_.GetTypeVariable(node);
if (source.has_value()) {
XLS_RETURN_IF_ERROR(table_.SetTypeVariable(*source, type_variable));
}
XLS_ASSIGN_OR_RETURN(
std::optional<StructOrProcRef> struct_or_proc_ref,
GetStructOrProcRef(node->struct_ref(), import_data_, true));

if (!struct_or_proc_ref.has_value()) {
return TypeInferenceErrorStatusForAnnotation(
node->span(), node->struct_ref(),
Expand All @@ -2289,33 +2295,38 @@ class PopulateInferenceTableVisitor : public PopulateTableVisitor,
file_table_);
}

const StructDefBase* struct_def = struct_or_proc_ref->def;
absl::flat_hash_map<std::string, const StructMemberNode*> formal_member_map;
bool is_generic = false;
bool allow_missing_members = false;
if (struct_or_proc_ref->is_generic) {
// If the struct ref is a `GenericTypeAnnotation`, then we are
// instantiating a struct that is typed as a generic parametric. In this
// case, we don't try to resolve the struct def and we just create
// annotations based on the instantiation members.
is_generic = true;
} else {
const StructDefBase* struct_def = struct_or_proc_ref->def;

const NameRef* type_variable = *table_.GetTypeVariable(node);
if (source.has_value()) {
XLS_RETURN_IF_ERROR(table_.SetTypeVariable(*source, type_variable));
XLS_RETURN_IF_ERROR(table_.SetTypeAnnotation(
node, CreateStructOrProcAnnotation(
module_, const_cast<StructDefBase*>(struct_def),
struct_or_proc_ref->parametrics, node)));
const StructDef* concrete_struct_def =
dynamic_cast<const StructDef*>(struct_def);
allow_missing_members =
in_fuzz_test_domain_ || (concrete_struct_def != nullptr &&
concrete_struct_def->is_domain_struct());
XLS_RETURN_IF_ERROR(ValidateStructInstanceMemberNames(
*node, *struct_def, allow_missing_members));
formal_member_map.reserve(struct_def->members().size());
for (const StructMemberNode* formal_member : struct_def->members()) {
formal_member_map.emplace(formal_member->name(), formal_member);
}
}
XLS_RETURN_IF_ERROR(table_.SetTypeAnnotation(
node, CreateStructOrProcAnnotation(
module_, const_cast<StructDefBase*>(struct_def),
struct_or_proc_ref->parametrics, node)));
const StructDef* concrete_struct_def =
dynamic_cast<const StructDef*>(struct_def);
bool allow_missing_members =
in_fuzz_test_domain_ || (concrete_struct_def != nullptr &&
concrete_struct_def->is_domain_struct());
XLS_RETURN_IF_ERROR(ValidateStructInstanceMemberNames(
*node, *struct_def, allow_missing_members));

absl::flat_hash_map<std::string, const StructMemberNode*> formal_member_map;
for (const StructMemberNode* formal_member : struct_def->members()) {
formal_member_map.emplace(formal_member->name(), formal_member);
}
const TypeAnnotation* struct_variable_type =
module_.Make<TypeVariableTypeAnnotation>(type_variable);
for (const auto& [name, actual_member] : node->members()) {
const StructMemberNode* formal_member = formal_member_map.at(name);

if (allow_missing_members) {
// In a fuzz test domain, the actual member expression represents a
// domain (e.g. `u32:0..10` which has type `u32[10]`) rather than a
Expand All @@ -2326,20 +2337,29 @@ class PopulateInferenceTableVisitor : public PopulateTableVisitor,
DefineAndSetTypeVariable(actual_member, "actual_member_domain"));
XLS_RETURN_IF_ERROR(actual_member->Accept(this));
} else {
// In the context of instance initialization only, we require the RHS of
// proc state assignment to be T rather than State<T>.
const TypeAnnotation* formal_member_type =
module_.Make<MemberTypeAnnotation>(
formal_member->name_def()->span(), struct_variable_type,
formal_member->name(),
/*use_wrapped_type_if_proc_state=*/false);

table_.SetAnnotationFlag(formal_member_type,
TypeInferenceFlag::kFormalMemberType);
const TypeAnnotation* member_type = nullptr;
if (is_generic) {
// For generic types, construct the member type based on the actual
// member.
member_type = module_.Make<MemberTypeAnnotation>(
actual_member->span(), struct_variable_type, name,
/*use_wrapped_type_if_proc_state=*/false);
} else {
const StructMemberNode* formal_member = formal_member_map.at(name);
// In the context of instance initialization only, we require the RHS
// of proc state assignment to be T rather than State<T>.
member_type = module_.Make<MemberTypeAnnotation>(
formal_member->name_def()->span(), struct_variable_type,
formal_member->name(),
/*use_wrapped_type_if_proc_state=*/false);

table_.SetAnnotationFlag(member_type,
TypeInferenceFlag::kFormalMemberType);
}
XLS_RETURN_IF_ERROR(DefineAndSetTypeVariable(
actual_member, "actual_member", formal_member_type));
actual_member, "actual_member", member_type));
XLS_RETURN_IF_ERROR(
table_.SetTypeAnnotation(actual_member, formal_member_type));
table_.SetTypeAnnotation(actual_member, member_type));
XLS_RETURN_IF_ERROR(actual_member->Accept(this));
}
}
Expand Down
1 change: 1 addition & 0 deletions xls/dslx/type_system_v2/type_annotation_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct StructOrProcRef {
std::vector<ExprOrType> parametrics;
std::optional<const StructInstanceBase*> instantiator;
std::optional<const TypeRefTypeAnnotation*> type_ref_type_annotation;
bool is_generic;
};

// The signedness and bit count extracted from a `TypeAnnotation`. The
Expand Down
Loading
Loading