diff --git a/compiler/ast.nim b/compiler/ast.nim index 860bf67e80..be11e80be2 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -477,6 +477,8 @@ type # wildcard type. tfHasAsgn # type has overloaded assignment operator tfBorrowDot # distinct type borrows '.' + tfTriggersCompileTime # uses the NimNode type which make the proc + # implicitly '.compiletime' TTypeFlags* = set[TTypeFlag] @@ -1380,6 +1382,9 @@ proc propagateToOwner*(owner, elem: PType) = o2.flags.incl tfHasAsgn owner.flags.incl tfHasAsgn + if tfTriggersCompileTime in elem.flags: + owner.flags.incl tfTriggersCompileTime + if owner.kind notin {tyProc, tyGenericInst, tyGenericBody, tyGenericInvocation, tyPtr}: let elemB = elem.skipTypes({tyGenericInst}) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 54063229fd..32fc76470b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1741,6 +1741,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mEcho: genEcho(p, e[1].skipConv) of mArrToSeq: genArrToSeq(p, e, d) of mNLen..mNError, mSlurp..mQuoteAst: + echo "from here ", p.prc.name.s, " ", p.prc.info + writestacktrace() localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s) of mSpawn: let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil) @@ -1973,6 +1975,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genProc(p.module, sym) putLocIntoDest(p, d, sym.loc) of skProc, skConverter, skIterators: + if sfCompileTime in sym.flags: + localError(n.info, "request to generate code for .compileTime proc: " & + sym.name.s) genProc(p.module, sym) if sym.loc.r == nil or sym.loc.t == nil: internalError(n.info, "expr: proc not init " & sym.name.s) @@ -2126,7 +2131,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = # due to a bug/limitation in the lambda lifting, unused inner procs # are not transformed correctly. We work around this issue (#411) here # by ensuring it's no inner proc (owner is a module): - if prc.skipGenericOwner.kind == skModule: + if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags: if (optDeadCodeElim notin gGlobalOptions and sfDeadCodeElim notin getModule(prc).flags) or ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3f88e63ee4..f63134b66b 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1110,7 +1110,7 @@ proc rawNewModule(module: PSym, filename: string): BModule = proc nullify[T](arr: var T) = for i in low(arr)..high(arr): - arr[i] = nil + arr[i] = Rope(nil) proc resetModule*(m: BModule) = # between two compilations in CAAS mode, we can throw diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 31bd85a067..60e8f28262 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -92,3 +92,4 @@ proc initDefines*() = defineSymbol("nimvarargstyped") defineSymbol("nimtypedescfixed") defineSymbol("nimKnowsNimvm") + defineSymbol("nimArrIdx") diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 8b3b11f4a7..c5bc44664c 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -514,6 +514,7 @@ const {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit, warnProveField, warnProveIndex, warnGcUnsafe, + hintPath, hintConf, hintDependency, hintExecuting, hintCodeBegin, hintCodeEnd, diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 2f181b5f37..f9fadeec75 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -308,7 +308,10 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = let gp = finalCallee.ast.sons[genericParamsPos] if gp.kind != nkEmpty: if x.calleeSym.kind notin {skMacro, skTemplate}: - finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info) + if x.calleeSym.magic in {mArrGet, mArrPut}: + finalCallee = x.calleeSym + else: + finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info) else: # For macros and templates, the resolved generic params # are added as normal params. diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 345a8c0d13..e6456293cd 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -45,7 +45,8 @@ type TExprFlag* = enum efLValue, efWantIterator, efInTypeof, efWantStmt, efAllowStmt, efDetermineType, - efAllowDestructor, efWantValue, efOperand, efNoSemCheck + efAllowDestructor, efWantValue, efOperand, efNoSemCheck, + efNoProcvarCheck TExprFlags* = set[TExprFlag] TTypeAttachedOp* = enum diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 3ff04a4fc0..0e1d52fd4c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -52,7 +52,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result.typ = errorType(c) else: # XXX tyGenericInst here? - semProcvarCheck(c, result) + if efNoProcvarCheck notin flags: semProcvarCheck(c, result) if result.typ.kind == tyVar: result = newDeref(result) semDestructorCheck(c, result, flags) @@ -452,18 +452,18 @@ proc changeType(n: PNode, newType: PType, check: bool) = let tup = newType.skipTypes({tyGenericInst}) if tup.kind != tyTuple: if tup.kind == tyObject: return - internalError(n.info, "changeType: no tuple type for constructor") + globalError(n.info, "no tuple type for constructor") elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: # named tuple? for i in countup(0, sonsLen(n) - 1): var m = n.sons[i].sons[0] if m.kind != nkSym: - internalError(m.info, "changeType(): invalid tuple constr") + globalError(m.info, "invalid tuple constructor") return if tup.n != nil: var f = getSymFromList(tup.n, m.sym.name) if f == nil: - internalError(m.info, "changeType(): invalid identifier") + globalError(m.info, "unknown identifier: " & m.sym.name.s) return changeType(n.sons[i].sons[1], f.typ, check) else: @@ -1156,7 +1156,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result.add(x[0]) return checkMinSonsLen(n, 2) - n.sons[0] = semExprWithType(c, n.sons[0]) + n.sons[0] = semExprWithType(c, n.sons[0], {efNoProcvarCheck}) let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) case arr.kind of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, @@ -1196,7 +1196,17 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = localError(n.info, errIndexTypesDoNotMatch) result = n else: - c.p.bracketExpr = n.sons[0] + let s = if n.sons[0].kind == nkSym: n.sons[0].sym + elif n[0].kind in nkSymChoices: n.sons[0][0].sym + else: nil + if s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators: + # type parameters: partial generic specialization + n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) + result = explicitGenericInstantiation(c, n, s) + elif s != nil and s.kind == skType: + result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) + else: + c.p.bracketExpr = n.sons[0] proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = let oldBracketExpr = c.p.bracketExpr @@ -1250,7 +1260,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = template resultTypeIsInferrable(typ: PType): expr = typ.isMetaType and typ.kind != tyTypeDesc -proc semAsgn(c: PContext, n: PNode): PNode = +proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = checkSonsLen(n, 2) var a = n.sons[0] case a.kind @@ -1273,12 +1283,15 @@ proc semAsgn(c: PContext, n: PNode): PNode = # --> `[]=`(a, i, x) let oldBracketExpr = c.p.bracketExpr a = semSubscript(c, a, {efLValue}) - if a == nil: + if a == nil and mode != noOverloadedSubscript: result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=") add(result, n[1]) result = semExprNoType(c, result) c.p.bracketExpr = oldBracketExpr return result + elif a == nil: + localError(n.info, "could not resolve: " & $n[0]) + return n c.p.bracketExpr = oldBracketExpr of nkCurlyExpr: # a{i} = x --> `{}=`(a, i, x) @@ -1323,7 +1336,8 @@ proc semAsgn(c: PContext, n: PNode): PNode = typeMismatch(n, lhs.typ, rhs.typ) n.sons[1] = fitNode(c, le, rhs) - if tfHasAsgn in lhs.typ.flags and not lhsIsResult: + if tfHasAsgn in lhs.typ.flags and not lhsIsResult and + mode != noOverloadedAsgn: return overloadedAsgn(c, lhs, n.sons[1]) fixAbstractType(c, n) @@ -1715,6 +1729,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mTypeOf: checkSonsLen(n, 2) result = semTypeOf(c, n.sons[1]) + #of mArrGet: result = semArrGet(c, n, flags) + #of mArrPut: result = semArrPut(c, n, flags) + #of mAsgn: result = semAsgnOpr(c, n) of mDefined: result = semDefined(c, setMs(n, s), false) of mDefinedInScope: result = semDefined(c, setMs(n, s), true) of mCompiles: result = semCompiles(c, setMs(n, s), flags) @@ -2066,6 +2083,19 @@ proc semExport(c: PContext, n: PNode): PNode = c.module.ast.add x result = n +proc shouldBeBracketExpr(n: PNode): bool = + assert n.kind in nkCallKinds + let a = n.sons[0] + if a.kind in nkCallKinds: + let b = a[0] + if b.kind in nkSymChoices: + for i in 0.. 2 and isNegative(n.sons[2])): localError(n.info, "use '^' instead of '-'; negative indexing is obsolete") of mRoof: - # error correction: - result = n.sons[1] - if c.p.bracketExpr.isNil: + let bracketExpr = if n.len == 3: n.sons[2] else: c.p.bracketExpr + if bracketExpr.isNil: localError(n.info, "no surrounding array access context for '^'") - elif c.p.bracketExpr.checkForSideEffects != seNoSideEffect: + result = n.sons[1] + elif bracketExpr.checkForSideEffects != seNoSideEffect: localError(n.info, "invalid context for '^' as '$#' has side effects" % - renderTree(c.p.bracketExpr)) - elif c.p.bracketExpr.typ.isStrangeArray: + renderTree(bracketExpr)) + result = n.sons[1] + elif bracketExpr.typ.isStrangeArray: localError(n.info, "invalid context for '^' as len!=high+1 for '$#'" % - renderTree(c.p.bracketExpr)) + renderTree(bracketExpr)) + result = n.sons[1] else: # ^x is rewritten to: len(a)-x let lenExpr = newNodeI(nkCall, n.info) lenExpr.add newIdentNode(getIdent"len", n.info) - lenExpr.add c.p.bracketExpr + lenExpr.add bracketExpr let lenExprB = semExprWithType(c, lenExpr) if lenExprB.typ.isNil or not isOrdinalType(lenExprB.typ): localError(n.info, "'$#' has to be of an ordinal type for '^'" % renderTree(lenExpr)) + result = n.sons[1] else: result = newNodeIT(nkCall, n.info, getSysType(tyInt)) result.add newSymNode(createMagic("-", mSubI), n.info) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4399c0ab05..f67ee2822a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1033,6 +1033,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T") incl(s.flags, sfUsed) of "=": + if s.magic == mAsgn: return incl(s.flags, sfUsed) let t = s.typ if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar: @@ -1131,6 +1132,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # semParamList(c, n.sons[ParamsPos], nil, s) else: s.typ = newProcType(c, n.info) + if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime) if n.sons[patternPos].kind != nkEmpty: n.sons[patternPos] = semPattern(c, n.sons[patternPos]) if s.kind in skIterators: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 371abe1e3d..fc1af72467 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -281,6 +281,35 @@ proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode = for i in 0.. < n.len: result.sons[i] = semTemplBody(c, n.sons[i]) +proc wrapInBind(c: var TemplCtx; n: PNode; opr: string): PNode = + let ident = getIdent(opr) + if ident.id in c.toInject: return n + + let s = searchInScopes(c.c, ident) + if s != nil: + var callee: PNode + if contains(c.toBind, s.id): + callee = symChoice(c.c, n, s, scClosed) + elif contains(c.toMixin, s.name.id): + callee = symChoice(c.c, n, s, scForceOpen) + elif s.owner == c.owner and sfGenSym in s.flags: + # template tmp[T](x: var seq[T]) = + # var yz: T + incl(s.flags, sfUsed) + callee = newSymNode(s, n.info) + styleCheckUse(n.info, s) + else: + callee = semTemplSymbol(c.c, n, s) + + let call = newNodeI(nkCall, n.info) + call.add(callee) + for i in 0 .. n.len-1: call.add(n[i]) + result = newNodeI(nkBind, n.info, 2) + result.sons[0] = n + result.sons[1] = call + else: + result = n + proc semTemplBody(c: var TemplCtx, n: PNode): PNode = result = n semIdeForTemplateOrGenericCheck(n, c.cursorInBody) @@ -423,6 +452,28 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = result.sons[1] = semTemplBody(c, n.sons[1]) of nkPragma: result = onlyReplaceParams(c, n) + of nkBracketExpr, nkCurlyExpr: + result = newNodeI(nkCall, n.info) + result.add newIdentNode(getIdent(if n.kind == nkBracketExpr:"[]" else:"{}"), + n.info) + for i in 0 ..< n.len: result.add(n[i]) + result = semTemplBodySons(c, result) + of nkAsgn, nkFastAsgn: + checkSonsLen(n, 2) + let a = n.sons[0] + let b = n.sons[1] + + let k = a.kind + case k + of nkBracketExpr, nkCurlyExpr: + result = newNodeI(nkCall, n.info) + result.add newIdentNode(getIdent(if k == nkBracketExpr:"[]=" else:"{}="), + n.info) + for i in 0 ..< a.len: result.add(a[i]) + result.add(b) + else: + result = n + result = semTemplBodySons(c, result) else: # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam', # so we use the generic code for nkDotExpr too diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 2ee17fcaf9..1cfbc368bb 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -718,12 +718,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, if paramType == nil: return # (e.g. proc return type) proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType = - let finalTypId = if typId != nil: typId - else: getIdent(paramName & ":type") if genericParams == nil: # This happens with anonymous proc types appearing in signatures # XXX: we need to lift these earlier return + let finalTypId = if typId != nil: typId + else: getIdent(paramName & ":type") # is this a bindOnce type class already present in the param list? for i in countup(0, genericParams.len - 1): if genericParams.sons[i].sym.name.id == finalTypId.id: @@ -757,7 +757,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, case paramType.kind: of tyAnything: - result = addImplicitGeneric(newTypeS(tyGenericParam, c)) + result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil) of tyStatic: # proc(a: expr{string}, b: expr{nkLambda}) @@ -868,6 +868,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyExpr: if procKind notin {skMacro, skTemplate}: result = addImplicitGeneric(newTypeS(tyAnything, c)) + #result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil) of tyGenericParam: markUsed(info, paramType.sym) @@ -977,7 +978,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, # compiler only checks for 'nil': if skipTypes(r, {tyGenericInst}).kind != tyEmpty: # 'auto' as a return type does not imply a generic: - if r.kind != tyExpr: + if r.kind == tyAnything: + # 'p(): auto' and 'p(): expr' are equivalent, but the rest of the + # compiler is hardly aware of 'auto': + r = newTypeS(tyExpr, c) + elif r.kind != tyExpr: if r.sym == nil or sfAnon notin r.sym.flags: let lifted = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info) @@ -1149,7 +1154,17 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = else: result = semAnonTuple(c, n, prev) of nkCallKinds: - if isRange(n): + 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..".} -proc wait*(a1: var cint): Pid {.importc, header: "".} +proc wait*(a1: ptr cint): Pid {.importc, discardable, header: "".} proc waitid*(a1: cint, a2: Id, a3: var SigInfo, a4: cint): cint {. importc, header: "".} proc waitpid*(a1: Pid, a2: var cint, a3: cint): Pid {. diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 141543c703..0ce5b4d25d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -533,6 +533,18 @@ proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {. var res = getSockOptInt(socket.fd, cint(level), toCInt(opt)) result = res != 0 +proc getLocalAddr*(socket: Socket): (string, Port) = + ## Get the socket's local address and port number. + ## + ## This is high-level interface for `getsockname`:idx:. + getLocalAddr(socket.fd, socket.domain) + +proc getPeerAddr*(socket: Socket): (string, Port) = + ## Get the socket's peer address and port number. + ## + ## This is high-level interface for `getpeername`:idx:. + getPeerAddr(socket.fd, socket.domain) + proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {. tags: [WriteIOEffect].} = ## Sets option ``opt`` to a boolean value specified by ``value``. diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim index 7873e7226a..f5860ef282 100644 --- a/lib/pure/rawsockets.nim +++ b/lib/pure/rawsockets.nim @@ -371,6 +371,76 @@ proc getSockName*(socket: SocketHandle): Port = raiseOSError(osLastError()) result = Port(rawsockets.ntohs(name.sin_port)) +proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = + ## returns the socket's local address and port number. + ## + ## Similar to POSIX's `getsockname`:idx:. + case domain + of AF_INET: + var name: Sockaddr_in + when useWinVersion: + name.sin_family = int16(ord(AF_INET)) + else: + name.sin_family = posix.AF_INET + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + result = ($inet_ntoa(name.sin_addr), Port(rawsockets.ntohs(name.sin_port))) + of AF_INET6: + var name: Sockaddr_in6 + when useWinVersion: + name.sin6_family = int16(ord(AF_INET6)) + else: + name.sin6_family = posix.AF_INET6 + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + # Cannot use INET6_ADDRSTRLEN here, because it's a C define. + var buf: array[64, char] + if inet_ntop(name.sin6_family.cint, + addr name, buf.cstring, sizeof(buf).int32).isNil: + raiseOSError(osLastError()) + result = ($buf, Port(rawsockets.ntohs(name.sin6_port))) + else: + raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") + +proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = + ## returns the socket's peer address and port number. + ## + ## Similar to POSIX's `getpeername`:idx: + case domain + of AF_INET: + var name: Sockaddr_in + when useWinVersion: + name.sin_family = int16(ord(AF_INET)) + else: + name.sin_family = posix.AF_INET + var namelen = sizeof(name).SockLen + if getpeername(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + result = ($inet_ntoa(name.sin_addr), Port(rawsockets.ntohs(name.sin_port))) + of AF_INET6: + var name: Sockaddr_in6 + when useWinVersion: + name.sin6_family = int16(ord(AF_INET6)) + else: + name.sin6_family = posix.AF_INET6 + var namelen = sizeof(name).SockLen + if getpeername(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + # Cannot use INET6_ADDRSTRLEN here, because it's a C define. + var buf: array[64, char] + if inet_ntop(name.sin6_family.cint, + addr name, buf.cstring, sizeof(buf).int32).isNil: + raiseOSError(osLastError()) + result = ($buf, Port(rawsockets.ntohs(name.sin6_port))) + else: + raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") + proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {. tags: [ReadIOEffect].} = ## getsockopt for integer options. diff --git a/lib/system.nim b/lib/system.nim index 1890ce5bef..8f529b8c0f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -78,7 +78,7 @@ type stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates) typedesc* {.magic: TypeDesc.} ## meta type to denote a type description void* {.magic: "VoidType".} ## meta type to denote the absence of any type - auto* = expr ## meta type for automatic type determination + auto* {.magic: Expr.} ## meta type for automatic type determination any* = distinct auto ## meta type for any supported type untyped* {.magic: Expr.} ## meta type to denote an expression that ## is not resolved (for templates) @@ -104,7 +104,7 @@ type SomeNumber* = SomeInteger|SomeReal ## type class matching all number types -proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.} +proc defined*(x: expr): bool {.magic: "Defined", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## defined. ## `x` is an external symbol introduced through the compiler's @@ -125,7 +125,7 @@ when defined(nimalias): TNumber: SomeNumber, TOrdinal: SomeOrdinal].} -proc declared*(x: expr): bool {.magic: "Defined", noSideEffect.} +proc declared*(x: expr): bool {.magic: "Defined", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## declared. `x` has to be an identifier or a qualified identifier. ## This can be used to check whether a library provides a certain @@ -140,11 +140,11 @@ when defined(useNimRtl): {.deadCodeElim: on.} proc definedInScope*(x: expr): bool {. - magic: "DefinedInScope", noSideEffect, deprecated.} + magic: "DefinedInScope", noSideEffect, deprecated, compileTime.} ## **Deprecated since version 0.9.6**: Use ``declaredInScope`` instead. proc declaredInScope*(x: expr): bool {. - magic: "DefinedInScope", noSideEffect.} + magic: "DefinedInScope", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## declared in the current scope. `x` has to be an identifier. @@ -160,7 +160,7 @@ proc unsafeAddr*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = ## Cannot be overloaded. discard -proc `type`*(x: expr): typeDesc {.magic: "TypeOf", noSideEffect.} = +proc `type`*(x: expr): typeDesc {.magic: "TypeOf", noSideEffect, compileTime.} = ## Builtin 'type' operator for accessing the type of an expression. ## Cannot be overloaded. discard @@ -239,6 +239,14 @@ type seq*{.magic: "Seq".}[T] ## Generic type to construct sequences. set*{.magic: "Set".}[T] ## Generic type to construct bit sets. +when defined(nimArrIdx): + # :array|openarray|string|seq|cstring|tuple + proc `[]`*[I: Ordinal;T](a: T; i: I): T {. + noSideEffect, magic: "ArrGet".} + proc `[]=`*[I: Ordinal;T,S](a: var T; i: I; + x: S) {.noSideEffect, magic: "ArrPut".} + proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} + type Slice*[T] = object ## builtin slice type a*, b*: T ## the bounds @@ -3384,7 +3392,7 @@ when hasAlloc: x[j+i] = item[j] inc(j) -proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} = +proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect, compileTime.} = ## Special compile-time procedure that checks whether `x` can be compiled ## without any semantic error. ## This can be used to check whether a type supports some operation: @@ -3448,7 +3456,7 @@ when hasAlloc and not defined(nimscript) and not defined(JS): include "system/deepcopy" -proc procCall*(x: expr) {.magic: "ProcCall".} = +proc procCall*(x: expr) {.magic: "ProcCall", compileTime.} = ## special magic to prohibit dynamic binding for `method`:idx: calls. ## This is similar to `super`:idx: in ordinary OO languages. ## @@ -3457,6 +3465,7 @@ proc procCall*(x: expr) {.magic: "ProcCall".} = ## procCall someMethod(a, b) discard +proc `^`*[T](x: int; y: openArray[T]): int {.noSideEffect, magic: "Roof".} proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} = ## builtin `roof`:idx: operator that can be used for convenient array access. ## ``a[^x]`` is rewritten to ``a[a.len-x]``. However currently the ``a`` diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 24015dd3a6..84dac6d798 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -409,7 +409,7 @@ type bytes*: array[0..15, char] Sockaddr_in6* {.importc: "SOCKADDR_IN6", - header: "winsock2.h".} = object + header: "ws2tcpip.h".} = object sin6_family*: int16 sin6_port*: int16 # unsigned sin6_flowinfo*: int32 # unsigned @@ -511,6 +511,9 @@ proc connect*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {. proc getsockname*(s: SocketHandle, name: ptr SockAddr, namelen: ptr SockLen): cint {. stdcall, importc: "getsockname", dynlib: ws2dll.} +proc getpeername*(s: SocketHandle, name: ptr SockAddr, + namelen: ptr SockLen): cint {. + stdcall, importc, dynlib: ws2dll.} proc getsockopt*(s: SocketHandle, level, optname: cint, optval: pointer, optlen: ptr SockLen): cint {. stdcall, importc: "getsockopt", dynlib: ws2dll.} @@ -572,6 +575,9 @@ proc freeaddrinfo*(ai: ptr AddrInfo) {. proc inet_ntoa*(i: InAddr): cstring {. stdcall, importc, dynlib: ws2dll.} +proc inet_ntop*(family: cint, paddr: pointer, pStringBuffer: cstring, + stringBufSize: int32): cstring {.stdcall, importc, dynlib: ws2dll.} + const MAXIMUM_WAIT_OBJECTS* = 0x00000040 diff --git a/tests/ccgbugs/tnocodegen_for_compiletime.nim b/tests/ccgbugs/tnocodegen_for_compiletime.nim new file mode 100644 index 0000000000..a88ba4b325 --- /dev/null +++ b/tests/ccgbugs/tnocodegen_for_compiletime.nim @@ -0,0 +1,9 @@ +# bug #1679 +import macros, tables, hashes +proc hash(v: NimNode): Hash = 4 # performance is for suckers +macro test(body: stmt): stmt {.immediate.} = + var a = initCountTable[NimNode]() + a.inc(body) + +test: + 1 + 1 diff --git a/tests/generics/mbind_bracket.nim b/tests/generics/mbind_bracket.nim new file mode 100644 index 0000000000..4bf18b471a --- /dev/null +++ b/tests/generics/mbind_bracket.nim @@ -0,0 +1,17 @@ + +import tables + +type + UUIDObject* = ref object + uuid: string + + Registry*[T] = ref object + objects: Table[string, T] + +proc newRegistry*[T](): Registry[T] = + result = Registry[T]() + result.objects = initTable[string, T](128) + +proc register*[T](self: Registry[T], obj: T) = + self.objects[obj.uuid] = obj + diff --git a/tests/generics/tbind_bracket.nim b/tests/generics/tbind_bracket.nim new file mode 100644 index 0000000000..d0c5e2c6b8 --- /dev/null +++ b/tests/generics/tbind_bracket.nim @@ -0,0 +1,20 @@ +discard """ + output: "317" +""" + +# bug #2599 + +import mbind_bracket + +# also test that `[]` can be passed now as a first class construct: + +template takeBracket(x, a, i: untyped) = + echo x(a, i) + +var a: array[10, int] +a[8] = 317 + +takeBracket(`[]`, a, 8) + +let reg = newRegistry[UUIDObject]() +reg.register(UUIDObject()) diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim index d34b24628e..e8946caf63 100644 --- a/tests/generics/tthread_generic.nim +++ b/tests/generics/tthread_generic.nim @@ -3,7 +3,7 @@ discard """ """ type - TThreadFuncArgs[T] = object of TObject + TThreadFuncArgs[T] = object of RootObj a: proc(): T {.thread.} b: proc(val: T) {.thread.} diff --git a/tests/metatype/ttypedesc1.nim b/tests/metatype/ttypedesc1.nim index 19072d9669..d78c62a94f 100644 --- a/tests/metatype/ttypedesc1.nim +++ b/tests/metatype/ttypedesc1.nim @@ -7,7 +7,7 @@ type proc getTypeName(t: typedesc): string = t.name -proc foo(T: typedesc[float], a: expr): string = +proc foo(T: typedesc[float], a: auto): string = result = "float " & $(a.len > 5) proc foo(T: typedesc[TFoo], a: int): string = diff --git a/tests/types/tauto_excessive.nim b/tests/types/tauto_excessive.nim new file mode 100644 index 0000000000..2626b0cf4f --- /dev/null +++ b/tests/types/tauto_excessive.nim @@ -0,0 +1,20 @@ +discard """ + output: '''10 +10.0 +1.0hiho''' +""" + +# bug #3224 +proc f(x: auto): auto = + result = $(x+10) + +proc f(x, y: auto): auto = + result = $(x+y) + + +echo f(0) # prints 10 +echo f(0.0) # prints 10.0 + +proc `+`(a, b: string): string = a & b + +echo f(0.7, 0.3), f("hi", "ho") diff --git a/todo.txt b/todo.txt index 91c6f16255..306b7008e4 100644 --- a/todo.txt +++ b/todo.txt @@ -24,7 +24,6 @@ version 1.0 - The bitwise 'not' operator will be renamed to 'bnot' to prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs! - split docgen into separate tool -- special rule for ``[]=``, items, pairs - BUG: echo with template `$`*(info: TLineInfo): expr = toFileLineCol(info) - make 'nil' work for 'add': - resizeString diff --git a/web/news.txt b/web/news.txt index 1a312f67b3..aaa27cfee1 100644 --- a/web/news.txt +++ b/web/news.txt @@ -3,7 +3,7 @@ News ==== .. - 2015-05-05 Version 0.11.4 released + 2015-09-14 Version 0.11.4 released ================================== Changes affecting backwards compatibility @@ -58,7 +58,7 @@ News of all the DLLs the standard library needs. This means that the following DLLs are now split into 32 and 64 versions: - * ``prce.dll``: Split into ``prce32.dll`` and ``prce64.dll``. + * ``pcre.dll``: Split into ``pcre32.dll`` and ``pcre64.dll``. * ``pdcurses.dll``: Split into ``pdcurses32.dll`` and ``pdcurses64.dll``. * ``sqlite3.dll``: Split into ``sqlite3_32.dll`` and ``sqlite3_64.dll``. * ``ssleay32.dll``: Split into ``ssleay32.dll`` and ``ssleay64.dll``. @@ -75,6 +75,13 @@ News with Unix's ``#!``. - An implicit return type for an iterator is now deprecated. Use ``auto`` if you want more type inference. + - The type ``auto`` is now a "multi-bind" metatype, so the following compiles: + + .. code-block:: nim + proc f(x, y: auto): auto = + result = $x & y + + echo f(0, "abc") Library Additions @@ -95,6 +102,9 @@ News - The compiler now supports a new configuration system based on `NimScript `_. + - The compiler finally considers symbol binding rules in templates and + generics for overloaded ``[]``, ``[]=``, ``{}``, ``{}=`` operators + (issue `#2599 `_). Language Additions @@ -112,22 +122,21 @@ News this ``let (x, y) == f()`` still needs to be used. - ``when nimvm`` can now be used for compiletime versions of some code sections. Click `here `_ for details. + - Usage of the type ``NimNode`` in a proc now implicitly annotates the proc + with ``.compileTime``. This means generics work much better for ``NimNode``. Bugfixes -------- - - Fixed "Compiler internal error on iterator it(T: typedesc[Base]) called with - it(Child), where Child = object of Base" + - Fixed "Compiler internal error on iterator it(T: typedesc[Base]) called with it(Child), where Child = object of Base" (`#2662 `_) - Fixed "repr() misses base object field in 2nd level derived object" (`#2749 `_) - Fixed "nimsuggest doesn't work more than once on the non-main file" (`#2694 `_) - - Fixed "JS Codegen. Passing arguments by var in certain cases leads to invali -d JS." + - Fixed "JS Codegen. Passing arguments by var in certain cases leads to invalid JS." (`#2798 `_) - - Fixed ""check" proc in unittest.nim prevents the propagation of changes to v -ar parameters." + - Fixed ""check" proc in unittest.nim prevents the propagation of changes to var parameters." (`#964 `_) - Fixed "Excessive letters in integer literals are not an error" (`#2523 `_) @@ -141,8 +150,7 @@ ar parameters." (`#2687 `_) - Fixed "Compile error using object in const array" (`#2774 `_) - - Fixed "httpclient async requests with method httpPOST isn't sending Content- -Length header" + - Fixed "httpclient async requests with method httpPOST isn't sending Content-Length header" (`#2884 `_) - Fixed "Streams module not working with JS backend" (`#2148 `_) @@ -173,8 +181,7 @@ Length header" (`#2974 `_) - Fixed "repr is broken" (`#2992 `_) - - Fixed "Ipv6 devel - add IPv6 support for asyncsockets, make AF_INET6 a defau -lt" + - Fixed "Ipv6 devel - add IPv6 support for asyncsockets, make AF_INET6 a default" (`#2976 `_) - Fixed "Compilation broken on windows" (`#2996 `_) @@ -184,8 +191,7 @@ lt" (`#2672 `_) - Fixed "Uncatched exception in async procedure on raise statement" (`#3014 `_) - - Fixed "nim doc2 fails in Mac OS X due to system.nim (possibly related to #18 -98)" + - Fixed "nim doc2 fails in Mac OS X due to system.nim (possibly related to #1898)" (`#3005 `_) - Fixed "IndexError when rebuilding Nim on iteration 2" (`#3018 `_) @@ -233,8 +239,7 @@ lt" (`#3054 `_) - Fixed "Wrong sharing of static_t instantations" (`#3112 `_) - - Fixed "Automatically generated proc conflicts with user-defined proc when .e -xportc.'ed" + - Fixed "Automatically generated proc conflicts with user-defined proc when .exportc.'ed" (`#3134 `_) - Fixed "getTypeInfo call crashes nim" (`#3099 `_) @@ -254,15 +259,13 @@ xportc.'ed" (`#3149 `_) - Fixed "Inference of `static[T]` in sequences" (`#3144 `_) - - Fixed "Argument named "closure" to proc inside template interfere with closu -re pragma" + - Fixed "Argument named "closure" to proc inside template interfere with closure pragma" (`#3171 `_) - Fixed "Internal error with aliasing inside template" (`#3158 `_) - Fixed "Cardinality of sets prints unexpected value" (`#3135 `_) - - Fixed "Nim crashes on const assignment from function returning var ref objec -t" + - Fixed "Nim crashes on const assignment from function returning var ref object" (`#3103 `_) - Fixed "`repr` cstring" (`#3080 `_) @@ -270,8 +273,7 @@ t" (`#3052 `_) - Fixed "Compiler assertion when evaluating template with static[T]" (`#1858 `_) - - Fixed "Erroneous overflow in iterators when compiler built with overflowChec -ks enabled" + - Fixed "Erroneous overflow in iterators when compiler built with overflowChecks enabled" (`#3140 `_) - Fixed "Unicode dashes as "lisp'ish" alternative to hump and snake notation" (`#2811 `_) @@ -283,8 +285,7 @@ ks enabled" (`#3193 `_) - Fixed "VM crash when accessing array's element" (`#3192 `_) - - Fixed "Unexpected proc invoked when different modules add procs to a type fr -om a 3rd module" + - Fixed "Unexpected proc invoked when different modules add procs to a type from a 3rd module" (`#2664 `_) - Fixed "Nim crashes on conditional declaration inside a template" (`#2670 `_) @@ -292,8 +293,7 @@ om a 3rd module" (`#2752 `_) - Fixed "VM: Cannot assign int value to ref variable" (`#1329 `_) - - Fixed "Incorrect code generated for tagged unions with enums not starting at - zero" + - Fixed "Incorrect code generated for tagged unions with enums not starting at zero" (`#3096 `_) - Fixed "Compile time procs using forward declarations are silently ignored" (`#3066 `_) @@ -301,8 +301,7 @@ om a 3rd module" (`#1965 `_) - Fixed "os.getCreationTime is incorrect/impossible on Posix systems" (`#1058 `_) - - Fixed "Improve error message for osproc.startProcess when command does not e -xist" + - Fixed "Improve error message for osproc.startProcess when command does not exist" (`#2183 `_) - Fixed "gctest segfaults with --gc:markandsweep on x86_64" (`#2305 `_)