Merge branch 'araq2' into devel

This commit is contained in:
Araq 2017-05-17 22:13:57 +02:00
commit 8f67b90997
54 changed files with 2479 additions and 340 deletions

View file

@ -224,7 +224,7 @@ type
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # already 32 flags!
TSymFlag* = enum # already 33 flags!
sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed
@ -452,10 +452,12 @@ type
nfExprCall # this is an attempt to call a regular expression
nfIsRef # this node is a 'ref' node; used for the VM
nfPreventCg # this node should be ignored by the codegen
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 30)
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that)
tfVarargs, # procedure has C styled varargs
# tyArray type represeting a varargs list
tfNoSideEffect, # procedure type does not allow side effects
tfFinal, # is the object final?
tfInheritable, # is the object inheritable?
@ -506,6 +508,9 @@ type
tfTriggersCompileTime # uses the NimNode type which make the proc
# implicitly '.compiletime'
tfRefsAnonObj # used for 'ref object' and 'ptr object'
tfCovariant # covariant generic param mimicing a ptr type
tfWeakCovariant # covariant generic param mimicing a seq/array type
tfContravariant # contravariant generic param
TTypeFlags* = set[TTypeFlag]
@ -1002,15 +1007,17 @@ proc add*(father, son: PNode) =
if isNil(father.sons): father.sons = @[]
add(father.sons, son)
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
result = n.sons[i]
type Indexable = PNode | PType
template `[]`*(n: Indexable, i: int): Indexable =
n.sons[i]
template `-|`*(b, s: untyped): untyped =
(if b >= 0: b else: s.len + b)
# son access operators with support for negative indices
template `{}`*(n: PNode, i: int): untyped = n[i -| n]
template `{}=`*(n: PNode, i: int, s: PNode) =
template `{}`*(n: Indexable, i: int): untyped = n[i -| n]
template `{}=`*(n: Indexable, i: int, s: Indexable) =
n.sons[i -| n] = s
when defined(useNodeIds):
@ -1346,6 +1353,9 @@ proc initIdTable*(x: var TIdTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc newIdTable*: TIdTable =
initIdTable(result)
proc resetIdTable*(x: var TIdTable) =
x.counter = 0
# clear and set to old initial size:

View file

@ -70,6 +70,8 @@ proc debug*(n: PNode) {.deprecated.}
template mdbg*: bool {.dirty.} =
when compiles(c.module):
c.module.fileIdx == gProjectMainIdx
elif compiles(c.c.module):
c.c.module.fileIdx == gProjectMainIdx
elif compiles(m.c.module):
m.c.module.fileIdx == gProjectMainIdx
elif compiles(cl.c.module):
@ -79,6 +81,8 @@ template mdbg*: bool {.dirty.} =
p.lex.fileIdx == gProjectMainIdx
else:
p.module.module.fileIdx == gProjectMainIdx
elif compiles(m.module.fileIdx):
m.module.fileIdx == gProjectMainIdx
elif compiles(L.fileIdx):
L.fileIdx == gProjectMainIdx
else:

View file

@ -269,7 +269,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# little HACK to support the new 'var T' as return type:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
return
let ty = skipTypes(dest.t, abstractRange)
let ty = skipTypes(dest.t, abstractRange + tyUserTypeClasses)
case ty.kind
of tyRef:
genRefAssign(p, dest, src, flags)
@ -758,7 +758,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
genRecordFieldAux(p, e, d, a)
var r = rdLoc(a)
var f = e.sons[1].sym
let ty = skipTypes(a.t, abstractInst)
let ty = skipTypes(a.t, abstractInst + tyUserTypeClasses)
if ty.kind == tyTuple:
# we found a unique tuple type which lacks field information
# so we use Field$i
@ -2205,7 +2205,7 @@ proc getNullValueAux(p: BProc; obj, cons: PNode, result: var Rope) =
let field = obj.sym
for i in 1..<cons.len:
if cons[i].kind == nkExprColonExpr:
if cons[i][0].sym == field:
if cons[i][0].sym.name == field.name:
result.add genConstExpr(p, cons[i][1])
return
elif i == field.position:

View file

@ -164,7 +164,7 @@ proc mapType(typ: PType): TCTypeKind =
of tySet: result = mapSetType(typ)
of tyOpenArray, tyArray, tyVarargs: result = ctArray
of tyObject, tyTuple: result = ctStruct
of tyUserTypeClass, tyUserTypeClassInst:
of tyUserTypeClasses:
internalAssert typ.isResolvedUserTypeClass
return mapType(typ.lastSon)
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
@ -1094,7 +1094,7 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
proc genTypeInfo(m: BModule, t: PType): Rope =
let origType = t
var t = skipTypes(origType, irrelevantForBackend)
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
let sig = hashType(origType)
result = m.typeInfoMarker.getOrDefault(sig)
@ -1131,6 +1131,9 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
of tyStatic:
if t.n != nil: result = genTypeInfo(m, lastSon t)
else: internalError("genTypeInfo(" & $t.kind & ')')
of tyUserTypeClasses:
internalAssert t.isResolvedUserTypeClass
return genTypeInfo(m, t.lastSon)
of tyProc:
if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, rope"0")

View file

@ -103,3 +103,4 @@ proc initDefines*() =
defineSymbol("nimNewShiftOps")
defineSymbol("nimDistros")
defineSymbol("nimHasCppDefine")
defineSymbol("nimGenericInOutFlags")

View file

@ -90,7 +90,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
result = newNodeI(nkArgList, n.info)
for i in 1 .. givenRegularParams:
result.addSon n.sons[i]
result.addSon n[i]
# handle parameters with default values, which were
# not supplied by the user

View file

@ -113,6 +113,7 @@ type
errGenericLambdaNotAllowed,
errProcHasNoConcreteType,
errCompilerDoesntSupportTarget,
errInOutFlagNotExtern,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
@ -380,6 +381,7 @@ const
"of the generic paramers can be inferred from the expected signature.",
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types",
errUser: "$1",
warnCannotOpenFile: "cannot open \'$1\'",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",

View file

