HaxeFoundation / HaxeFoundation/haxe

Cannot typedef a @:const parameterised type

Open
#7,291 2 comments 0 reactions 0 assignees View on GitHub
type-system
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.