diff --git a/compiler/sem.nim b/compiler/sem.nim index a42719a753bf..0cc5b6b39ac8 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -333,7 +333,7 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode = if hasCycle(result): result = localErrorNode(c, eOrig, "the resulting AST is cyclic and cannot be processed further") else: - semmacrosanity.annotateType(result, expectedType, c.config) + result = semmacrosanity.annotateType(result, expectedType, c.config) else: result = semExprWithType(c, evaluated) #result = fitNode(c, e.typ, result) inlined with special case: diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index 67cc86a14d9f..362bbced681d 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -10,9 +10,28 @@ ## Implements type sanity checking for ASTs resulting from macros. Lots of ## room for improvement here. -import ast, msgs, types, options +import ast, msgs, types, options, trees, nimsets -proc ithField(n: PNode, field: var int): PSym = +type + FieldTracker = object + index: int + remaining: int + constr: PNode + delete: bool # to delete fields from inactive case branches + FieldInfo = ref object + sym: PSym + delete: bool + +proc caseBranchMatchesExpr(branch, matched: PNode): bool = + # copied from sem + result = false + for i in 0 ..< branch.len-1: + if branch[i].kind == nkRange: + if overlap(branch[i], matched): return true + elif exprStructuralEquivalent(branch[i], matched): + return true + +proc ithField(n: PNode, field: var FieldTracker): FieldInfo = result = nil case n.kind of nkRecList: @@ -23,18 +42,42 @@ proc ithField(n: PNode, field: var int): PSym = if n[0].kind != nkSym: return result = ithField(n[0], field) if result != nil: return + # value of the discriminator field, from (index - remaining - 1 + 1): + # - 1 because the `ithField` call above decreased it by 1, + # + 1 because the constructor node has an initial type child + let val = field.constr[field.index - field.remaining][1] + var branchFound = false for i in 1..= x.kidsLen: globalError conf, n.info, "invalid field at index " & $i - else: annotateType(n[i], x[i], conf) + else: n[i] = annotateType(n[i], x[i], conf) elif x.kind == tyProc and x.callConv == ccClosure: n.typ() = t elif x.kind == tyOpenArray: # `opcSlice` transforms slices into tuples @@ -79,11 +127,11 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) = of nkStrKinds: for i in left..right: bracketExpr.add newIntNode(nkCharLit, BiggestInt n[0].strVal[i]) - annotateType(bracketExpr[^1], x.elementType, conf) + bracketExpr[^1] = annotateType(bracketExpr[^1], x.elementType, conf) of nkBracket: for i in left..right: bracketExpr.add n[0][i] - annotateType(bracketExpr[^1], x.elementType, conf) + bracketExpr[^1] = annotateType(bracketExpr[^1], x.elementType, conf) else: globalError(conf, n.info, "Incorrectly generated tuple constr") n[] = bracketExpr[] @@ -94,13 +142,15 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) = of nkBracket: if x.kind in {tyArray, tySequence, tyOpenArray}: n.typ() = t - for m in n: annotateType(m, x.elemType, conf) + for i in 0 ..< n.len: + n[i] = annotateType(n[i], x.elemType, conf) else: globalError(conf, n.info, "[] must have some form of array type") of nkCurly: if x.kind in {tySet}: n.typ() = t - for m in n: annotateType(m, x.elemType, conf) + for i in 0 ..< n.len: + n[i] = annotateType(n[i], x.elemType, conf) else: globalError(conf, n.info, "{} must have the set type") of nkFloatLit..nkFloat128Lit: diff --git a/compiler/vm.nim b/compiler/vm.nim index f26d41324fa0..177fdf64dbc3 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1458,10 +1458,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var macroCall = newNodeI(nkCall, c.debug[pc]) macroCall.add(newSymNode(prc)) for i in 1..rc-1: - let node = regs[rb+i].regToNode + var node = regs[rb+i].regToNode node.info = c.debug[pc] if prc.typ[i].kind notin {tyTyped, tyUntyped}: - node.annotateType(prc.typ[i], c.config) + node = node.annotateType(prc.typ[i], c.config) macroCall.add(node) var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter, c.idgen) diff --git a/tests/vm/tcaseobj.nim b/tests/vm/tcaseobj.nim new file mode 100644 index 000000000000..80730f45a836 --- /dev/null +++ b/tests/vm/tcaseobj.nim @@ -0,0 +1,19 @@ +# issue #17571 + +import std/[macros, objectdollar] + +type + MyEnum = enum + F, S, T + Foo = object + case o: MyEnum + of F: + f: string + of S: + s: string + of T: + t: string + +let val = static(Foo(o: F, f: "foo")).f +doAssert val == "foo" +doAssert $static(Foo(o: F, f: "foo")) == $Foo(o: F, f: "foo")