# # # The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # this module does the semantic checking of type declarations # included from sem.nim const errStringOrIdentNodeExpected = "string or ident node expected" errStringLiteralExpected = "string literal expected" errIntLiteralExpected = "integer literal expected" errWrongNumberOfVariables = "wrong number of variables" errDuplicateAliasInEnumX = "duplicate value in enum '$1'" errOverflowInEnumX = "The enum '$1' exceeds its maximum value ($2)" errOrdinalTypeExpected = "ordinal type expected; given: $1" errSetTooBig = "set is too large; use `std/sets` for ordinal types with more than 2^16 elements" errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal" errInheritanceOnlyWithNonFinalObjects = "inheritance only works with non-final objects" errXExpectsOneTypeParam = "'$1' expects one type parameter" errArrayExpectsTwoTypeParams = "array expects two type parameters" errInvalidVisibilityX = "invalid visibility: '$1'" errXCannotBeAssignedTo = "'$1' cannot be assigned to" errIteratorNotAllowed = "iterators can only be defined at the module's top level" errXNeedsReturnType = "$1 needs a return type" errNoReturnTypeDeclared = "no return type declared" errTIsNotAConcreteType = "'$1' is not a concrete type" errTypeExpected = "type expected" errXOnlyAtModuleScope = "'$1' is only allowed at top level" errDuplicateCaseLabel = "duplicate case label" errMacroBodyDependsOnGenericTypes = "the macro body cannot be compiled, " & "because the parameter '$1' has a generic type" errIllegalRecursionInTypeX = "illegal recursion in type '$1'" errNoGenericParamsAllowedForX = "no generic parameters allowed for $1" errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types" proc reusePrev(prev: PType): bool {.inline.} = # only overwrite `prev` if it is a forward type, partial object or magic type result = prev != nil and (prev.kind == tyForward or (prev.sym != nil and # partial object marks sym as `sfForward` (sfForward in prev.sym.flags or prev.sym.magic != mNone))) proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext, son: sink PType): PType = if reusePrev(prev): result = prev result.setSon(son) if result.kind == tyForward: result.kind = kind else: result = newTypeS(kind, c, son) #if kind == tyError: result.flags.incl tfCheckedForDestructor proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = if reusePrev(prev): result = prev if result.kind == tyForward: result.kind = kind else: result = newTypeS(kind, c) proc newConstraint(c: PContext, k: TTypeKind): PType = result = newTypeS(tyBuiltInTypeClass, c) result.flags.incl tfCheckedForDestructor result.addSonSkipIntLit(newTypeS(k, c), c.idgen) proc semEnum(c: PContext, n: PNode, prev: PType): PType = if n.len == 0: return newConstraint(c, tyEnum) elif n.len == 1: # don't create an empty tyEnum; fixes #3052 return errorType(c) var counter, x: BiggestInt = 0 e: PSym = nil base: PType = nil identToReplace: ptr PNode = nil counterSet = initPackedSet[BiggestInt]() counter = 0 base = nil result = newOrPrevType(tyEnum, prev, c) result.n = newNodeI(nkEnumTy, n.info) checkMinSonsLen(n, 1, c.config) if n[0].kind != nkEmpty: base = semTypeNode(c, n[0][0], nil) if base.kind != tyEnum: localError(c.config, n[0].info, "inheritance only works with an enum") counter = toInt64(lastOrd(c.config, base)) + 1 rawAddSon(result, base) let isPure = result.sym != nil and sfPure in result.sym.flags var symbols: TStrTable = initStrTable() var hasNull = false var needsReorder = false for i in 1.. 1 and result.n[i-2].sym.position == high(int): localError(c.config, n[i].info, errOverflowInEnumX % [e.name.s, $high(typeof(counter))]) else: inc(counter) if needsReorder: result.n.sons.sort( proc (x, y: PNode): int = result = cmp(x.sym.position, y.sym.position) ) if isPure and sfExported in result.sym.flags: addPureEnum(c, LazySym(sym: result.sym)) if tfNotNil in e.typ.flags and not hasNull: result.flags.incl tfRequiresInit setToStringProc(c.graph, result, genEnumToStrProc(result, n.info, c.graph, c.idgen)) proc semSet(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tySet, prev, c) if n.len == 2 and n[1].kind != nkEmpty: var base = semTypeNode(c, n[1], nil) addSonSkipIntLit(result, base, c.idgen) if base.kind in {tyGenericInst, tyAlias, tySink}: base = skipModifier(base) if base.kind notin {tyGenericParam, tyGenericInvocation}: if base.kind == tyForward: c.skipTypes.add n elif not isOrdinalType(base, allowEnumWithHoles = true): localError(c.config, n.info, errOrdinalTypeExpected % typeToString(base, preferDesc)) elif lengthOrd(c.config, base) > MaxSetElements: localError(c.config, n.info, errSetTooBig) else: localError(c.config, n.info, errXExpectsOneTypeParam % "set") addSonSkipIntLit(result, errorType(c), c.idgen) proc semContainerArg(c: PContext; n: PNode, kindStr: string; result: PType) = if n.len == 2: var base = semTypeNode(c, n[1], nil) if base.kind == tyVoid: localError(c.config, n.info, errTIsNotAConcreteType % typeToString(base)) addSonSkipIntLit(result, base, c.idgen) else: localError(c.config, n.info, errXExpectsOneTypeParam % kindStr) addSonSkipIntLit(result, errorType(c), c.idgen) proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, prev: PType): PType = result = newOrPrevType(kind, prev, c) semContainerArg(c, n, kindStr, result) proc semVarargs(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyVarargs, prev, c) if n.len == 2 or n.len == 3: var base = semTypeNode(c, n[1], nil) addSonSkipIntLit(result, base, c.idgen) if n.len == 3: result.n = newIdentNode(considerQuotedIdent(c, n[2]), n[2].info) else: localError(c.config, n.info, errXExpectsOneTypeParam % "varargs") addSonSkipIntLit(result, errorType(c), c.idgen) proc semVarOutType(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType = if n.len == 1: result = newOrPrevType(tyVar, prev, c) result.flags = flags var base = semTypeNode(c, n[0], nil) if base.kind == tyTypeDesc and not isSelf(base): base = base[0] if base.kind == tyVar: localError(c.config, n.info, "type 'var var' is not allowed") base = base[0] addSonSkipIntLit(result, base, c.idgen) else: result = newConstraint(c, tyVar) proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool = if t == nil: return false if cycleDetector.containsOrIncl(t.id): return true case t.kind of tyAlias, tyGenericInst, tyDistinct: return isRecursiveType(t.skipModifier, cycleDetector) else: return false proc annotateClosureConv(n: PNode) = case n.kind of {nkNone..nkNilLit}: discard of nkTupleConstr: if n.typ.kind == tyProc and n.typ.callConv == ccClosure and n[0].typ.kind == tyProc and n[0].typ.callConv != ccClosure: # restores `transf.generateThunk` n[0] = newTreeIT(nkHiddenSubConv, n[0].info, n.typ, newNodeI(nkEmpty, n[0].info), n[0]) n.transitionSonsKind(nkClosure) n.flags.incl nfTransf else: for i in 0.. 1: result.n = n[1] proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = assert isRange(n) checkSonsLen(n, 3, c.config) result = newOrPrevType(tyRange, prev, c) result.n = newNodeI(nkRange, n.info) # always create a 'valid' range type, but overwrite it later # because 'semExprWithType' can raise an exception. See bug #6895. addSonSkipIntLit(result, errorType(c), c.idgen) if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty): localError(c.config, n.info, "range is empty") var range: array[2, PNode] # XXX this is still a hard compilation in a generic context, this can # result in unresolved generic parameters being treated like real types range[0] = semExprWithType(c, n[1], {efDetermineType}) range[1] = semExprWithType(c, n[2], {efDetermineType}) var rangeT: array[2, PType] = default(array[2, PType]) for i in 0..1: rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit(c.idgen) let hasUnknownTypes = c.inGenericContext > 0 and (rangeT[0].kind == tyFromExpr or rangeT[1].kind == tyFromExpr) if not hasUnknownTypes: if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})): typeMismatch(c.config, n.info, rangeT[0], rangeT[1], n) elif not isOrdinalType(rangeT[0]) and rangeT[0].kind notin {tyFloat..tyFloat128} or rangeT[0].kind == tyBool: localError(c.config, n.info, "ordinal or float type expected, but got " & typeToString(rangeT[0])) elif enumHasHoles(rangeT[0]): localError(c.config, n.info, "enum '$1' has holes" % typeToString(rangeT[0])) for i in 0..1: if hasUnresolvedArgs(c, range[i]): result.n.add makeStaticExpr(c, range[i]) result.flags.incl tfUnresolved else: result.n.add semConstExpr(c, range[i]) if result.n[i].kind in {nkFloatLit..nkFloat64Lit} and result.n[i].floatVal.isNaN: localError(c.config, n.info, "NaN is not a valid range " & (if i == 0: "start" else: "end")) if weakLeValue(result.n[0], result.n[1]) == impNo: localError(c.config, n.info, "range is empty") result[0] = rangeT[0] proc semRange(c: PContext, n: PNode, prev: PType): PType = result = nil if n.len == 2: if isRange(n[1]): result = semRangeAux(c, n[1], prev) if not isDefined(c.config, "nimPreviewRangeDefault"): let n = result.n if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0: incl(result.flags, tfRequiresInit) elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0: incl(result.flags, tfRequiresInit) elif n[0].kind in {nkFloatLit..nkFloat64Lit} and n[0].floatVal > 0.0: incl(result.flags, tfRequiresInit) elif n[1].kind in {nkFloatLit..nkFloat64Lit} and n[1].floatVal < 0.0: incl(result.flags, tfRequiresInit) else: if n[1].kind == nkInfix and considerQuotedIdent(c, n[1][0]).s == "..<": localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported") else: localError(c.config, n[0].info, "expected range") result = newOrPrevType(tyError, prev, c) else: localError(c.config, n.info, errXExpectsOneTypeParam % "range") result = newOrPrevType(tyError, prev, c) proc semArrayIndexConst(c: PContext, e: PNode, info: TLineInfo): PType = let x = semConstExpr(c, e) if x.kind in {nkIntLit..nkUInt64Lit}: result = makeRangeType(c, 0, x.intVal-1, info, x.typ.skipTypes({tyTypeDesc})) else: result = x.typ.skipTypes({tyTypeDesc}) proc semArrayIndex(c: PContext, n: PNode): PType = if isRange(n): result = semRangeAux(c, n, nil) elif n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "..<": result = errorType(c) else: # XXX this is still a hard compilation in a generic context, this can # result in unresolved generic parameters being treated like real types let e = semExprWithType(c, n, {efDetermineType}) if e.typ.kind == tyFromExpr: result = makeRangeWithStaticExpr(c, e.typ.n) elif e.kind in {nkIntLit..nkUInt64Lit}: if e.intVal < 0: if e.kind in {nkIntLit..nkInt64Lit}: localError(c.config, n.info, "Array length can't be negative, but was " & $e.intVal) else: localError(c.config, n.info, "Array length can't exceed its maximum value (9223372036854775807), but was " & $cast[BiggestUInt](e.intVal)) result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ) elif e.kind == nkSym and (e.typ.kind == tyStatic or e.typ.kind == tyTypeDesc): if e.typ.kind == tyStatic: if e.sym.ast != nil: return semArrayIndex(c, e.sym.ast) if e.typ.skipModifier.kind != tyGenericParam and not isOrdinalType(e.typ.skipModifier): let info = if n.safeLen > 1: n[1].info else: n.info localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc)) result = makeRangeWithStaticExpr(c, e) if c.inGenericContext > 0: result.flags.incl tfUnresolved else: result = e.typ.skipTypes({tyTypeDesc}) result.flags.incl tfImplicitStatic elif e.kind in (nkCallKinds + {nkBracketExpr}) and hasUnresolvedArgs(c, e): if not isOrdinalType(e.typ.skipTypes({tyStatic, tyAlias, tyGenericInst, tySink})): localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc)) # This is an int returning call, depending on an # yet unknown generic param (see tuninstantiatedgenericcalls). # We are going to construct a range type that will be # properly filled-out in semtypinst (see how tyStaticExpr # is handled there). result = makeRangeWithStaticExpr(c, e) elif e.kind == nkIdent: result = e.typ.skipTypes({tyTypeDesc}) else: result = semArrayIndexConst(c, e, n.info) #localError(c.config, n[1].info, errConstExprExpected) proc semArray(c: PContext, n: PNode, prev: PType): PType = var base: PType if n.len == 3: # 3 = length(array indx base) let indx = semArrayIndex(c, n[1]) var indxB = indx if indxB.kind in {tyGenericInst, tyAlias, tySink}: indxB = skipModifier(indxB) if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr} and tfUnresolved notin indxB.flags: if not isOrdinalType(indxB): localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(indxB, preferDesc)) elif enumHasHoles(indxB): localError(c.config, n[1].info, "enum '$1' has holes" % typeToString(indxB.skipTypes({tyRange}))) elif indxB.kind != tyRange and lengthOrd(c.config, indxB) > high(uint16).int: # assume range type is intentional localError(c.config, n[1].info, "index type '$1' for array is too large" % typeToString(indxB)) base = semTypeNode(c, n[2], nil) # ensure we only construct a tyArray when there was no error (bug #3048): # bug #6682: Do not propagate initialization requirements etc for the # index type: result = newOrPrevType(tyArray, prev, c, indx) addSonSkipIntLit(result, base, c.idgen) else: localError(c.config, n.info, errArrayExpectsTwoTypeParams) result = newOrPrevType(tyError, prev, c) proc semIterableType(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyIterable, prev, c) if n.len == 2: let base = semTypeNode(c, n[1], nil) addSonSkipIntLit(result, base, c.idgen) else: localError(c.config, n.info, errXExpectsOneTypeParam % "iterable") result = newOrPrevType(tyError, prev, c) proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyOrdinal, prev, c) if n.len == 2: var base = semTypeNode(c, n[1], nil) if base.kind != tyGenericParam: if not isOrdinalType(base): localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(base, preferDesc)) addSonSkipIntLit(result, base, c.idgen) else: localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal") result = newOrPrevType(tyError, prev, c) proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType = if n.len == 0: localError(c.config, n.info, errTypeExpected) result = newOrPrevType(tyTuple, prev, c) for it in n: let t = semTypeNode(c, it, nil) addSonSkipIntLitChecked(c, result, t, it, c.idgen) proc firstRange(config: ConfigRef, t: PType): PNode = if t.skipModifier().kind in tyFloat..tyFloat64: result = newFloatNode(nkFloatLit, firstFloat(t)) else: result = newIntNode(nkIntLit, firstOrd(config, t)) result.typ() = t proc semTuple(c: PContext, n: PNode, prev: PType): PType = var typ: PType result = newOrPrevType(tyTuple, prev, c) result.n = newNodeI(nkRecList, n.info) var check = initIntSet() var counter = 0 for i in ord(n.kind == nkBracketExpr).. 0: a[^1] = semExprWithType(c, a[^1], {efDetermineType, efAllowSymChoice}, typ) if typ == nil: typ = a[^1].typ else: fitDefaultNode(c, a[^1], typ) typ = a[^1].typ.skipIntLit(c.idgen) elif a[^2].kind != nkEmpty: typ = semTypeNode(c, a[^2], nil) if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange: a[^1] = firstRange(c.config, typ) hasDefaultField = true else: localError(c.config, a.info, errTypeExpected) typ = errorType(c) for j in 0.. 1: result &= ", " case t.kind: of tyEnum, tyBool: while t.n[enumSymOffset].sym.position < val: inc(enumSymOffset) result &= t.n[enumSymOffset].sym.name.s of tyChar: result.addQuoted(char(val)) else: if i == 64: result &= "omitted $1 values..." % $(vals.len - i) break else: result &= $val inc(i) result &= "}" proc formatMissingEnums(c: PContext, n: PNode): string = var coveredCases = initIntSet() for i in 1.. 0x00007FFF: localError(c.config, n.info, "len($1) must be less than 32768" % a[0].sym.name.s) for i in 1.. 0 and cannotResolve: # use a new check intset here for each branch: var newCheck: IntSet = check var newPos = pos var newf = newNodeI(nkRecList, n.info) semRecordNodeAux(c, it[idx], newCheck, newPos, newf, rectype, hasCaseFields) it[idx] = if newf.len == 1: newf[0] else: newf if branch != nil: semRecordNodeAux(c, branch, check, pos, father, rectype, hasCaseFields) elif cannotResolve: father.add a elif father.kind in {nkElse, nkOfBranch}: father.add newNodeI(nkRecList, n.info) of nkRecCase: semRecordCase(c, n, check, pos, father, rectype) of nkNilLit: if father.kind != nkRecList: father.add newNodeI(nkRecList, n.info) of nkRecList: # attempt to keep the nesting at a sane level: var a = if father.kind == nkRecList: father else: copyNode(n) for i in 0..= 4: a = newNodeI(nkRecList, n.info) else: a = newNodeI(nkEmpty, n.info) var typ: PType var hasDefaultField = n[^1].kind != nkEmpty if hasDefaultField: typ = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil if c.inGenericContext > 0: n[^1] = semExprWithType(c, n[^1], {efDetermineType, efAllowSymChoice}, typ) if typ == nil: typ = n[^1].typ else: fitDefaultNode(c, n[^1], typ) typ = n[^1].typ.skipIntLit(c.idgen) propagateToOwner(rectype, typ) elif n[^2].kind == nkEmpty: localError(c.config, n.info, errTypeExpected) typ = errorType(c) else: typ = semTypeNode(c, n[^2], nil) if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange: n[^1] = firstRange(c.config, typ) hasDefaultField = true propagateToOwner(rectype, typ) var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner else: rectype.sym for i in 0.. 0) and (obj[0] != nil): result = result and tryAddInheritedFields(c, check, pos, obj[0].skipGenericInvocation, n, false, obj) addInheritedFieldsAux(c, check, pos, obj.n) else: result = true proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType = result = nil if n.len == 0: return newConstraint(c, tyObject) var check = initIntSet() var pos = 0 var base, realBase: PType = nil # n[0] contains the pragmas (if any). We process these later... checkSonsLen(n, 3, c.config) if n[1].kind != nkEmpty: realBase = semTypeNode(c, n[1][0], nil) base = skipTypesOrNil(realBase, skipPtrs) if base.isNil: localError(c.config, n.info, "cannot inherit from a type that is not an object type") else: var concreteBase = skipGenericInvocation(base) if concreteBase.kind in {tyObject, tyGenericParam, tyGenericInvocation} and tfFinal notin concreteBase.flags: # we only check fields duplication of object inherited from # concrete object. If inheriting from generic object or partial # specialized object, there will be second check after instantiation # located in semGeneric. if concreteBase.kind == tyObject: if concreteBase.sym != nil and concreteBase.sym.magic == mException and sfSystemModule notin c.module.flags: message(c.config, n.info, warnInheritFromException, "") if not tryAddInheritedFields(c, check, pos, concreteBase, n): return newType(tyError, c.idgen, result.owner) elif concreteBase.kind == tyForward: c.skipTypes.add n #we retry in the final pass else: if concreteBase.kind != tyError: localError(c.config, n[1].info, "inheritance only works with non-final objects; " & "for " & typeToString(realBase) & " to be inheritable it must be " & "'object of RootObj' instead of 'object'") base = nil realBase = nil if n.kind != nkObjectTy: internalError(c.config, n.info, "semObjectNode") result = newOrPrevType(tyObject, prev, c) rawAddSon(result, realBase) if realBase == nil and tfInheritable in flags: result.flags.incl tfInheritable if tfAcyclic in flags: result.flags.incl tfAcyclic if result.n.isNil: result.n = newNodeI(nkRecList, n.info) else: # partial object so add things to the check if not tryAddInheritedFields(c, check, pos, result, n, isPartial = true): return newType(tyError, c.idgen, result.owner) semRecordNodeAux(c, n[2], check, pos, result.n, result) if n[0].kind != nkEmpty: # dummy symbol for `pragma`: var s = newSymS(skType, newIdentNode(getIdent(c.cache, "dummy"), n.info), c) s.typ = result pragma(c, s, n[0], typePragmas) if base == nil and tfInheritable notin result.flags: incl(result.flags, tfFinal) if c.inGenericContext == 0 and computeRequiresInit(c, result): result.flags.incl tfRequiresInit proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = if n.len < 1: result = newConstraint(c, kind) else: let isCall = int ord(n.kind in nkCallKinds+{nkBracketExpr}) let n = if n[0].kind == nkBracket: n[0] else: n checkMinSonsLen(n, 1, c.config) let body = n.lastSon var t = if prev != nil and prev.kind != tyGenericBody and body.kind == nkObjectTy: semObjectNode(c, body, nil, prev.flags) else: semTypeNode(c, body, nil) if t.kind == tyTypeDesc and tfUnresolved notin t.flags: t = t.base if t.kind == tyVoid: localError(c.config, n.info, "type '$1 void' is not allowed" % kind.toHumanStr) result = newOrPrevType(kind, prev, c) var isNilable = false var wrapperKind = tyNone # check every except the last is an object: for i in isCall.. 0 for i in 1.. 3: var msg = "" for j in 0 ..< a.len - 2: if msg.len != 0: msg.add(", ") msg.add($a[j]) msg.add(" all have default value '") msg.add(def.renderTree) msg.add("', this may be unintentional, " & "either use ';' (semicolon) or explicitly write each default value") message(c.config, a.info, warnImplicitDefaultValue, msg) block determineType: var canBeVoid = false if kind == skTemplate: if typ != nil and typ.kind == tyUntyped: # don't do any typechecking or assign a type for # `untyped` parameter default value break determineType elif hasUnresolvedArgs(c, def): # template default value depends on other parameter # don't do any typechecking def.typ() = makeTypeFromExpr(c, def.copyTree) break determineType elif typ != nil and typ.kind == tyTyped: canBeVoid = true let isGeneric = isCurrentlyGeneric() inc c.inGenericContext, ord(isGeneric) if canBeVoid: def = semExpr(c, def, {efDetermineType, efAllowSymChoice}, typ) else: def = semExprWithType(c, def, {efDetermineType, efAllowSymChoice}, typ) dec c.inGenericContext, ord(isGeneric) if def.referencesAnotherParam(getCurrOwner(c)): def.flags.incl nfDefaultRefsParam if typ == nil: typ = def.typ if isEmptyContainer(typ): localError(c.config, a.info, "cannot infer the type of parameter '" & $a[0] & "'") if typ.kind == tyTypeDesc: # consider a proc such as: # proc takesType(T = int) # a naive analysis may conclude that the proc type is type[int] # which will prevent other types from matching - clearly a very # surprising behavior. We must instead fix the expected type of # the proc to be the unbound typedesc type: typ = newTypeS(tyTypeDesc, c, newTypeS(tyNone, c)) typ.flags.incl tfCheckedForDestructor elif def.typ != nil and def.typ.kind != tyFromExpr: # def.typ can be void # if def.typ != nil and def.typ.kind != tyNone: # example code that triggers it: # proc sort[T](cmp: proc(a, b: T): int = cmp) if not containsGenericType(typ): # check type compatibility between def.typ and typ: def = fitNode(c, typ, def, def.info) elif typ.kind == tyStatic: def = semConstExpr(c, def) def = fitNode(c, typ, def, def.info) if not hasType and not hasDefault: if isType: localError(c.config, a.info, "':' expected") if kind in {skTemplate, skMacro}: typ = newTypeS(tyUntyped, c) elif isRecursiveStructuralType(typ): localError(c.config, a[^2].info, errIllegalRecursionInTypeX % typeToString(typ)) elif skipTypes(typ, {tyGenericInst, tyAlias, tySink}).kind == tyVoid: continue for j in 0.. 0: result = semTypeNode(c, n[^1], prev) n.typ() = result n[^1].typ() = result else: result = nil proc semBlockType(c: PContext, n: PNode, prev: PType): PType = inc(c.p.nestedBlockCounter) let oldBreakInLoop = c.p.breakInLoop c.p.breakInLoop = false checkSonsLen(n, 2, c.config) openScope(c) if n[0].kind notin {nkEmpty, nkSym}: addDecl(c, newSymS(skLabel, n[0], c)) result = semStmtListType(c, n[1], prev) n[1].typ() = result n.typ() = result closeScope(c) c.p.breakInLoop = oldBreakInLoop dec(c.p.nestedBlockCounter) proc semGenericParamInInvocation(c: PContext, n: PNode): PType = result = semTypeNode(c, n, nil) n.typ() = makeTypeDesc(c, result) proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): bool = var check = initIntSet() pos = 0 let realBase = t.baseClass base = skipTypesOrNil(realBase, skipPtrs) result = true if base.isNil: localError(c.config, n.info, errIllegalRecursionInTypeX % "object") else: let concreteBase = skipGenericInvocation(base) if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: if not tryAddInheritedFields(c, check, pos, concreteBase, n): return false else: if concreteBase.kind != tyError: localError(c.config, n.info, errInheritanceOnlyWithNonFinalObjects) var newf = newNodeI(nkRecList, n.info) semRecordNodeAux(c, t.n, check, pos, newf, t) proc containsGenericInvocationWithForward(n: PNode): bool = if n.kind == nkSym and n.sym.ast != nil and n.sym.ast.len > 1 and n.sym.ast[2].kind == nkObjectTy: for p in n.sym.ast[2][^1]: if p.kind == nkIdentDefs and p[1].typ != nil and p[1].typ.kind == tyGenericInvocation and p[1][0].kind == nkSym and p[1][0].typ.kind == tyForward: return true return false proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = if s.typ == nil: localError(c.config, n.info, "cannot instantiate the '$1' $2" % [s.name.s, s.kind.toHumanStr]) return newOrPrevType(tyError, prev, c) var t = s.typ.skipTypes({tyAlias}) if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody: t = t.base result = newOrPrevType(tyGenericInvocation, prev, c) addSonSkipIntLit(result, t, c.idgen) template addToResult(typ, skip) = if typ.isNil: internalAssert c.config, false rawAddSon(result, typ) else: if skip: addSonSkipIntLit(result, typ, c.idgen) else: rawAddSon(result, makeRangeWithStaticExpr(c, typ.n)) if t.kind == tyForward: for i in 1..\nbut expected: <$2>" % [describeArgs(c, n), describeArgs(c, t.n, 0)] if m.firstMismatch.kind == kTypeMismatch and m.firstMismatch.arg < n.len: let nArg = n[m.firstMismatch.arg] if nArg.kind in nkSymChoices: err.add "\n" err.add ambiguousIdentifierMsg(nArg) localError(c.config, n.info, errGenerated, err) return newOrPrevType(tyError, prev, c) var isConcrete = true let rType = m.call[0].typ let mIndex = if rType != nil: rType.len - 1 else: -1 for i in 1..= i - 1 and tfImplicitStatic in rType[i - 1].flags and isIntLit(typ): skip = false addToResult(typ, skip) if isConcrete: if s.ast == nil and s.typ.kind != tyCompositeTypeClass: # XXX: What kind of error is this? is it still relevant? localError(c.config, n.info, errCannotInstantiateX % s.name.s) result = newOrPrevType(tyError, prev, c) elif containsGenericInvocationWithForward(n[0]): c.skipTypes.add n #fixes 1500 else: result = instGenericContainer(c, n.info, result, allowMetaTypes = false) # special check for generic object with # generic/partial specialized parent let tx = result.skipTypes(abstractPtrs, 50) if tx.isNil or isRecursiveStructuralType(tx): localError(c.config, n.info, "illegal recursion in type '$1'" % typeToString(result[0])) return errorType(c) if tx != result and tx.kind == tyObject: if tx[0] != nil: if not trySemObjectTypeForInheritedGenericInst(c, n, tx): return newOrPrevType(tyError, prev, c) var position = 0 recomputeFieldPositions(tx, tx.n, position) proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType = if prev != nil and (prev.kind == tyGenericBody or typeExpr.kind in {tyObject, tyEnum, tyDistinct, tyForward, tyGenericBody}): result = newTypeS(tyAlias, c) result.rawAddSon typeExpr result.sym = prev.sym if prev.kind != tyGenericBody: assignType(prev, result) else: result = nil proc fixupTypeOf(c: PContext, prev: PType, typ: PType) = if prev != nil: let result = newTypeS(tyAlias, c) result.rawAddSon typ result.sym = prev.sym if prev.kind != tyGenericBody: assignType(prev, result) proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType = var n = semExprWithType(c, n, {efDetermineType}) if n.typ.kind == tyTypeDesc: result = n.typ.base # fix types constructed by macros/template: if prev != nil and prev.kind != tyGenericBody and prev.sym != nil: if result.sym.isNil: # Behold! you're witnessing enormous power yielded # by macros. Only macros can summon unnamed types # and cast spell upon AST. Here we need to give # it a name taken from left hand side's node result.sym = prev.sym result.sym.typ = result else: # Less powerful routine like template do not have # the ability to produce unnamed types. But still # it has wild power to push a type a bit too far. # So we need to hold it back using alias and prevent # unnecessary new type creation let alias = maybeAliasType(c, result, prev) if alias != nil: result = alias elif n.typ.kind == tyFromExpr and c.inGenericContext > 0: # sometimes not possible to distinguish type from value in generic body, # for example `T.Foo`, so both are handled under `tyFromExpr` result = n.typ else: localError(c.config, n.info, "expected type, but got: " & n.renderTree) result = errorType(c) proc freshType(c: PContext; res, prev: PType): PType {.inline.} = if prev.isNil or prev.kind == tyGenericBody: result = copyType(res, c.idgen, res.owner) copyTypeProps(c.graph, c.idgen.module, result, res) else: result = res template modifierTypeKindOfNode(n: PNode): TTypeKind = case n.kind of nkVarTy: tyVar of nkRefTy: tyRef of nkPtrTy: tyPtr of nkStaticTy: tyStatic of nkTypeOfExpr: tyTypeDesc else: tyNone proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = # if n.len == 0: return newConstraint(c, tyTypeClass) if isNewStyleConcept(n): result = newOrPrevType(tyConcept, prev, c) result.flags.incl tfCheckedForDestructor result.n = semConceptDeclaration(c, n) return result let pragmas = n[1] inherited = n[2] var owner = getCurrOwner(c) var candidateTypeSlot = newTypeS(tyAlias, c, c.errorType) result = newOrPrevType(tyUserTypeClass, prev, c, son = candidateTypeSlot) result.flags.incl tfCheckedForDestructor result.n = n if inherited.kind != nkEmpty: for n in inherited.sons: let typ = semTypeNode(c, n, nil) result.add(typ) openScope(c) for param in n[0]: var dummyName: PNode dummyType: PType let modifier = param.modifierTypeKindOfNode if modifier != tyNone: dummyName = param[0] dummyType = c.makeTypeWithModifier(modifier, candidateTypeSlot) # if modifier == tyRef: # dummyType.flags.incl tfNotNil if modifier == tyTypeDesc: dummyType.flags.incl tfConceptMatchedTypeSym dummyType.flags.incl tfCheckedForDestructor else: dummyName = param dummyType = candidateTypeSlot # this can be true for 'nim check' on incomplete concepts, # see bug #8230 if dummyName.kind == nkEmpty: continue internalAssert c.config, dummyName.kind == nkIdent var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar, dummyName.ident, c.idgen, owner, param.info) dummyParam.typ = dummyType incl dummyParam.flags, sfUsed addDecl(c, dummyParam) result.n[3] = semConceptBody(c, n[3]) closeScope(c) proc applyTypeSectionPragmas(c: PContext; pragmas, operand: PNode): PNode = result = nil for p in pragmas: let key = if p.kind in nkPragmaCallKinds and p.len >= 1: p[0] else: p if p.kind == nkEmpty or whichPragma(p) != wInvalid: discard "builtin pragma" else: trySuggestPragmas(c, key) let ident = if key.kind in nkIdentKinds: considerQuotedIdent(c, key) else: nil if ident != nil and strTableGet(c.userPragmas, ident) != nil: discard "User-defined pragma" else: let sym = qualifiedLookUp(c, key, {}) # XXX: What to do here if amb is true? if sym != nil and sfCustomPragma in sym.flags: discard "Custom user pragma" else: # we transform ``(arg1, arg2: T) {.m, rest.}`` into ``m((arg1, arg2: T) {.rest.})`` and # let the semantic checker deal with it: var x = newNodeI(nkCall, key.info) x.add(key) if p.kind in nkPragmaCallKinds and p.len > 1: # pass pragma arguments to the macro too: for i in 1 ..< p.len: x.add(p[i]) # Also pass the node the pragma has been applied to x.add(operand.copyTreeWithoutNode(p)) # recursion assures that this works for multiple macro annotations too: var r = semOverloadedCall(c, x, x, {skMacro, skTemplate}, {efNoUndeclared}) if r != nil and (r.typ == nil or r.typ.kind != tyFromExpr): doAssert r[0].kind == nkSym let m = r[0].sym case m.kind of skMacro: return semMacroExpr(c, r, r, m, {efNoSemCheck}) of skTemplate: return semTemplateExpr(c, r, m, {efNoSemCheck}) else: doAssert(false, "cannot happen") proc semProcTypeWithScope(c: PContext, n: PNode, prev: PType, kind: TSymKind): PType = checkSonsLen(n, 2, c.config) if n[1].kind != nkEmpty and n[1].len > 0: let macroEval = applyTypeSectionPragmas(c, n[1], n) if macroEval != nil: return semTypeNode(c, macroEval, prev) openScope(c) result = semProcTypeNode(c, n[0], nil, prev, kind, isType=true) # start with 'ccClosure', but of course pragmas can overwrite this: result.callConv = ccClosure # dummy symbol for `pragma`: var s = newSymS(kind, newIdentNode(getIdent(c.cache, "dummy"), n.info), c) s.typ = result if n[1].kind != nkEmpty and n[1].len > 0: pragma(c, s, n[1], procTypePragmas) when useEffectSystem: setEffectsForProcType(c.graph, result, n[1]) elif c.optionStack.len > 0: # we construct a fake 'nkProcDef' for the 'mergePragmas' inside 'implicitPragmas'... s.ast = newTree(nkProcDef, newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info)) implicitPragmas(c, s, n.info, {wTags, wRaises}) when useEffectSystem: setEffectsForProcType(c.graph, result, s.ast[pragmasPos]) closeScope(c) proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym = if n.kind == nkType: result = symFromType(c, n.typ, n.info) else: localError(c.config, n.info, errTypeExpected) result = errorSym(c, n) proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType = result = newOrPrevType(tyStatic, prev, c) var base = semTypeNode(c, childNode, nil).skipTypes({tyTypeDesc, tyAlias}) result.rawAddSon(base) result.flags.incl tfHasStatic proc semTypeOf(c: PContext; n: PNode; prev: PType): PType = openScope(c) inc c.inTypeofContext defer: dec c.inTypeofContext # compiles can raise an exception let ex = semExprWithType(c, n, {efInTypeof}) closeScope(c) result = ex.typ if result.kind == tyFromExpr: result.flags.incl tfNonConstExpr elif result.kind == tyStatic: let base = result.skipTypes({tyStatic}) if c.inGenericContext > 0 and base.containsGenericType: result = makeTypeFromExpr(c, copyTree(ex)) result.flags.incl tfNonConstExpr else: result = base fixupTypeOf(c, prev, result) proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType = openScope(c) var m = BiggestInt 1 # typeOfIter if n.len == 3: let mode = semConstExpr(c, n[2]) if mode.kind != nkIntLit: localError(c.config, n.info, "typeof: cannot evaluate 'mode' parameter at compile-time") else: m = mode.intVal inc c.inTypeofContext defer: dec c.inTypeofContext # compiles can raise an exception let ex = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {}) closeScope(c) result = ex.typ if result.kind == tyFromExpr: result.flags.incl tfNonConstExpr elif result.kind == tyStatic: let base = result.skipTypes({tyStatic}) if c.inGenericContext > 0 and base.containsGenericType: result = makeTypeFromExpr(c, copyTree(ex)) result.flags.incl tfNonConstExpr else: result = base fixupTypeOf(c, prev, result) proc semTypeIdent(c: PContext, n: PNode): PSym = if n.kind == nkSym: result = getGenSym(c, n.sym) else: result = pickSym(c, n, {skType, skGenericParam, skParam}) if result.isNil: result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if result != nil: markUsed(c, n.info, result) onUse(n.info, result) # alias syntax, see semSym for skTemplate, skMacro if result.kind in {skTemplate, skMacro} and sfNoalias notin result.flags: let t = semTypeExpr(c, n, nil) result = symFromType(c, t, n.info) if result.kind == skParam and result.typ.kind == tyTypeDesc: # This is a typedesc param. is it already bound? # it's not bound when it's used multiple times in the # proc signature for example if c.inGenericInst > 0: let bound = result.typ.elementType.sym if bound != nil: return bound return result if result.typ.sym == nil: localError(c.config, n.info, errTypeExpected) return errorSym(c, n) result = result.typ.sym.copySym(c.idgen) result.typ = exactReplica(result.typ) result.typ.flags.incl tfUnresolved if result.kind == skGenericParam: if result.typ.kind == tyGenericParam and result.typ.len == 0 and tfWildcard in result.typ.flags: # collapse the wild-card param to a type result.transitionGenericParamToType() result.typ.flags.excl tfWildcard return else: localError(c.config, n.info, errTypeExpected) return errorSym(c, n) if result.kind != skType and result.magic notin {mStatic, mType, mTypeOf}: # this implements the wanted ``var v: V, x: V`` feature ... var ov: TOverloadIter = default(TOverloadIter) var amb = initOverloadIter(ov, c, n) while amb != nil and amb.kind != skType: amb = nextOverloadIter(ov, c, n) if amb != nil: result = amb else: if result.kind != skError: localError(c.config, n.info, errTypeExpected) return errorSym(c, n) if result.typ.kind != tyGenericParam: # XXX get rid of this hack! var oldInfo = n.info when defined(useNodeIds): let oldId = n.id reset(n[]) when defined(useNodeIds): n.id = oldId n.transitionNoneToSym() n.sym = result n.info = oldInfo n.typ() = result.typ else: localError(c.config, n.info, "identifier expected") result = errorSym(c, n) proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = nil inc c.inTypeContext if c.config.cmd == cmdIdeTools: suggestExpr(c, n) case n.kind of nkEmpty: result = n.typ of nkTypeOfExpr: # for ``typeof(countup(1,3))``, see ``tests/ttoseq``. checkSonsLen(n, 1, c.config) result = semTypeOf(c, n[0], prev) if result.kind == tyTypeDesc: result.flags.incl tfExplicit of nkPar: if n.len == 1: result = semTypeNode(c, n[0], prev) else: result = semAnonTuple(c, n, prev) of nkTupleConstr: result = semAnonTuple(c, n, prev) of nkCallKinds: let x = n[0] let ident = x.getPIdent if ident != nil and ident.s == "[]": let b = newNodeI(nkBracketExpr, n.info) for i in 1.. 0 and n[1].kind != nkEmpty and n[1].len > 0: # typeclass with pragma let symKind = if n.kind == nkIteratorTy: skIterator else: skProc # dummy symbol for `pragma`: var s = newSymS(symKind, newIdentNode(getIdent(c.cache, "dummy"), n.info), c) s.typ = child # for now only call convention pragmas supported in proc typeclass pragma(c, s, n[1], {FirstCallConv..LastCallConv}) result.addSonSkipIntLit(child, c.idgen) else: let symKind = if n.kind == nkIteratorTy: skIterator else: skProc result = semProcTypeWithScope(c, n, prev, symKind) if result == nil: localError(c.config, n.info, "type expected, but got: " & renderTree(n)) result = newOrPrevType(tyError, prev, c) if n.kind == nkIteratorTy and result.kind == tyProc: result.flags.incl(tfIterator) if result.callConv == ccClosure and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: result.flags.incl tfHasAsgn of nkEnumTy: result = semEnum(c, n, prev) of nkType: result = n.typ of nkStmtListType: result = semStmtListType(c, n, prev) of nkBlockType: result = semBlockType(c, n, prev) of nkOpenSym: result = semTypeNode(c, n[0], prev) else: result = semTypeExpr(c, n, prev) when false: localError(c.config, n.info, "type expected, but got: " & renderTree(n)) result = newOrPrevType(tyError, prev, c) n.typ() = result dec c.inTypeContext proc setMagicType(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) = # source : https://en.wikipedia.org/wiki/Data_structure_alignment#x86 m.typ.kind = kind m.typ.size = size # this usually works for most basic types # Assuming that since ARM, ARM64 don't support unaligned access # data is aligned to type size m.typ.align = size.int16 # FIXME: proper support for clongdouble should be added. # long double size can be 8, 10, 12, 16 bytes depending on platform & compiler if kind in {tyFloat64, tyFloat, tyInt, tyUInt, tyInt64, tyUInt64} and size == 8: m.typ.align = int16(conf.floatInt64Align) proc setMagicIntegral(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) = setMagicType(conf, m, kind, size) incl m.typ.flags, tfCheckedForDestructor proc processMagicType(c: PContext, m: PSym) = case m.magic of mInt: setMagicIntegral(c.config, m, tyInt, c.config.target.intSize) of mInt8: setMagicIntegral(c.config, m, tyInt8, 1) of mInt16: setMagicIntegral(c.config, m, tyInt16, 2) of mInt32: setMagicIntegral(c.config, m, tyInt32, 4) of mInt64: setMagicIntegral(c.config, m, tyInt64, 8) of mUInt: setMagicIntegral(c.config, m, tyUInt, c.config.target.intSize) of mUInt8: setMagicIntegral(c.config, m, tyUInt8, 1) of mUInt16: setMagicIntegral(c.config, m, tyUInt16, 2) of mUInt32: setMagicIntegral(c.config, m, tyUInt32, 4) of mUInt64: setMagicIntegral(c.config, m, tyUInt64, 8) of mFloat: setMagicIntegral(c.config, m, tyFloat, c.config.target.floatSize) of mFloat32: setMagicIntegral(c.config, m, tyFloat32, 4) of mFloat64: setMagicIntegral(c.config, m, tyFloat64, 8) of mFloat128: setMagicIntegral(c.config, m, tyFloat128, 16) of mBool: setMagicIntegral(c.config, m, tyBool, 1) of mChar: setMagicIntegral(c.config, m, tyChar, 1) of mString: setMagicType(c.config, m, tyString, szUncomputedSize) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) if optSeqDestructors in c.config.globalOptions: incl m.typ.flags, tfHasAsgn of mCstring: setMagicIntegral(c.config, m, tyCstring, c.config.target.ptrSize) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) of mPointer: setMagicIntegral(c.config, m, tyPointer, c.config.target.ptrSize) of mNil: setMagicType(c.config, m, tyNil, c.config.target.ptrSize) of mExpr: if m.name.s == "auto": setMagicIntegral(c.config, m, tyAnything, 0) else: setMagicIntegral(c.config, m, tyUntyped, 0) of mStmt: setMagicIntegral(c.config, m, tyTyped, 0) of mTypeDesc, mType: setMagicIntegral(c.config, m, tyTypeDesc, 0) rawAddSon(m.typ, newTypeS(tyNone, c)) of mStatic: setMagicType(c.config, m, tyStatic, 0) rawAddSon(m.typ, newTypeS(tyNone, c)) of mVoidType: setMagicIntegral(c.config, m, tyVoid, 0) of mArray: setMagicType(c.config, m, tyArray, szUncomputedSize) of mOpenArray: setMagicType(c.config, m, tyOpenArray, szUncomputedSize) of mVarargs: setMagicType(c.config, m, tyVarargs, szUncomputedSize) of mRange: setMagicIntegral(c.config, m, tyRange, szUncomputedSize) rawAddSon(m.typ, newTypeS(tyNone, c)) of mSet: setMagicIntegral(c.config, m, tySet, szUncomputedSize) of mUncheckedArray: setMagicIntegral(c.config, m, tyUncheckedArray, szUncomputedSize) of mSeq: setMagicType(c.config, m, tySequence, szUncomputedSize) if optSeqDestructors in c.config.globalOptions: incl m.typ.flags, tfHasAsgn if defined(nimsuggest) or c.config.cmd == cmdCheck: # bug #18985 discard else: assert c.graph.sysTypes[tySequence] == nil c.graph.sysTypes[tySequence] = m.typ of mOrdinal: setMagicIntegral(c.config, m, tyOrdinal, szUncomputedSize) rawAddSon(m.typ, newTypeS(tyNone, c)) of mIterableType: setMagicIntegral(c.config, m, tyIterable, 0) rawAddSon(m.typ, newTypeS(tyNone, c)) of mPNimrodNode: incl m.typ.flags, tfTriggersCompileTime incl m.typ.flags, tfCheckedForDestructor of mException: discard of mBuiltinType: case m.name.s of "lent": setMagicType(c.config, m, tyLent, c.config.target.ptrSize) of "sink": setMagicType(c.config, m, tySink, szUncomputedSize) of "owned": setMagicType(c.config, m, tyOwned, c.config.target.ptrSize) incl m.typ.flags, tfHasOwned else: localError(c.config, m.info, errTypeExpected) else: localError(c.config, m.info, errTypeExpected) proc semGenericConstraints(c: PContext, x: PType): PType = result = newTypeS(tyGenericParam, c, x) proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = template addSym(result: PNode, s: PSym): untyped = if father != nil: addSonSkipIntLit(father, s.typ, c.idgen) if sfGenSym notin s.flags: addDecl(c, s) result.add newSymNode(s) result = copyNode(n) if n.kind != nkGenericParams: illFormedAst(n, c.config) return for i in 0..