have completion for @:op(a.b)
Asked Answered
E

0

6

The @:op(a.b) feature is described here: https://haxe.io/releases/3.3.0/ I have May<T> abstract which is used for null safety. Here is the simplified version of it:

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(a.b) 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. It's the new feature that I want to add to my actual May abstract. It allows to safely get fields from May and call unwrap() only once. For example:

may.exist() ? may.unwrap().someField : defaultValue

becomes

may.someField.unwrapOr(defaultValue)

That's very handy and works good. But the completion does not work. It only gives fields from May: unwrap(), exist() etc., but no fields from the underlying class.

I've decided to add @:forward metadata for completion:

#if display @:forward #end

This makes the compiler see all fields during completion. It's better than nothing, but fields have an incorrect type: T instead of May<T>, so I do not get completion for May fields.

I understand why the compiler can't know all possible fields when using @:op(a.b), but maybe there is some more clever trick that will help?

Evade answered 17/2, 2017 at 11:50 Comment(1)
Just discovered that it's quite possible to @:genericBuild an abstract. And manually add a field for every corresponding field of base class. That should work, but this is not an easy way...Evade

© 2022 - 2024 — McMap. All rights reserved.