# # # 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" errInvalidOrderInEnumX = "invalid order in enum '$1'" errOrdinalTypeExpected = "ordinal type expected" errSetTooBig = "set is too large" 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'" errInitHereNotAllowed = "initialization not allowed here" 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 newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = if prev == nil: result = newTypeS(kind, c) else: result = prev if result.kind == tyForward: result.kind = kind #if kind == tyError: result.flags.incl tfCheckedForDestructor 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 e: PSym base: PType identToReplace: ptr PNode 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 if isPure: initStrTable(symbols) var hasNull = false for i in 1.. 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; kind: TTypeKind): PType = if n.len == 1: result = newOrPrevType(kind, prev, c) 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, kind) proc semDistinct(c: PContext, n: PNode, prev: PType): PType = if n.len == 0: return newConstraint(c, tyDistinct) result = newOrPrevType(tyDistinct, prev, c) addSonSkipIntLit(result, semTypeNode(c, n[0], nil), c.idgen) if n.len > 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] range[0] = semExprWithType(c, n[1], {efDetermineType}) range[1] = semExprWithType(c, n[2], {efDetermineType}) var rangeT: 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") 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[0].kind in {nkFloatLit..nkFloat64Lit} and result.n[0].floatVal.isNaN) or (result.n[1].kind in {nkFloatLit..nkFloat64Lit} and result.n[1].floatVal.isNaN): localError(c.config, n.info, "NaN is not a valid start or end for a range") 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) 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 semArrayIndex(c: PContext, n: PNode): PType = if isRange(n): result = semRangeAux(c, n, nil) else: 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: localError(c.config, n.info, "Array length can't be negative, but was " & $e.intVal) result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ) elif e.kind == nkSym and e.typ.kind == tyStatic: if e.sym.ast != nil: return semArrayIndex(c, e.sym.ast) if not isOrdinalType(e.typ.lastSon): let info = if n.safeLen > 1: n[1].info else: n.info localError(c.config, info, errOrdinalTypeExpected) result = makeRangeWithStaticExpr(c, e) if c.inGenericContext > 0: result.flags.incl tfUnresolved 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) # This is an int returning call, depending on an # yet unknown generic param (see tgenericshardcases). # 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: let x = semConstExpr(c, e) if x.kind in {nkIntLit..nkUInt64Lit}: result = makeRangeType(c, 0, x.intVal-1, n.info, x.typ.skipTypes({tyTypeDesc})) else: result = x.typ.skipTypes({tyTypeDesc}) #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 = lastSon(indxB) if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr}: if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}: discard elif not isOrdinalType(indxB): localError(c.config, n[1].info, errOrdinalTypeExpected) elif enumHasHoles(indxB): localError(c.config, n[1].info, "enum '$1' has holes" % typeToString(indxB.skipTypes({tyRange}))) base = semTypeNode(c, n[2], nil) # ensure we only construct a tyArray when there was no error (bug #3048): result = newOrPrevType(tyArray, prev, c) # bug #6682: Do not propagate initialization requirements etc for the # index type: rawAddSonNoPropagationOfTypeFlags(result, 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) addSonSkipIntLit(result, base, c.idgen) else: localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal") result = newOrPrevType(tyError, prev, c) 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) 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[0].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(nextSymId 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 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 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: addSonSkipIntLit(result, semTypeNode(c, it, nil), c.idgen) 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).. 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: # use a new check intset here for each branch: var newCheck: IntSet assign(newCheck, 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 c.inGenericContext > 0: father.add n elif branch != nil: semRecordNodeAux(c, branch, check, pos, father, rectype, hasCaseFields) 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) if n[^1].kind != nkEmpty: localError(c.config, n[^1].info, errInitHereNotAllowed) var typ: PType if n[^2].kind == nkEmpty: localError(c.config, n.info, errTypeExpected) typ = errorType(c) else: typ = semTypeNode(c, n[^2], nil) propagateToOwner(rectype, typ) var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner else: rectype.sym for i in 0.. 0) and (obj[0] != nil): addInheritedFields(c, check, pos, obj[0].skipGenericInvocation) addInheritedFieldsAux(c, check, pos, obj.n) proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType = 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, "") addInheritedFields(c, check, pos, concreteBase) 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 addInheritedFields(c, check, pos, result) 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 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: 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) 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) dec(c.p.nestedBlockCounter) 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 check = initIntSet() pos = 0 let realBase = t[0] base = skipTypesOrNil(realBase, skipPtrs) if base.isNil: localError(c.config, n.info, errIllegalRecursionInTypeX % "object") else: let concreteBase = skipGenericInvocation(base) if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: addInheritedFields(c, check, pos, concreteBase) 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 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) = if typ.isNil: internalAssert c.config, false rawAddSon(result, typ) else: addSonSkipIntLit(result, typ, c.idgen) if t.kind == tyForward: for i in 1..\nbut expected: <$2>" % [describeArgs(c, n), describeArgs(c, t.n, 0)] localError(c.config, n.info, errGenerated, err) return newOrPrevType(tyError, prev, c) var isConcrete = true for i in 1..= 1: p[0] else: p if p.kind == nkEmpty or whichPragma(p) != wInvalid: discard "builtin pragma" else: let ident = considerQuotedIdent(c, key) if strTableGet(c.userPragmas, ident) != nil: discard "User-defined pragma" else: var amb = false let sym = searchInScopes(c, ident, amb) # 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: 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 and optNimV1Emulation notin c.config.globalOptions: # 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) let t = semExprWithType(c, n, {efInTypeof}) closeScope(c) fixupTypeOf(c, prev, t) result = t.typ 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 let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {}) closeScope(c) fixupTypeOf(c, prev, t) result = t.typ 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 = case x.kind of nkIdent: x.ident of nkSym: x.sym.name of nkClosedSymChoice, nkOpenSymChoice: x[0].sym.name else: nil if ident != nil and ident.s == "[]": let b = newNodeI(nkBracketExpr, n.info) for i in 1.. 0 and n.kind == nkCall: result = makeTypeFromExpr(c, n.copyTree) else: result = semTypeExpr(c, n, prev) of nkWhenStmt: var whenResult = semWhen(c, n, false) if whenResult.kind == nkStmtList: whenResult.transitionSonsKind(nkStmtListType) result = semTypeNode(c, whenResult, prev) of nkBracketExpr: checkMinSonsLen(n, 2, c.config) var head = n[0] var s = if head.kind notin nkCallKinds: semTypeIdent(c, head) else: symFromExpectedTypeNode(c, semExpr(c, head)) case s.magic of mArray: result = semArray(c, n, prev) of mOpenArray: result = semContainer(c, n, tyOpenArray, "openarray", prev) of mUncheckedArray: result = semContainer(c, n, tyUncheckedArray, "UncheckedArray", prev) of mRange: result = semRange(c, n, prev) of mSet: result = semSet(c, n, prev) of mOrdinal: result = semOrdinal(c, n, prev) of mIterableType: result = semIterableType(c, n, prev) of mSeq: result = semContainer(c, n, tySequence, "seq", prev) if optSeqDestructors in c.config.globalOptions: incl result.flags, tfHasAsgn of mVarargs: result = semVarargs(c, n, prev) of mTypeDesc, mType, mTypeOf: result = makeTypeDesc(c, semTypeNode(c, n[1], nil)) result.flags.incl tfExplicit of mStatic: result = semStaticType(c, n[1], prev) of mExpr: result = semTypeNode(c, n[0], nil) if result != nil: let old = result result = copyType(result, nextTypeId c.idgen, getCurrOwner(c)) copyTypeProps(c.graph, c.idgen.module, result, old) for i in 1..