@ -67,6 +67,8 @@ proc parseTry(p: var TParser; isExpr: bool): PNode
proc parseCase(p: var TParser): PNode
proc parseStmtPragma(p: var TParser): PNode
proc parsePragma(p: var TParser): PNode
proc postExprBlocks(p: var TParser, x: PNode): PNode
proc parseExprStmt(p: var TParser): PNode
# implementation
proc getTok(p: var TParser) =
@ -194,7 +196,6 @@ proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
proc parseExpr(p: var TParser): PNode
proc parseStmt(p: var TParser): PNode
proc parseTypeDesc(p: var TParser): PNode
proc parseDoBlocks(p: var TParser, call: PNode)
proc parseParamList(p: var TParser, retColon = true): PNode
proc isSigilLike(tok: TToken): bool {.inline.} =
@ -365,7 +366,10 @@ proc colonOrEquals(p: var TParser, a: PNode): PNode =
proc exprColonEqExpr(p: var TParser): PNode =
#| exprColonEqExpr = expr (':'|'=' expr)?
var a = parseExpr(p)
result = colonOrEquals(p, a)
if p.tok.tokType == tkDo:
result = postExprBlocks(p, a)
else:
result = colonOrEquals(p, a)
proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
#| exprList = expr ^+ comma
@ -520,7 +524,9 @@ proc parsePar(p: var TParser): PNode =
result.add(parseStmtPragma(p))
elif p.tok.tokType != tkParRi:
var a = simpleExpr(p)
if p.tok.tokType == tkEquals:
if p.tok.tokType == tkDo:
result = postExprBlocks(p, a)
elif p.tok.tokType == tkEquals:
# special case: allow assignments
let asgn = newNodeP(nkAsgn, p)
getTok(p)
@ -669,7 +675,6 @@ proc namedParams(p: var TParser, callee: PNode,
# progress guaranteed
exprColonEqExprListAux(p, endTok, result)
proc parseMacroColon(p: var TParser, x: PNode): PNode
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
#| | doBlocks
@ -696,14 +701,6 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
result = namedParams(p, result, nkCall, tkParRi)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
result.kind = nkObjConstr
elif p.tok.tokType == tkDo:
parseDoBlocks(p, result)
of tkDo:
# progress guaranteed
var a = result
result = newNodeP(nkCall, p)
addSon(result, a)
parseDoBlocks(p, result)
of tkDot:
# progress guaranteed
result = dotExpr(p, result)
@ -735,10 +732,7 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, x)
if p.tok.tokType == tkDo:
parseDoBlocks(p, result)
else:
result = parseMacroColon(p, result)
result = postExprBlocks(p, result)
break
else:
break
@ -977,16 +971,9 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
let params = parseParamList(p, retColon=false)
let pragmas = optPragmas(p)
colcom(p, result)
result = newProcNode(nkDo, info, parseStmt(p),
params = params,
pragmas = pragmas)
proc parseDoBlocks(p: var TParser, call: PNode) =
#| doBlocks = doBlock ^* IND{=}
while sameOrNoInd(p) and p.tok.tokType == tkDo:
let info = parLineInfo(p)
getTok(p)
addSon(call, parseDoBlock(p, info))
result = parseStmt(p)
if params.kind != nkEmpty:
result = newProcNode(nkDo, info, result, params = params, pragmas = pragmas)
proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
@ -1162,49 +1149,75 @@ proc makeCall(n: PNode): PNode =
result = newNodeI(nkCall, n.info)
result.add n
proc parseMacroColon(p: var TParser, x: PNode): PNode =
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
proc postExprBlocks(p: var TParser, x: PNode): PNode =
#| postExprBlocks = ':' stmt? ( IND{=} doBlock
#| | IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
result = x
if p.tok.tokType == tkColon and p.tok.indent < 0:
if p.tok.indent >= 0: return
var
openingParams = emptyNode
openingPragmas = emptyNode
if p.tok.tokType == tkDo:
getTok(p)
openingParams = parseParamList(p, retColon=false)
openingPragmas = optPragmas(p)
if p.tok.tokType == tkColon:
result = makeCall(result)
getTok(p)
skipComment(p, result)
let stmtList = newNodeP(nkStmtList, p)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
stmtList.add body
#addSon(result, makeStmtList(body))
# progress guaranteed
while sameInd(p):
var b: PNode
case p.tok.tokType
of tkOf:
b = newNodeP(nkOfBranch, p)
exprList(p, tkColon, b)
of tkElif:
b = newNodeP(nkElifBranch, p)
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
else: break
eat(p, tkColon)
addSon(b, parseStmt(p))
addSon(stmtList, b)
if b.kind == nkElse: break
if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
var stmtList = newNodeP(nkStmtList, p)
stmtList.add parseStmt(p)
# to keep backwards compatibility (see tests/vm/tstringnil)
result.add stmtList[0]
else:
result.add stmtList
if stmtList[0].kind == nkStmtList: stmtList = stmtList[0]
stmtList.flags.incl nfBlockArg
if openingParams.kind != nkEmpty:
result.add newProcNode(nkDo, stmtList.info, stmtList,
params = openingParams, pragmas = openingPragmas)
else:
result.add stmtList
while sameInd(p):
var nextBlock: PNode
let nextToken = p.tok.tokType
if nextToken == tkDo:
let info = parLineInfo(p)
getTok(p)
nextBlock = parseDoBlock(p, info)
else:
case nextToken:
of tkOf:
nextBlock = newNodeP(nkOfBranch, p)
exprList(p, tkColon, nextBlock)
of tkElif:
nextBlock = newNodeP(nkElifBranch, p)
getTok(p)
optInd(p, nextBlock)
nextBlock.addSon parseExpr(p)
of tkExcept:
nextBlock = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, nextBlock)
of tkElse:
nextBlock = newNodeP(nkElse, p)
getTok(p)
else: break
eat(p, tkColon)
nextBlock.addSon parseStmt(p)
nextBlock.flags.incl nfBlockArg
result.add nextBlock
if nextBlock.kind == nkElse: break
else:
if openingParams.kind != nkEmpty:
parMessage(p, errTokenExpected, ":")
proc parseExprStmt(p: var TParser): PNode =
#| exprStmt = simpleExpr
@ -1219,12 +1232,7 @@ proc parseExprStmt(p: var TParser): PNode =
getTok(p)
optInd(p, result)
var b = parseExpr(p)
if p.tok.tokType == tkColon and p.tok.indent < 0:
if b.kind != nkEmpty:
let call = makeCall(b)
call.add parseDoBlock(p, parLineInfo(p))
parseDoBlocks(p, call)
b = call
b = postExprBlocks(p, b)
addSon(result, a)
addSon(result, b)
else:
@ -1247,11 +1255,7 @@ proc parseExprStmt(p: var TParser): PNode =
optInd(p, result)
else:
result = a
if p.tok.tokType == tkDo and p.tok.indent < 0:
result = makeCall(result)
parseDoBlocks(p, result)
return result
result = parseMacroColon(p, result)
result = postExprBlocks(p, result)
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
result = parseExpr(p)
@ -1341,7 +1345,9 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
# NL terminates:
addSon(result, ast.emptyNode)
else:
addSon(result, parseExpr(p))
var e = parseExpr(p)
e = postExprBlocks(p, e)
addSon(result, e)
proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
#| condStmt = expr colcom stmt COMMENT?
@ -1514,6 +1520,13 @@ proc parseGenericParam(p: var TParser): PNode =
# progress guaranteed
while true:
case p.tok.tokType
of tkIn, tkOut:
let x = p.lex.cache.getIdent(if p.tok.tokType == tkIn: "in" else: "out")
a = newNodeP(nkPrefix, p)
a.addSon newIdentNodeP(x, p)
getTok(p)
expectIdent(p)
a.addSon(parseSymbol(p))
of tkSymbol, tkAccent:
a = parseSymbol(p)
if a.kind == nkEmpty: return
@ -1542,7 +1555,7 @@ proc parseGenericParamList(p: var TParser): PNode =
getTok(p)
optInd(p, result)
# progress guaranteed
while p.tok.tokType in {tkSymbol, tkAccent}:
while p.tok.tokType in {tkSymbol, tkAccent, tkIn, tkOut}:
var a = parseGenericParam(p)
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break
@ -1893,14 +1906,7 @@ proc parseVariable(p: var TParser): PNode =
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
if p.tok.tokType == tkParLe: result = parseVarTuple(p)
else: result = parseIdentColonEquals(p, {withPragma})
if p.tok.tokType == tkColon and p.tok.indent < 0:
let last = result.len-1
let ex = result.sons[last]
if ex.kind != nkEmpty:
let call = makeCall(ex)
call.add parseDoBlock(p, parLineInfo(p))
parseDoBlocks(p, call)
result.sons[last] = call
result{-1} = postExprBlocks(p, result{-1})
indAndComment(p, result)
proc parseBind(p: var TParser, k: TNodeKind): PNode =

View file

