HaxeFoundation / HaxeFoundation/haxe
Cannot typedef a @:const parameterised type
- Dominant language
- Haxe
- Stars
- 6.9k
- Forks
- 715
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 11
Description
Today I used `@:const` to create an abstract String with a fixed (maximum) length (e.g. `FixedString<16>`).
First I tried accessing the type parameter `Size` in an `public inline new` constructor for the abstract, but "Type parameter is expected to be a constant value".
So I used the big guns and defined the macro below. This worked well.
Then I tried to generalise it to all things that have a `.length` accessor.
Declaring a typedef however breaks this.
Console:
```
> haxe -x Main
FixedString.hx:7: characters 42-68 : Type parameter is expected to be a constant value
Main.hx:3: lines 3-8 : Defined in this class
```
---
FixedString.hx
```haxe
package;
import haxe.macro.Expr;
import haxe.macro.Context;
using haxe.macro.ExprTools;
using haxe.macro.TypeTools;
typedef FixedString <@:const Size:Int> = FixedLength ;
abstract FixedLength <@:const Size:Int, T> (T)
{
@:from static public macro function fromString (str : ExprOf) : Expr return fixedStringCast(str);
static public macro function fixedString (str : ExprOf, size:Int) : Expr return fixedStringCast(str,size);
#if macro
static public function parameters(type : haxe.macro.Type) : Array return switch (type) {
case TAbstract(n, [TInst(size, _), type_T]):
var value = switch size.get().kind {
case KExpr(e): e.getValue();
default:
Context.error(n + " first type parameter must be a constant", Context.currentPos());
}
[value, type_T];
case other:
Context.error("Unexpected: " + other, Context.currentPos());
}
static public function fixedStringCast (str : ExprOf, ?size:Int) : Expr {
var p = parameters(Context.getExpectedType());
var size:Int = size != null? size : p[0];
var sizeParam = TPExpr(macro $v{size});
var returnType = TPath({name: "FixedString", pack: [], params: [sizeParam]});
return macro {
var str = $str;
if (str.length > $v{size})
throw $v{TypeTools.toString(p[1])} + ".length is " + str.length + " but should be <= " + $v{size};
else cast(str,$returnType);
}
}
#end
}
```
Main.hx
```haxe
class Main {
static public function main ()
{
var str : FixedString<16> = "haxe is still nice";
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.