Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support indirection for struct and tuple field access #671

Merged
merged 1 commit into from Sep 13, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 44 additions & 7 deletions gcc/rust/backend/rust-compile-expr.h
Expand Up @@ -46,6 +46,26 @@ class CompileExpr : public HIRCompileBase
TupleIndex index = expr.get_tuple_index ();

Bexpression *receiver_ref = CompileExpr::Compile (tuple_expr, ctx);

TyTy::BaseType *tuple_expr_ty = nullptr;
bool ok = ctx->get_tyctx ()->lookup_type (
tuple_expr->get_mappings ().get_hirid (), &tuple_expr_ty);
rust_assert (ok);

// do we need to add an indirect reference
if (tuple_expr_ty->get_kind () == TyTy::TypeKind::REF)
{
TyTy::ReferenceType *r
= static_cast<TyTy::ReferenceType *> (tuple_expr_ty);
TyTy::BaseType *tuple_type = r->get_base ();
Btype *tuple_tyty = TyTyResolveCompile::compile (ctx, tuple_type);

Bexpression *indirect
= ctx->get_backend ()->indirect_expression (tuple_tyty, receiver_ref,
true, expr.get_locus ());
receiver_ref = indirect;
}

translated
= ctx->get_backend ()->struct_field_expression (receiver_ref, index,
expr.get_locus ());
Expand Down Expand Up @@ -606,6 +626,9 @@ class CompileExpr : public HIRCompileBase

void visit (HIR::FieldAccessExpr &expr) override
{
Bexpression *receiver_ref
= CompileExpr::Compile (expr.get_receiver_expr ().get (), ctx);

// resolve the receiver back to ADT type
TyTy::BaseType *receiver = nullptr;
if (!ctx->get_tyctx ()->lookup_type (
Expand All @@ -615,17 +638,31 @@ class CompileExpr : public HIRCompileBase
"unresolved type for receiver");
return;
}
rust_assert (receiver->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver);

size_t index = 0;
adt->get_field (expr.get_field_name (), &index);
size_t field_index = 0;
if (receiver->get_kind () == TyTy::TypeKind::ADT)
{
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver);
adt->get_field (expr.get_field_name (), &field_index);
}
else if (receiver->get_kind () == TyTy::TypeKind::REF)
{
TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver);
TyTy::BaseType *b = r->get_base ();
rust_assert (b->get_kind () == TyTy::TypeKind::ADT);

Bexpression *struct_ref
= CompileExpr::Compile (expr.get_receiver_expr ().get (), ctx);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (b);
adt->get_field (expr.get_field_name (), &field_index);
Btype *adt_tyty = TyTyResolveCompile::compile (ctx, adt);

Bexpression *indirect
= ctx->get_backend ()->indirect_expression (adt_tyty, receiver_ref,
true, expr.get_locus ());
receiver_ref = indirect;
}

translated
= ctx->get_backend ()->struct_field_expression (struct_ref, index,
= ctx->get_backend ()->struct_field_expression (receiver_ref, field_index,
expr.get_locus ());
}

Expand Down
20 changes: 17 additions & 3 deletions gcc/rust/lint/rust-lint-marklive.cc
Expand Up @@ -214,9 +214,22 @@ MarkLive::visit (HIR::FieldAccessExpr &expr)
rust_error_at (expr.get_receiver_expr ()->get_locus (),
"unresolved type for receiver");
}
bool ok = receiver->get_kind () == TyTy::TypeKind::ADT;
rust_assert (ok);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver);

TyTy::ADTType *adt = nullptr;
if (receiver->get_kind () == TyTy::TypeKind::ADT)
{
adt = static_cast<TyTy::ADTType *> (receiver);
}
else if (receiver->get_kind () == TyTy::TypeKind::REF)
{
TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver);
TyTy::BaseType *b = r->get_base ();
rust_assert (b->get_kind () == TyTy::TypeKind::ADT);

adt = static_cast<TyTy::ADTType *> (b);
}

rust_assert (adt != nullptr);

// get the field index
size_t index = 0;
Expand All @@ -228,6 +241,7 @@ MarkLive::visit (HIR::FieldAccessExpr &expr)
adt->get_name ().c_str (), index);
return;
}

// get the field hir id
HirId field_id = adt->get_field (index)->get_ref ();
mark_hir_id (field_id);
Expand Down
17 changes: 16 additions & 1 deletion gcc/rust/typecheck/rust-hir-type-check-expr.h
Expand Up @@ -64,13 +64,20 @@ class TypeCheckExpr : public TypeCheckBase
{
auto resolved
= TypeCheckExpr::Resolve (expr.get_tuple_expr ().get (), inside_loop);
if (resolved == nullptr)
if (resolved->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (expr.get_tuple_expr ()->get_locus (),
"failed to resolve TupleIndexExpr receiver");
return;
}

// FIXME does this require autoderef here?
if (resolved->get_kind () == TyTy::TypeKind::REF)
{
TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (resolved);
resolved = r->get_base ();
}

bool is_valid_type = resolved->get_kind () == TyTy::TypeKind::ADT
|| resolved->get_kind () == TyTy::TypeKind::TUPLE;
if (!is_valid_type)
Expand Down Expand Up @@ -902,6 +909,14 @@ class TypeCheckExpr : public TypeCheckBase
auto struct_base
= TypeCheckExpr::Resolve (expr.get_receiver_expr ().get (), false);

// FIXME does this require autoderef here?
if (struct_base->get_kind () == TyTy::TypeKind::REF)
{
TyTy::ReferenceType *r
= static_cast<TyTy::ReferenceType *> (struct_base);
struct_base = r->get_base ();
}

bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT;
if (!is_valid_type)
{
Expand Down
15 changes: 15 additions & 0 deletions gcc/testsuite/rust/compile/torture/autoderef1.rs
@@ -0,0 +1,15 @@
struct Foo(i32, bool);
struct Bar {
a: i32,
b: bool,
}

fn main() {
let a = &Foo(123, false);
let _b: i32 = a.0;
let _c: bool = a.1;

let a = &Bar { a: 456, b: false };
let _b: i32 = a.a;
let _c: bool = a.b;
}