@ -1336,6 +1336,11 @@ proc parseGenericParam(p: var TParser): PNode =
result = newNodeP(nkIdentDefs, p)
while true:
case p.tok.tokType
of tkIn, tkOut:
let t = p.tok.tokType
getTok(p)
expectIdent(p)
a = parseSymbol(p)
of tkSymbol, tkAccent:
a = parseSymbol(p)
if a.kind == nkEmpty: return

View file

@ -351,8 +351,8 @@ when false:
for i in 0 ..< n.safeLen:
resetSemFlag(n[i])
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
flags: TExprFlags): PNode =
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
s: PSym, flags: TExprFlags): PNode =
## Semantically check the output of a macro.
## This involves processes such as re-checking the macro output for type
## coherence, making sure that variables declared with 'let' aren't
@ -363,8 +363,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
globalError(s.info, errTemplateInstantiationTooNested)
c.friendModules.add(s.owner.getModule)
result = n
excl(n.flags, nfSem)
result = macroResult
excl(result.flags, nfSem)
#resetSemFlag n
if s.typ.sons[0] == nil:
result = semStmt(c, result)
@ -378,13 +378,26 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
of tyStmt:
result = semStmt(c, result)
of tyTypeDesc:
if n.kind == nkStmtList: result.kind = nkStmtListType
if result.kind == nkStmtList: result.kind = nkStmtListType
var typ = semTypeNode(c, result, nil)
result.typ = makeTypeDesc(c, typ)
#result = symNodeFromType(c, typ, n.info)
else:
var retType = s.typ.sons[0]
if s.ast[genericParamsPos] != nil and retType.isMetaType:
# The return type may depend on the Macro arguments
# e.g. template foo(T: typedesc): seq[T]
# We will instantiate the return type here, because
# we now know the supplied arguments
var paramTypes = newIdTable()
for param, value in genericParamsInMacroCall(s, call):
idTablePut(paramTypes, param.typ, value.typ)
retType = generateTypeInstance(c, paramTypes,
macroResult.info, retType)
result = semExpr(c, result, flags)
result = fitNode(c, s.typ.sons[0], result, result.info)
result = fitNode(c, retType, result, result.info)
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(evalTemplateCounter)
discard c.friendModules.pop()
@ -409,7 +422,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, result, sym, flags)
result = semAfterMacroCall(c, n, result, sym, flags)
result = wrapInComesFrom(nOrig.info, result)
popInfoContext()

View file

@ -429,7 +429,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
for i in 1..sonsLen(n)-1:
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
let arg = n[i].typ
let tm = typeRel(m, formal, arg, true)
let tm = typeRel(m, formal, arg)
if tm in {isNone, isConvertible}: return nil
var newInst = generateInstance(c, s, m.bindings, n.info)
newInst.typ.flags.excl tfUnresolved

View file

@ -277,6 +277,10 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
assert n != nil
result.n = n
proc newTypeWithSons2*(kind: TTypeKind, owner: PSym, sons: seq[PType]): PType =
result = newType(kind, owner)
result.sons = sons
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
sons: seq[PType]): PType =
result = newType(kind, getCurrOwner(c))

View file

@ -16,7 +16,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
styleCheckUse(n.info, s)
pushInfoContext(n.info)
result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
popInfoContext()
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
@ -47,10 +47,11 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
#raiseRecoverableError("")
result = errorNode(c, n)
if result.typ == nil or result.typ == enforceVoidContext:
# we cannot check for 'void' in macros ...
localError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
if n.kind != nkStmtList:
# we cannot check for 'void' in macros ...
localError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
else:
if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
if result.typ.kind == tyVar: result = newDeref(result)
@ -682,27 +683,9 @@ proc bracketedMacro(n: PNode): PSym =
if result.kind notin {skMacro, skTemplate}:
result = nil
proc semBracketedMacro(c: PContext; outer, inner: PNode; s: PSym;
flags: TExprFlags): PNode =
# We received untransformed bracket expression coming from macroOrTmpl[].
# Transform it to macro or template call, where first come normal
# arguments, next come generic template arguments.
var sons = newSeq[PNode]()
sons.add inner.sons[0]
# Normal arguments:
for i in 1..<outer.len:
sons.add outer.sons[i]
# Generic template arguments from bracket expression:
for i in 1..<inner.len:
sons.add inner.sons[i]
shallowCopy(outer.sons, sons)
# FIXME: Shouldn't we check sfImmediate and call semDirectOp?
# However passing to semDirectOp doesn't work here.
case s.kind
of skMacro: result = semMacroExpr(c, outer, outer, s, flags)
of skTemplate: result = semTemplateExpr(c, outer, s, flags)
else: assert(false)
return
proc setGenericParams(c: PContext, n: PNode) =
for i in 1 .. <n.len:
n[i].typ = semTypeNode(c, n[i], nil)
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
result = n
@ -744,7 +727,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
elif n.sons[0].kind == nkBracketExpr:
let s = bracketedMacro(n.sons[0])
if s != nil:
return semBracketedMacro(c, n, n.sons[0], s, flags)
setGenericParams(c, n[0])
return semDirectOp(c, n, flags)
let nOrig = n.copyTree
semOpAux(c, n)
@ -1155,6 +1139,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
ty = n.sons[0].typ
return nil
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
ty = ty.lastSon
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
var check: PNode = nil
if ty.kind == tyObject:
@ -1713,7 +1699,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
# We transform the do block into a template with a param for
# each interpolation. We'll pass this template to getAst.
var
doBlk = n{-1}
quotedBlock = n{-1}
op = if n.len == 3: expectString(c, n[1]) else: "``"
quotes = newSeq[PNode](1)
# the quotes will be added to a nkCall statement
@ -1721,20 +1707,23 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
ids = newSeq[PNode]()
# this will store the generated param names
if doBlk.kind != nkDo:
if quotedBlock.kind != nkStmtList:
localError(n.info, errXExpected, "block")
processQuotations(doBlk.sons[bodyPos], op, quotes, ids)
processQuotations(quotedBlock, op, quotes, ids)
var dummyTemplate = newProcNode(
nkTemplateDef, quotedBlock.info, quotedBlock,
name = newAnonSym(c, skTemplate, n.info).newSymNode)
doBlk.sons[namePos] = newAnonSym(c, skTemplate, n.info).newSymNode
if ids.len > 0:
doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
doBlk[paramsPos].add getSysSym("typed").newSymNode # return type
dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
dummyTemplate[paramsPos].add getSysSym("typed").newSymNode # return type
ids.add getSysSym("untyped").newSymNode # params type
ids.add emptyNode # no default value
doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids)
dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
var tmpl = semTemplateDef(c, doBlk)
var tmpl = semTemplateDef(c, dummyTemplate)
quotes[0] = tmpl[namePos]
result = newNode(nkCall, n.info, @[
getMagicSym(mExpandToAst).newSymNode,
@ -2158,10 +2147,6 @@ proc shouldBeBracketExpr(n: PNode): bool =
n.sons[0] = be
return true
proc setGenericParams(c: PContext, n: PNode) =
for i in 1 .. <n.len:
n[i].typ = semTypeNode(c, n[i], nil)
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = n
if gCmd == cmdIdeTools: suggestExpr(c, n)
@ -2325,8 +2310,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n, flags)
of nkObjConstr: result = semObjConstr(c, n, flags)
of nkLambda: result = semLambda(c, n, flags)
of nkDo: result = semDo(c, n, flags)
of nkLambdaKinds: result = semLambda(c, n, flags)
of nkDerefExpr: result = semDeref(c, n)
of nkAddr:
result = n

View file

@ -121,12 +121,13 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
localError(n.info, errWrongNumberOfVariables)
return result
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
const skippedTypesForFields = abstractVar - {tyTypeDesc} + tyUserTypeClasses
var tupleTypeA = skipTypes(call.sons[1].typ, skippedTypesForFields)
if tupleTypeA.kind notin {tyTuple, tyObject}:
localError(n.info, errGenerated, "no object or tuple type")
return result
for i in 1..call.len-1:
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields)
if not sameType(tupleTypeA, tupleTypeB):
typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB)

