The @:op(ab) function is described here: https://haxe.io/releases/3.3.0/ I have a May<T> annotation that is used for zero security. Here is a simplified version:
package; import haxe.macro.Expr; abstract May<T>(Null<T>) from(Null<T>){ // convert T, Null<T> or May<T> to May<T> // accepts Null<T because of 'from(Null<T>)' // accepts T because Null<T> has 'from(T)' // we need to accept May<T> to avoid returning May<May<T>> from resolve() if field is already a May public static inline function from<T>(t:May<T>):May<T> return t; public inline function exist():Bool return this != null; public inline function unwrap():T return exist() ? unsafeUnwrap() : throw 'unwrap null'; public inline function unwrapOr(defaultValue:T):T return exist() ? unsafeUnwrap() : defaultValue; public inline function unsafeUnwrap():T return this; // return same field from underlying type but as May<FieldType> @:op(ab) static macro function resolve<T>(ethis:ExprOf<May<T>>, name:String):Expr { return macro { var me = $ethis; var result = May.from(me.exist() ? me.unsafeUnwrap().$name : null); result; } } }
Note the resolve() function. This is a new feature that I want to add to my actual May tag. It allows you to safely get fields from May and call unwrap() only once. For instance:
may.exist() ? may.unwrap().someField : defaultValue
becomes
may.someField.unwrapOr(defaultValue)
It is very convenient and works well. But the completion does not work. It gives only fields from May : unwrap() , exist() , etc., but does not contain fields from the base class.
I decided to add @:forward metadata to complete:
#if display @:forward
This allows the compiler to see all fields at completion time. This is better than nothing, but the fields are of the wrong type: T instead of May<T> , so I don't get completion for May fields.
I understand why the compiler cannot know all the possible fields when using @:op(ab) , but maybe there is an even smarter trick that will help?
source share