Skip to content

Commit

Permalink
[hl] disable field ref to dynamic and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Apprentice-Alchemist committed Oct 9, 2024
1 parent 96a6c6b commit 5bfd0b1
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 33 deletions.
5 changes: 3 additions & 2 deletions src/generators/genhl.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2099,8 +2099,9 @@ and eval_expr ctx e =
op ctx (OGetGlobal (o,g));
op ctx (OFieldRef (r,o,fid));
| ADynamic (ethis, fid) ->
let robj = eval_null_check ctx ethis in
op ctx (OFieldRef (r,robj,fid));
abort "Taking a reference to a field of Dynamic is not supported" e.epos
(* let robj = eval_null_check ctx ethis in
op ctx (OFieldRef (r,robj,fid)); *)
| AInstanceField (ethis,fid) ->
let robj = eval_null_check ctx ethis in
let t = rtype ctx robj in begin match t with
Expand Down
8 changes: 7 additions & 1 deletion std/hl/Ref.hx
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,11 @@ package hl;
return untyped $refoffset(this, v);
}

public static macro function fieldRef(obj:haxe.macro.Expr):haxe.macro.Expr;
/**
Take reference to the field of an object.
Usage: ```
hl.Ref.fieldRef(obj.a);
```
**/
public static macro function fieldRef<T>(val:haxe.macro.Expr.ExprOf<T>):haxe.macro.Expr.ExprOf<Ref<T>>;
}
27 changes: 11 additions & 16 deletions std/hl/Ref.macro.hx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ import haxe.macro.Expr;

@:noPackageRestrict
@:coreType abstract Ref<T> {
/**
Take reference to the field of an object.
Usage: ```
hl.Ref.fieldRef(obj.a);
```
**/
public static macro function fieldRef(expr:Expr):Expr {
switch expr.expr {
case EField(_, _, _):
Expand All @@ -30,16 +24,17 @@ import haxe.macro.Expr;

switch typedFieldExpr.expr {
case TField(e, FDynamic(s)):
final expectedType = Context.getExpectedType();
switch expectedType {
case TAbstract(_.get() => {pack: ["hl"], name: "Ref"}, [param]):
refType = expectedType;
valType = param;
case null, TMono(_):
Context.error("Taking reference to a field of a dynamic requires an explicit type hint", pos);
case _:
// this case will fail later
}
Context.error("Taking reference to a field of a dynamic is not supported", pos);
// final expectedType = Context.getExpectedType();
// switch expectedType {
// case TAbstract(_.get() => {pack: ["hl"], name: "Ref"}, [param]):
// refType = expectedType;
// valType = param;
// case null, TMono(_):
// Context.error("Taking reference to a field of a dynamic requires an explicit type hint", pos);
// case _:
// // this case will fail later
// }
case _:
}

Expand Down
84 changes: 70 additions & 14 deletions tests/unit/src/unit/TestHL.hx
Original file line number Diff line number Diff line change
@@ -1,25 +1,81 @@
package unit;

class TestHL extends Test {

//private function refTest(i:hl.types.Ref<Int>):Void
//{
//i *= 2;
//}
import hl.Ref;

private function refTestAssign(i:hl.Ref<Int>):Void
{
class TestHL extends Test {
private function refTestAssign(i:hl.Ref<Int>):Void {
i.set(2);
}

public function testRef()
{
public function testRef() {
var i = 10;
refTestAssign(i);
eq(i, 2);
}

function take<T>(o:T) {}

public function testObjFieldRef() {
var o = {foo: 10};
take(o); // prevent the compiler from optimizing o into a local variable
var ref = hl.Ref.fieldRef(o.foo);
ref.set(5);
eq(o.foo, 5);
o.foo = 4;
eq(ref.get(), 4);
}

public function testClassFieldRef() {
var c:Foo = {foo: 10};
var ref = hl.Ref.fieldRef(c.foo);
ref.set(5);
eq(c.foo, 5);
c.foo = 4;
eq(ref.get(), 4);
}

public function testInterfaceFieldRef() {
var i:IFoo = ({foo: 10} : Foo);
var ref = hl.Ref.fieldRef(i.foo);
ref.set(5);
eq(i.foo, 5);
i.foo = 4;
eq(ref.get(), 4);
}

// public function testDynamicFieldRef() {
// var d:Dynamic = ({foo: 10}:Foo);
// var ref:Ref<Int> = hl.Ref.fieldRef(d.foo);
// ref.set(5);
// eq(d.foo, 5);
// d.foo = 4;
// eq(ref.get(), 4);
// }

//var i = 10;
//refTest(i);
//eq(i, 20);
private function testGenericFieldRef() {
var obj = {foo: 10};
bar(obj);
eq(obj.foo, 3);
foo(obj, 2);
eq(obj.foo, 2);
}
}
}

@:generic function bar<T:{foo:Int}>(obj:T) {
var ref = hl.Ref.fieldRef(obj.foo);
ref.set(3);
}

@:generic function foo<T>(obj:{foo:T}, val:T) {
var ref = hl.Ref.fieldRef(obj.foo);
ref.set(val);
}

private interface IFoo {
var foo:Int;
}

@:structInit
private class Foo implements IFoo {
public var foo:Int;
}

0 comments on commit 5bfd0b1

Please sign in to comment.