View file

@ -36,7 +36,8 @@ proc rawPushProcCon(c: PContext, owner: PSym) =
c.p = x
proc rawHandleSelf(c: PContext; owner: PSym) =
if c.selfName != nil and owner.kind in {skProc, skMethod, skConverter, skIterator, skMacro} and owner.typ != nil:
const callableSymbols = {skProc, skMethod, skConverter, skIterator, skMacro}
if c.selfName != nil and owner.kind in callableSymbols and owner.typ != nil:
let params = owner.typ.n
if params.len > 1:
let arg = params[1].sym

View file

@ -89,9 +89,9 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
proc toNode(t: PType, i: TLineInfo): PNode =
result = newNodeIT(nkType, i, t)
const
const
# these are types that use the bracket syntax for instantiation
# they can be subjected to the type traits `genericHead` and
# they can be subjected to the type traits `genericHead` and
# `Uninstantiated`
tyUserDefinedGenerics* = {tyGenericInst, tyGenericInvocation,
tyUserTypeClassInst}
@ -109,27 +109,43 @@ proc uninstantiate(t: PType): PType =
of tyCompositeTypeClass: uninstantiate t.sons[1]
else: t
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
var typ = operand.skipTypes({tyTypeDesc})
proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
const skippedTypes = {tyTypeDesc}
let trait = traitCall[0]
internalAssert trait.kind == nkSym
var operand = operand.skipTypes(skippedTypes)
template operand2: PType =
traitCall.sons[2].typ.skipTypes({tyTypeDesc})
template typeWithSonsResult(kind, sons): PNode =
newTypeWithSons2(kind, context, sons).toNode(traitCall.info)
case trait.sym.name.s
of "or", "|":
return typeWithSonsResult(tyOr, @[operand, operand2])
of "and":
return typeWithSonsResult(tyAnd, @[operand, operand2])
of "not":
return typeWithSonsResult(tyNot, @[operand])
of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferName))
result = newStrNode(nkStrLit, operand.typeToString(preferName))
result.typ = newType(tyString, context)
result.info = trait.info
result.info = traitCall.info
of "arity":
result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
result = newIntNode(nkIntLit, operand.len - ord(operand.kind==tyProc))
result.typ = newType(tyInt, context)
result.info = trait.info
result.info = traitCall.info
of "genericHead":
var res = uninstantiate(typ)
if res == typ and res.kind notin tyMagicGenerics:
localError(trait.info,
var res = uninstantiate(operand)
if res == operand and res.kind notin tyMagicGenerics:
localError(traitCall.info,
"genericHead expects a generic type. The given type was " &
typeToString(typ))
return newType(tyError, context).toNode(trait.info)
result = res.base.toNode(trait.info)
typeToString(operand))
return newType(tyError, context).toNode(traitCall.info)
result = res.base.toNode(traitCall.info)
of "stripGenericParams":
result = uninstantiate(typ).toNode(trait.info)
result = uninstantiate(operand).toNode(traitCall.info)
else:
internalAssert false
@ -140,7 +156,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
if t.sonsLen > 0:
# This is either a type known to sem or a typedesc
# param to a regular proc (again, known at instantiation)
result = evalTypeTrait(n[0], t, getCurrOwner(c))
result = evalTypeTrait(n, t, getCurrOwner(c))
else:
# a typedesc variable, pass unmodified to evals
result = n

View file

