diff --git a/compiler/ast.nim b/compiler/ast.nim index a76a675240..a04fc0fdc6 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -87,11 +87,11 @@ proc unsealForTransform*(t: PType) {.inline.} = if t.state == Partial: loadType(t) if t.state == Sealed: t.state = Complete -proc owner*(s: PSym): PSym {.inline.} = +proc owner*(s: PSym): lent PSym {.inline.} = if s.state == Partial: loadSym(s) result = s.ownerFieldImpl -proc owner*(s: PType): PSym {.inline.} = +proc owner*(s: PType): lent PSym {.inline.} = if s.state == Partial: loadType(s) result = s.ownerFieldImpl @@ -114,7 +114,7 @@ proc `kind=`*(s: PSym, val: TSymKind) {.inline.} = if s.state == Partial: loadSym(s) s.kindImpl = val -proc gcUnsafetyReason*(s: PSym): PSym {.inline.} = +proc gcUnsafetyReason*(s: PSym): lent PSym {.inline.} = if s.state == Partial: loadSym(s) result = s.gcUnsafetyReasonImpl @@ -123,7 +123,7 @@ proc `gcUnsafetyReason=`*(s: PSym, val: PSym) {.inline.} = if s.state == Partial: loadSym(s) s.gcUnsafetyReasonImpl = val -proc transformedBody*(s: PSym): PNode {.inline.} = +proc transformedBody*(s: PSym): lent PNode {.inline.} = if s.state == Partial: loadSym(s) result = s.transformedBodyImpl @@ -133,7 +133,7 @@ proc `transformedBody=`*(s: PSym, val: PNode) {.inline.} = if s.state == Partial: loadSym(s) s.transformedBodyImpl = val -proc guard*(s: PSym): PSym {.inline.} = +proc guard*(s: PSym): lent PSym {.inline.} = if s.state == Partial: loadSym(s) result = s.guardImpl @@ -169,7 +169,7 @@ proc `magic=`*(s: PSym, val: TMagic) {.inline.} = if s.state == Partial: loadSym(s) s.magicImpl = val -proc typ*(s: PSym): PType {.inline.} = +proc typ*(s: PSym): lent PType {.inline.} = if s.state == Partial: loadSym(s) result = s.typImpl @@ -215,7 +215,7 @@ proc `flags=`*(s: PSym, val: TSymFlags) {.inline.} = if s.state == Partial: loadSym(s) s.flagsImpl = val -proc ast*(s: PSym): PNode {.inline.} = +proc ast*(s: PSym): lent PNode {.inline.} = if s.state == Partial: loadSym(s) result = s.astImpl @@ -263,7 +263,7 @@ proc `loc=`*(s: PSym, val: TLoc) {.inline.} = if s.state == Partial: loadSym(s) s.locImpl = val -proc annex*(s: PSym): PLib {.inline.} = +proc annex*(s: PSym): lent PLib {.inline.} = if s.state == Partial: loadSym(s) result = s.annexImpl @@ -282,7 +282,7 @@ when hasFFI: if s.state == Partial: loadSym(s) s.cnameImpl = val -proc constraint*(s: PSym): PNode {.inline.} = +proc constraint*(s: PSym): lent PNode {.inline.} = if s.state == Partial: loadSym(s) result = s.constraintImpl @@ -291,7 +291,7 @@ proc `constraint=`*(s: PSym, val: PNode) {.inline.} = if s.state == Partial: loadSym(s) s.constraintImpl = val -proc instantiatedFrom*(s: PSym): PSym {.inline.} = +proc instantiatedFrom*(s: PSym): lent PSym {.inline.} = if s.state == Partial: loadSym(s) result = s.instantiatedFromImpl @@ -367,7 +367,7 @@ proc `sons=`*(t: PType, val: sink TTypeSeq) {.inline.} = if t.state == Partial: loadType(t) t.sonsImpl = val -proc n*(t: PType): PNode {.inline.} = +proc n*(t: PType): lent PNode {.inline.} = if t.state == Partial: loadType(t) result = t.nImpl @@ -376,7 +376,7 @@ proc `n=`*(t: PType, val: PNode) {.inline.} = if t.state == Partial: loadType(t) t.nImpl = val -proc sym*(t: PType): PSym {.inline.} = +proc sym*(t: PType): lent PSym {.inline.} = if t.state == Partial: loadType(t) result = t.symImpl @@ -418,7 +418,7 @@ proc `loc=`*(t: PType, val: TLoc) {.inline.} = if t.state == Partial: loadType(t) t.locImpl = val -proc typeInst*(t: PType): PType {.inline.} = +proc typeInst*(t: PType): lent PType {.inline.} = if t.state == Partial: loadType(t) result = t.typeInstImpl @@ -447,7 +447,7 @@ proc excl*(t: PType; flags: set[TTypeFlag]) {.inline.} = if t.state == Partial: loadType(t) t.flagsImpl.excl(flags) -proc typ*(n: PNode): PType {.inline.} = +proc typ*(n: PNode): lent PType {.inline.} = result = n.typField if result == nil and nfLazyType in n.flags: result = n.sym.typ @@ -866,7 +866,7 @@ proc newIntNode*(kind: TNodeKind, intVal: Int128): PNode = result = newNode(kind) result.intVal = castToInt64(intVal) -proc lastSon*(n: PNode): PNode {.inline.} = n.sons[^1] +proc lastSon*(n: PNode): lent PNode {.inline.} = n.sons[^1] template setLastSon*(n: PNode, s: PNode) = n.sons[^1] = s template firstSon*(n: PNode): PNode = n.sons[0] @@ -888,29 +888,29 @@ proc last*(n: PType): PType {.inline.} = else: n.sonsImpl[^1] -proc elementType*(n: PType): PType {.inline.} = +proc elementType*(n: PType): lent PType {.inline.} = if n.state == Partial: loadType(n) - n.sonsImpl[^1] + result = n.sonsImpl[^1] -proc skipModifier*(n: PType): PType {.inline.} = +proc skipModifier*(n: PType): lent PType {.inline.} = if n.state == Partial: loadType(n) - n.sonsImpl[^1] + result = n.sonsImpl[^1] -proc indexType*(n: PType): PType {.inline.} = +proc indexType*(n: PType): lent PType {.inline.} = if n.state == Partial: loadType(n) - n.sonsImpl[0] + result = n.sonsImpl[0] -proc baseClass*(n: PType): PType {.inline.} = +proc baseClass*(n: PType): lent PType {.inline.} = if n.state == Partial: loadType(n) - n.sonsImpl[0] + result = n.sonsImpl[0] -proc base*(t: PType): PType {.inline.} = +proc base*(t: PType): lent PType {.inline.} = if t.state == Partial: loadType(t) result = t.sonsImpl[0] -proc returnType*(n: PType): PType {.inline.} = +proc returnType*(n: PType): lent PType {.inline.} = if n.state == Partial: loadType(n) - n.sonsImpl[0] + result = n.sonsImpl[0] proc setReturnType*(n, r: PType) {.inline.} = if n.state == Partial: loadType(n) @@ -927,17 +927,17 @@ proc firstParamType*(n: PType): PType {.inline.} = else: n.sonsImpl[1] -proc firstGenericParam*(n: PType): PType {.inline.} = +proc firstGenericParam*(n: PType): lent PType {.inline.} = if n.state == Partial: loadType(n) - n.sonsImpl[1] + result = n.sonsImpl[1] -proc typeBodyImpl*(n: PType): PType {.inline.} = +proc typeBodyImpl*(n: PType): lent PType {.inline.} = if n.state == Partial: loadType(n) - n.sonsImpl[^1] + result = n.sonsImpl[^1] -proc genericHead*(n: PType): PType {.inline.} = +proc genericHead*(n: PType): lent PType {.inline.} = if n.state == Partial: loadType(n) - n.sonsImpl[0] + result = n.sonsImpl[0] proc skipTypes*(t: PType, kinds: TTypeKinds): PType = ## Used throughout the compiler code to test whether a type tree contains or diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index baa852b9e0..1851e7895f 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -529,8 +529,11 @@ proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool = type TIdentIter* = object # iterator over all syms with same identifier h*: Hash # current hash - name*: PIdent + name* {.cursor.}: PIdent +# String tables are always initialized with non-empty, power-of-two storage, +# and every probe is masked by `high(tab.data)`. +{.push boundChecks: off.} proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym = # hot spots var h = ti.h and high(tab.data) @@ -548,6 +551,7 @@ proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym = else: result = nil ti.h = nextTry(h, high(tab.data)) +{.pop.} proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym = ti.h = s.h diff --git a/compiler/astdef.nim b/compiler/astdef.nim index eb0e49da64..23fee12baf 100644 --- a/compiler/astdef.nim +++ b/compiler/astdef.nim @@ -1105,8 +1105,11 @@ const # for all kind of hash tables: GrowthFactor* = 2 # must be power of 2, > 0 StartSize* = 8 # must be power of 2, > 0 +{.push overflowChecks: off.} proc nextTry*(h, maxHash: Hash): Hash {.inline.} = + # Overflow is intentional: only the low bits selected by maxHash are used. result = ((5 * h) + 1) and maxHash +{.pop.} # For any initial h in range(maxHash), repeating that maxHash times # generates each int in range(maxHash) exactly once (see any text on # random-number generation for proof). diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 5117c3db0c..89e8911975 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -306,7 +306,7 @@ proc getGenSym*(c: PContext; s: PSym): PSym = it = it.next result = s -proc considerGenSyms*(c: PContext; n: PNode) = +proc considerGenSymsAux(c: PContext; n: PNode) = if n == nil: discard "can happen for nkFormalParams/nkArgList" elif n.kind == nkSym: @@ -315,7 +315,16 @@ proc considerGenSyms*(c: PContext; n: PNode) = n.sym = s else: for i in 0.. 1: + it = it.nImpl[^1].sym.typ + else: + it = it.sonsImpl[^1] + + var aOrig {.cursor.} = aOrig + if useTypeLoweringRuleInTypeClass: + skipTypeCursor(aOrig, {tyTypeDesc}) if aOrig.kind == tyInferred: let prev = aOrig.previouslyInferred @@ -1289,8 +1287,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, template doBind: bool = trDontBind notin flags # var, sink and static arguments match regular modifier-free types - var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyLent, tySink}), c.calleeSym) - # XXX: Theoretically, maybeSkipDistinct could be called before we even + var a {.cursor.} = aOrig + skipTypeCursor(a, {tyStatic, tyVar, tyLent, tySink}) + # Keep this expanded: an expression template materializes a PType temporary + # here, adding an otherwise avoidable reference-counting pair. + if a.kind == tyDistinct and a.n != nil and + shouldSkipDistinct(c, a.n, c.calleeSym.name): + a = a.base + # XXX: Theoretically, distinct types could be skipped before we even # start the param matching process. This could be done in `prepareOperand` # for example, but unfortunately `prepareOperand` is not called in certain # situation when nkDotExpr are rotated to nkDotCalls @@ -2448,11 +2452,13 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, argSemantized, argOrig: PNode): PNode = result = nil var - fMaybeStatic = f.skipTypes({tyDistinct}) arg = argSemantized a = a c = m.c - if tfHasStatic in fMaybeStatic.flags: + let hasStatic = tfHasStatic in f.flags or + (f.kind == tyDistinct and tfHasStatic in f.skipTypes({tyDistinct}).flags) + if hasStatic: + let fMaybeStatic = if f.kind == tyDistinct: f.skipTypes({tyDistinct}) else: f # XXX: When implicit statics are the default # this will be done earlier - we just have to # make sure that static types enter here diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index 93c55498e8..039bf7a912 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -56,11 +56,14 @@ proc mustRehash[T](t: T): bool {.inline.} = assert length > t.counter result = (length * 2 < t.counter * 3) or (length - t.counter < 4) +{.push overflowChecks: off.} proc nextTry(h, maxHash: Hash, perturb: var Hash): Hash {.inline.} = const PERTURB_SHIFT = 5 var perturb2 = cast[uint](perturb) shr PERTURB_SHIFT perturb = cast[Hash](perturb2) + # Overflow is intentional: only the low bits selected by maxHash are used. result = ((5 * h) + 1 + perturb) and maxHash +{.pop.} proc packedSetGet[A](t: PackedSet[A], key: int): Trunk = var h = key and t.max