fixes #21377; fixes @[] and {} type inference as returns in generics (#21475)

* fixes `@[]` type inference in generics

* add issue links

* fixes macros and iterators

* refactor

* add one more test
This commit is contained in:
ringabout 2023-03-06 22:30:22 +08:00 • committed by GitHub
commit 64a0355f3f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 5 deletions

View file

@ -998,7 +998,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
fixAbstractType(c, result) fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result) analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone: if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags) result = magicsAfterOverloadResolution(c, result, flags, expectedType)
when false: when false:
if result.typ != nil and if result.typ != nil and
not (result.typ.kind == tySequence and result.typ[0].kind == tyEmpty): not (result.typ.kind == tySequence and result.typ[0].kind == tyEmpty):

View file

@ -127,11 +127,18 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
if sfGenSym in param.flags: if sfGenSym in param.flags:
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym) idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
freshGenSyms(c, b, result, orig, symMap) freshGenSyms(c, b, result, orig, symMap)
if sfBorrow notin orig.flags: if sfBorrow notin orig.flags:
# We do not want to generate a body for generic borrowed procs. # We do not want to generate a body for generic borrowed procs.
# As body is a sym to the borrowed proc. # As body is a sym to the borrowed proc.
b = semProcBody(c, b) let resultType = # todo probably refactor it into a function
if result.kind == skMacro:
sysTypeFromName(c.graph, n.info, "NimNode")
elif not isInlineIterator(result.typ):
result.typ[0]
else:
nil
b = semProcBody(c, b, resultType)
result.ast[bodyPos] = hloBody(c, b) result.ast[bodyPos] = hloBody(c, b)
excl(result.flags, sfForward) excl(result.flags, sfForward)
trackProc(c, result, result.ast[bodyPos]) trackProc(c, result, result.ast[bodyPos])

View file

@ -526,7 +526,7 @@ proc checkDefault(c: PContext, n: PNode): PNode =
message(c.config, n.info, warnUnsafeDefault, typeToString(constructed)) message(c.config, n.info, warnUnsafeDefault, typeToString(constructed))
proc magicsAfterOverloadResolution(c: PContext, n: PNode, proc magicsAfterOverloadResolution(c: PContext, n: PNode,
flags: TExprFlags): PNode = flags: TExprFlags; expectedType: PType = nil): PNode =
## This is the preferred code point to implement magics. ## This is the preferred code point to implement magics.
## ``c`` the current module, a symbol table to a very good approximation ## ``c`` the current module, a symbol table to a very good approximation
## ``n`` the ast like it would be passed to a real macro ## ``n`` the ast like it would be passed to a real macro
@ -635,5 +635,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = n result = n
of mPrivateAccess: of mPrivateAccess:
result = semPrivateAccess(c, n) result = semPrivateAccess(c, n)
of mArrToSeq:
result = n
if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and expectedType.kind == tySequence and result.typ[0].kind == tyEmpty:
result.typ = expectedType # type inference for empty sequence # bug #21377
else: else:
result = n result = n

View file

@ -245,7 +245,7 @@ block: # bug #11777
var s: S = {1, 2} var s: S = {1, 2}
doAssert 1 in s doAssert 1 in s
block: # regression #20807 block: # bug #20807
var s: seq[string] var s: seq[string]
template fail = template fail =
s = @[] s = @[]
@ -255,3 +255,38 @@ block: # regression #20807
test: fail() test: fail()
doAssert not (compiles do: doAssert not (compiles do:
let x: seq[int] = `@`[string]([])) let x: seq[int] = `@`[string]([]))
block: # bug #21377
proc b[T](v: T): seq[int] =
let x = 0
@[]
doAssert b(0) == @[]
block: # bug #21377
proc b[T](v: T): seq[T] =
let x = 0
@[]
doAssert b(0) == @[]
block: # bug #21377
proc b[T](v: T): set[bool] =
let x = 0
{}
doAssert b(0) == {}
block: # bug #21377
proc b[T](v: T): array[0, int] =
let x = 0
[]
doAssert b(0) == []
block: # bug #21377
proc b[T](v: T): array[0, (string, string)] =
let x = 0
{:}
doAssert b(0) == {:}