@ -730,7 +730,9 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
var s: PSym
if name.kind == nkDotExpr:
s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
if s.kind != skType or
s.typ.skipTypes(abstractPtrs).kind != tyObject or
tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
localError(name.info, "only .partial objects can be extended")
else:
s = semIdentDef(c, name, skType)
@ -742,6 +744,87 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
a.sons[0] = newSymNode(s)
proc checkCovariantParamsUsages(genericType: PType) =
var body = genericType{-1}
proc traverseSubTypes(t: PType): bool =
template error(msg) = localError(genericType.sym.info, msg)
result = false
template subresult(r) =
let sub = r
result = result or sub
case t.kind
of tyGenericParam:
t.flags.incl tfWeakCovariant
return true
of tyObject:
for field in t.n:
subresult traverseSubTypes(field.typ)
of tyArray:
return traverseSubTypes(t[1])
of tyProc:
for subType in t.sons:
if subType != nil:
subresult traverseSubTypes(subType)
if result:
error("non-invariant type param used in a proc type: " & $t)
of tySequence:
return traverseSubTypes(t[0])
of tyGenericInvocation:
let targetBody = t[0]
for i in 1 .. <t.len:
let param = t[i]
if param.kind == tyGenericParam:
if tfCovariant in param.flags:
let formalFlags = targetBody[i-1].flags
if tfCovariant notin formalFlags:
error("covariant param '" & param.sym.name.s &
"' used in a non-covariant position")
elif tfWeakCovariant in formalFlags:
param.flags.incl tfWeakCovariant
result = true
elif tfContravariant in param.flags:
let formalParam = targetBody[i-1].sym
if tfContravariant notin formalParam.typ.flags:
error("contravariant param '" & param.sym.name.s &
"' used in a non-contravariant position")
result = true
else:
subresult traverseSubTypes(param)
of tyAnd, tyOr, tyNot, tyStatic, tyBuiltInTypeClass, tyCompositeTypeClass:
error("non-invariant type parameters cannot be used with types such '" & $t & "'")
of tyUserTypeClass, tyUserTypeClassInst:
error("non-invariant type parameters are not supported in concepts")
of tyTuple:
for fieldType in t.sons:
subresult traverseSubTypes(fieldType)
of tyPtr, tyRef, tyVar:
if t.base.kind == tyGenericParam: return true
return traverseSubTypes(t.base)
of tyDistinct, tyAlias:
return traverseSubTypes(t.lastSon)
of tyGenericInst:
internalAssert false
else:
discard
discard traverseSubTypes(body)
proc typeSectionRightSidePass(c: PContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
@ -782,6 +865,22 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
body.sym = s
body.size = -1 # could not be computed properly
s.typ.sons[sonsLen(s.typ) - 1] = body
if tfCovariant in s.typ.flags:
checkCovariantParamsUsages(s.typ)
# XXX: This is a temporary limitation:
# The codegen currently produces various failures with
# generic imported types that have fields, but we need
# the fields specified in order to detect weak covariance.
# The proper solution is to teach the codegen how to handle
# such types, because this would offer various interesting
# possibilities such as instantiating C++ generic types with
# garbage collected Nim types.
if sfImportc in s.flags:
var body = s.typ.lastSon
if body.kind == tyObject:
# erases all declared fields
body.n.sons = nil
popOwner(c)
closeScope(c)
elif a.sons[2].kind != nkEmpty:
@ -851,9 +950,12 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
# type aliases are hard:
var t = semTypeNode(c, x, nil)
assert t != nil
if t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
if s.typ.kind != tyAlias:
if s.typ != nil and s.typ.kind != tyAlias:
if t.kind in {tyProc, tyGenericInst} and not t.isMetaType:
assignType(s.typ, t)
s.typ.id = t.id
elif t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
assignType(s.typ, t)
s.typ.id = t.id # same id
checkConstructedType(s.info, s.typ)
@ -1066,13 +1168,6 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
popOwner(c)
result.typ = s.typ
proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
# 'do' without params produces a stmt:
if n[genericParamsPos].kind == nkEmpty and n[paramsPos].kind == nkEmpty:
result = semStmt(c, n[bodyPos])
else:
result = semLambda(c, n, flags)
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
var n = n
@ -1177,7 +1272,8 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
var objB = t.sons[2]
while true:
if objB.kind == tyGenericBody: objB = objB.lastSon
elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
elif objB.kind in {tyGenericInvocation, tyGenericInst}:
objB = objB.sons[0]
else: break
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
if obj.assignment.isNil:
@ -1666,7 +1762,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
else: discard
if result.len == 1 and
c.inTypeClass == 0 and # concept bodies should be preserved as a stmt list
# concept bodies should be preserved as a stmt list:
c.inTypeClass == 0 and
# also, don't make life complicated for macros.
# they will always expect a proper stmtlist:
nfBlockArg notin n.flags and
result.sons[0].kind != nkDefer:
result = result.sons[0]

View file

@ -135,7 +135,9 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
let n = if n[0].kind == nkBracket: n[0] else: n
checkMinSonsLen(n, 1)
var base = semTypeNode(c, n.lastSon, nil).skipTypes({tyTypeDesc})
var t = semTypeNode(c, n.lastSon, nil)
if t.kind == tyTypeDesc and tfUnresolved notin t.flags:
t = t.base
result = newOrPrevType(kind, prev, c)
var isNilable = false
# check every except the last is an object:
@ -149,7 +151,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
tyError, tyObject}:
message n[i].info, errGenerated, "region needs to be an object type"
addSonSkipIntLit(result, region)
addSonSkipIntLit(result, base)
addSonSkipIntLit(result, t)
#if not isNilable: result.flags.incl tfNotNil
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
@ -891,13 +893,20 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
let lifted = liftingWalk(paramType.sons[i])
if lifted != nil: paramType.sons[i] = lifted
if paramType.base.lastSon.kind == tyUserTypeClass:
let body = paramType.base
if body.kind == tyForward:
# this may happen for proc type appearing in a type section
# before one of its param types
return
if body.lastSon.kind == tyUserTypeClass:
let expanded = instGenericContainer(c, info, paramType,
allowMetaTypes = true)
result = liftingWalk(expanded, true)
of tyUserTypeClasses, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), true))
of tyUserTypeClasses, tyBuiltInTypeClass, tyCompositeTypeClass,
tyAnd, tyOr, tyNot:
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), false))
of tyGenericParam:
markUsed(info, paramType.sym, c.graph.usageSym)
@ -1065,6 +1074,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
result = semTypeNode(c, n, nil)
n.typ = makeTypeDesc(c, result)
proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
var
@ -1574,10 +1584,24 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
# type for each generic param. the index
# of the parameter will be stored in the
# attached symbol.
var paramName = a.sons[j]
var covarianceFlag = tfUnresolved
if paramName.safeLen == 2:
if not nimEnableCovariance or paramName[0].ident.s == "in":
if father == nil or sfImportc notin father.sym.flags:
localError(paramName.info, errInOutFlagNotExtern, paramName[0].ident.s)
covarianceFlag = if paramName[0].ident.s == "in": tfContravariant
else: tfCovariant
if father != nil: father.flags.incl tfCovariant
paramName = paramName[1]
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
newSymG(skGenericParam, paramName, c).linkTo(finalType)
else:
newSymG(skType, a.sons[j], c).linkTo(finalType)
newSymG(skType, paramName, c).linkTo(finalType)
if covarianceFlag != tfUnresolved: s.typ.flags.incl(covarianceFlag)
if def.kind != nkEmpty: s.ast = def
if father != nil: addSonSkipIntLit(father, s.typ)
s.position = result.len

View file

@ -9,10 +9,10 @@
# This module does the instantiation of generic types.
import ast, astalgo, msgs, types, magicsys, semdata, renderer
import ast, astalgo, msgs, types, magicsys, semdata, renderer, options
const
tfInstClearedFlags = {tfHasMeta}
tfInstClearedFlags = {tfHasMeta, tfUnresolved}
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
@ -50,6 +50,9 @@ proc searchInstTypes*(key: PType): PType =
# types such as Channel[empty]. Why?
# See the notes for PActor in handleGenericInvocation
return
if not sameFlags(inst, key):
continue
block matchType:
for j in 1 .. high(key.sons):
# XXX sameType is not really correct for nested generics?
@ -231,6 +234,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
# XXX: relying on allowMetaTypes is a kludge
result = copyType(t, t.owner, cl.allowMetaTypes)
if cl.allowMetaTypes: return
result.flags.incl tfFromGeneric
if not (t.kind in tyMetaTypes or
(t.kind == tyStatic and t.n == nil)):
@ -247,10 +251,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.localCache, t))
else:
result = searchInstTypes(t)
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
for i in countup(1, sonsLen(t) - 1):
var x = t.sons[i]
if x.kind == tyGenericParam:
if x.kind in {tyGenericParam}:
x = lookupTypeVar(cl, x)
if x != nil:
if header == t: header = instCopyType(cl, t)
@ -307,31 +312,32 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
rawAddSon(result, newbody)
checkPartialConstructedType(cl.info, newbody)
let dc = newbody.deepCopy
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
# 'deepCopy' needs to be instantiated for
# generics *when the type is constructed*:
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
attachedDeepCopy, 1)
if bodyIsNew and newbody.typeInst == nil:
#doassert newbody.typeInst == nil
newbody.typeInst = result
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
# need to look into this issue later
assert newbody.kind in {tyRef, tyPtr}
assert newbody.lastSon.typeInst == nil
newbody.lastSon.typeInst = result
let asgn = newbody.assignment
if asgn != nil and sfFromGeneric notin asgn.flags:
# '=' needs to be instantiated for generics when the type is constructed:
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
attachedAsgn, 1)
let methods = skipTypes(bbody, abstractPtrs).methods
for col, meth in items(methods):
# we instantiate the known methods belonging to that type, this causes
# them to be registered and that's enough, so we 'discard' the result.
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
attachedAsgn, col)
if cl.allowMetaTypes == false:
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
# 'deepCopy' needs to be instantiated for
# generics *when the type is constructed*:
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
attachedDeepCopy, 1)
if bodyIsNew and newbody.typeInst == nil:
#doassert newbody.typeInst == nil
newbody.typeInst = result
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
# need to look into this issue later
assert newbody.kind in {tyRef, tyPtr}
assert newbody.lastSon.typeInst == nil
newbody.lastSon.typeInst = result
let asgn = newbody.assignment
if asgn != nil and sfFromGeneric notin asgn.flags:
# '=' needs to be instantiated for generics when the type is constructed:
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
attachedAsgn, 1)
let methods = skipTypes(bbody, abstractPtrs).methods
for col, meth in items(methods):
# we instantiate the known methods belonging to that type, this causes
# them to be registered and that's enough, so we 'discard' the result.
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
attachedAsgn, col)
proc eraseVoidParams*(t: PType) =
# transform '(): void' into '()' because old parts of the compiler really
@ -526,6 +532,14 @@ proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
result = replaceTypeVarsT(cl, t)
popInfoContext()
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType =
var cl = initTypeVars(p, pt, info, nil)
cl.allowMetaTypes = true
pushInfoContext(info)
result = replaceTypeVarsT(cl, t)
popInfoContext()
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): untyped =
generateTypeInstance(p, pt, arg.info, t)

