Skip to content

Commit e64591e

Browse files
committed
Add support compound assignment operator overloads
Fixes #249
1 parent c4b11ff commit e64591e

File tree

5 files changed

+387
-25
lines changed

5 files changed

+387
-25
lines changed

gcc/rust/backend/rust-compile-expr.cc

+115
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,121 @@ CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
135135
nullptr, expr.get_locus ());
136136
}
137137

138+
void
139+
CompileExpr::visit (HIR::CompoundAssignmentExpr &expr)
140+
{
141+
fncontext fn = ctx->peek_fn ();
142+
143+
auto op = expr.get_expr_type ();
144+
auto lhs = CompileExpr::Compile (expr.get_left_expr ().get (), ctx);
145+
auto rhs = CompileExpr::Compile (expr.get_right_expr ().get (), ctx);
146+
147+
// this might be an operator overload situation lets check
148+
TyTy::FnType *fntype;
149+
bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
150+
expr.get_mappings ().get_hirid (), &fntype);
151+
if (!is_op_overload)
152+
{
153+
auto operator_expr
154+
= ctx->get_backend ()->arithmetic_or_logical_expression (
155+
op, lhs, rhs, expr.get_locus ());
156+
Bstatement *assignment
157+
= ctx->get_backend ()->assignment_statement (fn.fndecl, lhs,
158+
operator_expr,
159+
expr.get_locus ());
160+
ctx->add_statement (assignment);
161+
return;
162+
}
163+
164+
// lookup the resolved name
165+
NodeId resolved_node_id = UNKNOWN_NODEID;
166+
if (!ctx->get_resolver ()->lookup_resolved_name (
167+
expr.get_mappings ().get_nodeid (), &resolved_node_id))
168+
{
169+
rust_error_at (expr.get_locus (), "failed to lookup resolved MethodCall");
170+
return;
171+
}
172+
173+
// reverse lookup
174+
HirId ref;
175+
if (!ctx->get_mappings ()->lookup_node_to_hir (
176+
expr.get_mappings ().get_crate_num (), resolved_node_id, &ref))
177+
{
178+
rust_fatal_error (expr.get_locus (), "reverse lookup failure");
179+
return;
180+
}
181+
182+
TyTy::BaseType *receiver = nullptr;
183+
bool ok
184+
= ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (),
185+
&receiver);
186+
rust_assert (ok);
187+
188+
bool is_dyn_dispatch
189+
= receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC;
190+
bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
191+
if (is_generic_receiver)
192+
{
193+
TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
194+
receiver = p->resolve ();
195+
}
196+
197+
if (is_dyn_dispatch)
198+
{
199+
const TyTy::DynamicObjectType *dyn
200+
= static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ());
201+
202+
std::vector<HIR::Expr *> arguments;
203+
arguments.push_back (expr.get_right_expr ().get ());
204+
205+
translated = compile_dyn_dispatch_call (dyn, receiver, fntype, lhs,
206+
arguments, expr.get_locus ());
207+
return;
208+
}
209+
210+
// lookup compiled functions since it may have already been compiled
211+
HIR::PathIdentSegment segment_name ("add_assign");
212+
Bexpression *fn_expr
213+
= resolve_method_address (fntype, ref, receiver, segment_name,
214+
expr.get_mappings (), expr.get_locus ());
215+
216+
// lookup the autoderef mappings
217+
std::vector<Resolver::Adjustment> *adjustments = nullptr;
218+
ok = ctx->get_tyctx ()->lookup_autoderef_mappings (
219+
expr.get_mappings ().get_hirid (), &adjustments);
220+
rust_assert (ok);
221+
222+
Bexpression *self = lhs;
223+
for (auto &adjustment : *adjustments)
224+
{
225+
switch (adjustment.get_type ())
226+
{
227+
case Resolver::Adjustment::AdjustmentType::IMM_REF:
228+
case Resolver::Adjustment::AdjustmentType::MUT_REF:
229+
self = ctx->get_backend ()->address_expression (
230+
self, expr.get_left_expr ()->get_locus ());
231+
break;
232+
233+
case Resolver::Adjustment::AdjustmentType::DEREF_REF:
234+
Btype *expected_type
235+
= TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
236+
self = ctx->get_backend ()->indirect_expression (
237+
expected_type, self, true, /* known_valid*/
238+
expr.get_left_expr ()->get_locus ());
239+
break;
240+
}
241+
}
242+
243+
std::vector<Bexpression *> args;
244+
args.push_back (self); // adjusted self
245+
args.push_back (rhs);
246+
247+
auto fncontext = ctx->peek_fn ();
248+
translated
249+
= ctx->get_backend ()->call_expression (fncontext.fndecl, fn_expr, args,
250+
nullptr, expr.get_locus ());
251+
}
252+
138253
Bexpression *
139254
CompileExpr::compile_dyn_dispatch_call (const TyTy::DynamicObjectType *dyn,
140255
TyTy::BaseType *receiver,

gcc/rust/backend/rust-compile-expr.h

+1-16
Original file line numberDiff line numberDiff line change
@@ -388,22 +388,7 @@ class CompileExpr : public HIRCompileBase
388388
ctx->add_statement (assignment);
389389
}
390390

