diff --git a/src/back/CodeGen/Expr.hs b/src/back/CodeGen/Expr.hs index d08cf9025..b62ebf437 100644 --- a/src/back/CodeGen/Expr.hs +++ b/src/back/CodeGen/Expr.hs @@ -442,12 +442,12 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where in do typeArgs <- mapM getTypeVar typeParams - (nnew, ctorCall) <- namedTmpVar "new" ty callCtor + (nnew, constructorCall) <- namedTmpVar "new" ty callCtor (initArgs, result) <- methodCall nnew ty initName args ty return (nnew, Seq $ - [ctorCall] ++ + [constructorCall] ++ initArgs ++ [ Statement $ callTypeParamsInit $ (AsExpr nnew):typeArgs , Statement result] @@ -521,12 +521,13 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where (Call arraySize [ntarg]) return (Var tmp, Seq [ttarg, theSize]) - translate call@(A.MethodCall { A.target, A.name, A.args}) + translate call@(A.MethodCall { A.emeta, A.target, A.name, A.args}) | (Ty.isTraitType . A.getType) target = do (ntarget, ttarget) <- translate target (nCall, tCall) <- traitMethod ntarget (A.getType target) name args (translate (A.getType call)) - return (nCall, Seq $ ttarget : [tCall]) + let recvNullCheck = targetNullCheck ntarget target name emeta "." + return (nCall, Seq $ ttarget : recvNullCheck : [tCall]) | syncAccess = delegateUse callTheMethodSync "sync_method_call" | sharedAccess = delegateUse callTheMethodFuture "shared_method_call" | isActive && isStream = delegateUse callTheMethodStream "stream" @@ -543,6 +544,7 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where return (Var result, Seq $ ttarget : + targetNullCheck ntarget target name emeta "." : initArgs ++ [Assign (Decl (translate retTy, Var result)) resultExpr] ) @@ -553,7 +555,7 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where isStream = Ty.isStreamType retTy isFuture = Ty.isFutureType retTy - translate call@(A.MessageSend { A.target, A.name, A.args }) + translate call@(A.MessageSend { A.emeta, A.target, A.name, A.args }) | (Ty.isActiveClassType . A.getType) target = messageSend | sharedAccess = sharedObjectMethodOneWay call | otherwise = error "Tried to send a message to something that was not an active reference" @@ -563,7 +565,9 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where messageSend = do (ntarg, ttarg) <- translate target theSend <- activeMessageSend ntarg (A.getType target) name args - return (unit, Seq (Comm "message send" : ttarg : [theSend])) + let recvNullCheck = targetNullCheck ntarg target name emeta + return (unit, Seq (Comm "message send" : + ttarg : recvNullCheck " ! " : [theSend])) translate w@(A.While {A.cond, A.body}) = do (ncond,tcond) <- translate cond @@ -1273,3 +1277,12 @@ getTypeVar ty = do msgSize :: CCode Ty -> CCode Expr msgSize t = Call (Nam "POOL_INDEX") [Sizeof t] + +targetNullCheck ntarget target name meta op = + Statement $ + Call (Nam "check_reciever") + [AsExpr $ ntarget, + String op, + String (show (PP.ppExpr target)), + String (show name), + String (show (Meta.getPos meta))] diff --git a/src/runtime/encore/encore.h b/src/runtime/encore/encore.h index 8259eee30..13cb7f48c 100644 --- a/src/runtime/encore/encore.h +++ b/src/runtime/encore/encore.h @@ -16,6 +16,8 @@ #include #include +#define check_reciever(this, op, recv, msg, file) if (!this) { fprintf(stderr, "Error: empty receiver in " recv op msg "(...) in " file "\n"); abort(); } + typedef struct context { ucontext_t uctx; struct context *next; diff --git a/src/tests/encore/basic/recvNullCall.enc b/src/tests/encore/basic/recvNullCall.enc new file mode 100644 index 000000000..d539b58b7 --- /dev/null +++ b/src/tests/encore/basic/recvNullCall.enc @@ -0,0 +1,9 @@ +class Main + def test() : void + print("If you can read this, then recvNullCall failed") + def main() : void + let + x = null:Main + in + x.test() + diff --git a/src/tests/encore/basic/recvNullCall.err b/src/tests/encore/basic/recvNullCall.err new file mode 100644 index 000000000..062d1effa --- /dev/null +++ b/src/tests/encore/basic/recvNullCall.err @@ -0,0 +1 @@ +Error: empty receiver in x.test(...) in "recvNullCall.enc" (line 8, column 7) diff --git a/src/tests/encore/basic/recvNullSend.enc b/src/tests/encore/basic/recvNullSend.enc new file mode 100644 index 000000000..087081caa --- /dev/null +++ b/src/tests/encore/basic/recvNullSend.enc @@ -0,0 +1,9 @@ +class Main + def test() : void + print("If you can read this, then recvNullSend failed") + def main() : void + let + x = null:Main + in + x ! test() + diff --git a/src/tests/encore/basic/recvNullSend.err b/src/tests/encore/basic/recvNullSend.err new file mode 100644 index 000000000..fe0b7d18b --- /dev/null +++ b/src/tests/encore/basic/recvNullSend.err @@ -0,0 +1 @@ +Error: empty receiver in x ! test(...) in "recvNullSend.enc" (line 8, column 9)