View file

@ -154,7 +154,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
else:
c.hashSym(t.sym)
return
of tyAlias, tyGenericInst:
of tyAlias, tyGenericInst, tyUserTypeClasses:
c.hashType t.lastSon, flags
return
else:
@ -201,16 +201,6 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
of tyRef, tyPtr, tyGenericBody, tyVar:
c.hashType t.lastSon, flags
if tfVarIsPtr in t.flags: c &= ".varisptr"
of tyUserTypeClass:
if t.sym != nil and t.sym.owner != nil:
c &= t.sym.owner.name.s
else:
c &= "unknown typeclass"
of tyUserTypeClassInst:
let body = t.sons[0]
c.hashSym body.sym
for i in countup(1, sonsLen(t) - 2):
c.hashType t.sons[i], flags
of tyFromExpr, tyFieldAccessor:
c.hashTree(t.n)
of tyTuple:

View file

@ -26,7 +26,7 @@ type
sym*: PSym
unmatchedVarParam*: int
diagnostics*: seq[string]
CandidateErrors* = seq[CandidateError]
TCandidate* = object
@ -68,7 +68,13 @@ type
# future.
mutabilityProblem*: uint8 # tyVar mismatch
inheritancePenalty: int # to prefer closest father object type
TTypeRelFlag* = enum
trDontBind
trNoCovariance
TTypeRelFlags* = set[TTypeRelFlag]
TTypeRelation* = enum # order is important!
isNone, isConvertible,
isIntConv,
@ -177,6 +183,13 @@ proc sumGeneric(t: PType): int =
tyOpenArray, tyVarargs, tySet, tyRange, tySequence, tyGenericBody:
t = t.lastSon
inc result
of tyOr:
var maxBranch = 0
for branch in t.sons:
let branchSum = branch.sumGeneric
if branchSum > maxBranch: maxBranch = branchSum
inc result, maxBranch + 1
break
of tyVar:
t = t.sons[0]
inc result
@ -185,8 +198,8 @@ proc sumGeneric(t: PType): int =
t = t.lastSon
if t.kind == tyEmpty: break
inc result
of tyGenericInvocation, tyTuple, tyProc:
result += ord(t.kind == tyGenericInvocation)
of tyGenericInvocation, tyTuple, tyProc, tyAnd:
result += ord(t.kind in {tyGenericInvocation, tyAnd})
for i in 0 .. <t.len:
if t.sons[i] != nil:
result += t.sons[i].sumGeneric
@ -228,6 +241,15 @@ proc complexDisambiguation(a, b: PType): int =
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
result = x - y
proc writeMatches*(c: TCandidate) =
echo "Candidate '", c.calleeSym.name.s, "' at ", c.calleeSym.info
echo " exact matches: ", c.exactMatches
echo " generic matches: ", c.genericMatches
echo " subtype matches: ", c.subtypeMatches
echo " intconv matches: ", c.intConvMatches
echo " conv matches: ", c.convMatches
echo " inheritance: ", c.inheritancePenalty
proc cmpCandidates*(a, b: TCandidate): int =
result = a.exactMatches - b.exactMatches
if result != 0: return
@ -248,14 +270,6 @@ proc cmpCandidates*(a, b: TCandidate): int =
if result != 0: return
result = a.calleeScope - b.calleeScope
proc writeMatches*(c: TCandidate) =
writeLine(stdout, "exact matches: " & $c.exactMatches)
writeLine(stdout, "generic matches: " & $c.genericMatches)
writeLine(stdout, "subtype matches: " & $c.subtypeMatches)
writeLine(stdout, "intconv matches: " & $c.intConvMatches)
writeLine(stdout, "conv matches: " & $c.convMatches)
writeLine(stdout, "inheritance: " & $c.inheritancePenalty)
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
if arg.kind in nkSymChoices:
result = typeToString(arg[0].typ, prefer)
@ -288,7 +302,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
add(result, argTypeToString(arg, prefer))
if i != sonsLen(n) - 1: add(result, ", ")
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
proc typeRel*(c: var TCandidate, f, aOrig: PType,
flags: TTypeRelFlags = {}): TTypeRelation
proc concreteType(c: TCandidate, t: PType): PType =
case t.kind
of tyNil:
@ -639,7 +655,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
makeTypeDesc(c, typ)
typeParams.safeAdd((param, typ))
addDecl(c, param)
for param in typeClass.n[0]:
@ -676,7 +692,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
flags: TExprFlags = {}
collectDiagnostics = m.diagnostics != nil or
sfExplain in typeClass.sym.flags
if collectDiagnostics:
oldWriteHook = writelnHook
# XXX: we can't write to m.diagnostics directly, because
@ -688,13 +704,13 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
let msg = s.replace("Error:", errorPrefix)
if oldWriteHook != nil: oldWriteHook msg
diagnostics.add msg
var checkedBody = c.semTryExpr(c, body.copyTree, flags)
if collectDiagnostics:
writelnHook = oldWriteHook
for msg in diagnostics: m.diagnostics.safeAdd msg
if checkedBody == nil: return nil
# The inferrable type params have been identified during the semTryExpr above.
@ -739,14 +755,14 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
allowMetaTypes = allowUnresolved)
result = c.c.semExpr(c.c, instantiated)
proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
# This is a simple integer arithimetic equation solver,
# capable of deriving the value of a static parameter in
# expressions such as (N + 5) / 2 = rhs
#
# Preconditions:
#
# * The input of this proc must be semantized
# * The input of this proc must be semantized
# - all templates should be expanded
# - aby constant folding possible should already be performed
#
@ -754,64 +770,69 @@ proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
#
# Result:
#
# The proc will return the inferred static type with the `n` field
# populated with the inferred value.
#
# `nil` will be returned if the inference was not possible
# The proc will return true if the static types was successfully
# inferred. The result will be bound to the original static type
# in the TCandidate.
#
if lhs.kind in nkCallKinds and lhs[0].kind == nkSym:
case lhs[0].sym.magic
of mUnaryLt:
return inferStaticParam(lhs[1], rhs + 1)
return inferStaticParam(c, lhs[1], rhs + 1)
of mAddI, mAddU, mInc, mSucc:
if lhs[1].kind == nkIntLit:
return inferStaticParam(lhs[2], rhs - lhs[1].intVal)
return inferStaticParam(c, lhs[2], rhs - lhs[1].intVal)
elif lhs[2].kind == nkIntLit:
return inferStaticParam(lhs[1], rhs - lhs[2].intVal)
return inferStaticParam(c, lhs[1], rhs - lhs[2].intVal)
of mDec, mSubI, mSubU, mPred:
if lhs[1].kind == nkIntLit:
return inferStaticParam(lhs[2], lhs[1].intVal - rhs)
return inferStaticParam(c, lhs[2], lhs[1].intVal - rhs)
elif lhs[2].kind == nkIntLit:
return inferStaticParam(lhs[1], rhs + lhs[2].intVal)
return inferStaticParam(c, lhs[1], rhs + lhs[2].intVal)
of mMulI, mMulU:
if lhs[1].kind == nkIntLit:
if rhs mod lhs[1].intVal == 0:
return inferStaticParam(lhs[2], rhs div lhs[1].intVal)
return inferStaticParam(c, lhs[2], rhs div lhs[1].intVal)
elif lhs[2].kind == nkIntLit:
if rhs mod lhs[2].intVal == 0:
return inferStaticParam(lhs[1], rhs div lhs[2].intVal)
return inferStaticParam(c, lhs[1], rhs div lhs[2].intVal)
of mDivI, mDivU:
if lhs[1].kind == nkIntLit:
if lhs[1].intVal mod rhs == 0:
return inferStaticParam(lhs[2], lhs[1].intVal div rhs)
return inferStaticParam(c, lhs[2], lhs[1].intVal div rhs)
elif lhs[2].kind == nkIntLit:
return inferStaticParam(lhs[1], lhs[2].intVal * rhs)
return inferStaticParam(c, lhs[1], lhs[2].intVal * rhs)
of mShlI:
if lhs[2].kind == nkIntLit:
return inferStaticParam(lhs[1], rhs shr lhs[2].intVal)
return inferStaticParam(c, lhs[1], rhs shr lhs[2].intVal)
of mShrI:
if lhs[2].kind == nkIntLit:
return inferStaticParam(lhs[1], rhs shl lhs[2].intVal)
return inferStaticParam(c, lhs[1], rhs shl lhs[2].intVal)
of mUnaryMinusI:
return inferStaticParam(lhs[1], -rhs)
return inferStaticParam(c, lhs[1], -rhs)
of mUnaryPlusI, mToInt, mToBiggestInt:
return inferStaticParam(lhs[1], rhs)
return inferStaticParam(c, lhs[1], rhs)
else: discard
elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil:
lhs.typ.n = newIntNode(nkIntLit, rhs)
return lhs.typ
return nil
var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons)
inferred.n = newIntNode(nkIntLit, rhs)
put(c, lhs.typ, inferred)
if c.c.inTypeClass > 0:
# inside concepts, binding is currently done with
# direct mutation of the involved types:
lhs.typ.n = inferred.n
return true
return false
proc failureToInferStaticParam(n: PNode) =
let staticParam = n.findUnresolvedStatic
@ -825,13 +846,10 @@ proc inferStaticsInRange(c: var TCandidate,
allowUnresolved = true)
let upperBound = tryResolvingStaticExpr(c, inferred.n[1],
allowUnresolved = true)
template doInferStatic(c: var TCandidate, e: PNode, r: BiggestInt) =
template doInferStatic(e: PNode, r: BiggestInt) =
var exp = e
var rhs = r
var inferred = inferStaticParam(exp, rhs)
if inferred != nil:
put(c, inferred, inferred)
if inferStaticParam(c, exp, rhs):
return isGeneric
else:
failureToInferStaticParam exp
@ -842,15 +860,36 @@ proc inferStaticsInRange(c: var TCandidate,
return isGeneric
else:
return isNone
doInferStatic(c, upperBound, lengthOrd(concrete) + lowerBound.intVal - 1)
doInferStatic(upperBound, lengthOrd(concrete) + lowerBound.intVal - 1)
elif upperBound.kind == nkIntLit:
doInferStatic(c, lowerBound, upperBound.intVal + 1 - lengthOrd(concrete))
doInferStatic(lowerBound, upperBound.intVal + 1 - lengthOrd(concrete))
template subtypeCheck() =
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
result = isNone
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
# this proc is always called for a pair of matching types
assert f.kind == a.kind
template baseTypesCheck(lhs, rhs: PType): bool =
lhs.kind notin {tyPtr, tyRef, tyVar} and
typeRel(c, lhs, rhs, {trNoCovariance}) == isSubtype
case f.kind
of tyRef, tyPtr:
return baseTypesCheck(f.base, a.base)
of tyGenericInst:
let body = f.base
return body == a.base and
a.sonsLen == 3 and
tfWeakCovariant notin body.sons[0].flags and
baseTypesCheck(f.sons[1], a.sons[1])
else:
return false
proc typeRel(c: var TCandidate, f, aOrig: PType,
flags: TTypeRelFlags = {}): TTypeRelation =
# typeRel can be used to establish various relationships between types:
#
# 1) When used with concrete types, it will check for type equivalence
@ -917,6 +956,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = isEqual
return
template doBind: bool = trDontBind notin flags
# var and static arguments match regular modifier-free types
var a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
# XXX: Theoretically, maybeSkipDistinct could be called before we even
@ -946,23 +987,28 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
case a.kind
of tyOr:
# XXX: deal with the current dual meaning of tyGenericParam
c.typedescMatched = true
# seq[int|string] vs seq[number]
# both int and string must match against number
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
result = isGeneric
for branch in a.sons:
let x = typeRel(c, f, branch, false)
let x = typeRel(c, f, branch, flags + {trDontBind})
if x == isNone: return isNone
if x < result: result = x
return
of tyAnd:
# XXX: deal with the current dual meaning of tyGenericParam
c.typedescMatched = true
# seq[Sortable and Iterable] vs seq[Sortable]
# only one match is enough
for branch in a.sons:
let x = typeRel(c, f, branch, false)
let x = typeRel(c, f, branch, flags + {trDontBind})
if x != isNone:
return if x >= isGeneric: isGeneric else: x
result = isNone
return isNone
of tyNot:
case f.kind
@ -986,7 +1032,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyUserTypeClass, tyUserTypeClassInst:
# consider this: 'var g: Node' *within* a concept where 'Node'
# is a concept too (tgraph)
let x = typeRel(c, a, f, false)
let x = typeRel(c, a, f, flags + {trDontBind})
if x >= isGeneric:
return isGeneric
else: discard
@ -1032,7 +1078,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyFloat128: result = handleFloatRange(f, a)
of tyVar:
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
else: result = typeRel(c, f.base, aOrig)
else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance})
subtypeCheck()
of tyArray:
case a.kind
@ -1046,38 +1092,60 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
fRange = a
else:
fRange = prev
result = typeRel(c, f.sons[1].skipTypes({tyTypeDesc}),
a.sons[1].skipTypes({tyTypeDesc}))
if result < isGeneric: return isNone
let ff = f.sons[1].skipTypes({tyTypeDesc})
let aa = a.sons[1].skipTypes({tyTypeDesc})
result = typeRel(c, ff, aa)
if result < isGeneric:
if nimEnableCovariance and
trNoCovariance notin flags and
ff.kind == aa.kind and
isCovariantPtr(c, ff, aa):
result = isSubtype
else:
return isNone
if fRange.rangeHasUnresolvedStatic:
return inferStaticsInRange(c, fRange, a)
elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
return inferStaticsInRange(c, aRange, f)
elif lengthOrd(fRange) != lengthOrd(a):
result = isNone
else:
if lengthOrd(fRange) != lengthOrd(aRange):
result = isNone
else: discard
of tyOpenArray, tyVarargs:
# varargs[expr] is special too but handled earlier. So we only need to
# handle varargs[stmt] which is the same as varargs[typed]:
if f.kind == tyVarargs:
if tfVarargs in a.flags:
return typeRel(c, f.base, a.lastSon)
if tfOldSchoolExprStmt in f.sons[0].flags:
if f.sons[0].kind == tyExpr: return
elif f.sons[0].kind == tyStmt: return
template matchArrayOrSeq(aBase: PType) =
let ff = f.base
let aa = aBase
let baseRel = typeRel(c, ff, aa)
if baseRel >= isGeneric:
result = isConvertible
elif nimEnableCovariance and
trNoCovariance notin flags and
ff.kind == aa.kind and
isCovariantPtr(c, ff, aa):
result = isConvertible
case a.kind
of tyOpenArray, tyVarargs:
result = typeRel(c, base(f), base(a))
if result < isGeneric: result = isNone
of tyArray:
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
result = isSubtype
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
result = isConvertible
return isSubtype
matchArrayOrSeq(a.sons[1])
of tySequence:
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
result = isConvertible
elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
result = isConvertible
return isConvertible
matchArrayOrSeq(a.sons[0])
of tyString:
if f.kind == tyOpenArray:
if f.sons[0].kind == tyChar:
@ -1092,8 +1160,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
result = isSubtype
else:
result = typeRel(c, f.sons[0], a.sons[0])
if result < isGeneric: result = isNone
let ff = f.sons[0]
let aa = a.sons[0]
result = typeRel(c, ff, aa)
if result < isGeneric:
if nimEnableCovariance and
trNoCovariance notin flags and
ff.kind == aa.kind and
isCovariantPtr(c, ff, aa):
result = isSubtype
else:
result = isNone
elif tfNotNil in f.flags and tfNotNil notin a.flags:
result = isNilConversion
of tyNil: result = f.allowsNil
@ -1145,7 +1222,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if a.len < f.len: return isNone
for i in 0..f.len-2:
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
result = typeRel(c, f.lastSon, a.lastSon)
result = typeRel(c, f.lastSon, a.lastSon, flags + {trNoCovariance})
subtypeCheck()
if result <= isConvertible: result = isNone
elif tfNotNil in f.flags and tfNotNil notin a.flags:
@ -1204,9 +1281,66 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyEmpty, tyVoid:
if a.kind == f.kind: result = isEqual
of tyGenericInst, tyAlias:
of tyAlias:
result = typeRel(c, lastSon(f), a)
of tyGenericInst:
var prev = PType(idTableGet(c.bindings, f))
var f = if prev == nil: f else: prev
let roota = a.skipGenericAlias
let rootf = f.skipGenericAlias
var m = c
if a.kind == tyGenericInst:
if roota.base == rootf.base:
let nextFlags = flags + {trNoCovariance}
var hasCovariance = false
for i in 1 .. rootf.sonsLen-2:
let ff = rootf.sons[i]
let aa = roota.sons[i]
result = typeRel(c, ff, aa, nextFlags)
if result notin {isEqual, isGeneric}:
if trNoCovariance notin flags and ff.kind == aa.kind:
let paramFlags = rootf.base.sons[i-1].flags
hasCovariance =
if tfCovariant in paramFlags:
if tfWeakCovariant in paramFlags:
isCovariantPtr(c, ff, aa)
else:
ff.kind notin {tyRef, tyPtr} and result == isSubtype
else:
tfContravariant in paramFlags and
typeRel(c, aa, ff) == isSubtype
if hasCovariance:
continue
return isNone
if prev == nil: put(c, f, a)
result = isGeneric
else:
let fKind = rootf.lastSon.kind
if fKind in {tyAnd, tyOr}:
result = typeRel(c, lastSon(f), a)
if result != isNone: put(c, f, a)
return
var aAsObject = roota.lastSon
if fKind in {tyRef, tyPtr} and aAsObject.kind == fKind:
aAsObject = aAsObject.base
if aAsObject.kind == tyObject:
let baseType = aAsObject.base
if baseType != nil:
c.inheritancePenalty += 1
return typeRel(c, f, baseType)
result = isNone
else:
result = typeRel(c, lastSon(f), a)
if result != isNone: put(c, f, a)
of tyGenericBody:
considerPreviousT:
if a.kind == tyGenericInst and a.sons[0] == f:
@ -1217,6 +1351,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyGenericInvocation:
var x = a.skipGenericAlias
# XXX: This is very hacky. It should be moved back into liftTypeParam
if x.kind in {tyGenericInst, tyArray} and
c.calleeSym != nil and
c.calleeSym.kind == skProc:
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
return typeRel(c, inst, a)
var depth = 0
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
@ -1333,13 +1474,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if f.isResolvedUserTypeClass:
result = typeRel(c, f.lastSon, a)
else:
var matched = matchUserTypeClass(c.c, c, f, aOrig)
if matched != nil:
bindConcreteTypeToUserTypeClass(matched, a)
put(c, f, matched)
result = isGeneric
else:
result = isNone
considerPreviousT:
var matched = matchUserTypeClass(c.c, c, f, aOrig)
if matched != nil:
bindConcreteTypeToUserTypeClass(matched, a)
if doBind: put(c, f, matched)
result = isGeneric
else:
result = isNone
of tyCompositeTypeClass:
considerPreviousT:
@ -1357,6 +1499,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if result != isNone:
put(c, f, a)
result = isGeneric
of tyGenericParam:
var x = PType(idTableGet(c.bindings, f))
if x == nil:
@ -1376,16 +1519,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
internalAssert a.sons != nil and a.sons.len > 0
c.typedescMatched = true
var aa = a
while aa.kind in {tyTypeDesc, tyGenericParam} and
aa.len > 0:
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
aa = lastSon(aa)
if aa.kind == tyGenericParam:
return isGeneric
result = typeRel(c, f.base, aa)
if result > isGeneric: result = isGeneric
else:
result = isNone
else:
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
result = typeRel(c, f.lastSon, a)
result = typeRel(c, f.lastSon, a, flags + {trDontBind})
if doBind and result notin {isNone, isGeneric}:
let concrete = concreteType(c, a)
if concrete == nil: return isNone
@ -1590,6 +1734,10 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
of isEqual: inc(m.exactMatches)
of isNone: discard
template matchesVoidProc(t: PType): bool =
(t.kind == tyProc and t.len == 1 and t.sons[0] == nil) or
(t.kind == tyBuiltInTypeClass and t.sons[0].kind == tyProc)
proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
argSemantized, argOrig: PNode): PNode =
var
@ -1726,6 +1874,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
inc(m.genericMatches)
m.fauxMatch = a.kind
return arg
elif a.kind == tyVoid and f.matchesVoidProc and argOrig.kind == nkStmtList:
# lift do blocks without params to lambdas
let lifted = c.semExpr(c, newProcNode(nkDo, argOrig.info, argOrig), {})
if f.kind == tyBuiltInTypeClass:
inc m.genericMatches
put(m, f, lifted.typ)
inc m.convMatches
return implicitConv(nkHiddenStdConv, f, lifted, m, c)
result = userConvMatch(c, m, f, a, arg)
# check for a base type match, which supports varargs[T] without []
# constructor in a call:
@ -2008,6 +2164,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
#assert(container == nil)
if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
container.typ.flags.incl tfVarargs
else:
incrIndexType(container.typ)
addSon(container, arg)
@ -2086,6 +2243,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
return nil
var f = dc.typ.sons[col]
if op == attachedDeepCopy:
if f.kind in {tyRef, tyPtr}: f = f.lastSon
else:

View file

@ -886,6 +886,9 @@ proc isGenericAlias*(t: PType): bool =
proc skipGenericAlias*(t: PType): PType =
return if t.isGenericAlias: t.lastSon else: t
proc sameFlags*(a, b: PType): bool {.inline.} =
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
template cycleCheck() =
# believe it or not, the direct check for ``containsOrIncl(c, a, b)``
@ -898,9 +901,6 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
else:
if containsOrIncl(c, a, b): return true
proc sameFlags(a, b: PType): bool {.inline.} =
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
if x == y: return true
var a = skipTypes(x, {tyGenericInst, tyAlias})
var b = skipTypes(y, {tyGenericInst, tyAlias})

View file

@ -1606,6 +1606,13 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
n.typ = x.typ
result.node = n
iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
let gp = macroSym.ast[genericParamsPos]
for i in 0 .. <gp.len:
let genericParam = gp[i].sym
let posInCall = macroSym.typ.len + i
yield (genericParam, call[posInCall])
var evalMacroCounter: int
proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,