391-
void visit (HIR::CompoundAssignmentExpr &expr) override
392-
{
393-
fncontext fn = ctx->peek_fn ();
394-
auto lvalue = CompileExpr::Compile (expr.get_left_expr ().get (), ctx);
395-
auto rvalue = CompileExpr::Compile (expr.get_right_expr ().get (), ctx);
396-
397-
auto op = expr.get_expr_type ();
398-
auto operator_expr = ctx->get_backend ()->arithmetic_or_logical_expression (
399-
op, lvalue, rvalue, expr.get_locus ());
400-
401-
Bstatement *assignment
402-
= ctx->get_backend ()->assignment_statement (fn.fndecl, lvalue,
403-
operator_expr,
404-
expr.get_locus ());
405-
ctx->add_statement (assignment);
406-
}
391+
void visit (HIR::CompoundAssignmentExpr &expr) override;
407392

408393
void visit (HIR::ArrayIndexExpr &expr) override
409394
{

gcc/rust/typecheck/rust-autoderef.h

+41
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,47 @@ class Adjustment
6868
const TyTy::BaseType *expected;
6969
};
7070

71+
class Adjuster
72+
{
73+
public:
74+
Adjuster (const TyTy::BaseType *ty) : base (ty) {}
75+
76+
TyTy::BaseType *adjust_type (std::vector<Adjustment> adjustments)
77+
{
78+
TyTy::BaseType *ty = base->clone ();
79+
for (auto &adjustment : adjustments)
80+
{
81+
switch (adjustment.get_type ())
82+
{
83+
case Resolver::Adjustment::AdjustmentType::IMM_REF:
84+
ty = new TyTy::ReferenceType (ty->get_ref (),
85+
TyTy::TyVar (ty->get_ref ()),
86+
Mutability::Imm);
87+
break;
88+
89+
case Resolver::Adjustment::AdjustmentType::MUT_REF:
90+
ty = new TyTy::ReferenceType (ty->get_ref (),
91+
TyTy::TyVar (ty->get_ref ()),
92+
Mutability::Mut);
93+
break;
94+
95+
case Resolver::Adjustment::AdjustmentType::DEREF_REF:
96+
// FIXME this really needs to support deref lang-item operator
97+
// overloads
98+
rust_assert (ty->get_kind () == TyTy::TypeKind::REF);
99+
const TyTy::ReferenceType *rr
100+
= static_cast<const TyTy::ReferenceType *> (ty);
101+
ty = rr->get_base ();
102+
break;
103+
}
104+
}
105+
return ty;
106+
}
107+
108+
private:
109+
const TyTy::BaseType *base;
110+
};
111+
71112
} // namespace Resolver
72113
} // namespace Rust
73114

0 commit comments

Comments
 (0)