Skip to content

Commit

Permalink
don't construct array type for already typed nkBracket node (#24224)
Browse files Browse the repository at this point in the history
fixes #23010, split from #24195

When resemming bracket nodes, the compiler currently unconditionally
makes a new node with an array type based on the node. However the VM
can generate bracket nodes with `seq` types, which this erases. To fix
this, if a bracket node already has a type, we still resem the bracket
node, but don't construct a new type for it, instead using the type of
the original node.

A version of this was rejected that didn't resem the node at all if it
was typed, but I can't find it. The difference with this one is that the
individual elements are still resemmed.

This should fix the break caused by #24184 so we could redo it after
this PR but it might still have issues, not to mention the related
pre-existing issues like #22793, #12559 etc.
  • Loading branch information
metagn authored Oct 3, 2024
1 parent 89978b4 commit d98ef31
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 22 deletions.
65 changes: 43 additions & 22 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -722,29 +722,41 @@ proc arrayConstrType(c: PContext, n: PNode): PType =

proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = newNodeI(nkBracket, n.info)
result.typ = newTypeS(tyArray, c)
# nkBracket nodes can also be produced by the VM as seq constant nodes
# in which case, we cannot produce a new array type for the node,
# as this might lose type info even when the node has array type
let constructType = n.typ.isNil
var expectedElementType, expectedIndexType: PType = nil
if expectedType != nil:
let expected = expectedType.skipTypes(abstractRange-{tyDistinct})
case expected.kind
var expectedBase: PType = nil
if constructType:
result.typ = newTypeS(tyArray, c)
rawAddSon(result.typ, nil) # index type
if expectedType != nil:
expectedBase = expectedType.skipTypes(abstractRange-{tyDistinct})
else:
result.typ = n.typ
expectedBase = n.typ.skipTypes(abstractRange) # include tyDistinct this time
if expectedBase != nil:
case expectedBase.kind
of tyArray:
expectedIndexType = expected[0]
expectedElementType = expected[1]
of tyOpenArray:
expectedElementType = expected[0]
expectedIndexType = expectedBase[0]
expectedElementType = expectedBase[1]
of tyOpenArray, tySequence:
# typed bracket expressions can also have seq type
expectedElementType = expectedBase[0]
else: discard
rawAddSon(result.typ, nil) # index type
var
firstIndex, lastIndex: Int128 = Zero
indexType = getSysType(c.graph, n.info, tyInt)
lastValidIndex = lastOrd(c.config, indexType)
if n.len == 0:
rawAddSon(result.typ,
if expectedElementType != nil and
typeAllowed(expectedElementType, skLet, c) == nil:
expectedElementType
else:
newTypeS(tyEmpty, c)) # needs an empty basetype!
if constructType:
rawAddSon(result.typ,
if expectedElementType != nil and
typeAllowed(expectedElementType, skLet, c) == nil:
expectedElementType
else:
newTypeS(tyEmpty, c)) # needs an empty basetype!
lastIndex = toInt128(-1)
else:
var x = n[0]
Expand All @@ -761,9 +773,13 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
x = x[1]

let yy = semExprWithType(c, x, {efTypeAllowed}, expectedElementType)
var typ = yy.typ
if expectedElementType == nil:
expectedElementType = typ
var typ: PType
if constructType:
typ = yy.typ
if expectedElementType == nil:
expectedElementType = typ
else:
typ = expectedElementType
result.add yy
#var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
for i in 1..<n.len:
Expand All @@ -783,15 +799,20 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp

let xx = semExprWithType(c, x, {efTypeAllowed}, expectedElementType)
result.add xx
typ = commonType(c, typ, xx.typ)
if constructType:
typ = commonType(c, typ, xx.typ)
#n[i] = semExprWithType(c, x, {})
#result.add fitNode(c, typ, n[i])
inc(lastIndex)
addSonSkipIntLit(result.typ, typ, c.idgen)
if constructType:
addSonSkipIntLit(result.typ, typ, c.idgen)
for i in 0..<result.len:
result[i] = fitNode(c, typ, result[i], result[i].info)
result.typ.setIndexType makeRangeType(c, toInt64(firstIndex), toInt64(lastIndex), n.info,
indexType)
if constructType:
result.typ.setIndexType(
makeRangeType(c,
toInt64(firstIndex), toInt64(lastIndex),
n.info, indexType))

proc fixAbstractType(c: PContext, n: PNode) =
for i in 1..<n.len:
Expand Down
29 changes: 29 additions & 0 deletions tests/vm/tconstarrayresem.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# issue #23010

type
Result[T, E] = object
case oResult: bool
of false:
discard
of true:
vResult: T

Opt[T] = Result[T, void]

template ok[T, E](R: type Result[T, E], x: untyped): R =
R(oResult: true, vResult: x)

template c[T](v: T): Opt[T] = Opt[T].ok(v)

type
FixedBytes[N: static[int]] = distinct array[N, byte]

H = object
d: FixedBytes[2]

const b = default(H)
template g(): untyped =
const t = default(H)
b

discard c(g())

0 comments on commit d98ef31

Please sign in to comment.