-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Invalid expected type, but got: Raising(Future[void], E)
on macro returning type (regression from 1.6)
#23432
Comments
Changing You probably don't want the macro evaluation delayed anyway because then we would have to explicitly instantiate This also works without the last 2 lines in the example which forces the delayed macro evaluation because of #23406: type X[E] = Raising(Future[void], E) But then actually calling The reason we don't want unresolved generic parameters to match proc foo(x: typedesc): int =
sizeof(x) |
My expectation would have been that Btw, like so? import std/[sequtils, macros]
type
Future[T] = object
InternalRaisesFuture[T, E] = object
macro Raising2*[T](F: typedesc[Future[T]], E: varargs[untyped]): untyped =
E.expectKind(nnkArgList)
let raises = nnkTupleConstr.newTree(E.mapIt(it))
nnkBracketExpr.newTree(
ident "InternalRaisesFuture",
nnkDotExpr.newTree(F, ident"T"),
raises
)
type Abc = object
field: Future[void].Raising2([ValueError]) gives:
|
Because of Also |
A workaround could be using import std/[sequtils, macros]
type
Future[T] = object
InternalRaisesFuture[T, E] = object
macro Raising*[T](F: typedesc[Future[T]], E: varargs[typed]): untyped =
## Given a Future type instance, return a type storing `{.raises.}`
## information
##
## Note; this type may change in the future
E.expectKind(nnkBracket)
for typ in E:
if typ.getTypeInst.typeKind != ntyTypeDesc:
error("Expected typedesc, but got: '" & typ.repr & "'.", typ)
let raises = nnkTupleConstr.newTree(E.mapIt(it))
nnkBracketExpr.newTree(
ident "InternalRaisesFuture",
nnkDotExpr.newTree(F, ident"T"),
raises
)
type X[E] = Future[void].Raising(E)
proc f(x: X) = discard
var v: Future[void].Raising(ValueError, 42)
f(v) |
* make `Raising` compatible with 2.0 See nim-lang/Nim#23432 * Update tests/testfut.nim * Update tests/testfut.nim
@beef331 thanks for the workaround, the final version ended up looking like this: status-im/nim-chronos#526 - there are some limitations but the outcome is more or less consistent with how it worked in 1.6, at least for the use cases we had already. Of course, it's sad to have to manually implement a poor version of what the compiler should be doing already better - worth considering in the next round of macro changes ;) |
!nim c import std/[sequtils, macros]
type
Future[T] = object
InternalRaisesFuture[T, E] = object
macro Raising*[T](F: typedesc[Future[T]], E: varargs[typedesc]): untyped =
## Given a Future type instance, return a type storing `{.raises.}`
## information
##
## Note; this type may change in the future
E.expectKind(nnkBracket)
let raises = nnkTupleConstr.newTree(E.mapIt(it))
nnkBracketExpr.newTree(
ident "InternalRaisesFuture",
nnkDotExpr.newTree(F, ident"T"),
raises
)
type X[E] = Future[void].Raising(E)
proc f(x: X) = discard
var v: Future[void].Raising([ValueError])
f(v) |
🐧 Linux bisect by @ringabout (member)devel 👎 FAILOutput
IRCompiled filesize0 bytes (0 bytes)
Stats
ASTnnkStmtList.newTree(
nnkImportStmt.newTree(
nnkInfix.newTree(
newIdentNode("/"),
newIdentNode("std"),
nnkBracket.newTree(
newIdentNode("sequtils"),
newIdentNode("macros")
)
)
),
nnkTypeSection.newTree(
nnkTypeDef.newTree(
newIdentNode("Future"),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("T"),
newEmptyNode(),
newEmptyNode()
)
),
nnkObjectTy.newTree(
newEmptyNode(),
newEmptyNode(),
newEmptyNode()
)
),
nnkTypeDef.newTree(
newIdentNode("InternalRaisesFuture"),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("T"),
newIdentNode("E"),
newEmptyNode(),
newEmptyNode()
)
),
nnkObjectTy.newTree(
newEmptyNode(),
newEmptyNode(),
newEmptyNode()
)
)
),
nnkMacroDef.newTree(
nnkPostfix.newTree(
newIdentNode("*"),
newIdentNode("Raising")
),
newEmptyNode(),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("T"),
newEmptyNode(),
newEmptyNode()
)
),
nnkFormalParams.newTree(
newIdentNode("untyped"),
nnkIdentDefs.newTree(
newIdentNode("F"),
nnkBracketExpr.newTree(
newIdentNode("typedesc"),
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode("T")
)
),
newEmptyNode()
),
nnkIdentDefs.newTree(
newIdentNode("E"),
nnkBracketExpr.newTree(
newIdentNode("varargs"),
newIdentNode("typedesc")
),
newEmptyNode()
)
),
newEmptyNode(),
newEmptyNode(),
nnkStmtList.newTree(
newCommentStmtNode("Given a Future type instance, return a type storing `{.raises.}`\ninformation\n\nNote; this type may change in the future"),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("E"),
newIdentNode("expectKind")
),
newIdentNode("nnkBracket")
),
nnkLetSection.newTree(
nnkIdentDefs.newTree(
newIdentNode("raises"),
newEmptyNode(),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("nnkTupleConstr"),
newIdentNode("newTree")
),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("E"),
newIdentNode("mapIt")
),
newIdentNode("it")
)
)
)
),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("nnkBracketExpr"),
newIdentNode("newTree")
),
nnkCommand.newTree(
newIdentNode("ident"),
newLit("InternalRaisesFuture")
),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("nnkDotExpr"),
newIdentNode("newTree")
),
newIdentNode("F"),
nnkCallStrLit.newTree(
newIdentNode("ident"),
newLit("T")
)
),
newIdentNode("raises")
)
)
),
nnkTypeSection.newTree(
nnkTypeDef.newTree(
newIdentNode("X"),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("E"),
newEmptyNode(),
newEmptyNode()
)
),
nnkCall.newTree(
nnkDotExpr.newTree(
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode("void")
),
newIdentNode("Raising")
),
newIdentNode("E")
)
)
),
nnkProcDef.newTree(
newIdentNode("f"),
newEmptyNode(),
newEmptyNode(),
nnkFormalParams.newTree(
newEmptyNode(),
nnkIdentDefs.newTree(
newIdentNode("x"),
newIdentNode("X"),
newEmptyNode()
)
),
newEmptyNode(),
newEmptyNode(),
nnkStmtList.newTree(
nnkDiscardStmt.newTree(
newEmptyNode()
)
)
),
nnkVarSection.newTree(
nnkIdentDefs.newTree(
newIdentNode("v"),
nnkCall.newTree(
nnkDotExpr.newTree(
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode("void")
),
newIdentNode("Raising")
),
nnkBracket.newTree(
newIdentNode("ValueError")
)
),
newEmptyNode()
)
),
nnkCall.newTree(
newIdentNode("f"),
newIdentNode("v")
)
) stable 👎 FAILOutput
IRCompiled filesize0 bytes (0 bytes)
Stats
ASTnnkStmtList.newTree(
nnkImportStmt.newTree(
nnkInfix.newTree(
newIdentNode("/"),
newIdentNode("std"),
nnkBracket.newTree(
newIdentNode("sequtils"),
newIdentNode("macros")
)
)
),
nnkTypeSection.newTree(
nnkTypeDef.newTree(
newIdentNode("Future"),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("T"),
newEmptyNode(),
newEmptyNode()
)
),
nnkObjectTy.newTree(
newEmptyNode(),
newEmptyNode(),
newEmptyNode()
)
),
nnkTypeDef.newTree(
newIdentNode("InternalRaisesFuture"),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("T"),
newIdentNode("E"),
newEmptyNode(),
newEmptyNode()
)
),
nnkObjectTy.newTree(
newEmptyNode(),
newEmptyNode(),
newEmptyNode()
)
)
),
nnkMacroDef.newTree(
nnkPostfix.newTree(
newIdentNode("*"),
newIdentNode("Raising")
),
newEmptyNode(),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("T"),
newEmptyNode(),
newEmptyNode()
)
),
nnkFormalParams.newTree(
newIdentNode("untyped"),
nnkIdentDefs.newTree(
newIdentNode("F"),
nnkBracketExpr.newTree(
newIdentNode("typedesc"),
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode("T")
)
),
newEmptyNode()
),
nnkIdentDefs.newTree(
newIdentNode("E"),
nnkBracketExpr.newTree(
newIdentNode("varargs"),
newIdentNode("typedesc")
),
newEmptyNode()
)
),
newEmptyNode(),
newEmptyNode(),
nnkStmtList.newTree(
newCommentStmtNode("Given a Future type instance, return a type storing `{.raises.}`\ninformation\n\nNote; this type may change in the future"),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("E"),
newIdentNode("expectKind")
),
newIdentNode("nnkBracket")
),
nnkLetSection.newTree(
nnkIdentDefs.newTree(
newIdentNode("raises"),
newEmptyNode(),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("nnkTupleConstr"),
newIdentNode("newTree")
),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("E"),
newIdentNode("mapIt")
),
newIdentNode("it")
)
)
)
),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("nnkBracketExpr"),
newIdentNode("newTree")
),
nnkCommand.newTree(
newIdentNode("ident"),
newLit("InternalRaisesFuture")
),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("nnkDotExpr"),
newIdentNode("newTree")
),
newIdentNode("F"),
nnkCallStrLit.newTree(
newIdentNode("ident"),
newLit("T")
)
),
newIdentNode("raises")
)
)
),
nnkTypeSection.newTree(
nnkTypeDef.newTree(
newIdentNode("X"),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("E"),
newEmptyNode(),
newEmptyNode()
)
),
nnkCall.newTree(
nnkDotExpr.newTree(
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode("void")
),
newIdentNode("Raising")
),
newIdentNode("E")
)
)
),
nnkProcDef.newTree(
newIdentNode("f"),
newEmptyNode(),
newEmptyNode(),
nnkFormalParams.newTree(
newEmptyNode(),
nnkIdentDefs.newTree(
newIdentNode("x"),
newIdentNode("X"),
newEmptyNode()
)
),
newEmptyNode(),
newEmptyNode(),
nnkStmtList.newTree(
nnkDiscardStmt.newTree(
newEmptyNode()
)
)
),
nnkVarSection.newTree(
nnkIdentDefs.newTree(
newIdentNode("v"),
nnkCall.newTree(
nnkDotExpr.newTree(
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode("void")
),
newIdentNode("Raising")
),
nnkBracket.newTree(
newIdentNode("ValueError")
)
),
newEmptyNode()
)
),
nnkCall.newTree(
newIdentNode("f"),
newIdentNode("v")
)
) 2.0.2 👎 FAILOutput
IRCompiled filesize0 bytes (0 bytes)
Stats
ASTnnkStmtList.newTree(
nnkImportStmt.newTree(
nnkInfix.newTree(
newIdentNode("/"),
newIdentNode("std"),
nnkBracket.newTree(
newIdentNode("sequtils"),
newIdentNode("macros")
)
)
),
nnkTypeSection.newTree(
nnkTypeDef.newTree(
newIdentNode("Future"),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("T"),
newEmptyNode(),
newEmptyNode()
)
),
nnkObjectTy.newTree(
newEmptyNode(),
newEmptyNode(),
newEmptyNode()
)
),
nnkTypeDef.newTree(
newIdentNode("InternalRaisesFuture"),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("T"),
newIdentNode("E"),
newEmptyNode(),
newEmptyNode()
)
),
nnkObjectTy.newTree(
newEmptyNode(),
newEmptyNode(),
newEmptyNode()
)
)
),
nnkMacroDef.newTree(
nnkPostfix.newTree(
newIdentNode("*"),
newIdentNode("Raising")
),
newEmptyNode(),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("T"),
newEmptyNode(),
newEmptyNode()
)
),
nnkFormalParams.newTree(
newIdentNode("untyped"),
nnkIdentDefs.newTree(
newIdentNode("F"),
nnkBracketExpr.newTree(
newIdentNode("typedesc"),
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode("T")
)
),
newEmptyNode()
),
nnkIdentDefs.newTree(
newIdentNode("E"),
nnkBracketExpr.newTree(
newIdentNode("varargs"),
newIdentNode("typedesc")
),
newEmptyNode()
)
),
newEmptyNode(),
newEmptyNode(),
nnkStmtList.newTree(
newCommentStmtNode("Given a Future type instance, return a type storing `{.raises.}`\ninformation\n\nNote; this type may change in the future"),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("E"),
newIdentNode("expectKind")
),
newIdentNode("nnkBracket")
),
nnkLetSection.newTree(
nnkIdentDefs.newTree(
newIdentNode("raises"),
newEmptyNode(),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("nnkTupleConstr"),
newIdentNode("newTree")
),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("E"),
newIdentNode("mapIt")
),
newIdentNode("it")
)
)
)
),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("nnkBracketExpr"),
newIdentNode("newTree")
),
nnkCommand.newTree(
newIdentNode("ident"),
newLit("InternalRaisesFuture")
),
nnkCall.newTree(
nnkDotExpr.newTree(
newIdentNode("nnkDotExpr"),
newIdentNode("newTree")
),
newIdentNode("F"),
nnkCallStrLit.newTree(
newIdentNode("ident"),
newLit("T")
)
),
newIdentNode("raises")
)
)
),
nnkTypeSection.newTree(
nnkTypeDef.newTree(
newIdentNode("X"),
nnkGenericParams.newTree(
nnkIdentDefs.newTree(
newIdentNode("E"),
newEmptyNode(),
newEmptyNode()
)
),
nnkCall.newTree(
nnkDotExpr.newTree(
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode("void")
),
newIdentNode("Raising")
),
newIdentNode("E")
)
)
),
nnkProcDef.newTree(
newIdentNode("f"),
newEmptyNode(),
newEmptyNode(),
nnkFormalParams.newTree(
newEmptyNode(),
nnkIdentDefs.newTree(
newIdentNode("x"),
newIdentNode("X"),
newEmptyNode()
)
),
newEmptyNode(),
newEmptyNode(),
nnkStmtList.newTree(
nnkDiscardStmt.newTree(
newEmptyNode()
)
)
),
nnkVarSection.newTree(
nnkIdentDefs.newTree(
newIdentNode("v"),
nnkCall.newTree(
nnkDotExpr.newTree(
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode("void")
),
newIdentNode("Raising")
),
nnkBracket.newTree(
newIdentNode("ValueError")
)
),
newEmptyNode()
)
),
nnkCall.newTree(
newIdentNode("f"),
newIdentNode("v")
)
) 1.6.14 👍 OKOutput
IRCompiled filesize95.41 Kb (97,696 bytes)
#define NIM_INTBITS 64
#include "nimbase.h"
# define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_);
# define nimfrs_(proc, file, slots, length) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; nimFrame((TFrame*)&FR_);
# define nimln_(n, file) \
FR_.line = n; FR_.filename = file;
typedef struct tyObject_InternalRaisesFuture__joXl9brPglJfwBVacGXd5yg tyObject_InternalRaisesFuture__joXl9brPglJfwBVacGXd5yg;
struct tyObject_InternalRaisesFuture__joXl9brPglJfwBVacGXd5yg {
char dummy;
};
N_LIB_PRIVATE N_NIMCALL(void, f__temp_76)(tyObject_InternalRaisesFuture__joXl9brPglJfwBVacGXd5yg x);
static N_INLINE(void, nimFrame)(TFrame* s);
N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__system_2997)(void);
static N_INLINE(void, popFrame)(void);
static N_INLINE(void, initStackBottomWith)(void* locals);
N_LIB_PRIVATE N_NOINLINE(void, nimGC_setStackBottom)(void* theStackBottom);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus1dot6dot14atslibatssystemdotnim_DatInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus1dot6dot14atslibatssystemdotnim_Init000)(void);
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void);
N_LIB_PRIVATE tyObject_InternalRaisesFuture__joXl9brPglJfwBVacGXd5yg v__temp_75;
extern TFrame* framePtr__system_2564;
extern TFrame* framePtr__system_2564;
extern TFrame* framePtr__system_2564;
extern TFrame* framePtr__system_2564;
extern TFrame* framePtr__system_2564;
extern TFrame* framePtr__system_2564;
static N_INLINE(void, nimFrame)(TFrame* s) {
{
if (!(framePtr__system_2564 == ((TFrame*) NIM_NIL))) goto LA3_;
(*s).calldepth = ((NI16) 0);
}
goto LA1_;
LA3_: ;
{
(*s).calldepth = (NI16)((*framePtr__system_2564).calldepth + ((NI16) 1));
}
LA1_: ;
(*s).prev = framePtr__system_2564;
framePtr__system_2564 = s;
{
if (!((*s).calldepth == ((NI16) 2000))) goto LA8_;
callDepthLimitReached__system_2997();
}
LA8_: ;
}
static N_INLINE(void, popFrame)(void) {
framePtr__system_2564 = (*framePtr__system_2564).prev;
}
N_LIB_PRIVATE N_NIMCALL(void, f__temp_76)(tyObject_InternalRaisesFuture__joXl9brPglJfwBVacGXd5yg x) {
nimfr_("f", "/home/runner/work/Nim/Nim/temp.nim");
popFrame();
}
static N_INLINE(void, initStackBottomWith)(void* locals) {
nimGC_setStackBottom(locals);
}
N_LIB_PRIVATE void PreMainInner(void) {
}
N_LIB_PRIVATE int cmdCount;
N_LIB_PRIVATE char** cmdLine;
N_LIB_PRIVATE char** gEnv;
N_LIB_PRIVATE void PreMain(void) {
void (*volatile inner)(void);
inner = PreMainInner;
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus1dot6dot14atslibatssystemdotnim_DatInit000();
initStackBottomWith((void *)&inner);
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus1dot6dot14atslibatssystemdotnim_Init000();
(*inner)();
}
N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {
NimMainModule();
}
N_CDECL(void, NimMain)(void) {
void (*volatile inner)(void);
PreMain();
inner = NimMainInner;
initStackBottomWith((void *)&inner);
(*inner)();
}
int main(int argc, char** args, char** env) {
cmdLine = args;
cmdCount = argc;
gEnv = env;
NimMain();
return nim_program_result;
}
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
nimfr_("temp", "/home/runner/work/Nim/Nim/temp.nim");
f__temp_76(v__temp_75);
popFrame();
}
} Stats
1.4.8 👍 OKOutput
IRCompiled filesize91.30 Kb (93,496 bytes)
#define NIM_INTBITS 64
#include "nimbase.h"
# define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_);
# define nimfrs_(proc, file, slots, length) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; nimFrame((TFrame*)&FR_);
# define nimln_(n, file) \
FR_.line = n; FR_.filename = file;
typedef struct tyObject_InternalRaisesFuture__SoZdjWYx5qf9aGd4M3pBJdg tyObject_InternalRaisesFuture__SoZdjWYx5qf9aGd4M3pBJdg;
struct tyObject_InternalRaisesFuture__SoZdjWYx5qf9aGd4M3pBJdg {
char dummy;
};
N_LIB_PRIVATE N_NIMCALL(void, f__Qr2Z0OouGgYw3QfhyalszA)(tyObject_InternalRaisesFuture__SoZdjWYx5qf9aGd4M3pBJdg x);
static N_INLINE(void, nimFrame)(TFrame* s);
N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__mMRdr4sgmnykA9aWeM9aDZlw)(void);
static N_INLINE(void, popFrame)(void);
static N_INLINE(void, initStackBottomWith)(void* locals);
N_LIB_PRIVATE N_NOINLINE(void, nimGC_setStackBottom)(void* theStackBottom);
N_LIB_PRIVATE N_NIMCALL(void, systemDatInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, systemInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void);
N_LIB_PRIVATE tyObject_InternalRaisesFuture__SoZdjWYx5qf9aGd4M3pBJdg v__ZBo9advJ7u8QecSF0Bd4bHA;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
static N_INLINE(void, nimFrame)(TFrame* s) {
{
if (!(framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw == ((TFrame*) NIM_NIL))) goto LA3_;
(*s).calldepth = ((NI16) 0);
}
goto LA1_;
LA3_: ;
{
(*s).calldepth = (NI16)((*framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw).calldepth + ((NI16) 1));
}
LA1_: ;
(*s).prev = framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw = s;
{
if (!((*s).calldepth == ((NI16) 2000))) goto LA8_;
callDepthLimitReached__mMRdr4sgmnykA9aWeM9aDZlw();
}
LA8_: ;
}
static N_INLINE(void, popFrame)(void) {
framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw = (*framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw).prev;
}
N_LIB_PRIVATE N_NIMCALL(void, f__Qr2Z0OouGgYw3QfhyalszA)(tyObject_InternalRaisesFuture__SoZdjWYx5qf9aGd4M3pBJdg x) {
nimfr_("f", "/home/runner/work/Nim/Nim/temp.nim");
popFrame();
}
static N_INLINE(void, initStackBottomWith)(void* locals) {
nimGC_setStackBottom(locals);
}
N_LIB_PRIVATE void PreMainInner(void) {
}
N_LIB_PRIVATE int cmdCount;
N_LIB_PRIVATE char** cmdLine;
N_LIB_PRIVATE char** gEnv;
N_LIB_PRIVATE void PreMain(void) {
void (*volatile inner)(void);
inner = PreMainInner;
systemDatInit000();
initStackBottomWith((void *)&inner);
systemInit000();
(*inner)();
}
N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {
NimMainModule();
}
N_CDECL(void, NimMain)(void) {
void (*volatile inner)(void);
PreMain();
inner = NimMainInner;
initStackBottomWith((void *)&inner);
(*inner)();
}
int main(int argc, char** args, char** env) {
cmdLine = args;
cmdCount = argc;
gEnv = env;
NimMain();
return nim_program_result;
}
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
nimfr_("temp", "/home/runner/work/Nim/Nim/temp.nim");
f__Qr2Z0OouGgYw3QfhyalszA(v__ZBo9advJ7u8QecSF0Bd4bHA);
popFrame();
}
} Stats
1.2.18 👍 OKOutput
IRCompiled filesize87.03 Kb (89,120 bytes)
#define NIM_INTBITS 64
#include "nimbase.h"
# define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_);
# define nimfrs_(proc, file, slots, length) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; nimFrame((TFrame*)&FR_);
# define nimln_(n, file) \
FR_.line = n; FR_.filename = file;
typedef struct tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ;
struct tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ {
char dummy;
};
N_LIB_PRIVATE N_NIMCALL(void, f__7BqHdHV1GTsUzckBHACG6Q)(tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ x);
static N_INLINE(void, nimFrame)(TFrame* s);
N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__mMRdr4sgmnykA9aWeM9aDZlw)(void);
static N_INLINE(void, popFrame)(void);
static N_INLINE(void, initStackBottomWith)(void* locals);
N_LIB_PRIVATE N_NOINLINE(void, nimGC_setStackBottom)(void* theStackBottom);
N_LIB_PRIVATE N_NIMCALL(void, systemDatInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, systemInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void);
N_LIB_PRIVATE tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ v__ZBo9advJ7u8QecSF0Bd4bHA;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
static N_INLINE(void, nimFrame)(TFrame* s) {
{
if (!(framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw == NIM_NIL)) goto LA3_;
(*s).calldepth = ((NI16) 0);
}
goto LA1_;
LA3_: ;
{
(*s).calldepth = (NI16)((*framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw).calldepth + ((NI16) 1));
}
LA1_: ;
(*s).prev = framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw = s;
{
if (!((*s).calldepth == ((NI16) (((NI) 2000))))) goto LA8_;
callDepthLimitReached__mMRdr4sgmnykA9aWeM9aDZlw();
}
LA8_: ;
}
static N_INLINE(void, popFrame)(void) {
framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw = (*framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw).prev;
}
N_LIB_PRIVATE N_NIMCALL(void, f__7BqHdHV1GTsUzckBHACG6Q)(tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ x) {
nimfr_("f", "/home/runner/work/Nim/Nim/temp.nim");
popFrame();
}
static N_INLINE(void, initStackBottomWith)(void* locals) {
nimGC_setStackBottom(locals);
}
N_LIB_PRIVATE void PreMainInner(void) {
}
N_LIB_PRIVATE int cmdCount;
N_LIB_PRIVATE char** cmdLine;
N_LIB_PRIVATE char** gEnv;
N_LIB_PRIVATE void PreMain(void) {
void (*volatile inner)(void);
inner = PreMainInner;
systemDatInit000();
initStackBottomWith((void *)&inner);
systemInit000();
(*inner)();
}
N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {
NimMainModule();
}
N_CDECL(void, NimMain)(void) {
void (*volatile inner)(void);
PreMain();
inner = NimMainInner;
initStackBottomWith((void *)&inner);
(*inner)();
}
int main(int argc, char** args, char** env) {
cmdLine = args;
cmdCount = argc;
gEnv = env;
NimMain();
return nim_program_result;
}
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
nimfr_("temp", "/home/runner/work/Nim/Nim/temp.nim");
f__7BqHdHV1GTsUzckBHACG6Q(v__ZBo9advJ7u8QecSF0Bd4bHA);
popFrame();
}
} Stats
1.0.10 👍 OKOutput
IRCompiled filesize86.13 Kb (88,192 bytes)
#define NIM_INTBITS 64
#include "nimbase.h"
# define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_);
# define nimfrs_(proc, file, slots, length) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; nimFrame((TFrame*)&FR_);
# define nimln_(n, file) \
FR_.line = n; FR_.filename = file;
typedef struct tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ;
struct tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ {
char dummy;
};
N_LIB_PRIVATE N_NIMCALL(void, f__7BqHdHV1GTsUzckBHACG6Q)(tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ x);
static N_INLINE(void, nimFrame)(TFrame* s);
N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__mMRdr4sgmnykA9aWeM9aDZlw)(void);
static N_INLINE(void, popFrame)(void);
static N_INLINE(void, initStackBottomWith)(void* locals);
N_NOINLINE(void, nimGC_setStackBottom)(void* theStackBottom);
N_LIB_PRIVATE N_NIMCALL(void, systemDatInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, systemInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void);
tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ v__ZBo9advJ7u8QecSF0Bd4bHA;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
extern TFrame* framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
static N_INLINE(void, nimFrame)(TFrame* s) { NI T1_;
T1_ = (NI)0;
{
if (!(framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw == NIM_NIL)) goto LA4_;
T1_ = ((NI) 0);
}
goto LA2_;
LA4_: ;
{
T1_ = ((NI) ((NI16)((*framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw).calldepth + ((NI16) 1))));
}
LA2_: ;
(*s).calldepth = ((NI16) (T1_));
(*s).prev = framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw;
framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw = s;
{
if (!((*s).calldepth == ((NI16) (((NI) 2000))))) goto LA9_;
callDepthLimitReached__mMRdr4sgmnykA9aWeM9aDZlw();
}
LA9_: ;
}
static N_INLINE(void, popFrame)(void) { framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw = (*framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw).prev;
}
N_LIB_PRIVATE N_NIMCALL(void, f__7BqHdHV1GTsUzckBHACG6Q)(tyObject_InternalRaisesFuture__Er05yBj9atIFRAN6fCwoRwQ x) { nimfr_("f", "/home/runner/work/Nim/Nim/temp.nim");
popFrame();
}
static N_INLINE(void, initStackBottomWith)(void* locals) { nimGC_setStackBottom(locals);
}
void PreMainInner(void) {
}
int cmdCount;
char** cmdLine;
char** gEnv;
void PreMain(void) {
void (*volatile inner)(void);
inner = PreMainInner;
systemDatInit000();
initStackBottomWith((void *)&inner);
systemInit000();
(*inner)();
}
N_CDECL(void, NimMainInner)(void) {
NimMainModule();
}
N_CDECL(void, NimMain)(void) {
void (*volatile inner)(void);
PreMain();
inner = NimMainInner;
initStackBottomWith((void *)&inner);
(*inner)();
}
int main(int argc, char** args, char** env) {
cmdLine = args;
cmdCount = argc;
gEnv = env;
NimMain();
return nim_program_result;
}
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
nimfr_("temp", "/home/runner/work/Nim/Nim/temp.nim");
f__7BqHdHV1GTsUzckBHACG6Q(v__ZBo9advJ7u8QecSF0Bd4bHA);
popFrame();
}
} Stats
??? ➡️ 🐛DiagnosticsThe commit that introduced the bug can not be found, but the bug is in the commits: (Can not find the commit because Nim can not be re-built commit-by-commit to bisect). Stats
🤖 Bug found in |
Should have mentioned the origin is more than likely #22029 To be clear this isn't just a simple regression but needs a design choice:
|
I've been thinking about this, and I wonder if there's room for post-monomorphization macros somewhere in the language - when thinking about this problem, that's what I actually wanted. Going further back in my reasoning around |
Sorry, after looking into it more it seems like some code even depends on I still understand the need for better type safety than just |
fixes #23406, closes #23854, closes #23855 (test code of both compiles but separate issue exists), refs #23432, follows #23411 In generic bodies, previously all regular `nkCall` nodes like `foo(a, b)` were directly treated as generic statements and delayed immediately, but other call kinds like `a.foo(b)`, `foo a, b` etc underwent typechecking before making sure they have to be delayed, as implemented in #22029. Since the behavior for `nkCall` was slightly buggy (as in #23406), the behavior for all call kinds is now to call `semTypeExpr`. However the vast majority of calls in generic bodies out there are `nkCall`, and while there isn't a difference in the expected behavior, this exposes many issues with the implementation started in #22029 given how much more code uses it now. The portion of these issues that CI has caught are fixed in this PR but it's possible there are more. 1. Deref expressions, dot expressions and calls to dot expressions now handle and propagate `tyFromExpr`. This is most of the changes in `semexprs`. 2. For deref expressions to work in `typeof`, a new type flag `tfNonConstExpr` is added for `tyFromExpr` that calls `semExprWithType` with `efInTypeof` on the expression instead of `semConstExpr`. This type flag is set for every `tyFromExpr` type of a node that `prepareNode` encounters, so that the node itself isn't evaluated at compile time when just trying to get the type of the node. 3. Unresolved `static` types matching `static` parameters is now treated the same as unresolved generic types matching `typedesc` parameters in generic type bodies, it causes a failed match which delays the call instantiation. 4. `typedesc` parameters now reject all types containing unresolved generic types like `seq[T]`, not just generic param types by themselves. (using `containsGenericType`) 5. `semgnrc` now doesn't leave generic param symbols it encounters in generic type contexts as just identifiers, and instead turns them into symbol nodes. Normally in generic procs, this isn't a problem since the generic param symbols will be provided again at instantiation time (and in fact creating symbol nodes causes issues since `seminst` doesn't actually instantiate proc body node types). But generic types can try to be instantiated early in `sigmatch` which will give an undeclared identifier error when the param is not provided. Nodes in generic types (specifically in `tyFromExpr` which should be the only use for `semGenericStmt`) undergo full generic type instantiation with `prepareNode`, so there is no issue of these symbols remaining as uninstantiated generic types. 6. `prepareNode` now has more logic for which nodes to avoid instantiating. Subscripts and subscripts turned into calls to `[]` by `semgnrc` need to avoid instantiating the first operand, since it may be a generic body type like `Generic` in an expression like `Generic[int]`. Dot expressions cannot instantiate their RHS as it may be a generic proc symbol or even an undeclared identifier for generic param fields, but have to instantiate their LHS, so calls and subscripts need to still instantiate their first node if it's a dot expression. This logic still isn't perfect and needs the same level of detail as in `semexprs` for which nodes can be left as "untyped" for overloading/dot exprs/subscripts to handle, but should handle the majority of cases. Also the `efDetermineType` requirement for which calls become `tyFromExpr` is removed and as a result `efDetermineType` is entirely unused again.
fixes #23406, closes #23854, closes #23855 (test code of both compiles but separate issue exists), refs #23432, follows #23411 In generic bodies, previously all regular `nkCall` nodes like `foo(a, b)` were directly treated as generic statements and delayed immediately, but other call kinds like `a.foo(b)`, `foo a, b` etc underwent typechecking before making sure they have to be delayed, as implemented in #22029. Since the behavior for `nkCall` was slightly buggy (as in However the vast majority of calls in generic bodies out there are `nkCall`, and while there isn't a difference in the expected behavior, this exposes many issues with the implementation started in #22029 given how much more code uses it now. The portion of these issues that CI has caught are fixed in this PR but it's possible there are more. 1. Deref expressions, dot expressions and calls to dot expressions now handle and propagate `tyFromExpr`. This is most of the changes in `semexprs`. 2. For deref expressions to work in `typeof`, a new type flag `tfNonConstExpr` is added for `tyFromExpr` that calls `semExprWithType` with `efInTypeof` on the expression instead of `semConstExpr`. This type flag is set for every `tyFromExpr` type of a node that `prepareNode` encounters, so that the node itself isn't evaluated at compile time when just trying to get the type of the node. 3. Unresolved `static` types matching `static` parameters is now treated the same as unresolved generic types matching `typedesc` parameters in generic type bodies, it causes a failed match which delays the call instantiation. 4. `typedesc` parameters now reject all types containing unresolved generic types like `seq[T]`, not just generic param types by themselves. (using `containsGenericType`) 5. `semgnrc` now doesn't leave generic param symbols it encounters in generic type contexts as just identifiers, and instead turns them into symbol nodes. Normally in generic procs, this isn't a problem since the generic param symbols will be provided again at instantiation time (and in fact creating symbol nodes causes issues since `seminst` doesn't actually instantiate proc body node types). But generic types can try to be instantiated early in `sigmatch` which will give an undeclared identifier error when the param is not provided. Nodes in generic types (specifically in `tyFromExpr` which should be the only use for `semGenericStmt`) undergo full generic type instantiation with `prepareNode`, so there is no issue of these symbols remaining as uninstantiated generic types. 6. `prepareNode` now has more logic for which nodes to avoid instantiating. Subscripts and subscripts turned into calls to `[]` by `semgnrc` need to avoid instantiating the first operand, since it may be a generic body type like `Generic` in an expression like `Generic[int]`. Dot expressions cannot instantiate their RHS as it may be a generic proc symbol or even an undeclared identifier for generic param fields, but have to instantiate their LHS, so calls and subscripts need to still instantiate their first node if it's a dot expression. This logic still isn't perfect and needs the same level of detail as in `semexprs` for which nodes can be left as "untyped" for overloading/dot exprs/subscripts to handle, but should handle the majority of cases. Also the `efDetermineType` requirement for which calls become `tyFromExpr` is removed and as a result `efDetermineType` is entirely unused again. (cherry picked from commit ab18962)
Description
Nim Version
works in 1.6, broken in 2.0, devel
Current Output
Expected Output
No response
Possible Solution
No response
Additional Information
No response
The text was updated successfully, but these errors were encountered: