fixes #4371
This commit is contained in:
parent
caa7f42e8e
commit
b47d9b7b91
21 changed files with 84 additions and 39 deletions
|
|
@ -395,6 +395,9 @@ type
|
|||
# sons[1]: field type
|
||||
# .n: nkDotExpr storing the field name
|
||||
|
||||
tyVoid #\
|
||||
# now different from tyEmpty, hurray!
|
||||
|
||||
static:
|
||||
# remind us when TTypeKind stops to fit in a single 64-bit word
|
||||
assert TTypeKind.high.ord <= 63
|
||||
|
|
@ -528,8 +531,6 @@ const
|
|||
tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \
|
||||
# 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be
|
||||
# deprecated and this mess can be cleaned up.
|
||||
tfVoid* = tfVarargs # for historical reasons we conflated 'void' with
|
||||
# 'empty' ('@[]' has the type 'seq[empty]').
|
||||
tfReturnsNew* = tfInheritable
|
||||
skError* = skUnknown
|
||||
|
||||
|
|
@ -1588,7 +1589,7 @@ proc isAtom*(n: PNode): bool {.inline.} =
|
|||
|
||||
proc isEmptyType*(t: PType): bool {.inline.} =
|
||||
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
|
||||
result = t == nil or t.kind in {tyEmpty, tyStmt}
|
||||
result = t == nil or t.kind in {tyVoid, tyStmt}
|
||||
|
||||
proc makeStmtList*(n: PNode): PNode =
|
||||
if n.kind == nkStmtList:
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
|
|||
result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
|
||||
of tyArray, tyArrayConstr:
|
||||
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))]
|
||||
else:
|
||||
else:
|
||||
internalError("openArrayLoc: " & typeToString(a.t))
|
||||
else: internalError("openArrayLoc: " & typeToString(a.t))
|
||||
|
||||
|
|
|
|||
|
|
@ -1320,7 +1320,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
|||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprAny($1, $2)", [
|
||||
rdLoc(a), genTypeInfo(p.module, t)]), a.s)
|
||||
of tyEmpty:
|
||||
of tyEmpty, tyVoid:
|
||||
localError(e.info, "'repr' doesn't support 'void' type")
|
||||
else:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
|||
addf(result, "union{$n$1} $2;$n", [unionBody, uname])
|
||||
of nkSym:
|
||||
field = n.sym
|
||||
if field.typ.kind == tyEmpty: return
|
||||
if field.typ.kind == tyVoid: return
|
||||
#assert(field.ast == nil)
|
||||
sname = mangleRecFieldName(field, rectype)
|
||||
if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname]
|
||||
|
|
@ -663,7 +663,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
|||
chunkStart = i
|
||||
|
||||
let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars)
|
||||
if typeInSlot == nil or typeInSlot.kind == tyEmpty:
|
||||
if typeInSlot == nil or typeInSlot.kind == tyVoid:
|
||||
result.add(~"void")
|
||||
else:
|
||||
result.add getTypeDescAux(m, typeInSlot, check)
|
||||
|
|
@ -1022,7 +1022,7 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
|
|||
[result, rope(typeToString(t))])
|
||||
return "(&".rope & result & ")".rope
|
||||
case t.kind
|
||||
of tyEmpty: result = rope"0"
|
||||
of tyEmpty, tyVoid: result = rope"0"
|
||||
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
|
||||
genTypeInfoAuxBase(m, t, t, result, rope"0")
|
||||
of tyProc:
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ proc getUniqueType*(key: PType): PType =
|
|||
# produced instead of ``NI``.
|
||||
result = key
|
||||
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
|
||||
tyCString, tyNone, tyBigNum:
|
||||
tyCString, tyNone, tyBigNum, tyVoid:
|
||||
result = gCanonicalTypes[k]
|
||||
if result == nil:
|
||||
gCanonicalTypes[k] = key
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ proc mapType(typ: PType): TJSTypeKind =
|
|||
of tyNil: result = etyNull
|
||||
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
|
||||
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
|
||||
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
|
||||
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses, tyVoid:
|
||||
result = etyNone
|
||||
of tyProc: result = etyProc
|
||||
of tyCString: result = etyString
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
|
|||
result = matchNodeKinds(p.constraint, n)
|
||||
if not result: return
|
||||
if isNil(n.typ):
|
||||
result = p.typ.kind in {tyEmpty, tyStmt}
|
||||
result = p.typ.kind in {tyVoid, tyStmt}
|
||||
else:
|
||||
result = sigmatch.argtypeMatches(c.c, p.typ, n.typ)
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ proc newSeqCall(c: PContext; x, y: PNode): PNode =
|
|||
|
||||
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case t.kind
|
||||
of tyNone, tyEmpty: discard
|
||||
of tyNone, tyEmpty, tyVoid: discard
|
||||
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
|
||||
tyPtr, tyString, tyRef:
|
||||
defaultOp(c, t, body, x, y)
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
# XXX tyGenericInst here?
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
elif {efWantStmt, efAllowStmt} * flags != {}:
|
||||
result.typ = newTypeS(tyEmpty, c)
|
||||
result.typ.flags.incl tfVoid
|
||||
result.typ = newTypeS(tyVoid, c)
|
||||
else:
|
||||
localError(n.info, errExprXHasNoType,
|
||||
renderTree(result, {renderNoComments}))
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ proc fixNilType(n: PNode) =
|
|||
|
||||
proc discardCheck(c: PContext, result: PNode) =
|
||||
if c.inTypeClass > 0: return
|
||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
|
||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||
if result.kind == nkNilLit:
|
||||
result.typ = nil
|
||||
message(result.info, warnNilStatement)
|
||||
|
|
@ -711,7 +711,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
|||
a.sons[1] = s.typ.n
|
||||
s.typ.size = -1 # could not be computed properly
|
||||
# we fill it out later. For magic generics like 'seq', it won't be filled
|
||||
# so we use tyEmpty instead of nil to not crash for strange conversions
|
||||
# so we use tyNone instead of nil to not crash for strange conversions
|
||||
# like: mydata.seq
|
||||
rawAddSon(s.typ, newTypeS(tyNone, c))
|
||||
s.ast = a
|
||||
|
|
|
|||
|
|
@ -945,7 +945,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
if isType: localError(a.info, "':' expected")
|
||||
if kind in {skTemplate, skMacro}:
|
||||
typ = newTypeS(tyExpr, c)
|
||||
elif skipTypes(typ, {tyGenericInst}).kind == tyEmpty:
|
||||
elif skipTypes(typ, {tyGenericInst}).kind == tyVoid:
|
||||
continue
|
||||
for j in countup(0, length-3):
|
||||
var arg = newSymG(skParam, a.sons[j], c)
|
||||
|
|
@ -977,7 +977,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
if r != nil:
|
||||
# turn explicit 'void' return type into 'nil' because the rest of the
|
||||
# compiler only checks for 'nil':
|
||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||
if skipTypes(r, {tyGenericInst}).kind != tyVoid:
|
||||
# 'auto' as a return type does not imply a generic:
|
||||
if r.kind == tyAnything:
|
||||
# 'p(): auto' and 'p(): expr' are equivalent, but the rest of the
|
||||
|
|
@ -1390,10 +1390,7 @@ proc processMagicType(c: PContext, m: PSym) =
|
|||
setMagicType(m, tyTypeDesc, 0)
|
||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||
of mVoidType:
|
||||
setMagicType(m, tyEmpty, 0)
|
||||
# for historical reasons we conflate 'void' with 'empty' so that '@[]'
|
||||
# has the type 'seq[void]'.
|
||||
m.typ.flags.incl tfVoid
|
||||
setMagicType(m, tyVoid, 0)
|
||||
of mArray:
|
||||
setMagicType(m, tyArray, 0)
|
||||
of mOpenArray:
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
|||
discard
|
||||
of nkSym:
|
||||
result.sym = replaceTypeVarsS(cl, n.sym)
|
||||
if result.sym.typ.kind == tyEmpty:
|
||||
if result.sym.typ.kind == tyVoid:
|
||||
# don't add the 'void' field
|
||||
result = newNode(nkRecList, n.info)
|
||||
of nkRecWhen:
|
||||
|
|
@ -316,15 +316,15 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
|||
proc eraseVoidParams*(t: PType) =
|
||||
# transform '(): void' into '()' because old parts of the compiler really
|
||||
# don't deal with '(): void':
|
||||
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
|
||||
if t.sons[0] != nil and t.sons[0].kind == tyVoid:
|
||||
t.sons[0] = nil
|
||||
|
||||
for i in 1 .. <t.sonsLen:
|
||||
# don't touch any memory unless necessary
|
||||
if t.sons[i].kind == tyEmpty:
|
||||
if t.sons[i].kind == tyVoid:
|
||||
var pos = i
|
||||
for j in i+1 .. <t.sonsLen:
|
||||
if t.sons[j].kind != tyEmpty:
|
||||
if t.sons[j].kind != tyVoid:
|
||||
t.sons[pos] = t.sons[j]
|
||||
t.n.sons[pos] = t.n.sons[j]
|
||||
inc pos
|
||||
|
|
|
|||
|
|
@ -949,8 +949,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = isConvertible
|
||||
else: discard
|
||||
|
||||
of tyEmpty:
|
||||
if a.kind == tyEmpty: result = isEqual
|
||||
of tyEmpty, tyVoid:
|
||||
if a.kind == f.kind: result = isEqual
|
||||
|
||||
of tyGenericInst:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
|
|
|
|||
|
|
@ -407,7 +407,8 @@ const
|
|||
"!", "varargs[$1]", "iter[$1]", "Error Type",
|
||||
"BuiltInTypeClass", "UserTypeClass",
|
||||
"UserTypeClassInst", "CompositeTypeClass",
|
||||
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"]
|
||||
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor",
|
||||
"void"]
|
||||
|
||||
const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
|
||||
|
||||
|
|
@ -923,7 +924,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
|||
|
||||
case a.kind
|
||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||
tyInt..tyBigNum, tyStmt, tyExpr:
|
||||
tyInt..tyBigNum, tyStmt, tyExpr, tyVoid:
|
||||
result = sameFlags(a, b)
|
||||
of tyStatic, tyFromExpr:
|
||||
result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
|
||||
|
|
@ -1109,7 +1110,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
|||
result = nil
|
||||
of tyExpr, tyStmt, tyStatic:
|
||||
if kind notin {skParam, skResult}: result = t
|
||||
of tyEmpty:
|
||||
of tyVoid:
|
||||
if taField notin flags: result = t
|
||||
of tyTypeClasses:
|
||||
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
|
||||
|
|
@ -1154,7 +1155,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
|||
if result != nil: break
|
||||
if result.isNil and t.n != nil:
|
||||
result = typeAllowedNode(marker, t.n, kind, flags)
|
||||
of tyProxy:
|
||||
of tyProxy, tyEmpty:
|
||||
# for now same as error node; we say it's a valid type as it should
|
||||
# prevent cascading errors:
|
||||
result = nil
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ proc mapTypeToBracketX(name: string; m: TMagic; t: PType; info: TLineInfo;
|
|||
for i in 0 .. < t.len:
|
||||
if t.sons[i] == nil:
|
||||
let void = atomicTypeX("void", mVoid, t, info)
|
||||
void.typ = newType(tyEmpty, t.owner)
|
||||
void.typ = newType(tyVoid, t.owner)
|
||||
result.add void
|
||||
else:
|
||||
result.add mapTypeToAstX(t.sons[i], info, inst)
|
||||
|
|
@ -124,7 +124,8 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
|
|||
of tyNil: result = atomicType("nil", mNil)
|
||||
of tyExpr: result = atomicType("expr", mExpr)
|
||||
of tyStmt: result = atomicType("stmt", mStmt)
|
||||
of tyEmpty: result = atomicType("void", mVoid)
|
||||
of tyVoid: result = atomicType("void", mVoid)
|
||||
of tyEmpty: result = atomicType("empty", mNone)
|
||||
of tyArrayConstr, tyArray:
|
||||
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
|
||||
result.add atomicType("array", mArray)
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
|
|||
proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
|
||||
# stmt is different from 'void' in meta programming contexts.
|
||||
# So we only set dest to -1 if 'void':
|
||||
if dest >= 0 and (n.typ.isNil or n.typ.kind == tyEmpty):
|
||||
if dest >= 0 and (n.typ.isNil or n.typ.kind == tyVoid):
|
||||
c.freeTemp(dest)
|
||||
dest = -1
|
||||
|
||||
|
|
|
|||
|
|
@ -1699,8 +1699,10 @@ proc processBody(node, retFutureSym: NimNode,
|
|||
else:
|
||||
result.add newCall(newIdentNode("complete"), retFutureSym)
|
||||
else:
|
||||
result.add newCall(newIdentNode("complete"), retFutureSym,
|
||||
node[0].processBody(retFutureSym, subTypeIsVoid, tryStmt))
|
||||
let x = node[0].processBody(retFutureSym, subTypeIsVoid, tryStmt)
|
||||
if x.kind == nnkYieldStmt: result.add x
|
||||
else:
|
||||
result.add newCall(newIdentNode("complete"), retFutureSym, x)
|
||||
|
||||
result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
|
||||
return # Don't process the children of this return stmt
|
||||
|
|
|
|||
23
tests/async/treturn_await.nim
Normal file
23
tests/async/treturn_await.nim
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
# bug #4371
|
||||
|
||||
import strutils, asyncdispatch, asynchttpserver
|
||||
|
||||
type
|
||||
List[A] = ref object
|
||||
value: A
|
||||
next: List[A]
|
||||
StrPair* = tuple[k, v: string]
|
||||
Context* = object
|
||||
position*: int
|
||||
accept*: bool
|
||||
headers*: List[StrPair]
|
||||
Handler* = proc(req: ref Request, ctx: Context): Future[Context]
|
||||
|
||||
proc logging*(handler: Handler): auto =
|
||||
proc h(req: ref Request, ctx: Context): Future[Context] {.async.} =
|
||||
let ret = handler(req, ctx)
|
||||
debugEcho "$3 $1 $2".format(req.reqMethod, req.url.path, req.hostname)
|
||||
return await ret
|
||||
|
||||
return h
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
discard """
|
||||
output: "empty"
|
||||
output: "void"
|
||||
"""
|
||||
|
||||
# bug #898
|
||||
|
|
|
|||
21
tests/metatype/tvoid_must_not_match.nim
Normal file
21
tests/metatype/tvoid_must_not_match.nim
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
discard """
|
||||
errormsg: "type mismatch: got (Future[system.int], void)"
|
||||
line: 20
|
||||
"""
|
||||
|
||||
type
|
||||
Future[T] = object
|
||||
value: T
|
||||
|
||||
proc complete[T](x: T) =
|
||||
echo "completed"
|
||||
let y = x
|
||||
|
||||
|
||||
proc complete*[T](future: var Future[T], val: T) =
|
||||
future.value = val
|
||||
|
||||
var a: Future[int]
|
||||
|
||||
complete(a):
|
||||
echo "yielding void"
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
discard """
|
||||
line: 16
|
||||
errormsg: "type mismatch: got (empty)"
|
||||
errormsg: "type mismatch: got (void)"
|
||||
"""
|
||||
|
||||
# bug #950
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue