fixes #2216
This commit is contained in:
parent
5d9663e4de
commit
9053799bf5
5 changed files with 47 additions and 16 deletions
|
|
@ -95,15 +95,6 @@ proc inferWithMetatype(c: PContext, formal: PType,
|
||||||
|
|
||||||
var commonTypeBegin = PType(kind: tyExpr)
|
var commonTypeBegin = PType(kind: tyExpr)
|
||||||
|
|
||||||
proc isEmptyContainer(t: PType): bool =
|
|
||||||
case t.kind
|
|
||||||
of tyExpr, tyNil: result = true
|
|
||||||
of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
|
|
||||||
of tySet, tySequence, tyOpenArray, tyVarargs:
|
|
||||||
result = t.sons[0].kind == tyEmpty
|
|
||||||
of tyGenericInst: result = isEmptyContainer(t.lastSon)
|
|
||||||
else: result = false
|
|
||||||
|
|
||||||
proc commonType*(x, y: PType): PType =
|
proc commonType*(x, y: PType): PType =
|
||||||
# new type relation that is used for array constructors,
|
# new type relation that is used for array constructors,
|
||||||
# if expressions, etc.:
|
# if expressions, etc.:
|
||||||
|
|
|
||||||
|
|
@ -1145,7 +1145,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
case n.len
|
case n.len
|
||||||
of 3:
|
of 3:
|
||||||
result = semTypeNode(c, n.sons[1], prev)
|
result = semTypeNode(c, n.sons[1], prev)
|
||||||
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
|
if result.skipTypes({tyGenericInst}).kind in NilableTypes+GenericTypes and
|
||||||
|
n.sons[2].kind == nkNilLit:
|
||||||
result = freshType(result, prev)
|
result = freshType(result, prev)
|
||||||
result.flags.incl(tfNotNil)
|
result.flags.incl(tfNotNil)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = PType(idTableGet(cl.localCache, t))
|
result = PType(idTableGet(cl.localCache, t))
|
||||||
else:
|
else:
|
||||||
result = searchInstTypes(t)
|
result = searchInstTypes(t)
|
||||||
if result != nil: return
|
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
var x = t.sons[i]
|
var x = t.sons[i]
|
||||||
if x.kind == tyGenericParam:
|
if x.kind == tyGenericParam:
|
||||||
|
|
@ -260,7 +260,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
if header != t:
|
if header != t:
|
||||||
# search again after first pass:
|
# search again after first pass:
|
||||||
result = searchInstTypes(header)
|
result = searchInstTypes(header)
|
||||||
if result != nil: return
|
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
|
||||||
else:
|
else:
|
||||||
header = instCopyType(cl, t)
|
header = instCopyType(cl, t)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1165,6 +1165,15 @@ proc isInlineIterator*(t: PType): bool =
|
||||||
result = t.kind == tyIter or
|
result = t.kind == tyIter or
|
||||||
(t.kind == tyBuiltInTypeClass and t.base.kind == tyIter)
|
(t.kind == tyBuiltInTypeClass and t.base.kind == tyIter)
|
||||||
|
|
||||||
|
proc isEmptyContainer*(t: PType): bool =
|
||||||
|
case t.kind
|
||||||
|
of tyExpr, tyNil: result = true
|
||||||
|
of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
|
||||||
|
of tySet, tySequence, tyOpenArray, tyVarargs:
|
||||||
|
result = t.sons[0].kind == tyEmpty
|
||||||
|
of tyGenericInst: result = isEmptyContainer(t.lastSon)
|
||||||
|
else: result = false
|
||||||
|
|
||||||
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
argSemantized, argOrig: PNode): PNode =
|
argSemantized, argOrig: PNode): PNode =
|
||||||
var
|
var
|
||||||
|
|
@ -1260,11 +1269,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
when false:
|
when true:
|
||||||
if skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
if skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||||
else:
|
elif arg.typ != nil and arg.typ.isEmptyContainer:
|
||||||
result = arg.copyTree
|
result = arg.copyTree
|
||||||
|
result.typ = getInstantiatedType(c, arg, m, f)
|
||||||
|
else:
|
||||||
|
result = arg
|
||||||
else:
|
else:
|
||||||
# XXX Why is this ever necessary? arg's type should not be retrofitted
|
# XXX Why is this ever necessary? arg's type should not be retrofitted
|
||||||
# to match formal's type in this way!
|
# to match formal's type in this way!
|
||||||
|
|
|
||||||
27
tests/notnil/tnotnil_in_generic.nim
Normal file
27
tests/notnil/tnotnil_in_generic.nim
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "cannot prove 'x' is not nil"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #2216
|
||||||
|
|
||||||
|
type
|
||||||
|
A[T] = ref object
|
||||||
|
x: int
|
||||||
|
ud: T
|
||||||
|
|
||||||
|
proc good[T](p: A[T]) =
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc bad[T](p: A[T] not nil) =
|
||||||
|
discard
|
||||||
|
|
||||||
|
|
||||||
|
proc go() =
|
||||||
|
let s = A[int](x: 1)
|
||||||
|
|
||||||
|
good(s)
|
||||||
|
bad(s)
|
||||||
|
var x: A[int]
|
||||||
|
bad(x)
|
||||||
|
|
||||||
|
go()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue