# # # The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # this module does the semantic checking for expressions # included from sem.nim when defined(nimCompilerStacktraceHints): import std/stackframes const errExprXHasNoType = "expression '$1' has no type (or is ambiguous)" errXExpectsTypeOrValue = "'$1' expects a type or value" errVarForOutParamNeededX = "for a 'var' type a variable needs to be passed; but '$1' is immutable" errXStackEscape = "address of '$1' may not escape its stack frame" errExprHasNoAddress = "expression has no address" errCannotInterpretNodeX = "cannot evaluate '$1'" errNamedExprExpected = "named expression expected" errNamedExprNotAllowed = "named expression not allowed here" errFieldInitTwice = "field initialized twice: '$1'" errUndeclaredFieldX = "undeclared field: '$1'" proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}; expectedType: PType = nil): PNode = rememberExpansion(c, n.info, s) let info = getCallLineInfo(n) markUsed(c, info, s) onUse(info, s) # Note: This is n.info on purpose. It prevents template from creating an info # context when called from an another template pushInfoContext(c.config, n.info, s.detailedInfo) result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, c.templInstCounter, c.idgen, efFromHlo in flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags, expectedType) popInfoContext(c.config) # XXX: A more elaborate line info rewrite might be needed result.info = info proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode template rejectEmptyNode(n: PNode) = # No matter what a nkEmpty node is not what we want here if n.kind == nkEmpty: illFormedAst(n, c.config) proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = rejectEmptyNode(n) # same as 'semExprWithType' but doesn't check for proc vars result = semExpr(c, n, flags + {efOperand, efAllowSymChoice}) if result.typ != nil: if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyVoid, c) else: localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType = nil): PNode = rejectEmptyNode(n) result = semExpr(c, n, flags+{efWantValue}, expectedType) let isEmpty = result.kind == nkEmpty isTypeError = result.typ != nil and result.typ.kind == tyError if isEmpty or isTypeError: # bug #12741, redundant error messages are the lesser evil here: localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) if isEmpty: # do not produce another redundant error message: result = errorNode(c, n) proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode = result = semExprCheck(c, n, flags-{efTypeAllowed}, expectedType) if result.typ == nil and efInTypeof in flags: result.typ = c.voidType elif result.typ == nil or result.typ == c.enforceVoidContext: localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) elif result.typ.kind == tyError: # associates the type error to the current owner result.typ = errorType(c) elif efTypeAllowed in flags and result.typ.kind == tyProc and hasUnresolvedParams(result, {}): # mirrored with semOperand but only on efTypeAllowed let owner = result.typ.owner let err = # consistent error message with evaltempl/semMacroExpr if owner != nil and owner.kind in {skTemplate, skMacro}: errMissingGenericParamsForTemplate % n.renderTree else: errProcHasNoConcreteType % n.renderTree localError(c.config, n.info, err) result.typ = errorType(c) else: if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExprCheck(c, n, flags) if result.typ == nil: localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = symChoice(c, n, s, scClosed) proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode proc isSymChoice(n: PNode): bool {.inline.} = result = n.kind in nkSymChoices proc resolveSymChoice(c: PContext, n: var PNode, flags: TExprFlags = {}, expectedType: PType = nil) = ## Attempts to resolve a symchoice `n`, `n` remains a symchoice if ## it cannot be resolved (this is the case even when `n.len == 1`). if expectedType != nil: # resolve from type inference, see paramTypesMatch n = fitNode(c, expectedType, n, n.info) if isSymChoice(n) and efAllowSymChoice notin flags: # some contexts might want sym choices preserved for later disambiguation # in general though they are ambiguous let first = n[0].sym var foundSym: PSym = nil if first.kind == skEnumField and not isAmbiguous(c, first.name, {skEnumField}, foundSym) and foundSym == first: # choose the first resolved enum field, i.e. the latest in scope # to mirror behavior before overloadable enums n = n[0] proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType, warnDisabled = false): PNode = ## sem the child of an `nkOpenSym` node, that is, captured symbols that can be ## replaced by newly injected symbols in generics. `s` must be the captured ## symbol if the original node is an `nkSym` node; and `nil` if it is an ## `nkOpenSymChoice`, in which case only non-overloadable injected symbols ## will be considered. let isSym = n.kind == nkSym let ident = n.getPIdent assert ident != nil let id = newIdentNode(ident, n.info) c.isAmbiguous = false let s2 = qualifiedLookUp(c, id, {}) # for `nkSym`, the first found symbol being different and unambiguous is # enough to replace the original # for `nkOpenSymChoice`, the first found symbol must be non-overloadable, # since otherwise we have to use regular `nkOpenSymChoice` functionality # but of the overloadable sym kinds, semExpr does not handle skModule, skMacro, skTemplate # as overloaded in the case where `nkIdent` finds them first if s2 != nil and not c.isAmbiguous and ((isSym and s2 != n.sym) or (not isSym and s2.kind notin OverloadableSyms-{skModule, skMacro, skTemplate})): # only consider symbols defined under current proc: var o = s2.owner while o != nil: if o == c.p.owner: if not warnDisabled: result = semExpr(c, id, flags, expectedType) return else: var msg = "a new symbol '" & ident.s & "' has been injected during " & # msgContext should show what is being instantiated: "template or generic instantiation, however " if isSym: msg.add( getSymRepr(c.config, n.sym) & " captured at " & "the proc declaration will be used instead; " & "either enable --experimental:openSym to use the injected symbol, " & "or `bind` this captured symbol explicitly") else: msg.add( "overloads of " & ident.s & " will be used instead; " & "either enable --experimental:openSym to use the injected symbol, " & "or `bind` this symbol explicitly") message(c.config, n.info, warnIgnoredSymbolInjection, msg) break o = o.owner # nothing found n.flags.excl nfDisabledOpenSym if not warnDisabled and isSym: result = semExpr(c, n, flags, expectedType) else: result = nil if not isSym: # set symchoice node type back to None n.typ = newTypeS(tyNone, c) proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode = if n.kind == nkOpenSymChoice: result = semOpenSym(c, n, flags, expectedType, warnDisabled = nfDisabledOpenSym in n.flags and genericsOpenSym notin c.features) if result != nil: return result = n resolveSymChoice(c, result, flags, expectedType) if isSymChoice(result) and result.len == 1: # resolveSymChoice can leave 1 sym result = result[0] if isSymChoice(result) and efAllowSymChoice notin flags: var err = "ambiguous identifier: '" & result[0].sym.name.s & "' -- use one of the following:\n" for child in n: let candidate = child.sym err.add " " & candidate.owner.name.s & "." & candidate.name.s err.add ": " & typeToString(candidate.typ) & "\n" localError(c.config, n.info, err) n.typ = errorType(c) result = n if result.kind == nkSym: result = semSym(c, result, result.sym, flags) proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} = result = copyTree(s.astdef) if result.isNil: localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value") result = newSymNode(s) else: result.typ = s.typ result.info = n.info type TConvStatus = enum convOK, convNotNeedeed, convNotLegal, convNotInRange proc checkConversionBetweenObjects(castDest, src: PType; pointers: int): TConvStatus = let diff = inheritanceDiff(castDest, src) return if diff == high(int) or (pointers > 1 and diff != 0): convNotLegal else: convOK const IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64} proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = let srcTyp = src.typ.skipTypes({tyStatic}) result = convOK if sameType(targetTyp, srcTyp) and targetTyp.sym == srcTyp.sym: # don't annoy conversions that may be needed on another processor: if targetTyp.kind notin IntegralTypes+{tyRange}: result = convNotNeedeed return var d = skipTypes(targetTyp, abstractVar) var s = srcTyp if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass: s = s.last s = skipTypes(s, abstractVar-{tyTypeDesc, tyOwned}) if s.kind == tyOwned and d.kind != tyOwned: s = s.skipModifier var pointers = 0 while (d != nil) and (d.kind in {tyPtr, tyRef, tyOwned}): if s.kind == tyOwned and d.kind != tyOwned: s = s.skipModifier elif d.kind != s.kind: break else: d = d.elementType s = s.elementType inc pointers let targetBaseTyp = skipTypes(targetTyp, abstractVarRange) let srcBaseTyp = skipTypes(srcTyp, abstractVarRange-{tyTypeDesc}) if d == nil: result = convNotLegal elif d.skipTypes(abstractInst).kind == tyObject and s.skipTypes(abstractInst).kind == tyObject: result = checkConversionBetweenObjects(d.skipTypes(abstractInst), s.skipTypes(abstractInst), pointers) elif (targetBaseTyp.kind in IntegralTypes) and (srcBaseTyp.kind in IntegralTypes): if targetTyp.kind == tyEnum and srcBaseTyp.kind == tyEnum and not sameType(targetTyp, srcBaseTyp): message(c.config, src.info, warnSuspiciousEnumConv, "suspicious code: enum to enum conversion") # `elif` would be incorrect here if targetTyp.kind == tyBool: discard "convOk" elif targetTyp.isOrdinalType: if src.kind in nkCharLit..nkUInt64Lit and src.getInt notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp) and targetTyp.kind notin {tyUInt..tyUInt64}: result = convNotInRange elif src.kind in nkFloatLit..nkFloat64Lit and (classify(src.floatVal) in {fcNan, fcNegInf, fcInf} or src.floatVal.int64 notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp)): result = convNotInRange elif targetBaseTyp.kind in tyFloat..tyFloat64: if src.kind in nkFloatLit..nkFloat64Lit and not floatRangeCheck(src.floatVal, targetTyp): result = convNotInRange elif src.kind in nkCharLit..nkUInt64Lit and not floatRangeCheck(src.intVal.float, targetTyp): result = convNotInRange else: # we use d, s here to speed up that operation a bit: if d.kind == tyFromExpr: result = convNotLegal return case cmpTypes(c, d, s) of isNone, isGeneric: if not compareTypes(targetTyp.skipTypes(abstractVar), srcTyp.skipTypes({tyOwned}), dcEqIgnoreDistinct): result = convNotLegal else: discard proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool = ## Checks whether the source type can be cast to the destination type. ## Casting is very unrestrictive; casts are allowed as long as ## dst.size >= src.size, and typeAllowed(dst, skParam) #const # castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString, # tySequence, tyPointer, tyNil, tyOpenArray, # tyProc, tySet, tyEnum, tyBool, tyChar} let src = src.skipTypes(tyUserTypeClasses) if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray: return false if skipTypes(src, abstractInst-{tyTypeDesc}).kind == tyTypeDesc: return false if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass: return false let conf = c.config if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}: let d = skipTypes(dst, abstractInst) let s = skipTypes(src, abstractInst) if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal: return false elif d.kind in IntegralTypes and s.kind in {tyString, tySequence}: return false var dstSize, srcSize: BiggestInt dstSize = computeSize(conf, dst) srcSize = computeSize(conf, src) if dstSize == -3 or srcSize == -3: # szUnknownSize # The Nim compiler can't detect if it's legal or not. # Just assume the programmer knows what he is doing. return true if dstSize < 0: return false elif srcSize < 0: return false elif typeAllowed(dst, skParam, c, {taIsCastable}) != nil: return false elif dst.kind == tyProc and dst.callConv == ccClosure: return src.kind == tyProc and src.callConv == ccClosure else: result = (dstSize >= srcSize) or (skipTypes(dst, abstractInst).kind in IntegralTypes) or (skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes) if result and src.kind == tyNil: return dst.size <= conf.target.ptrSize proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) = # XXX: liftParamType started to perform addDecl # we could do that instead in semTypeNode by snooping for added # gnrc. params, then it won't be necessary to open a new scope here openScope(c) var lifted = liftParamType(c, skType, newNodeI(nkArgList, info), t, ":anon", info) closeScope(c) if lifted != nil: t = lifted proc isOwnedSym(c: PContext; n: PNode): bool = let s = qualifiedLookUp(c, n, {}) result = s != nil and sfSystemModule in s.owner.flags and s.name.s == "owned" proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType = nil): PNode = if n.len != 2: localError(c.config, n.info, "a type conversion takes exactly one argument") return n result = newNodeI(nkConv, n.info) var targetType = semTypeNode(c, n[0], nil) case targetType.skipTypes({tyDistinct}).kind of tyTypeDesc: internalAssert c.config, targetType.len > 0 if targetType.base.kind == tyNone: return semTypeOf(c, n) else: targetType = targetType.base of tyStatic: var evaluated = semStaticExpr(c, n[1], expectedType) if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc: result = n result.typ = c.makeTypeDesc semStaticType(c, evaluated, nil) return elif targetType.base.kind == tyNone: return evaluated else: targetType = targetType.base of tyAnything, tyUntyped, tyTyped: localError(c.config, n.info, "illegal type conversion to '$1'" % typeToString(targetType)) else: discard maybeLiftType(targetType, c, n[0].info) if targetType.kind in {tySink, tyLent} or isOwnedSym(c, n[0]): let baseType = semTypeNode(c, n[1], nil).skipTypes({tyTypeDesc}) let t = newTypeS(targetType.kind, c, baseType) if targetType.kind == tyOwned: t.flags.incl tfHasOwned result = newNodeI(nkType, n.info) result.typ = makeTypeDesc(c, t) return result.add copyTree(n[0]) # special case to make MyObject(x = 3) produce a nicer error message: if n[1].kind == nkExprEqExpr and targetType.skipTypes(abstractPtrs).kind == tyObject: localError(c.config, n.info, "object construction uses ':', not '='") var op = semExprWithType(c, n[1], flags * {efDetermineType} + {efAllowSymChoice}) if isSymChoice(op) and op[0].sym.kind notin routineKinds: # T(foo) disambiguation syntax only allowed for routines op = semSymChoice(c, op) if targetType.kind != tyGenericParam and targetType.isMetaType: let final = inferWithMetatype(c, targetType, op, true) result.add final result.typ = final.typ return result.typ = targetType # XXX op is overwritten later on, this is likely added too early # here or needs to be overwritten too then. result.add op if targetType.kind == tyGenericParam or (op.typ != nil and op.typ.kind == tyFromExpr and c.inGenericContext > 0): # expression is compiled early in a generic body result.typ = makeTypeFromExpr(c, copyTree(result)) return result if not isSymChoice(op): let status = checkConvertible(c, result.typ, op) case status of convOK: # handle SomeProcType(SomeGenericProc) if op.kind == nkSym and op.sym.isGenericRoutine: result[1] = fitNode(c, result.typ, result[1], result.info) elif op.kind in {nkPar, nkTupleConstr} and targetType.kind == tyTuple: op = fitNode(c, targetType, op, result.info) of convNotNeedeed: if efNoSem2Check notin flags: message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) of convNotLegal: result = fitNode(c, result.typ, result[1], result.info) if result == nil: localError(c.config, n.info, "illegal conversion from '$1' to '$2'" % [op.typ.typeToString, result.typ.typeToString]) of convNotInRange: let value = if op.kind in {nkCharLit..nkUInt64Lit}: $op.getInt else: $op.getFloat localError(c.config, n.info, errGenerated, value & " can't be converted to " & result.typ.typeToString) else: for i in 0..= isSubtype # isNone # `res = sameType(t1, t2)` would be wrong, e.g. for `int is (int|float)` result = newIntNode(nkIntLit, ord(res)) result.typ = n.typ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode = if n.len != 3 or n[2].kind == nkEmpty: localError(c.config, n.info, "'is' operator takes 2 arguments") return errorNode(c, n) let boolType = getSysType(c.graph, n.info, tyBool) result = n n.typ = boolType var liftLhs = true n[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator}) if n[2].kind notin {nkStrLit..nkTripleStrLit}: let t2 = semTypeNode(c, n[2], nil) n[2] = newNodeIT(nkType, n[2].info, t2) if t2.kind == tyStatic: let evaluated = tryConstExpr(c, n[1]) if evaluated != nil: c.fixupStaticType(evaluated) n[1] = evaluated else: result = newIntNode(nkIntLit, 0) result.typ = boolType return elif t2.kind == tyTypeDesc and (t2.base.kind == tyNone or tfExplicit in t2.flags): # When the right-hand side is an explicit type, we must # not allow regular values to be matched against the type: liftLhs = false else: n[2] = semExpr(c, n[2]) var lhsType = n[1].typ if lhsType.kind != tyTypeDesc: if liftLhs: n[1] = makeTypeSymNode(c, lhsType, n[1].info) lhsType = n[1].typ else: if c.inGenericContext > 0 and lhsType.base.containsUnresolvedType: # BUGFIX: don't evaluate this too early: ``T is void`` return result = isOpImpl(c, n, flags) proc semOpAux(c: PContext, n: PNode) = const flags = {efDetermineType, efAllowSymChoice} for i in 1.. 0 and n[0].kind == nkExprColonExpr: # named tuple? for i in 0.. lastOrd(c.config, newType): localError(c.config, n.info, "cannot convert " & $value & " to " & typeNameAndDesc(newType)) of nkFloatLit..nkFloat64Lit: if check and not floatRangeCheck(n.floatVal, newType): localError(c.config, n.info, errFloatToString % [$n.floatVal, typeNameAndDesc(newType)]) of nkSym: if check and n.sym.kind == skEnumField and not sameTypeOrNil(n.sym.typ, newType): let value = n.sym.position if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType): localError(c.config, n.info, "cannot convert '" & n.sym.name.s & "' to '" & typeNameAndDesc(newType) & "'") else: discard n.typ = newType proc arrayConstrType(c: PContext, n: PNode): PType = var typ = newTypeS(tyArray, c) rawAddSon(typ, nil) # index type if n.len == 0: rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype! else: var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink}) addSonSkipIntLit(typ, t, c.idgen) typ.setIndexType makeRangeType(c, 0, n.len - 1, n.info) result = typ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode = result = newNodeI(nkBracket, n.info) result.typ = newTypeS(tyArray, c) var expectedElementType, expectedIndexType: PType = nil if expectedType != nil: let expected = expectedType.skipTypes(abstractRange-{tyDistinct}) case expected.kind of tyArray: expectedIndexType = expected[0] expectedElementType = expected[1] of tyOpenArray: expectedElementType = expected[0] else: discard rawAddSon(result.typ, nil) # index type var firstIndex, lastIndex: Int128 = Zero indexType = getSysType(c.graph, n.info, tyInt) lastValidIndex = lastOrd(c.config, indexType) if n.len == 0: rawAddSon(result.typ, if expectedElementType != nil and typeAllowed(expectedElementType, skLet, c) == nil: expectedElementType else: newTypeS(tyEmpty, c)) # needs an empty basetype! lastIndex = toInt128(-1) else: var x = n[0] if x.kind == nkExprColonExpr and x.len == 2: var idx = semConstExpr(c, x[0], expectedIndexType) if not isOrdinalType(idx.typ): localError(c.config, idx.info, "expected ordinal value for array " & "index, got '$1'" % renderTree(idx)) else: firstIndex = getOrdValue(idx) lastIndex = firstIndex indexType = idx.typ lastValidIndex = lastOrd(c.config, indexType) x = x[1] let yy = semExprWithType(c, x, {efTypeAllowed}, expectedElementType) var typ = yy.typ if expectedElementType == nil: expectedElementType = typ result.add yy #var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal}) for i in 1.. 0: discard "allow access within a cast(unsafeAssign) section" elif strictDefs in c.features and aa == arAddressableConst and sym != nil and sym.kind == skLet and isOutParam: discard "allow let varaibles to be passed to out parameters" else: localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n)) proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode = result = n case n.kind of nkSym: # n.sym.typ can be nil in 'check' mode ... if n.sym.typ != nil and skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}: incl(n.sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n, isOutParam) of nkDotExpr: checkSonsLen(n, 2, c.config) if n[1].kind != nkSym: internalError(c.config, n.info, "analyseIfAddressTaken") return if skipTypes(n[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}: incl(n[1].sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n, isOutParam) of nkBracketExpr: checkMinSonsLen(n, 1, c.config) if skipTypes(n[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}: if n[0].kind == nkSym: incl(n[0].sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n, isOutParam) else: result = newHiddenAddrTaken(c, n, isOutParam) proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) = checkMinSonsLen(n, 1, c.config) if n[0].typ == nil: # n[0] might be erroring node in nimsuggest return const FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, mAppendSeqElem, mNewSeq, mShallowCopy, mDeepCopy, mMove, mWasMoved} template checkIfConverterCalled(c: PContext, n: PNode) = ## Checks if there is a converter call which wouldn't be checked otherwise # Call can sometimes be wrapped in a deref let node = if n.kind == nkHiddenDeref: n[0] else: n if node.kind == nkHiddenCallConv: analyseIfAddressTakenInCall(c, node, true) # get the real type of the callee # it may be a proc var with a generic alias type, so we skip over them var t = n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink}) if n[0].kind == nkSym and n[0].sym.magic in FakeVarParams: # BUGFIX: check for L-Value still needs to be done for the arguments! # note sometimes this is eval'ed twice so we check for nkHiddenAddr here: for i in 1.. 0: discard "allow access within a cast(unsafeAssign) section" else: localError(c.config, it.info, errVarForOutParamNeededX % $it) # Make sure to still check arguments for converters c.checkIfConverterCalled(n[i]) # bug #5113: disallow newSeq(result) where result is a 'var T': if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}: var arg = n[1] #.skipAddr if arg.kind == nkHiddenDeref: arg = arg[0] if arg.kind == nkSym and arg.sym.kind == skResult and arg.typ.skipTypes(abstractInst).kind in {tyVar, tyLent}: localError(c.config, n.info, errXStackEscape % renderTree(n[1], {renderNoComments})) return for i in 1.. 1: for i in 1.. we don't want the restriction # to 'skIterator' anymore; skIterator is preferred in sigmatch already # for typeof support. # for ``typeof(countup(1,3))``, see ``tests/ttoseq``. result = semOverloadedCall(c, n, nOrig, {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate, skIterator}, flags, expectedType) else: result = semOverloadedCall(c, n, nOrig, {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}, flags, expectedType) if result != nil: if result[0].kind != nkSym: if not (c.inGenericContext > 0): # see generic context check in semOverloadedCall internalError(c.config, "semOverloadedCallAnalyseEffects") return let callee = result[0].sym case callee.kind of skMacro, skTemplate: discard else: if callee.kind == skIterator and callee.id == c.p.owner.id and not isClosureIterator(c.p.owner.typ): localError(c.config, n.info, errRecursiveDependencyIteratorX % callee.name.s) # error correction, prevents endless for loop elimination in transf. # See bug #2051: result[0] = newSymNode(errorSym(c, n)) elif callee.kind == skIterator: if efWantIterable in flags: let typ = newTypeS(tyIterable, c) rawAddSon(typ, result.typ) result.typ = typ proc resolveIndirectCall(c: PContext; n, nOrig: PNode; t: PType): TCandidate = result = initCandidate(c, t) matches(c, n, nOrig, result) proc finishOperand(c: PContext, a: PNode): PNode = if a.typ.isNil: result = c.semOperand(c, a, {efDetermineType}) else: result = a # XXX tyGenericInst here? if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}): #and tfUnresolved in result.typ.flags: let owner = result.typ.owner let err = # consistent error message with evaltempl/semMacroExpr if owner != nil and owner.kind in {skTemplate, skMacro}: errMissingGenericParamsForTemplate % a.renderTree else: errProcHasNoConcreteType % a.renderTree localError(c.config, a.info, err) considerGenSyms(c, result) proc semFinishOperands(c: PContext; n: PNode; isBracketExpr = false) = # this needs to be called to ensure that after overloading resolution every # argument has been sem'checked # skip the first argument for operands of `[]` since it may be an unresolved # generic proc, which is handled in semMagic let start = 1 + ord(isBracketExpr) for i in start.. 0: return n result = n when defined(nimsuggest): if c.config.expandProgress: if c.config.expandLevels == 0: return n else: c.config.expandLevels -= 1 let callee = result[0].sym case callee.kind of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType) of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType) else: semFinishOperands(c, result, isBracketExpr = callee.magic in {mArrGet, mArrPut}) activate(c, result) fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) if callee.magic != mNone: result = magicsAfterOverloadResolution(c, result, flags, expectedType) when false: if result.typ != nil and not (result.typ.kind == tySequence and result.elementType.kind == tyEmpty): liftTypeBoundOps(c, result.typ, n.info) #result = patchResolvedTypeBoundOp(c, result) if c.matchedConcept == nil and (c.inTypeofContext == 0 or callee.magic != mNone): # don't fold calls in concepts and typeof result = evalAtCompileTime(c, result) proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode = result = nil checkMinSonsLen(n, 1, c.config) var prc = n[0] if n[0].kind == nkDotExpr: checkSonsLen(n[0], 2, c.config) let n0 = semFieldAccess(c, n[0], {efIsDotCall}) if n0.kind == nkDotCall: # it is a static call! result = n0 result.transitionSonsKind(nkCall) result.flags.incl nfExplicitCall for i in 1.. 0: # don't make assumptions, entire expression needs to be tyFromExpr result = semGenericStmt(c, n) result.typ = makeTypeFromExpr(c, result.copyTree) return else: n[0] = n0 else: n[0] = semExpr(c, n[0], {efInCall, efAllowSymChoice}) let t = n[0].typ if t != nil and t.kind in {tyVar, tyLent}: n[0] = newDeref(n[0]) elif isSymChoice(n[0]) and nfDotField notin n.flags: # overloaded generic procs e.g. newSeq[int] can end up here return semDirectOp(c, n, flags, expectedType) var t: PType = nil if n[0].typ != nil: t = skipTypes(n[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct}) if t != nil and t.kind == tyTypeDesc: if n.len == 1: return semObjConstr(c, n, flags, expectedType) return semConv(c, n, flags) let nOrig = n.copyTree semOpAux(c, n) if t != nil and t.kind == tyProc: # This is a proc variable, apply normal overload resolution let m = resolveIndirectCall(c, n, nOrig, t) if m.state != csMatch: if c.config.m.errorOutputs == {}: # speed up error generation: globalError(c.config, n.info, "type mismatch") return c.graph.emptyNode else: var hasErrorType = false var msg = "type mismatch: got <" for i in 1.. 1: msg.add(", ") let nt = n[i].typ msg.add(typeToString(nt)) if nt.kind == tyError: hasErrorType = true break if not hasErrorType: let typ = n[0].typ msg.add(">\nbut expected one of:\n" & typeToString(typ)) # prefer notin preferToResolveSymbols # t.sym != nil # sfAnon notin t.sym.flags # t.kind != tySequence(It is tyProc) if typ.sym != nil and sfAnon notin typ.sym.flags and typ.kind == tyProc: # when can `typ.sym != nil` ever happen? msg.add(" = " & typeToString(typ, preferDesc)) msg.addDeclaredLocMaybe(c.config, typ) localError(c.config, n.info, msg) return errorNode(c, n) else: result = m.call instGenericConvertersSons(c, result, m) else: result = overloadedCallOpr(c, n) # this uses efNoUndeclared # Now that nkSym does not imply an iteration over the proc/iterator space, # the old ``prc`` (which is likely an nkIdent) has to be restored: if result == nil or result.kind == nkEmpty: # XXX: hmm, what kind of symbols will end up here? # do we really need to try the overload resolution? n[0] = prc nOrig[0] = prc n.flags.incl nfExprCall result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) if result == nil: return errorNode(c, n) elif result.kind notin nkCallKinds: # the semExpr() in overloadedCallOpr can even break this condition! # See bug #904 of how to trigger it: return result #result = afterCallActions(c, result, nOrig, flags) if result[0].kind == nkSym: result = afterCallActions(c, result, nOrig, flags, expectedType) else: fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode = # this seems to be a hotspot in the compiler! let nOrig = n.copyTree #semLazyOpAux(c, n) result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags, expectedType) if result != nil: result = afterCallActions(c, result, nOrig, flags, expectedType) else: result = errorNode(c, n) proc buildEchoStmt(c: PContext, n: PNode): PNode = # we MUST not check 'n' for semantics again here! But for now we give up: result = newNodeI(nkCall, n.info) let e = systemModuleSym(c.graph, getIdent(c.cache, "echo")) if e != nil: result.add(newSymNode(e)) else: result.add localErrorNode(c, n, "system needs: echo") result.add(n) result.add(newStrNode(nkStrLit, ": " & n.typ.typeToString)) result = semExpr(c, result) proc semExprNoType(c: PContext, n: PNode): PNode = let isPush = c.config.hasHint(hintExtendedContext) if isPush: pushInfoContext(c.config, n.info) result = semExpr(c, n, {efWantStmt}) discardCheck(c, result, {}) if isPush: popInfoContext(c.config) proc isTypeExpr(n: PNode): bool = case n.kind of nkType, nkTypeOfExpr: result = true of nkSym: result = n.sym.kind == skType else: result = false proc createSetType(c: PContext; baseType: PType): PType = assert baseType != nil result = newTypeS(tySet, c) rawAddSon(result, baseType) proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, check: var PNode): PSym = # transform in a node that contains the runtime check for the # field, if it is in a case-part... result = nil case r.kind of nkRecList: for i in 0.. 0: result = semGenericStmt(c, n) result.typ = makeTypeFromExpr(c, result.copyTree) else: result = nil of tyUserTypeClasses: if t.isResolvedUserTypeClass: result = readTypeParameter(c, t, i, n.info) elif c.inGenericContext > 0: result = semGenericStmt(c, n) result.typ = makeTypeFromExpr(c, copyTree(result)) else: result = nil of tyGenericBody, tyCompositeTypeClass: if c.inGenericContext > 0: result = readTypeParameter(c, t, i, n.info) if result != nil: # generic parameter exists, stop here but delay until instantiation result = semGenericStmt(c, n) result.typ = makeTypeFromExpr(c, copyTree(result)) else: result = nil elif c.inGenericContext > 0 and t.containsUnresolvedType: result = semGenericStmt(c, n) result.typ = makeTypeFromExpr(c, copyTree(result)) else: result = nil proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode = result = nil var ty = ty.skipTypes(tyDotOpTransparent) case ty.kind of tyEnum: # look up if the identifier belongs to the enum: var f = PSym(nil) while ty != nil: f = getSymFromList(ty.n, i) if f != nil: break ty = ty[0] # enum inheritance if f != nil: result = newSymNode(f) result.info = n.info result.typ = ty markUsed(c, n.info, f) onUse(n.info, f) of tyObject, tyTuple: if ty.n != nil and ty.n.kind == nkRecList: let field = lookupInRecord(ty.n, i) if field != nil: n.typ = makeTypeDesc(c, field.typ) result = n of tyGenericInst: result = tryReadingTypeField(c, n, i, ty.skipModifier) if result == nil: result = tryReadingGenericParam(c, n, i, ty) else: result = tryReadingGenericParam(c, n, i, ty) proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode = ## returns nil if it's not a built-in field access checkSonsLen(n, 2, c.config) # tests/bind/tbindoverload.nim wants an early exit here, but seems to # work without now. template/tsymchoicefield doesn't like an early exit # here at all! #if isSymChoice(n[1]): return when defined(nimsuggest): if c.config.cmd == cmdIdeTools: suggestExpr(c, n) if exactEquals(c.config.m.trackPos, n[1].info): suggestExprNoCheck(c, n) var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule}) if s != nil: if s.kind in OverloadableSyms: result = symChoice(c, n, s, scClosed) if result.kind == nkSym: result = semSym(c, n, s, flags) else: markUsed(c, n[1].info, s) result = semSym(c, n, s, flags) onUse(n[1].info, s) return # extra flags since LHS may become a call operand: n[0] = semExprWithType(c, n[0], flags+{efDetermineType, efWantIterable, efAllowSymChoice}) #restoreOldStyleType(n[0]) var i = considerQuotedIdent(c, n[1], n) var ty = n[0].typ var f: PSym = nil result = nil if ty.kind == tyTypeDesc: if ty.base.kind == tyNone: # This is a still unresolved typedesc parameter. # If this is a regular proc, then all bets are off and we must return # tyFromExpr, but when this happen in a macro this is not a built-in # field access and we leave the compiler to compile a normal call: if getCurrOwner(c).kind != skMacro: n.typ = makeTypeFromExpr(c, n.copyTree) flags.incl efCannotBeDotCall return n else: return nil else: flags.incl efCannotBeDotCall return tryReadingTypeField(c, n, i, ty.base) elif isTypeExpr(n.sons[0]): flags.incl efCannotBeDotCall return tryReadingTypeField(c, n, i, ty) elif ty.kind == tyError: # a type error doesn't have any builtin fields return nil if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass: ty = ty.last ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink, tyStatic}) while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst, tyAlias}) var check: PNode = nil if ty.kind == tyObject: while true: check = nil f = lookupInRecordAndBuildCheck(c, n, ty.n, i, check) if f != nil: break if ty[0] == nil: break ty = skipTypes(ty[0], skipPtrs) if f != nil: let visibilityCheckNeeded = if n[1].kind == nkSym and n[1].sym == f: false # field lookup was done already, likely by hygienic template or bindSym else: true if not visibilityCheckNeeded or fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? markUsed(c, n[1].info, f) onUse(n[1].info, f) let info = n[1].info n[0] = makeDeref(n[0]) n[1] = newSymNode(f) # we now have the correct field n[1].info = info # preserve the original info n.typ = f.typ if check == nil: result = n else: check[0] = n check.typ = n.typ result = check elif ty.kind == tyTuple and ty.n != nil: f = getSymFromList(ty.n, i) if f != nil: markUsed(c, n[1].info, f) onUse(n[1].info, f) n[0] = makeDeref(n[0]) n[1] = newSymNode(f) n.typ = f.typ result = n # we didn't find any field, let's look for a generic param if result == nil: let t = n[0].typ.skipTypes(tyDotOpTransparent) result = tryReadingGenericParam(c, n, i, t) flags.incl efCannotBeDotCall proc dotTransformation(c: PContext, n: PNode): PNode = if isSymChoice(n[1]) or # generics usually leave field names as symchoices, but not types (n[1].kind == nkSym and n[1].sym.kind == skType): result = newNodeI(nkDotCall, n.info) result.add n[1] result.add copyTree(n[0]) else: var i = considerQuotedIdent(c, n[1], n) result = newNodeI(nkDotCall, n.info) result.flags.incl nfDotField result.add newIdentNode(i, n[1].info) result.add copyTree(n[0]) proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # this is difficult, because the '.' is used in many different contexts # in Nim. We first allow types in the semantic checking. var f = flags - {efIsDotCall} result = builtinFieldAccess(c, n, f) if result == nil or ((result.typ == nil or result.typ.skipTypes(abstractInst).kind != tyProc) and efIsDotCall in flags and callOperator notin c.features and efCannotBeDotCall notin f): result = dotTransformation(c, n) proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode = result = newNodeI(nkCall, n.info) result.add(newIdentNode(ident, n.info)) for s in n: result.add s proc semDeref(c: PContext, n: PNode, flags: TExprFlags): PNode = checkSonsLen(n, 1, c.config) n[0] = semExprWithType(c, n[0]) let a = getConstExpr(c.module, n[0], c.idgen, c.graph) if a != nil: if a.kind == nkNilLit and efInTypeof notin flags: localError(c.config, n.info, "nil dereference is not allowed") n[0] = a result = n var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink, tyOwned}) case t.kind of tyRef, tyPtr: n.typ = t.elementType of tyMetaTypes, tyFromExpr: n.typ = makeTypeFromExpr(c, n.copyTree) else: result = nil #GlobalError(n[0].info, errCircumNeedsPointer) proc maybeInstantiateGeneric(c: PContext, n: PNode, s: PSym): PNode = ## Instantiates generic if not lacking implicit generics, ## otherwise returns n. let neededGenParams = s.ast[genericParamsPos].len heldGenParams = n.len - 1 var implicitParams = 0 for x in s.ast[genericParamsPos]: if tfImplicitTypeParam in x.typ.flags: inc implicitParams if heldGenParams != neededGenParams and implicitParams + heldGenParams == neededGenParams: # This is an implicit + explicit generic procedure without all args passed, # kicking back the sem'd symbol fixes #17212 # Uncertain the hackiness of this solution. result = n else: result = explicitGenericInstantiation(c, n, s) if result == n: n[0] = copyTree(result[0]) proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if not a built-in subscript operator; also called for the ## checking of assignments result = nil if n.len == 1: let x = semDeref(c, n, flags) if x == nil: return nil if x.typ.kind == tyFromExpr: # depends on generic type return x result = newNodeIT(nkDerefExpr, x.info, x.typ) result.add(x[0]) return checkMinSonsLen(n, 2, c.config) # signal that generic parameters may be applied after n[0] = semExprWithType(c, n[0], {efNoEvaluateGeneric, efAllowSymChoice}) var arr = skipTypes(n[0].typ, {tyGenericInst, tyUserTypeClassInst, tyOwned, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink}) if arr.kind == tyStatic: if arr.base.kind == tyNone: result = n result.typ = semStaticType(c, n[1], nil) return elif arr.n != nil: return semSubscript(c, arr.n, flags) else: arr = arr.base case arr.kind of tyArray, tyOpenArray, tyVarargs, tySequence, tyString, tyCstring, tyUncheckedArray: if n.len != 2: return nil n[0] = makeDeref(n[0]) for i in 1..= 0 and idx < arr.len: n.typ = arr[toInt(idx)] else: localError(c.config, n.info, "invalid index $1 in subscript for tuple of length $2" % [$idx, $arr.len]) result = n else: result = nil else: let s = if n[0].kind == nkSym: n[0].sym elif n[0].kind in nkSymChoices + {nkOpenSym}: n[0][0].sym else: nil if s != nil: case s.kind of skProc, skFunc, skMethod, skConverter, skIterator: # type parameters: partial generic specialization n[0] = semSymGenericInstantiation(c, n[0], s) result = maybeInstantiateGeneric(c, n, s) of skMacro, skTemplate: if efInCall in flags: # We are processing macroOrTmpl[] in macroOrTmpl[](...) call. # Return as is, so it can be transformed into complete macro or # template call in semIndirectOp caller. result = n else: # We are processing macroOrTmpl[] not in call. Transform it to the # macro or template call with generic arguments here. n.transitionSonsKind(nkCall) case s.kind of skMacro: result = semMacroExpr(c, n, n, s, flags) of skTemplate: result = semTemplateExpr(c, n, s, flags) else: discard of skType: result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) else: discard proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode = result = semSubscript(c, n, flags) if result == nil: # overloaded [] operator: result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]")), flags, expectedType) proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = var id = considerQuotedIdent(c, a[1], a) var setterId = newIdentNode(getIdent(c.cache, id.s & '='), n.info) # a[0] is already checked for semantics, that does ``builtinFieldAccess`` # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for # nodes? let aOrig = nOrig[0] result = newTreeI(nkCall, n.info, setterId, a[0], n[1]) result.flags.incl nfDotSetter let orig = newTreeI(nkCall, n.info, setterId, aOrig[0], nOrig[1]) result = semOverloadedCallAnalyseEffects(c, result, orig, {}) if result != nil: result = afterCallActions(c, result, nOrig, {}) #fixAbstractType(c, result) #analyseIfAddressTakenInCall(c, result) proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = # See RFC #7373, calls returning 'var T' are assumed to # return a view into the first argument (if there is one): let root = exprRoot(n) if root != nil and root.owner == c.p.owner: template url: string = "var_t_return.html".createDocLink if root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags: localError(c.config, n.info, "'$1' escapes its stack frame; context: '$2'; see $3" % [ root.name.s, renderTree(n, {renderNoComments}), url]) elif root.kind == skParam and root.position != 0: localError(c.config, n.info, "'$1' is not the first parameter; context: '$2'; see $3" % [ root.name.s, renderTree(n, {renderNoComments}), url]) case n.kind of nkHiddenAddr, nkAddr: return n of nkDerefExpr: return n[0] of nkBracketExpr: if n.len == 1: return n[0] of nkHiddenDeref: # issue #13848 # `proc fun(a: var int): var int = a` discard else: discard let valid = isAssignable(c, n) if valid != arLValue: if valid in {arAddressableConst, arLentValue} and isLent: discard "ok" elif valid == arLocalLValue: localError(c.config, n.info, errXStackEscape % renderTree(n, {renderNoComments})) else: localError(c.config, n.info, errExprHasNoAddress) result = newNodeIT(nkHiddenAddr, n.info, if n.typ.kind in {tyVar, tyLent}: n.typ else: makePtrType(c, n.typ)) if n.typ.kind in {tyVar, tyLent}: n.typ = n.typ.elementType result.add(n) proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = if le.kind == nkHiddenDeref: var x = le[0] if x.kind == nkSym: if x.sym.kind == skResult and (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView): n[0] = x # 'result[]' --> 'result' n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent) x.typ.flags.incl tfVarIsPtr #echo x.info, " setting it for this type ", typeToString(x.typ), " ", n.info elif sfGlobal in x.sym.flags: x.typ.flags.incl tfVarIsPtr proc borrowCheck(c: PContext, n, le, ri: PNode) = const PathKinds0 = {nkDotExpr, nkCheckedFieldExpr, nkBracketExpr, nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv} PathKinds1 = {nkHiddenStdConv, nkHiddenSubConv} proc getRoot(n: PNode; followDeref: bool): PNode = result = n while true: case result.kind of nkDerefExpr, nkHiddenDeref: if followDeref: result = result[0] else: break of PathKinds0: result = result[0] of PathKinds1: result = result[1] else: break proc scopedLifetime(c: PContext; ri: PNode): bool {.inline.} = let n = getRoot(ri, followDeref = false) result = (ri.kind in nkCallKinds+{nkObjConstr}) or (n.kind == nkSym and n.sym.owner == c.p.owner and n.sym.kind != skResult) proc escapes(c: PContext; le: PNode): bool {.inline.} = # param[].foo[] = self definitely escapes, we don't need to # care about pointer derefs: let n = getRoot(le, followDeref = true) result = n.kind == nkSym and n.sym.kind == skParam # Special typing rule: do not allow to pass 'owned T' to 'T' in 'result = x': const absInst = abstractInst - {tyOwned} if ri.typ != nil and ri.typ.skipTypes(absInst).kind == tyOwned and le.typ != nil and le.typ.skipTypes(absInst).kind != tyOwned and scopedLifetime(c, ri): if le.kind == nkSym and le.sym.kind == skResult: localError(c.config, n.info, "cannot return an owned pointer as an unowned pointer; " & "use 'owned(" & typeToString(le.typ) & ")' as the return type") elif escapes(c, le): localError(c.config, n.info, "assignment produces a dangling ref: the unowned ref lives longer than the owned ref") template resultTypeIsInferrable(typ: PType): untyped = typ.isMetaType and typ.kind != tyTypeDesc proc goodLineInfo(arg: PNode): TLineInfo = if arg.kind == nkStmtListExpr and arg.len > 0: goodLineInfo(arg[^1]) else: arg.info proc makeTupleAssignments(c: PContext; n: PNode): PNode = ## expand tuple unpacking assignment into series of assignments ## ## mirrored with semstmts.makeVarTupleSection let lhs = n[0] let value = semExprWithType(c, n[1], {efTypeAllowed}) if value.typ.kind != tyTuple: localError(c.config, n[1].info, errTupleUnpackingTupleExpected % [typeToString(value.typ, preferDesc)]) elif lhs.len != value.typ.len: localError(c.config, n.info, errTupleUnpackingDifferentLengths % [$lhs.len, typeToString(value.typ, preferDesc), $value.typ.len]) result = newNodeI(nkStmtList, n.info) let temp = newSym(skTemp, getIdent(c.cache, "tmpTupleAsgn"), c.idgen, getCurrOwner(c), n.info) temp.typ = value.typ temp.flags.incl(sfGenSym) var v = newNodeI(nkLetSection, value.info) let tempNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) var vpart = newNodeI(nkIdentDefs, v.info, 3) vpart[0] = tempNode vpart[1] = c.graph.emptyNode vpart[2] = value v.add vpart result.add(v) for i in 0.. `f=` (r, x) let nOrig = n.copyTree var flags = {efLValue} a = builtinFieldAccess(c, a, flags) if a == nil: a = propertyWriteAccess(c, n, nOrig, n[0]) if a != nil: return a # we try without the '='; proc that return 'var' or macros are still # possible: a = dotTransformation(c, n[0]) if a.kind == nkDotCall: a.transitionSonsKind(nkCall) a = semExprWithType(c, a, {efLValue}) of nkBracketExpr: # a[i] = x # --> `[]=`(a, i, x) a = semSubscript(c, a, {efLValue}) if a == nil: result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "[]=")) result.add(n[1]) if mode == noOverloadedSubscript: bracketNotFoundError(c, result, {}) return errorNode(c, n) else: result = semExprNoType(c, result) return result of nkCurlyExpr: # a{i} = x --> `{}=`(a, i, x) result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "{}=")) result.add(n[1]) return semExprNoType(c, result) of nkPar, nkTupleConstr: if a.len >= 2 or a.kind == nkTupleConstr: # unfortunately we need to rewrite ``(x, y) = foo()`` already here so # that overloading of the assignment operator still works. Usually we # prefer to do these rewritings in transf.nim: return semStmt(c, makeTupleAssignments(c, n), {}) else: a = semExprWithType(c, a, {efLValue}) else: a = semExprWithType(c, a, {efLValue}) n[0] = a # a = b # both are vars, means: a[] = b[] # a = b # b no 'var T' means: a = addr(b) var le = a.typ let assignable = isAssignable(c, a) let root = getRoot(a) let useStrictDefLet = root != nil and root.kind == skLet and assignable == arAddressableConst and strictDefs in c.features and isLocalSym(root) if le == nil: localError(c.config, a.info, "expression has no type") elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and assignable in {arNone, arLentValue, arAddressableConst} and not useStrictDefLet ) or (skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features): # Direct assignment to a discriminant is allowed! localError(c.config, a.info, errXCannotBeAssignedTo % renderTree(a, {renderNoComments})) else: let lhs = n[0] let rhs = semExprWithType(c, n[1], {efTypeAllowed}, le) if lhs.kind == nkSym and lhs.sym.kind == skResult: n.typ = c.enforceVoidContext if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ): var rhsTyp = rhs.typ if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass: rhsTyp = rhsTyp.last if lhs.sym.typ.kind == tyAnything: rhsTyp = rhsTyp.skipTypes({tySink}).skipIntLit(c.idgen) if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}: internalAssert c.config, c.p.resultSym != nil # Make sure the type is valid for the result variable typeAllowedCheck(c, n.info, rhsTyp, skResult) lhs.typ = rhsTyp c.p.resultSym.typ = rhsTyp c.p.owner.typ.setReturnType rhsTyp else: typeMismatch(c.config, n.info, lhs.typ, rhsTyp, rhs) borrowCheck(c, n, lhs, rhs) n[1] = fitNode(c, le, rhs, goodLineInfo(n[1])) when false: liftTypeBoundOps(c, lhs.typ, lhs.info) fixAbstractType(c, n) asgnToResultVar(c, n, n[0], n[1]) result = n proc semReturn(c: PContext, n: PNode): PNode = result = n checkSonsLen(n, 1, c.config) if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or (not c.p.owner.typ.isNil and isClosureIterator(c.p.owner.typ)): if n[0].kind != nkEmpty: if n[0].kind == nkAsgn and n[0][0].kind == nkSym and c.p.resultSym == n[0][0].sym: discard "return is already transformed" elif c.p.resultSym != nil: # transform ``return expr`` to ``result = expr; return`` var a = newNodeI(nkAsgn, n[0].info) a.add newSymNode(c.p.resultSym) a.add n[0] n[0] = a else: localError(c.config, n.info, errNoReturnTypeDeclared) return result[0] = semAsgn(c, n[0]) # optimize away ``result = result``: if result[0][1].kind == nkSym and result[0][1].sym == c.p.resultSym: result[0] = c.graph.emptyNode else: localError(c.config, n.info, "'return' not allowed here") proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode = when defined(nimsuggest): if c.graph.config.expandDone(): return n openScope(c) result = semExpr(c, n, expectedType = expectedType) if c.p.resultSym != nil and not isEmptyType(result.typ): if result.kind == nkNilLit: # or ImplicitlyDiscardable(result): # new semantic: 'result = x' triggers the void context result.typ = nil elif result.kind == nkStmtListExpr and result.typ.kind == tyNil: # to keep backwards compatibility bodies like: # nil # # comment # are not expressions: fixNilType(c, result) else: var a = newNodeI(nkAsgn, n.info, 2) a[0] = newSymNode(c.p.resultSym) a[1] = result result = semAsgn(c, a) else: discardCheck(c, result, {}) if c.p.owner.kind notin {skMacro, skTemplate} and c.p.resultSym != nil and c.p.resultSym.typ.isMetaType: if isEmptyType(result.typ): # we inferred a 'void' return type: c.p.resultSym.typ = errorType(c) c.p.owner.typ.setReturnType nil else: localError(c.config, c.p.resultSym.info, errCannotInferReturnType % c.p.owner.name.s) if isIterator(c.p.owner.typ) and c.p.owner.typ.returnType != nil and c.p.owner.typ.returnType.kind == tyAnything: localError(c.config, c.p.owner.info, errCannotInferReturnType % c.p.owner.name.s) closeScope(c) proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = var t = skipTypes(restype, {tyGenericInst, tyAlias, tySink}) case t.kind of tyVar, tyLent: t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892 if n[0].kind in {nkHiddenStdConv, nkHiddenSubConv}: n[0] = n[0][1] n[0] = takeImplicitAddr(c, n[0], t.kind == tyLent) of tyTuple: for i in 0..= 2: localError(c.config, n.info, "ambiguous symbol in 'getAst' context: " & $macroCall) else: let info = macroCall[0].info macroCall[0] = newSymNode(cand, info) markUsed(c, info, cand) onUse(info, cand) # we just perform overloading resolution here: #n[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro}) else: localError(c.config, n.info, "getAst takes a call, but got " & n.renderTree) # Preserve the magic symbol in order to be handled in evals.nim internalAssert c.config, n[0].sym.magic == mExpandToAst #n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType if n.kind == nkStmtList and n.len == 1: result = n[0] else: result = n result.typ = sysTypeFromName(c.graph, n.info, "NimNode") proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, flags: TExprFlags = {}): PNode = if n.len == 2: n[0] = newSymNode(magicSym, n.info) result = semExpandToAst(c, n) else: result = semDirectOp(c, n, flags) proc processQuotations(c: PContext; n: var PNode, op: string, quotes: var seq[PNode], ids: var seq[PNode]) = template returnQuote(q) = quotes.add q n = newIdentNode(getIdent(c.cache, $quotes.len), n.info) ids.add n return template handlePrefixOp(prefixed) = if prefixed[0].kind == nkIdent: let examinedOp = prefixed[0].ident.s if examinedOp == op: returnQuote prefixed[1] elif examinedOp.startsWith(op): prefixed[0] = newIdentNode(getIdent(c.cache, examinedOp.substr(op.len)), prefixed.info) if n.kind == nkPrefix: checkSonsLen(n, 2, c.config) handlePrefixOp(n) elif n.kind == nkAccQuoted: if op == "``": returnQuote n[0] else: # [bug #7589](https://github.com/nim-lang/Nim/issues/7589) if n.len == 2 and n[0].ident.s == op: var tempNode = nkPrefix.newTree() tempNode.newSons(2) tempNode[0] = n[0] tempNode[1] = n[1] handlePrefixOp(tempNode) elif n.kind == nkIdent: if n.ident.s == "result": n = ids[0] for i in 0.. 0: dummyTemplate[paramsPos] = newNodeI(nkFormalParams, n.info) dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[0], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode) for i in 1.. 1 and n[1].kind notin nkCallKinds: return localErrorNode(c, n, n[1].info, "'spawn' takes a call expression; got: " & $n[1]) let typ = result[^1].typ if not typ.isEmptyType: if spawnResult(typ, c.inParallelStmt > 0) == srFlowVar: result.typ = createFlowVar(c, typ, n.info) else: result.typ = typ result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode else: result.add c.graph.emptyNode of mProcCall: markUsed(c, n.info, s) result = setMs(n, s) result[1] = semExpr(c, n[1]) result.typ = n[1].typ of mPlugin: markUsed(c, n.info, s) # semDirectOp with conditional 'afterCallActions': let nOrig = n.copyTree #semLazyOpAux(c, n) result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) if result == nil: result = errorNode(c, n) else: let callee = result[0].sym if callee.magic == mNone: semFinishOperands(c, result) activate(c, result) fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) if callee.magic != mNone: result = magicsAfterOverloadResolution(c, result, flags) of mRunnableExamples: markUsed(c, n.info, s) if c.config.cmd in cmdDocLike and n.len >= 2 and n.lastSon.kind == nkStmtList: when false: # some of this dead code was moved to `prepareExamples` if sfMainModule in c.module.flags: let inp = toFullPath(c.config, c.module.info) if c.runnableExamples == nil: c.runnableExamples = newTree(nkStmtList, newTree(nkImportStmt, newStrNode(nkStrLit, expandFilename(inp)))) let imports = newTree(nkStmtList) var savedLastSon = copyTree n.lastSon extractImports(savedLastSon, imports) for imp in imports: c.runnableExamples.add imp c.runnableExamples.add newTree(nkBlockStmt, c.graph.emptyNode, copyTree savedLastSon) result = setMs(n, s) else: result = c.graph.emptyNode of mSizeOf: markUsed(c, n.info, s) result = semSizeof(c, setMs(n, s)) of mArrToSeq, mOpenArrayToSeq: if expectedType != nil and ( let expected = expectedType.skipTypes(abstractRange-{tyDistinct}); expected.kind in {tySequence, tyOpenArray}): # seq type inference var arrayType = newType(tyOpenArray, c.idgen, expected.owner) arrayType.rawAddSon(expected[0]) if n[0].kind == nkSym and sfFromGeneric in n[0].sym.flags: # may have been resolved to `@`[empty] at some point, # reset to `@` to deal with this n[0] = newSymNode(n[0].sym.instantiatedFrom, n[0].info) n[1] = semExpr(c, n[1], flags, arrayType) result = semDirectOp(c, n, flags, expectedType) else: result = semDirectOp(c, n, flags, expectedType) proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = # If semCheck is set to false, ``when`` will return the verbatim AST of # the correct branch. Otherwise the AST will be passed through semStmt. result = nil let flags = if semCheck: {efWantStmt} else: {} template setResult(e: untyped) = if semCheck: result = semExpr(c, e, flags) # do not open a new scope! else: result = e # Check if the node is "when nimvm" # when nimvm: # ... # else: # ... var whenNimvm = false var typ = commonTypeBegin if n.len in 1..2 and n[0].kind == nkElifBranch and ( n.len == 1 or n[1].kind == nkElse): var exprNode = n[0][0] if exprNode.kind == nkOpenSym: exprNode = exprNode[0] if exprNode.kind == nkIdent: whenNimvm = lookUp(c, exprNode).magic == mNimvm elif exprNode.kind == nkSym: whenNimvm = exprNode.sym.magic == mNimvm if whenNimvm: n.flags.incl nfLL var cannotResolve = false for i in 0.. 0: let e = semExprWithType(c, it[0]) if e.typ.kind == tyFromExpr: it[0] = makeStaticExpr(c, e) cannotResolve = true else: it[0] = forceBool(c, e) let val = getConstExpr(c.module, it[0], c.idgen, c.graph) if val == nil or val.kind != nkIntLit: cannotResolve = true elif not cannotResolve and val.intVal != 0 and result == nil: setResult(it[1]) return # we're not in nimvm and we already have a result else: let e = forceBool(c, semConstExpr(c, it[0])) if e.kind != nkIntLit: # can happen for cascading errors, assume false # InternalError(n.info, "semWhen") discard elif e.intVal != 0 and result == nil: setResult(it[1]) return # we're not in nimvm and we already have a result of nkElse, nkElseExpr: checkSonsLen(it, 1, c.config) if cannotResolve: discard elif result == nil or whenNimvm: if semCheck: it[0] = semExpr(c, it[0], flags) typ = commonType(c, typ, it[0].typ) if typ != nil and typ.kind != tyUntyped: it[0] = fitNode(c, typ, it[0], it[0].info) if result == nil: result = it[0] else: illFormedAst(n, c.config) if cannotResolve: result = semGenericStmt(c, n) result.typ = makeTypeFromExpr(c, result.copyTree) return if result == nil: result = newNodeI(nkEmpty, n.info) if whenNimvm: result.typ = typ if n.len == 1: result.add(newTree(nkElse, newNode(nkStmtList))) proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode = result = newNodeI(nkCurly, n.info) result.typ = newTypeS(tySet, c) result.typ.flags.incl tfIsConstructor var expectedElementType: PType = nil if expectedType != nil and ( let expected = expectedType.skipTypes(abstractRange-{tyDistinct}); expected.kind == tySet): expectedElementType = expected[0] if n.len == 0: rawAddSon(result.typ, if expectedElementType != nil and typeAllowed(expectedElementType, skLet, c) == nil: expectedElementType else: newTypeS(tyEmpty, c)) else: # only semantic checking for all elements, later type checking: var typ: PType = nil for i in 0.. MaxSetElements: message(c.config, n.info, warnAboveMaxSizeSet, "type '" & typeToString(typ, preferDesc) & "' is too big to be a `set` element, " & "assuming a range of 0.." & $(MaxSetElements - 1) & ", explicitly write this range to get rid of warning") typ = makeRangeType(c, 0, MaxSetElements-1, n.info) if expectedElementType == nil: expectedElementType = typ addSonSkipIntLit(result.typ, typ, c.idgen) for i in 0.. 0: # don't interpret () as type isTupleType = tupexp[0].typ.kind == tyTypeDesc # check if either everything or nothing is tyTypeDesc for i in 1.. 1 and isGeneric(c, n[1]): let b = n[0] if b.kind in nkSymChoices: for i in 0.. 1: break a = nextOverloadIter(o, c, n) let info = getCallLineInfo(n) if i <= 1: if sfGenSym notin s.flags: result = newSymNode(s, info) markUsed(c, info, s, efInCall notin flags) onUse(info, s) else: result = n else: result = newNodeIT(nkClosedSymChoice, info, newTypeS(tyNone, c)) a = initOverloadIter(o, c, n) while a != nil: if a.kind == skEnumField: incl(a.flags, sfUsed) markOwnerModuleAsUsed(c, a) result.add newSymNode(a, info) onUse(info, a) a = nextOverloadIter(o, c, n) proc semPragmaStmt(c: PContext; n: PNode) = if c.p.owner.kind == skModule: pragma(c, c.p.owner, n, stmtPragmas+stmtPragmasTopLevel, true) else: pragma(c, c.p.owner, n, stmtPragmas, true) proc resolveIdentToSym(c: PContext, n: PNode, resultNode: var PNode, flags: TExprFlags, expectedType: PType): PSym = # result is nil on error or if a node that can't produce a sym is resolved let ident = considerQuotedIdent(c, n) var filter = {low(TSymKind)..high(TSymKind)} if efNoEvaluateGeneric in flags or expectedType != nil: # `a[...]` where `a` is a module or package is not possible filter.excl {skModule, skPackage} let includePureEnum = expectedType != nil and expectedType.skipTypes(abstractRange-{tyDistinct}).kind == tyEnum let candidates = lookUpCandidates(c, ident, filter, includePureEnum = includePureEnum) if candidates.len == 0: result = errorUndeclaredIdentifierHint(c, ident, n.info) elif candidates.len == 1 or {efNoEvaluateGeneric, efInCall} * flags != {}: # unambiguous, or we don't care about ambiguity result = candidates[0] else: # ambiguous symbols have 1 last chance as a symchoice var choice = newNodeIT(nkClosedSymChoice, n.info, newTypeS(tyNone, c)) for cand in candidates: case cand.kind of skModule, skPackage: discard of skType: choice.add newSymNodeTypeDesc(cand, c.idgen, n.info) else: choice.add newSymNode(cand, n.info) if choice.len == 0: # we know candidates.len > 1, we just couldn't put any in a symchoice errorUseQualifier(c, n.info, candidates) return nil resolveSymChoice(c, choice, flags, expectedType) # choice.len == 1 can be true here but as long as it's a symchoice # it's still not resolved if isSymChoice(choice): result = nil if efAllowSymChoice in flags: resultNode = choice else: errorUseQualifier(c, n.info, candidates) else: if choice.kind == nkSym: result = choice.sym else: # resolution could have generated nkHiddenStdConv etc resultNode = semExpr(c, choice, flags, expectedType) result = nil proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode = when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind when false: # see `tdebugutils` if isCompilerDebug(): echo (">", c.config$n.info, n, flags, n.kind) defer: if isCompilerDebug(): echo ("<", c.config$n.info, n, ?.result.typ) template directLiteral(typeKind: TTypeKind) = if result.typ == nil: if expectedType != nil and ( let expected = expectedType.skipTypes(abstractRange-{tyDistinct}); expected.kind == typeKind): result.typ = expected changeType(c, result, expectedType, check=true) else: result.typ = getSysType(c.graph, n.info, typeKind) result = n when defined(nimsuggest): var expandStarted = false if c.config.ideCmd == ideExpand and not c.config.expandProgress and ((n.kind in {nkFuncDef, nkProcDef, nkIteratorDef, nkTemplateDef, nkMethodDef, nkConverterDef} and n.info.exactEquals(c.config.expandPosition)) or (n.kind in {nkCall, nkCommand} and n[0].info.exactEquals(c.config.expandPosition))): expandStarted = true c.config.expandProgress = true if c.config.expandLevels == 0: c.config.expandNodeResult = $n suggestQuit() if c.config.cmd == cmdIdeTools: suggestExpr(c, n) if nfSem in n.flags: return case n.kind of nkIdent, nkAccQuoted: let s = resolveIdentToSym(c, n, result, flags, expectedType) if s == nil: # resolveIdentToSym either errored or gave a result node return if c.matchedConcept == nil: semCaptureSym(s, c.p.owner) case s.kind of skProc, skFunc, skMethod, skConverter, skIterator: #performProcvarCheck(c, n, s) result = symChoice(c, n, s, scClosed) if result.kind == nkSym: markIndirect(c, result.sym) # if isGenericRoutine(result.sym): # localError(c.config, n.info, errInstantiateXExplicitly, s.name.s) # "procs literals" are 'owned' if optOwnedRefs in c.config.globalOptions: result.typ = makeVarType(c, result.typ, tyOwned) of skEnumField: result = enumFieldSymChoice(c, n, s, flags) else: result = semSym(c, n, s, flags) if isSymChoice(result): result = semSymChoice(c, result, flags, expectedType) of nkClosedSymChoice, nkOpenSymChoice: result = semSymChoice(c, n, flags, expectedType) of nkSym: let s = n.sym if nfDisabledOpenSym in n.flags: let override = genericsOpenSym in c.features let res = semOpenSym(c, n, flags, expectedType, warnDisabled = not override) if res != nil: assert override return res # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! result = semSym(c, n, s, flags) of nkOpenSym: assert n.len == 1 let inner = n[0] result = semOpenSym(c, inner, flags, expectedType) of nkEmpty, nkNone, nkCommentStmt, nkType: discard of nkNilLit: if result.typ == nil: result.typ = getNilType(c) if expectedType != nil and expectedType.kind notin {tyUntyped, tyTyped}: var m = newCandidate(c, result.typ) if typeRel(m, expectedType, result.typ) >= isSubtype: result.typ = expectedType # or: result = fitNode(c, expectedType, result, n.info) of nkIntLit: if result.typ == nil: if expectedType != nil and ( let expected = expectedType.skipTypes(abstractRange-{tyDistinct}); expected.kind in {tyInt..tyInt64, tyUInt..tyUInt64, tyFloat..tyFloat128}): if expected.kind in {tyFloat..tyFloat128}: n.transitionIntToFloatKind(nkFloatLit) changeType(c, result, expectedType, check=true) else: setIntLitType(c, result) of nkInt8Lit: directLiteral(tyInt8) of nkInt16Lit: directLiteral(tyInt16) of nkInt32Lit: directLiteral(tyInt32) of nkInt64Lit: directLiteral(tyInt64) of nkUIntLit: directLiteral(tyUInt) of nkUInt8Lit: directLiteral(tyUInt8) of nkUInt16Lit: directLiteral(tyUInt16) of nkUInt32Lit: directLiteral(tyUInt32) of nkUInt64Lit: directLiteral(tyUInt64) of nkFloatLit: if result.typ == nil: if expectedType != nil and ( let expected = expectedType.skipTypes(abstractRange-{tyDistinct}); expected.kind in {tyFloat..tyFloat128}): result.typ = expected changeType(c, result, expectedType, check=true) else: result.typ = getSysType(c.graph, n.info, tyFloat64) of nkFloat32Lit: directLiteral(tyFloat32) of nkFloat64Lit: directLiteral(tyFloat64) of nkFloat128Lit: directLiteral(tyFloat128) of nkStrLit..nkTripleStrLit: if result.typ == nil: if expectedType != nil and ( let expected = expectedType.skipTypes(abstractRange-{tyDistinct}); expected.kind in {tyString, tyCstring}): result.typ = expectedType else: result.typ = getSysType(c.graph, n.info, tyString) of nkCharLit: directLiteral(tyChar) of nkDotExpr: result = semFieldAccess(c, n, flags) if result.kind == nkDotCall: result.transitionSonsKind(nkCall) result = semExpr(c, result, flags, expectedType) of nkBind: message(c.config, n.info, warnDeprecated, "bind is deprecated") result = semExpr(c, n[0], flags, expectedType) of nkTypeOfExpr..nkTupleClassTy, nkStaticTy, nkRefTy..nkEnumTy: if c.matchedConcept != nil and n.len == 1: let modifier = n.modifierTypeKindOfNode if modifier != tyNone: var baseType = semExpr(c, n[0]).typ.skipTypes({tyTypeDesc}) result.typ = c.makeTypeDesc(newTypeS(modifier, c, baseType)) return var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc}) result.typ = makeTypeDesc(c, typ) of nkStmtListType: let typ = semTypeNode(c, n, nil) result.typ = makeTypeDesc(c, typ) of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1, c.config) #when defined(nimsuggest): # if gIdeCmd == ideCon and c.config.m.trackPos == n.info: suggestExprNoCheck(c, n) let mode = if nfDotField in n.flags: {} else: {checkUndeclared} c.isAmbiguous = false var s = qualifiedLookUp(c, n[0], mode) if s != nil: case s.kind of skMacro, skTemplate: result = semDirectOp(c, n, flags, expectedType) of skType: # XXX think about this more (``set`` procs) let ambig = c.isAmbiguous if not (n[0].kind in nkSymChoices + {nkIdent, nkDotExpr} and ambig) and n.len == 2: result = semConv(c, n, flags, expectedType) elif n.len == 1: if ambig: errorUseQualifier(c, n.info, s) else: result = semObjConstr(c, n, flags, expectedType) elif s.magic == mNone: result = semDirectOp(c, n, flags, expectedType) else: result = semMagic(c, n, s, flags, expectedType) of skProc, skFunc, skMethod, skConverter, skIterator: if s.magic == mNone: result = semDirectOp(c, n, flags, expectedType) else: result = semMagic(c, n, s, flags, expectedType) else: #liMessage(n.info, warnUser, renderTree(n)); result = semIndirectOp(c, n, flags, expectedType) elif isExplicitGenericCall(c, n): # this modifies `n` if true result = semDirectOp(c, n, flags, expectedType) elif nfDotField in n.flags: result = semDirectOp(c, n, flags, expectedType) elif isSymChoice(n[0]): let b = asBracketExpr(c, n) if b != nil: result = semExpr(c, b, flags, expectedType) else: result = semDirectOp(c, n, flags, expectedType) else: result = semIndirectOp(c, n, flags, expectedType) if nfDefaultRefsParam in result.flags: result = result.copyTree #XXX: Figure out what causes default param nodes to be shared.. (sigmatch bug?) # We've found a default value that references another param. # See the notes in `hoistParamsUsedInDefault` for more details. var hoistedParams = newNodeI(nkLetSection, result.info) for i in 1.. 2 + c.compilesContextId: localError(c.config, n.info, errXOnlyAtModuleScope % "import") result = evalImport(c, n) of nkImportExceptStmt: if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "import") result = evalImportExcept(c, n) of nkFromStmt: if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "from") result = evalFrom(c, n) of nkIncludeStmt: #if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "include") result = evalInclude(c, n) of nkExportStmt: if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export") result = semExport(c, n) of nkExportExceptStmt: if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export") result = semExportExcept(c, n) of nkPragmaBlock: result = semPragmaBlock(c, n, expectedType) of nkStaticStmt: result = semStaticStmt(c, n) of nkDefer: if c.currentScope == c.topLevelScope: localError(c.config, n.info, "defer statement not supported at top level") openScope(c) n[0] = semExpr(c, n[0]) closeScope(c) if not n[0].typ.isEmptyType and not implicitlyDiscardable(n[0]): localError(c.config, n.info, "'defer' takes a 'void' expression") #localError(c.config, n.info, errGenerated, "'defer' not allowed in this context") of nkGotoState, nkState: if n.len != 1 and n.len != 2: illFormedAst(n, c.config) for i in 0.. 0 and n[0].kind == nkSym: c.p.localBindStmts.add n else: localError(c.config, n.info, "invalid context for 'bind' statement: " & renderTree(n, {renderNoComments})) else: localError(c.config, n.info, "invalid expression: " & renderTree(n, {renderNoComments})) if result != nil: incl(result.flags, nfSem) when defined(nimsuggest): if expandStarted: c.config.expandNodeResult = $result suggestQuit()