Search code examples
macrostype-inferencehaxe

How to force Haxe macro return type to Array / Iterable?


I want to write a macro that returns an (expression of an) Array -- but I can't seem to convince the compiler that my returned value will be typed as an Array. I always get "you can't iterate on a Dynamic value", even though I've tried:

  1. Explicitly typing the return as: ExprOf<Array<Whatever>>
  2. Inserting a type hint in the output

http://try-haxe.mrcdk.com/#D7D82

import haxe.macro.Context;
import haxe.macro.Expr;

class Test {
  static function main() {
    trace("Haxe is great!");
    // ERROR: You can't iterate on a Dynamic value
    for (val in Macro.someArrayExpr()) {
      trace(val);
    }
  }
}

class Macro
{
  public static macro function someArrayExpr():ExprOf<Array<String>>
  {
    // Neither of these works:

    // Try to insert a type hint:
    // return Context.parse('([]:Array<String>)', Context.currentPos());

    return macro [];
  }
}

Solution

  • Uh oh, it looks like it's a side effect of defining my Macro class in the same module (file) as my invocation. Separating the classes into separate files makes it work!

    http://try-haxe.mrcdk.com/#57801

    Test.hx:

    class Test {
      static function main() {
        trace("Haxe is great!");
        // Hooray, it works!
        for (val in Macro.someArrayExpr()) {
          trace(val);
        }
      }
    }
    

    Macro.hx:

    import haxe.macro.Context;
    import haxe.macro.Expr;
    
    //use this for macros or other classes
    class Macro
    {
      public static macro function someArrayExpr():ExprOf<Array<String>>
      {
        return macro ["a", "b", "c"];
      }
    }
    

    The technical explanation for this (thanks to Juraj): the Test class is being typed in the macro context. In that case, it's calling the macro from a macro, which is always typed Dynamic, hence the error. So another solution is to exclude the class Test from being compiled into the macro context: http://try-haxe.mrcdk.com/#1f3b2