aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/expr.zc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/expr.zc')
-rw-r--r--src/compiler/expr.zc18
1 files changed, 16 insertions, 2 deletions
diff --git a/src/compiler/expr.zc b/src/compiler/expr.zc
index 8768658..e6acfc8 100644
--- a/src/compiler/expr.zc
+++ b/src/compiler/expr.zc
@@ -68,6 +68,7 @@ int args(int tags, word ft, int bs, int fat) {
freeing = sname[cs] == s_free || sname[cs] == s_recycle;
harmless = sname[cs] == s_put_s || rt.eq_w(sname[cs], "rt.put_n") || rt.eq_w(sname[cs], "rt.put_c") || rt.eq_w(sname[cs], "len") || rt.eq_w(sname[cs], "cap");
}
+ int sending = send_check; send_check = 0;
xgive = 0; ifcall = 0 - 1; effect_argument_base = 0;
expect(s_lp);
if (!is_op(s_rp)) {
@@ -76,6 +77,10 @@ int args(int tags, word ft, int bs, int fat) {
closure_expected = 0;
if (ft && np + parameter_base < ft[3] && is_id(s_fn)) closure_expected = subst(ft[7 + np + parameter_base], bs);
place = tpack(); c = expr(); rval(); closure_expected = expected;
+ if (sending && fchk && ((c >= C_VAR && ldroppable(lroot(c - C_VAR))) || tdroppable(xty) || (c == C_FRESH && drop_tail == here))) {
+ if (c >= C_VAR) serrn(lname[lroot(c - C_VAR)], "has drop and can't be copied into a message"); else serr("a value with drop can't be copied into a message");
+ }
+ if (freeing && o3on && fchk && c >= C_VAR && ldroppable(lroot(c - C_VAR))) serrn(lname[lroot(c - C_VAR)], "has drop and can't end inside an o3 region");
current = effect_origin(c); current_mask = effect_mask(c); origins = origins | current_mask; effect_args_mask(cs, np + parameter_base, current_mask);
if (!np) origin = current; else if (origin != current) origin = -1;
tag = (tags >> (np + np)) & 3;
@@ -176,6 +181,7 @@ int newtyped() {
expect(s_rp);
stamp_site();
if (fast) callname(s_new_k); else callname(s_new_t); vf_effect();
+ if (t[0] == TY_STRUCT && t[3] >= 0) { int dm = methof(t, intern("drop")); if (dm >= 0) { fnref(dm); callname(intern("rt.set_tdrop")); } }
xaf = af_new(length, 2, place);
lv = 0; lvk = LV_NONE; xty = tptr(t); xzero = 0; xstamp = 1;
return C_FRESH;
@@ -462,6 +468,7 @@ int call(int s) {
}
if (!(sflag[s] & F_DEF) || s == finsym) sflag[s] = sflag[s] | F_EARLY; // called before its body: an owned return is not inferred for it
if (sflag[s] & F_EXT) { lit(sval[s][-1]); op(620); } // an extern: the native call opcode, with the block's address
+ else if (!o3on && (sflag[s] & F_O3)) { o3_enter_code(); fnref(s); op(O_CALL); callname(intern("rt.o3_leave")); op(O_DROP); } // into o3 from normal code: no collection until it returns
else { fnref(s); op(O_CALL); }
if (!o3on && (sflag[s] & F_O3) && ft) { // non-o3 called o3: fatten the result here, not inside the callee
rhs_type = subst(ft[4], bs);
@@ -649,14 +656,18 @@ word closure_layout(int closure_index, int count) {
int closure() {
char* xcf;
int np = 0; char*[24] pn; word[24] pty; int hop, entry, i, t, envl, ncap, c, result, declared = 0, tags = 0, tag, lt, lfl = tline; word[24] ptags;
- word expected = closure_expected; closure_expected = 0;
+ word expected = closure_expected, this_type = closure_this; closure_expected = 0; closure_this = 0;
reserve_closures(nclo + 1);
if (o3on) serr("closures can't be made inside an o3 region");
next();
// fn:type(args) names the result; returns are coerced and checked against it
if (accept(s_colon)) declared = ptype0();
expect(s_lp);
- if (!is_op(s_rp)) {
+ if (this_type) { // a drop: fn() { ... } gets the value as this, borrowed
+ pn[0] = s_this; pty[0] = this_type; ptags[0] = 1; pnoffs[0] = toff; pnplaces[0] = tpack(); np = 1;
+ if (!is_op(s_rp)) serr("a drop takes no parameters; the value is this");
+ }
+ if (!is_op(s_rp) && !this_type) {
while (1) {
pty[np] = tword;
if (expected && expected[0] == TY_FN && np < expected[3]) pty[np] = expected[7 + np];
@@ -1022,6 +1033,7 @@ int primary() {
// wins over a global (a top-level function or constant) of the same name
if (mstruct && !ginst) { ms = lookup(methname(mstruct, n)); if (ms >= 0 && (skind[ms] == K_CONST || (skind[ms] == K_FN && (sflag[ms] & F_STATIC)))) s = ms; }
if (s < 0 && rt.eq_w(n, "new")) s = source_lookup(s_new);
+ if (s < 0 && (rt.eq_w(n, "heap") || rt.eq_w(n, "drop"))) { peek(); if (pk_tk == T_OP && pk_tv == s_lp) { if (rt.eq_w(n, "heap")) return heap_box(); return drop_call(); } }
if (s >= 0) rs_put(toff, RS_SYM, rs_sym(s), s);
if (s >= 0 && skind[s] == K_KW) {
if (!(sflag[s] & F_EXPR)) dien(n, "can't be used inside an expression");
@@ -1185,6 +1197,8 @@ word field(int c) {
}
fieldpos = tpack(); n = name(); fieldoff = nameoff;
st = xty;
+ if (rt.eq_w(n, "drop") && (is_op(s_lp) || is_op(s_eq)) && (isptr(st) || st == tword) && !(isptr(st) && st[4][0] == TY_STRUCT && tfindfield(st[4], n) >= 0)) return drop_member(c, borrowed);
+ if (rt.eq_w(n, "send") && is_op(s_lp) && isptr(st) && st[4][0] == TY_STRUCT && tfindfield(st[4], intern("__mailbox")) >= 0) send_check = 1;
if (st[0] == TY_ARR || st[0] == TY_DYN) {
if (pmatch) probe_member(st);
if (is_op(s_lp) && array_method(n)) { xaf = borrowed; return array_member(c, n); }