blob: e78d7505094b5593a4e5bb3ab60e32a10e0ad457 [file] [log] [blame]
#include "rust-bir-builder-pattern.h"
namespace Rust {
namespace BIR {
void
PatternBindingBuilder::visit_identifier (const Analysis::NodeMapping &node,
bool is_ref, location_t location,
bool is_mut)
{
if (is_ref)
{
translated = declare_variable (
node,
new TyTy::ReferenceType (node.get_hirid (),
TyTy::TyVar (node.get_hirid ()),
(is_mut) ? Mutability::Mut : Mutability::Imm));
}
else
{
translated = declare_variable (node);
}
if (init.has_value ())
{
push_assignment (translated, init.value (), location);
}
}
void
PatternBindingBuilder::visit (HIR::IdentifierPattern &pattern)
{
// Top-level identifiers are resolved directly to avoid useless temporary
// (for cleaner BIR).
visit_identifier (pattern.get_mappings (), pattern.get_is_ref (),
pattern.get_locus (), pattern.is_mut ());
}
void
PatternBindingBuilder::visit (HIR::ReferencePattern &pattern)
{
SavedState saved (this);
init = init.map ([&] (PlaceId id) {
return ctx.place_db.lookup_or_add_path (Place::DEREF, lookup_type (pattern),
id);
});
type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
return ty->as<TyTy::ReferenceType> ()->get_base ();
});
pattern.get_referenced_pattern ().accept_vis (*this);
}
void
PatternBindingBuilder::visit (HIR::SlicePattern &pattern)
{
SavedState saved (this);
// All indexes are supposed to point to the same place for borrow-checking.
// init = ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type
// (pattern), saved.init);
init = init.map ([&] (PlaceId id) {
return ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (pattern),
id);
});
type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
return ty->as<TyTy::SliceType> ()->get_element_type ();
});
// Regions are unchanged.
switch (pattern.get_items ().get_item_type ())
{
case HIR::SlicePatternItems::NO_REST:
{
auto &items
= static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
for (auto &member : items.get_patterns ())
{
member->accept_vis (*this);
}
break;
}
case HIR::SlicePatternItems::HAS_REST:
{
auto &items
= static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
for (auto &member : items.get_lower_patterns ())
{
member->accept_vis (*this);
}
for (auto &member : items.get_upper_patterns ())
{
member->accept_vis (*this);
}
break;
}
}
}
void
PatternBindingBuilder::visit (HIR::AltPattern &pattern)
{
rust_sorry_at (pattern.get_locus (),
"borrow-checking of alt patterns is not yet implemented");
}
void
PatternBindingBuilder::visit (HIR::StructPattern &pattern)
{
SavedState saved (this);
auto tyty = ctx.place_db[init.value ()].tyty;
rust_assert (tyty->get_kind () == TyTy::ADT);
auto adt_ty = static_cast<TyTy::ADTType *> (tyty);
rust_assert (adt_ty->is_struct_struct ());
auto struct_ty = adt_ty->get_variants ().at (0);
for (auto &field :
pattern.get_struct_pattern_elems ().get_struct_pattern_fields ())
{
switch (field->get_item_type ())
{
case HIR::StructPatternField::TUPLE_PAT:
{
auto tuple
= static_cast<HIR::StructPatternFieldTuplePat *> (field.get ());
init = init.map ([&] (PlaceId id) {
return ctx.place_db.lookup_or_add_path (
Place::FIELD, lookup_type (tuple->get_tuple_pattern ()), id,
tuple->get_index ());
});
type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
return ty->as<TyTy::ADTType> ()
->get_variants ()
.at (0)
->get_fields ()
.at (tuple->get_index ())
->get_field_type ();
});
tuple->get_tuple_pattern ().accept_vis (*this);
break;
}
case HIR::StructPatternField::IDENT_PAT:
{
auto ident_field
= static_cast<HIR::StructPatternFieldIdentPat *> (field.get ());
TyTy::StructFieldType *field_ty = nullptr;
size_t field_index = 0;
auto ok = struct_ty->lookup_field (
ident_field->get_identifier ().as_string (), &field_ty,
&field_index);
rust_assert (ok);
init = ctx.place_db.lookup_or_add_path (Place::FIELD,
field_ty->get_field_type (),
saved.init.value (),
field_index);
ident_field->get_pattern ().accept_vis (*this);
break;
}
case HIR::StructPatternField::IDENT:
{
auto ident_field
= static_cast<HIR::StructPatternFieldIdent *> (field.get ());
TyTy::StructFieldType *field_ty = nullptr;
size_t field_index = 0;
auto ok = struct_ty->lookup_field (
ident_field->get_identifier ().as_string (), &field_ty,
&field_index);
rust_assert (ok);
init = ctx.place_db.lookup_or_add_path (Place::FIELD,
field_ty->get_field_type (),
saved.init.value (),
field_index);
visit_identifier (ident_field->get_mappings (),
ident_field->get_has_ref (),
ident_field->get_locus (),
ident_field->is_mut ());
break;
}
}
}
}
void
PatternBindingBuilder::visit_tuple_fields (
std::vector<std::unique_ptr<HIR::Pattern>> &fields, SavedState &saved,
size_t &index)
{
for (auto &item : fields)
{
auto type = lookup_type (*item);
init = init.map ([&] (PlaceId id) {
return ctx.place_db.lookup_or_add_path (Place::FIELD, type, id, index);
});
type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
return ty->as<TyTy::TupleType> ()->get_fields ().at (index).get_tyty ();
});
regions = regions.map ([&] (FreeRegions regs) {
return bind_regions (Resolver::TypeCheckContext::get ()
->get_variance_analysis_ctx ()
.query_type_regions (type),
regs);
});
item->accept_vis (*this);
index++;
}
}
void
PatternBindingBuilder::visit (HIR::TuplePattern &pattern)
{
SavedState saved (this);
size_t index = 0;
switch (pattern.get_items ().get_item_type ())
{
case HIR::TuplePatternItems::NO_REST:
{
auto &items
= static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
visit_tuple_fields (items.get_patterns (), saved, index);
break;
}
case HIR::TuplePatternItems::HAS_REST:
{
auto &items
= static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
auto tyty = ctx.place_db[init.value ()].tyty;
rust_assert (tyty->get_kind () == TyTy::TUPLE);
auto skipped = (static_cast<TyTy::TupleType *> (tyty))->num_fields ()
- items.get_lower_patterns ().size ()
- items.get_upper_patterns ().size ();
visit_tuple_fields (items.get_lower_patterns (), saved, index);
index += skipped;
visit_tuple_fields (items.get_upper_patterns (), saved, index);
break;
}
}
init = saved.init;
}
void
PatternBindingBuilder::visit (HIR::TupleStructPattern &pattern)
{
SavedState saved (this);
type_annotation = tl::nullopt;
auto type = lookup_type (pattern);
regions = regions.map ([&] (FreeRegions regs) {
return bind_regions (Resolver::TypeCheckContext::get ()
->get_variance_analysis_ctx ()
.query_type_regions (type),
regs);
});
size_t index = 0;
switch (pattern.get_items ().get_item_type ())
{
case HIR::TupleStructItems::HAS_REST:
{
auto &items
= static_cast<HIR::TupleStructItemsHasRest &> (pattern.get_items ());
rust_assert (type->get_kind () == TyTy::ADT);
auto adt_ty = static_cast<TyTy::ADTType *> (type);
rust_assert (adt_ty->is_tuple_struct ());
auto skipped = adt_ty->get_variants ().at (0)->get_fields ().size ()
- items.get_lower_patterns ().size ()
- items.get_upper_patterns ().size ();
visit_tuple_fields (items.get_lower_patterns (), saved, index);
index += skipped;
visit_tuple_fields (items.get_upper_patterns (), saved, index);
break;
}
case HIR::TupleStructItems::NO_REST:
{
auto &items
= static_cast<HIR::TupleStructItemsNoRest &> (pattern.get_items ());
visit_tuple_fields (items.get_patterns (), saved, index);
break;
}
}
}
} // namespace BIR
} // namespace Rust