diff options
-rw-r--r-- | compiler/semcall.nim | 79 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 279 | ||||
-rw-r--r-- | compiler/types.nim | 484 | ||||
-rw-r--r-- | tests/ccgbugs/tuple_canon.nim | 80 | ||||
-rw-r--r-- | tests/overload/tsymtabchange_during_or.nim | 24 |
5 files changed, 523 insertions, 423 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 718a87232..647e75b3a 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -41,48 +41,55 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, best, alt: var TCandidate, errors: var CandidateErrors) = var o: TOverloadIter - var sym = initOverloadIter(o, c, headSymbol) + # thanks to the lazy semchecking for operands, we need to iterate over the + # symbol table *before* any call to 'initCandidate' which might invoke + # semExpr which might modify the symbol table in cases like + # 'init(a, 1, (var b = new(Type2); b))'. + var symx = initOverloadIter(o, c, headSymbol) let symScope = o.lastOverloadScope - var z: TCandidate + var syms: seq[tuple[a: PSym, b: int]] = @[] + while symx != nil: + if symx.kind in filter: syms.add((symx, o.lastOverloadScope)) + symx = nextOverloadIter(o, c, headSymbol) + if syms.len == 0: return - if sym == nil: return - initCandidate(c, best, sym, initialBinding, symScope) - initCandidate(c, alt, sym, initialBinding, symScope) + var z: TCandidate + initCandidate(c, best, syms[0][0], initialBinding, symScope) + initCandidate(c, alt, syms[0][0], initialBinding, symScope) best.state = csNoMatch - while sym != nil: - if sym.kind in filter: - determineType(c, sym) - initCandidate(c, z, sym, initialBinding, o.lastOverloadScope) - z.calleeSym = sym - + for i in 0 .. <syms.len: + let sym = syms[i][0] + determineType(c, sym) + initCandidate(c, z, sym, initialBinding, syms[i][1]) + z.calleeSym = sym + + #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140: + # gDebug = true + matches(c, n, orig, z) + if errors != nil: + errors.safeAdd(sym) + if z.errors != nil: + for err in z.errors: + errors.add(err) + if z.state == csMatch: + # little hack so that iterators are preferred over everything else: + if sym.kind in skIterators: inc(z.exactMatches, 200) + case best.state + of csEmpty, csNoMatch: best = z + of csMatch: + var cmp = cmpCandidates(best, z) + if cmp < 0: best = z # x is better than the best so far + elif cmp == 0: alt = z # x is as good as the best so far + else: discard #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140: - # gDebug = true - matches(c, n, orig, z) - if errors != nil: - errors.safeAdd(sym) - if z.errors != nil: - for err in z.errors: - errors.add(err) - if z.state == csMatch: - # little hack so that iterators are preferred over everything else: - if sym.kind in skIterators: inc(z.exactMatches, 200) - case best.state - of csEmpty, csNoMatch: best = z - of csMatch: - var cmp = cmpCandidates(best, z) - if cmp < 0: best = z # x is better than the best so far - elif cmp == 0: alt = z # x is as good as the best so far - else: discard - #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140: - # echo "Matches ", n.info, " ", typeToString(sym.typ) - # debug sym - # writeMatches(z) - # for i in 1 .. <len(z.call): - # z.call[i].typ.debug - # quit 1 - sym = nextOverloadIter(o, c, headSymbol) + # echo "Matches ", n.info, " ", typeToString(sym.typ) + # debug sym + # writeMatches(z) + # for i in 1 .. <len(z.call): + # z.call[i].typ.debug + # quit 1 proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = # Gives a detailed error message; this is separated from semOverloadedCall, diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index a1b5c8dc9..f34bdd3da 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -10,7 +10,7 @@ ## This module implements the signature matching for resolving ## the call to overloaded procs, generic procs and operators. -import +import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees, nimfix.pretty @@ -19,7 +19,7 @@ when not defined(noDocgen): import docgen type - TCandidateState* = enum + TCandidateState* = enum csEmpty, csMatch, csNoMatch CandidateErrors* = seq[PSym] @@ -62,10 +62,10 @@ type isGeneric, isFromIntLit, # conversion *from* int literal; proven safe isEqual - + const isNilConversion = isConvertible # maybe 'isIntConv' fits better? - + proc markUsed*(info: TLineInfo, s: PSym) template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone @@ -128,7 +128,7 @@ proc newCandidate*(ctx: PContext, callee: PSym, proc newCandidate*(ctx: PContext, callee: PType): TCandidate = initCandidate(ctx, result, callee) -proc copyCandidate(a: var TCandidate, b: TCandidate) = +proc copyCandidate(a: var TCandidate, b: TCandidate) = a.c = b.c a.exactMatches = b.exactMatches a.subtypeMatches = b.subtypeMatches @@ -176,7 +176,7 @@ proc complexDisambiguation(a, b: PType): int = let bb = b.sons[1].sumGeneric var a = a var b = b - + if aa < bb: swap(a, b) # all must be better for i in 2 .. <min(a.len, b.len): @@ -203,7 +203,7 @@ proc cmpCandidates*(a, b: TCandidate): int = # prefer more specialized generic over more general generic: result = complexDisambiguation(a.callee, b.callee) -proc writeMatches*(c: TCandidate) = +proc writeMatches*(c: TCandidate) = writeln(stdout, "exact matches: " & $c.exactMatches) writeln(stdout, "generic matches: " & $c.genericMatches) writeln(stdout, "subtype matches: " & $c.subtypeMatches) @@ -225,7 +225,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1; result = "" for i in countup(startIdx, n.len - 1): var arg = n.sons[i] - if n.sons[i].kind == nkExprEqExpr: + if n.sons[i].kind == nkExprEqExpr: add(result, renderTree(n.sons[i].sons[0])) add(result, ": ") if arg.typ.isNil: @@ -241,9 +241,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1; if i != sonsLen(n) - 1: add(result, ", ") proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation -proc concreteType(c: TCandidate, t: PType): PType = +proc concreteType(c: TCandidate, t: PType): PType = case t.kind - of tyArrayConstr: + of tyArrayConstr: # make it an array result = newType(tyArray, t.owner) addSonSkipIntLit(result, t.sons[0]) # XXX: t.owner is wrong for ID! @@ -255,7 +255,7 @@ proc concreteType(c: TCandidate, t: PType): PType = else: result = t of tyGenericParam, tyAnything: result = t - while true: + while true: result = PType(idTableGet(c.bindings, t)) if result == nil: break # it's ok, no match @@ -267,15 +267,15 @@ proc concreteType(c: TCandidate, t: PType): PType = result = t else: result = t # Note: empty is valid here - -proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = - if a.kind == f.kind: + +proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = + if a.kind == f.kind: result = isEqual else: let ab = skipTypes(a, {tyRange}) let k = ab.kind if k == f.kind: result = isSubrange - elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64, + elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64, tyUInt..tyUInt64} and isIntLit(ab) and ab.n.intVal >= firstOrd(f) and ab.n.intVal <= lastOrd(f): @@ -286,7 +286,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = result = isIntConv elif k >= min and k <= max: result = isConvertible - elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64, + elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64, tyUInt8..tyUInt32} and a.n[0].intVal >= firstOrd(f) and a.n[1].intVal <= lastOrd(f): @@ -318,12 +318,12 @@ proc handleFloatRange(f, a: PType): TTypeRelation = if f.kind == tyFloat32: result = isConvertible else: result = isIntConv else: result = isNone - + proc isObjectSubtype(a, f: PType): int = var t = a assert t.kind == tyObject var depth = 0 - while t != nil and not sameObjectTypes(f, t): + while t != nil and not sameObjectTypes(f, t): assert t.kind == tyObject t = t.sons[0] if t == nil: break @@ -332,17 +332,17 @@ proc isObjectSubtype(a, f: PType): int = if t != nil: result = depth -proc minRel(a, b: TTypeRelation): TTypeRelation = +proc minRel(a, b: TTypeRelation): TTypeRelation = if a <= b: result = a else: result = b - + proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation = result = isNone if sameType(f, a): result = isEqual elif sonsLen(a) == sonsLen(f): result = isEqual let firstField = if f.kind == tyTuple: 0 - else: 1 + else: 1 for i in countup(firstField, sonsLen(f) - 1): var m = typeRel(c, f.sons[i], a.sons[i]) if m < isSubtype: return isNone @@ -373,7 +373,7 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = # We are matching a generic proc (as proc param) # to another generic type appearing in the proc # signature. There is a change that the target - # type is already fully-determined, so we are + # type is already fully-determined, so we are # going to try resolve it f = generateTypeInstance(c.c, c.bindings, c.call.info, f) if f == nil or f.isMetaType: @@ -388,17 +388,17 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = if result <= isSubtype or inconsistentVarTypes(f, a): result = isNone - + if result == isEqual: inc c.exactMatches - + proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = case a.kind of tyProc: if sonsLen(f) != sonsLen(a): return result = isEqual # start with maximum; also correct for no # params at all - + template checkParam(f, a) = result = minRel(result, procParamTypeRel(c, f, a)) if result == isNone: return @@ -407,7 +407,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = # return type! for i in 1 .. <f.sonsLen: checkParam(f.sons[i], a.sons[i]) - + if f.sons[0] != nil: if a.sons[0] != nil: checkParam(f.sons[0], a.sons[0]) @@ -487,14 +487,14 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, else: param = paramSym skType param.typ = makeTypeDesc(c, typ) - + addDecl(c, param) for param in body.n[0]: var dummyName: PNode dummyType: PType - + if param.kind == nkVarTy: dummyName = param[0] dummyType = if a.kind != tyVar: makeVarType(c, a) @@ -520,7 +520,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, of nkTypeSection: discard of nkConstDef: discard else: discard - + return isGeneric proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool = @@ -554,7 +554,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # typeRel can be used to establish various relationships between types: # # 1) When used with concrete types, it will check for type equivalence - # or a subtype relationship. + # or a subtype relationship. # # 2) When used with a concrete type against a type class (such as generic # signature of a proc), it will check whether the concrete type is a member @@ -569,7 +569,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isNone assert(f != nil) - + if f.kind == tyExpr: if aOrig != nil: put(c.bindings, f, aOrig) return isGeneric @@ -582,7 +582,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # 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 - + if a.kind == tyGenericInst and skipTypes(f, {tyVar}).kind notin { tyGenericBody, tyGenericInvocation, @@ -626,9 +626,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # seq[!int] vs seq[!number] # seq[float] matches the first, but not the second # we must turn the problem around: - # is number a subset of int? + # is number a subset of int? return typeRel(c, a.lastSon, f.lastSon) - + else: # negative type classes are essentially infinite, # so only the `any` type class is their superset @@ -727,20 +727,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyOpenArray, tyVarargs: result = typeRel(c, base(f), base(a)) if result < isGeneric: result = isNone - of tyArrayConstr: - if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): + of tyArrayConstr: + if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): result = isSubtype # [] is allowed here - elif typeRel(c, base(f), a.sons[1]) >= isGeneric: + elif typeRel(c, base(f), a.sons[1]) >= isGeneric: result = isSubtype - of tyArray: - if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): + of tyArray: + if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): result = isSubtype - elif typeRel(c, base(f), a.sons[1]) >= isGeneric: + elif typeRel(c, base(f), a.sons[1]) >= isGeneric: result = isConvertible - of tySequence: - if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): + of tySequence: + if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): result = isConvertible - elif typeRel(c, base(f), a.sons[0]) >= isGeneric: + elif typeRel(c, base(f), a.sons[0]) >= isGeneric: result = isConvertible else: discard of tySequence: @@ -768,7 +768,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyForward: internalError("forward type in typeRel()") of tyNil: if a.kind == f.kind: result = isEqual - of tyTuple: + of tyTuple: if a.kind == tyTuple: result = recordRel(c, f, a) of tyObject: if a.kind == tyObject: @@ -783,13 +783,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyDistinct: if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual elif c.coerceDistincts: result = typeRel(c, f.base, a) - of tySet: - if a.kind == tySet: - if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): + of tySet: + if a.kind == tySet: + if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): result = isSubtype - else: + else: result = typeRel(c, f.sons[0], a.sons[0]) - if result <= isConvertible: + if result <= isConvertible: result = isNone # BUGFIX! of tyPtr, tyRef: if a.kind == f.kind: @@ -823,9 +823,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if a.len == 1: result = isConvertible of tyCString: result = isConvertible else: discard - of tyString: + of tyString: case a.kind - of tyString: + of tyString: if tfNotNil in f.flags and tfNotNil notin a.flags: result = isNilConversion else: @@ -848,7 +848,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyArray: if (firstOrd(a.sons[0]) == 0) and (skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and - (a.sons[1].kind == tyChar): + (a.sons[1].kind == tyChar): result = isConvertible else: discard @@ -863,7 +863,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = let ff = rootf.sons[i] let aa = roota.sons[i] result = typeRel(c, ff, aa) - if result == isNone: return + if result == isNone: return if ff.kind == tyRange and result != isEqual: return isNone result = isGeneric # XXX See bug #2220. A[int] should match A[int] better than some generic X @@ -883,13 +883,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation") # simply no match for now: discard - elif x.kind == tyGenericInst and + elif x.kind == tyGenericInst and (f.sons[0] == x.sons[0]) and (sonsLen(x) - 1 == sonsLen(f)): for i in countup(1, sonsLen(f) - 1): if x.sons[i].kind == tyGenericParam: internalError("wrong instantiated type!") - elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return + elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return result = isGeneric else: result = typeRel(c, f.sons[0], x) @@ -900,7 +900,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}: internalError("wrong instantiated type!") put(c.bindings, f.sons[i], x) - + of tyAnd: considerPreviousT: for branch in f.sons: @@ -914,7 +914,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = for branch in f.sons: if typeRel(c, branch, aOrig) >= isSubtype: bindingRet isGeneric - + return isNone of tyNot: @@ -922,7 +922,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = for branch in f.sons: if typeRel(c, branch, aOrig) != isNone: return isNone - + bindingRet isGeneric of tyAnything: @@ -961,7 +961,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if x == nil: if c.callee.kind == tyGenericBody and f.kind == tyGenericParam and not c.typedescMatched: - # XXX: The fact that generic types currently use tyGenericParam for + # XXX: The fact that generic types currently use tyGenericParam for # their parameters is really a misnomer. tyGenericParam means "match # any value" and what we need is "match any type", which can be encoded # by a tyTypeDesc params. Unfortunately, this requires more substantial @@ -1004,7 +1004,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isGeneric else: result = typeRel(c, x, a) # check if it fits - + of tyStatic: let prev = PType(idTableGet(c.bindings, f)) if prev == nil: @@ -1034,12 +1034,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # when `f` is an unresolved typedesc, `a` could be any # type, so we should not perform this check earlier if a.kind != tyTypeDesc: return isNone - + if f.base.kind == tyNone: result = isGeneric else: result = typeRel(c, f.base, a.base) - + if result != isNone: put(c.bindings, f, a) else: @@ -1049,9 +1049,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = typeRel(c, prev.base, a.base) else: result = isNone - + of tyIter: - if a.kind == tyIter or + if a.kind == tyIter or (a.kind == tyProc and tfIterator in a.flags): result = typeRel(c, f.base, a.base) else: @@ -1059,7 +1059,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyStmt: result = isGeneric - + of tyProxy: result = isEqual @@ -1078,11 +1078,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = else: localError(f.n.info, errTypeExpected) result = isNone - + else: internalAssert false - -proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = + +proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = var m: TCandidate initCandidate(c, m, f) result = typeRel(m, f, a) @@ -1095,9 +1095,9 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, if result == nil: internalError(arg.info, "getInstantiatedType") result = errorType(c) - -proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, - c: PContext): PNode = + +proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, + c: PContext): PNode = result = newNodeI(kind, arg.info) if containsGenericType(f): if not m.hasFauxMatch: @@ -1110,10 +1110,10 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, addSon(result, ast.emptyNode) addSon(result, arg) -proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, - arg: PNode): PNode = +proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, + arg: PNode): PNode = result = nil - for i in countup(0, len(c.converters) - 1): + for i in countup(0, len(c.converters) - 1): var src = c.converters[i].typ.sons[1] var dest = c.converters[i].typ.sons[0] # for generic type converters we need to check 'src <- a' before @@ -1121,12 +1121,12 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, # see tests/tgenericconverter: let srca = typeRel(m, src, a) if srca notin {isEqual, isGeneric}: continue - + let destIsGeneric = containsGenericType(dest) if destIsGeneric: dest = generateTypeInstance(c, m.bindings, arg, dest) let fdest = typeRel(m, f, dest) - if fdest in {isEqual, isGeneric}: + if fdest in {isEqual, isGeneric}: markUsed(arg.info, c.converters[i]) var s = newSymNode(c.converters[i]) s.typ = c.converters[i].typ @@ -1138,8 +1138,8 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, m.genericConverter = srca == isGeneric or destIsGeneric return result -proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, - arg: PNode): PNode = +proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, + arg: PNode): PNode = # arg.typ can be nil in 'suggest': if isNil(arg.typ): return nil @@ -1181,12 +1181,12 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, arg = argSemantized argType = argType c = m.c - + if tfHasStatic in fMaybeStatic.flags: # XXX: When implicit statics are the default # this will be done earlier - we just have to # make sure that static types enter here - + # XXX: weaken tyGenericParam and call it tyGenericPlaceholder # and finally start using tyTypedesc for generic types properly. if argType.kind == tyGenericParam and tfWildcard in argType.flags: @@ -1205,11 +1205,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, arg.typ.sons = @[evaluated.typ] arg.typ.n = evaluated argType = arg.typ - + var a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor}) else: argType - + r = typeRel(m, f, a) if r != isNone and m.calleeSym != nil and @@ -1244,19 +1244,18 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, case r of isConvertible: inc(m.convMatches) - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + result = implicitConv(nkHiddenStdConv, f, arg, m, c) of isIntConv: # I'm too lazy to introduce another ``*matches`` field, so we conflate # ``isIntConv`` and ``isIntLit`` here: inc(m.intConvMatches) - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) - of isSubtype: + result = implicitConv(nkHiddenStdConv, f, arg, m, c) + of isSubtype: inc(m.subtypeMatches) - result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c) + result = implicitConv(nkHiddenSubConv, f, arg, m, c) of isSubrange: inc(m.subtypeMatches) - #result = copyTree(arg) - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + result = implicitConv(nkHiddenStdConv, f, arg, m, c) of isInferred, isInferredConvertible: inc(m.genericMatches) if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds: @@ -1269,42 +1268,32 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, result = implicitConv(nkHiddenStdConv, f, result, m, c) of isGeneric: inc(m.genericMatches) - when true: - if arg.typ == nil: - result = arg - elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple: - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) - elif arg.typ.isEmptyContainer: - result = arg.copyTree - result.typ = getInstantiatedType(c, arg, m, f) - else: - result = arg - else: - # XXX Why is this ever necessary? arg's type should not be retrofitted - # to match formal's type in this way! - result = copyTree(arg) + if arg.typ == nil: + result = arg + elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple: + result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + elif arg.typ.isEmptyContainer: + result = arg.copyTree result.typ = getInstantiatedType(c, arg, m, f) - # BUG: f may not be the right key! - if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}: - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) - # BUGFIX: use ``result.typ`` and not `f` here + else: + result = arg of isFromIntLit: # too lazy to introduce another ``*matches`` field, so we conflate # ``isIntConv`` and ``isIntLit`` here: inc(m.intConvMatches, 256) - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) - of isEqual: + result = implicitConv(nkHiddenStdConv, f, arg, m, c) + of isEqual: inc(m.exactMatches) - result = copyTree(arg) + result = arg if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}: - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + result = implicitConv(nkHiddenStdConv, f, arg, m, c) of isNone: # do not do this in ``typeRel`` as it then can't infere T in ``ref T``: if a.kind in {tyProxy, tyUnknown}: inc(m.genericMatches) m.fauxMatch = a.kind - return copyTree(arg) - result = userConvMatch(c, m, f, a, arg) + return arg + result = userConvMatch(c, m, f, a, arg) # check for a base type match, which supports varargs[T] without [] # constructor in a call: if result == nil and f.kind == tyVarargs: @@ -1325,7 +1314,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, arg, argOrig: PNode): PNode = if arg == nil or arg.kind notin nkSymChoices: result = paramTypesMatchAux(m, f, a, arg, argOrig) - else: + else: # CAUTION: The order depends on the used hashing scheme. Thus it is # incorrect to simply use the first fitting match. However, to implement # this correctly is inefficient. We have to copy `m` here to be able to @@ -1339,28 +1328,28 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, y.calleeSym = m.calleeSym z.calleeSym = m.calleeSym var best = -1 - for i in countup(0, sonsLen(arg) - 1): + for i in countup(0, sonsLen(arg) - 1): if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators: copyCandidate(z, m) var r = typeRel(z, f, arg.sons[i].typ) - if r != isNone: + if r != isNone: case x.state - of csEmpty, csNoMatch: + of csEmpty, csNoMatch: x = z best = i x.state = csMatch - of csMatch: + of csMatch: var cmp = cmpCandidates(x, z) if cmp < 0: best = i x = z elif cmp == 0: y = z # z is as good as x - if x.state == csEmpty: + if x.state == csEmpty: result = nil - elif y.state == csMatch and cmpCandidates(x, y) == 0: - if x.state != csMatch: - internalError(arg.info, "x.state is not csMatch") + elif y.state == csMatch and cmpCandidates(x, y) == 0: + if x.state != csMatch: + internalError(arg.info, "x.state is not csMatch") # ambiguous: more than one symbol fits! # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match # anyway: @@ -1373,7 +1362,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], argOrig) -proc setSon(father: PNode, at: int, son: PNode) = +proc setSon(father: PNode, at: int, son: PNode) = if sonsLen(father) <= at: setLen(father.sons, at + 1) father.sons[at] = son @@ -1417,7 +1406,7 @@ proc incrIndexType(t: PType) = inc t.sons[0].n.sons[1].intVal proc matchesAux(c: PContext, n, nOrig: PNode, - m: var TCandidate, marker: var IntSet) = + m: var TCandidate, marker: var IntSet) = template checkConstraint(n: expr) {.immediate, dirty.} = if not formal.constraint.isNil: if matchNodeKinds(formal.constraint, n): @@ -1447,20 +1436,20 @@ proc matchesAux(c: PContext, n, nOrig: PNode, # named param # check if m.callee has such a param: prepareNamedParam(n.sons[a]) - if n.sons[a].sons[0].kind != nkIdent: + if n.sons[a].sons[0].kind != nkIdent: localError(n.sons[a].info, errNamedParamHasToBeIdent) m.state = csNoMatch - return + return formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1) - if formal == nil: + if formal == nil: # no error message! m.state = csNoMatch - return - if containsOrIncl(marker, formal.position): + return + if containsOrIncl(marker, formal.position): # already in namedParams: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) m.state = csNoMatch - return + return m.baseTypeMatch = false n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1]) n.sons[a].typ = n.sons[a].sons[1].typ @@ -1470,7 +1459,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m.state = csNoMatch return checkConstraint(n.sons[a].sons[1]) - if m.baseTypeMatch: + if m.baseTypeMatch: #assert(container == nil) container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) addSon(container, arg) @@ -1507,7 +1496,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m.state = csNoMatch return else: - if m.callee.n.sons[f].kind != nkSym: + if m.callee.n.sons[f].kind != nkSym: internalError(n.sons[a].info, "matches") return formal = m.callee.n.sons[f].sym @@ -1515,7 +1504,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, # already in namedParams: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) m.state = csNoMatch - return + return m.baseTypeMatch = false n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, @@ -1528,7 +1517,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, if container.isNil: container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) addSon(container, arg) - setSon(m.call, formal.position + 1, + setSon(m.call, formal.position + 1, implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) #if f != formalLen - 1: container = nil @@ -1603,7 +1592,7 @@ when not declared(tests): tests: var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo()) - + proc `|` (t1, t2: PType): PType = result = newType(tyOr, dummyOwner) result.rawAddSon(t1) @@ -1624,12 +1613,12 @@ tests: proc array(x: int, t: PType): PType = result = newType(tyArray, dummyOwner) - + var n = newNodeI(nkRange, UnknownLineInfo()) addSon(n, newIntNode(nkIntLit, 0)) addSon(n, newIntNode(nkIntLit, x)) let range = newType(tyRange, dummyOwner) - + result.rawAddSon(range) result.rawAddSon(t) @@ -1664,7 +1653,7 @@ tests: template no(x, y) = test astToStr(x) & " is not " & astToStr(y): check typeRel(c, y, x) == isNone - + yes seq(any), array(10, int) | seq(any) # Sure, seq[any] is directly included @@ -1672,16 +1661,16 @@ tests: yes seq(int), seq(number) # Sure, the int sequence is certainly # part of the number sequences (and all sequences) - + no seq(any), seq(float) # Nope, seq[any] includes types that are not seq[float] (e.g. seq[int]) yes seq(int|string), seq(any) # Sure - + yes seq(int&string), seq(any) # Again - + yes seq(int&string), seq(int) # A bit more complicated # seq[int&string] is not a real type, but it's analogous to @@ -1690,23 +1679,23 @@ tests: no seq(int|string), seq(int|float) # Nope, seq[string] is not included in not included in # the seq[int|float] set - + no seq(!(int|string)), seq(string) # A sequence that is neither seq[int] or seq[string] # is obviously not seq[string] - + no seq(!int), seq(number) # Now your head should start to hurt a bit # A sequence that is not seq[int] is not necessarily a number sequence # it could well be seq[string] for example - + yes seq(!(int|string)), seq(!string) # all sequnece types besides seq[int] and seq[string] # are subset of all sequence types that are not seq[string] no seq(!(int|string)), seq(!(string|TFoo)) # Nope, seq[TFoo] is included in the first set, but not in the second - + no seq(!string), seq(!number) # Nope, seq[int] in included in the first set, but not in the second @@ -1714,7 +1703,7 @@ tests: yes seq(!int), seq(any) no seq(any), seq(!any) no seq(!int), seq(!any) - + yes int, ordinal no string, ordinal diff --git a/compiler/types.nim b/compiler/types.nim index 5c3be7553..0cc5a212b 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -9,20 +9,20 @@ # this module contains routines for accessing and iterating over types -import +import intsets, ast, astalgo, trees, msgs, strutils, platform, renderer proc firstOrd*(t: PType): BiggestInt proc lastOrd*(t: PType): BiggestInt proc lengthOrd*(t: PType): BiggestInt -type +type TPreferedDesc* = enum preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string proc base*(t: PType): PType # ------------------- type iterator: ---------------------------------------- -type +type TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop TTypeMutator* = proc (t: PType, closure: RootRef): PType {.nimcall.} # copy t and mutate it TTypePredicate* = proc (t: PType): bool {.nimcall.} @@ -32,7 +32,7 @@ proc iterOverType*(t: PType, iter: TTypeIter, closure: RootRef): bool proc mutateType*(t: PType, iter: TTypeMutator, closure: RootRef): PType # Returns result of `iter`. -type +type TParamsEquality* = enum # they are equal, but their # identifiers or their return # type differ (i.e. they cannot be @@ -59,7 +59,7 @@ const abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal, tyTypeDesc} - skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, + skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, tyTypeDesc} typedescPtrs* = abstractPtrs + {tyTypeDesc} typedescInst* = abstractInst + {tyTypeDesc} @@ -75,9 +75,9 @@ proc getSize*(typ: PType): BiggestInt proc isPureObject*(typ: PType): bool proc invalidGenericInst*(f: PType): bool # for debugging -type - TTypeFieldResult* = enum - frNone, # type has no object type field +type + TTypeFieldResult* = enum + frNone, # type has no object type field frHeader, # type has an object type field only in the header frEmbedded # type has an object type field somewhere embedded @@ -86,15 +86,15 @@ proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult # made or intializing of the type field suffices or if there is no type field # at all in this type. -proc invalidGenericInst(f: PType): bool = +proc invalidGenericInst(f: PType): bool = result = f.kind == tyGenericInst and lastSon(f) == nil -proc isPureObject(typ: PType): bool = +proc isPureObject(typ: PType): bool = var t = typ while t.kind == tyObject and t.sons[0] != nil: t = t.sons[0] result = t.sym != nil and sfPure in t.sym.flags -proc getOrdValue(n: PNode): BiggestInt = +proc getOrdValue(n: PNode): BiggestInt = case n.kind of nkCharLit..nkUInt64Lit: result = n.intVal of nkNilLit: result = 0 @@ -109,21 +109,21 @@ proc isIntLit*(t: PType): bool {.inline.} = proc isFloatLit*(t: PType): bool {.inline.} = result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit -proc isCompatibleToCString(a: PType): bool = - if a.kind == tyArray: +proc isCompatibleToCString(a: PType): bool = + if a.kind == tyArray: if (firstOrd(a.sons[0]) == 0) and - (skipTypes(a.sons[0], {tyRange, tyConst, - tyMutable, tyGenericInst}).kind in + (skipTypes(a.sons[0], {tyRange, tyConst, + tyMutable, tyGenericInst}).kind in {tyInt..tyInt64, tyUInt..tyUInt64}) and - (a.sons[1].kind == tyChar): + (a.sons[1].kind == tyChar): result = true - -proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = + +proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = result = sym.owner.name.s & '.' & sym.name.s & '(' var n = sym.typ.n - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): var p = n.sons[i] - if p.kind == nkSym: + if p.kind == nkSym: add(result, p.sym.name.s) add(result, ": ") add(result, typeToString(p.sym.typ, prefer)) @@ -134,7 +134,7 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = if n.sons[0].typ != nil: result.add(": " & typeToString(n.sons[0].typ, prefer)) -proc elemType*(t: PType): PType = +proc elemType*(t: PType): PType = assert(t != nil) case t.kind of tyGenericInst, tyDistinct: result = elemType(lastSon(t)) @@ -142,10 +142,10 @@ proc elemType*(t: PType): PType = else: result = t.lastSon assert(result != nil) -proc skipGeneric(t: PType): PType = +proc skipGeneric(t: PType): PType = result = t while result.kind == tyGenericInst: result = lastSon(result) - + proc isOrdinalType(t: PType): bool = assert(t != nil) # caution: uint, uint64 are no ordinal types! @@ -153,134 +153,134 @@ proc isOrdinalType(t: PType): bool = (t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and isOrdinalType(t.sons[0]) -proc enumHasHoles(t: PType): bool = +proc enumHasHoles(t: PType): bool = var b = t while b.kind in {tyConst, tyMutable, tyRange, tyGenericInst}: b = b.sons[0] result = b.kind == tyEnum and tfEnumHasHoles in b.flags -proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, +proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, closure: RootRef): bool -proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, - closure: RootRef): bool = - if n != nil: +proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, + closure: RootRef): bool = + if n != nil: case n.kind - of nkNone..nkNilLit: + of nkNone..nkNilLit: # a leaf result = iterOverTypeAux(marker, n.typ, iter, closure) - else: - for i in countup(0, sonsLen(n) - 1): + else: + for i in countup(0, sonsLen(n) - 1): result = iterOverNode(marker, n.sons[i], iter, closure) - if result: return - -proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, - closure: RootRef): bool = + if result: return + +proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, + closure: RootRef): bool = result = false - if t == nil: return + if t == nil: return result = iter(t, closure) - if result: return - if not containsOrIncl(marker, t.id): + if result: return + if not containsOrIncl(marker, t.id): case t.kind - of tyGenericInst, tyGenericBody: + of tyGenericInst, tyGenericBody: result = iterOverTypeAux(marker, lastSon(t), iter, closure) - else: - for i in countup(0, sonsLen(t) - 1): + else: + for i in countup(0, sonsLen(t) - 1): result = iterOverTypeAux(marker, t.sons[i], iter, closure) - if result: return + if result: return if t.n != nil: result = iterOverNode(marker, t.n, iter, closure) - -proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool = + +proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool = var marker = initIntSet() result = iterOverTypeAux(marker, t, iter, closure) -proc searchTypeForAux(t: PType, predicate: TTypePredicate, +proc searchTypeForAux(t: PType, predicate: TTypePredicate, marker: var IntSet): bool -proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, - marker: var IntSet): bool = +proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, + marker: var IntSet): bool = result = false case n.kind - of nkRecList: - for i in countup(0, sonsLen(n) - 1): + of nkRecList: + for i in countup(0, sonsLen(n) - 1): result = searchTypeNodeForAux(n.sons[i], p, marker) - if result: return - of nkRecCase: + if result: return + of nkRecCase: assert(n.sons[0].kind == nkSym) result = searchTypeNodeForAux(n.sons[0], p, marker) - if result: return - for i in countup(1, sonsLen(n) - 1): + if result: return + for i in countup(1, sonsLen(n) - 1): case n.sons[i].kind - of nkOfBranch, nkElse: + of nkOfBranch, nkElse: result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker) - if result: return + if result: return else: internalError("searchTypeNodeForAux(record case branch)") - of nkSym: + of nkSym: result = searchTypeForAux(n.sym.typ, p, marker) else: internalError(n.info, "searchTypeNodeForAux()") - -proc searchTypeForAux(t: PType, predicate: TTypePredicate, - marker: var IntSet): bool = + +proc searchTypeForAux(t: PType, predicate: TTypePredicate, + marker: var IntSet): bool = # iterates over VALUE types! result = false - if t == nil: return - if containsOrIncl(marker, t.id): return + if t == nil: return + if containsOrIncl(marker, t.id): return result = predicate(t) - if result: return + if result: return case t.kind - of tyObject: + of tyObject: result = searchTypeForAux(t.sons[0], predicate, marker) if not result: result = searchTypeNodeForAux(t.n, predicate, marker) - of tyGenericInst, tyDistinct: + of tyGenericInst, tyDistinct: result = searchTypeForAux(lastSon(t), predicate, marker) - of tyArray, tyArrayConstr, tySet, tyTuple: - for i in countup(0, sonsLen(t) - 1): + of tyArray, tyArrayConstr, tySet, tyTuple: + for i in countup(0, sonsLen(t) - 1): result = searchTypeForAux(t.sons[i], predicate, marker) - if result: return - else: + if result: return + else: discard -proc searchTypeFor(t: PType, predicate: TTypePredicate): bool = +proc searchTypeFor(t: PType, predicate: TTypePredicate): bool = var marker = initIntSet() result = searchTypeForAux(t, predicate, marker) -proc isObjectPredicate(t: PType): bool = +proc isObjectPredicate(t: PType): bool = result = t.kind == tyObject -proc containsObject(t: PType): bool = +proc containsObject(t: PType): bool = result = searchTypeFor(t, isObjectPredicate) -proc isObjectWithTypeFieldPredicate(t: PType): bool = +proc isObjectWithTypeFieldPredicate(t: PType): bool = result = t.kind == tyObject and t.sons[0] == nil and not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and tfFinal notin t.flags -proc analyseObjectWithTypeFieldAux(t: PType, - marker: var IntSet): TTypeFieldResult = +proc analyseObjectWithTypeFieldAux(t: PType, + marker: var IntSet): TTypeFieldResult = var res: TTypeFieldResult result = frNone - if t == nil: return + if t == nil: return case t.kind - of tyObject: - if (t.n != nil): - if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): + of tyObject: + if (t.n != nil): + if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): return frEmbedded - for i in countup(0, sonsLen(t) - 1): + for i in countup(0, sonsLen(t) - 1): res = analyseObjectWithTypeFieldAux(t.sons[i], marker) - if res == frEmbedded: + if res == frEmbedded: return frEmbedded if res == frHeader: result = frHeader - if result == frNone: + if result == frNone: if isObjectWithTypeFieldPredicate(t): result = frHeader - of tyGenericInst, tyDistinct, tyConst, tyMutable: + of tyGenericInst, tyDistinct, tyConst, tyMutable: result = analyseObjectWithTypeFieldAux(lastSon(t), marker) - of tyArray, tyArrayConstr, tyTuple: - for i in countup(0, sonsLen(t) - 1): + of tyArray, tyArrayConstr, tyTuple: + for i in countup(0, sonsLen(t) - 1): res = analyseObjectWithTypeFieldAux(t.sons[i], marker) - if res != frNone: + if res != frNone: return frEmbedded - else: + else: discard -proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = +proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = var marker = initIntSet() result = analyseObjectWithTypeFieldAux(t, marker) @@ -288,7 +288,7 @@ proc isGCRef(t: PType): bool = result = t.kind in GcTypeKinds or (t.kind == tyProc and t.callConv == ccClosure) -proc containsGarbageCollectedRef(typ: PType): bool = +proc containsGarbageCollectedRef(typ: PType): bool = # returns true if typ contains a reference, sequence or string (all the # things that are garbage-collected) result = searchTypeFor(typ, isGCRef) @@ -296,47 +296,47 @@ proc containsGarbageCollectedRef(typ: PType): bool = proc isTyRef(t: PType): bool = result = t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure) -proc containsTyRef*(typ: PType): bool = +proc containsTyRef*(typ: PType): bool = # returns true if typ contains a 'ref' result = searchTypeFor(typ, isTyRef) -proc isHiddenPointer(t: PType): bool = +proc isHiddenPointer(t: PType): bool = result = t.kind in {tyString, tySequence} -proc containsHiddenPointer(typ: PType): bool = +proc containsHiddenPointer(typ: PType): bool = # returns true if typ contains a string, table or sequence (all the things # that need to be copied deeply) result = searchTypeFor(typ, isHiddenPointer) proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool -proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = +proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = result = false - if n != nil: + if n != nil: result = canFormAcycleAux(marker, n.typ, startId) - if not result: + if not result: case n.kind - of nkNone..nkNilLit: + of nkNone..nkNilLit: discard - else: - for i in countup(0, sonsLen(n) - 1): + else: + for i in countup(0, sonsLen(n) - 1): result = canFormAcycleNode(marker, n.sons[i], startId) - if result: return - -proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = + if result: return + +proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = result = false - if typ == nil: return - if tfAcyclic in typ.flags: return + if typ == nil: return + if tfAcyclic in typ.flags: return var t = skipTypes(typ, abstractInst-{tyTypeDesc}) - if tfAcyclic in t.flags: return + if tfAcyclic in t.flags: return case t.kind of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs: - if not containsOrIncl(marker, t.id): - for i in countup(0, sonsLen(t) - 1): + if not containsOrIncl(marker, t.id): + for i in countup(0, sonsLen(t) - 1): result = canFormAcycleAux(marker, t.sons[i], startId) - if result: return + if result: return if t.n != nil: result = canFormAcycleNode(marker, t.n, startId) - else: + else: result = t.id == startId # Inheritance can introduce cyclic types, however this is not relevant # as the type that is passed to 'new' is statically known! @@ -351,29 +351,29 @@ proc canFormAcycle(typ: PType): bool = var marker = initIntSet() result = canFormAcycleAux(marker, typ, typ.id) -proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, +proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, closure: RootRef): PType -proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator, - closure: RootRef): PNode = +proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator, + closure: RootRef): PNode = result = nil - if n != nil: + if n != nil: result = copyNode(n) result.typ = mutateTypeAux(marker, n.typ, iter, closure) case n.kind - of nkNone..nkNilLit: + of nkNone..nkNilLit: # a leaf discard - else: - for i in countup(0, sonsLen(n) - 1): + else: + for i in countup(0, sonsLen(n) - 1): addSon(result, mutateNode(marker, n.sons[i], iter, closure)) - -proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, - closure: RootRef): PType = + +proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, + closure: RootRef): PType = result = nil - if t == nil: return + if t == nil: return result = iter(t, closure) - if not containsOrIncl(marker, t.id): - for i in countup(0, sonsLen(t) - 1): + if not containsOrIncl(marker, t.id): + for i in countup(0, sonsLen(t) - 1): result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure) if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure) assert(result != nil) @@ -393,7 +393,7 @@ proc rangeToStr(n: PNode): string = assert(n.kind == nkRange) result = valueToString(n.sons[0]) & ".." & valueToString(n.sons[1]) -const +const typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty", "Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc", "GenericInvocation", "GenericBody", "GenericInst", "GenericParam", @@ -414,7 +414,7 @@ const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg} proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = var t = typ result = "" - if t == nil: return + if t == nil: return if prefer in preferToResolveSymbols and t.sym != nil and sfAnon notin t.sym.flags: if t.kind == tyInt and isIntLit(t): @@ -484,47 +484,47 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = "expr" of tyFromExpr, tyFieldAccessor: result = renderTree(t.n) - of tyArray: - if t.sons[0].kind == tyRange: + of tyArray: + if t.sons[0].kind == tyRange: result = "array[" & rangeToStr(t.sons[0].n) & ", " & typeToString(t.sons[1]) & ']' - else: + else: result = "array[" & typeToString(t.sons[0]) & ", " & typeToString(t.sons[1]) & ']' - of tyArrayConstr: + of tyArrayConstr: result = "Array constructor[" & rangeToStr(t.sons[0].n) & ", " & typeToString(t.sons[1]) & ']' - of tySequence: + of tySequence: result = "seq[" & typeToString(t.sons[0]) & ']' - of tyOrdinal: + of tyOrdinal: result = "ordinal[" & typeToString(t.sons[0]) & ']' - of tySet: + of tySet: result = "set[" & typeToString(t.sons[0]) & ']' - of tyOpenArray: + of tyOpenArray: result = "openarray[" & typeToString(t.sons[0]) & ']' of tyDistinct: result = "distinct " & typeToString(t.sons[0], if prefer == preferModuleInfo: preferModuleInfo else: preferName) - of tyTuple: + of tyTuple: # we iterate over t.sons here, because t.n may be nil result = "tuple[" - if t.n != nil: + if t.n != nil: assert(sonsLen(t.n) == sonsLen(t)) - for i in countup(0, sonsLen(t.n) - 1): + for i in countup(0, sonsLen(t.n) - 1): assert(t.n.sons[i].kind == nkSym) add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i])) if i < sonsLen(t.n) - 1: add(result, ", ") - else: - for i in countup(0, sonsLen(t) - 1): + else: + for i in countup(0, sonsLen(t) - 1): add(result, typeToString(t.sons[i])) if i < sonsLen(t) - 1: add(result, ", ") add(result, ']') - of tyPtr, tyRef, tyVar, tyMutable, tyConst: + of tyPtr, tyRef, tyVar, tyMutable, tyConst: result = typeToStr[t.kind] if t.len >= 2: setLen(result, result.len-1) result.add '[' - for i in countup(0, sonsLen(t) - 1): + for i in countup(0, sonsLen(t) - 1): add(result, typeToString(t.sons[i])) if i < sonsLen(t) - 1: add(result, ", ") result.add ']' @@ -536,7 +536,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add("(" & typeToString(t.sons[0]) & ")") of tyProc: result = if tfIterator in t.flags: "iterator (" else: "proc (" - for i in countup(1, sonsLen(t) - 1): + for i in countup(1, sonsLen(t) - 1): add(result, typeToString(t.sons[i])) if i < sonsLen(t) - 1: add(result, ", ") add(result, ')') @@ -554,29 +554,29 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if len(prag) != 0: add(result, "{." & prag & ".}") of tyVarargs, tyIter: result = typeToStr[t.kind] % typeToString(t.sons[0]) - else: + else: result = typeToStr[t.kind] if tfShared in t.flags: result = "shared " & result if tfNotNil in t.flags: result.add(" not nil") -proc resultType(t: PType): PType = +proc resultType(t: PType): PType = assert(t.kind == tyProc) result = t.sons[0] # nil is allowed - -proc base(t: PType): PType = + +proc base(t: PType): PType = result = t.sons[0] -proc firstOrd(t: PType): BiggestInt = +proc firstOrd(t: PType): BiggestInt = case t.kind of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: result = 0 of tySet, tyVar: result = firstOrd(t.sons[0]) of tyArray, tyArrayConstr: result = firstOrd(t.sons[0]) - of tyRange: + of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) result = getOrdValue(t.n.sons[0]) - of tyInt: + of tyInt: if platform.intSize == 4: result = - (2147483646) - 2 else: result = 0x8000000000000000'i64 of tyInt8: result = - 128 @@ -584,11 +584,11 @@ proc firstOrd(t: PType): BiggestInt = of tyInt32: result = - 2147483646 - 2 of tyInt64: result = 0x8000000000000000'i64 of tyUInt..tyUInt64: result = 0 - of tyEnum: + of tyEnum: # if basetype <> nil then return firstOrd of basetype - if (sonsLen(t) > 0) and (t.sons[0] != nil): + if (sonsLen(t) > 0) and (t.sons[0] != nil): result = firstOrd(t.sons[0]) - else: + else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc, tyFieldAccessor: @@ -600,31 +600,31 @@ proc firstOrd(t: PType): BiggestInt = internalError("invalid kind for first(" & $t.kind & ')') result = 0 -proc lastOrd(t: PType): BiggestInt = +proc lastOrd(t: PType): BiggestInt = case t.kind of tyBool: result = 1 of tyChar: result = 255 of tySet, tyVar: result = lastOrd(t.sons[0]) of tyArray, tyArrayConstr: result = lastOrd(t.sons[0]) - of tyRange: + of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) result = getOrdValue(t.n.sons[1]) - of tyInt: + of tyInt: if platform.intSize == 4: result = 0x7FFFFFFF else: result = 0x7FFFFFFFFFFFFFFF'i64 of tyInt8: result = 0x0000007F of tyInt16: result = 0x00007FFF of tyInt32: result = 0x7FFFFFFF of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64 - of tyUInt: + of tyUInt: if platform.intSize == 4: result = 0xFFFFFFFF else: result = 0x7FFFFFFFFFFFFFFF'i64 of tyUInt8: result = 0xFF of tyUInt16: result = 0xFFFF of tyUInt32: result = 0xFFFFFFFF of tyUInt64: result = 0x7FFFFFFFFFFFFFFF'i64 - of tyEnum: + of tyEnum: assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) result = t.n.sons[sonsLen(t.n) - 1].sym.position of tyGenericInst, tyDistinct, tyConst, tyMutable, @@ -638,7 +638,7 @@ proc lastOrd(t: PType): BiggestInt = internalError("invalid kind for last(" & $t.kind & ')') result = 0 -proc lengthOrd(t: PType): BiggestInt = +proc lengthOrd(t: PType): BiggestInt = case t.kind of tyInt64, tyInt32, tyInt: result = lastOrd(t) of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0]) @@ -654,7 +654,7 @@ type dcEqOrDistinctOf ## a equals b or a is distinct of b TTypeCmpFlag* = enum - IgnoreTupleFields + IgnoreTupleFields ## NOTE: Only set this flag for backends! IgnoreCC ExactTypeDescValues ExactGenericParams @@ -673,7 +673,7 @@ type proc initSameTypeClosure: TSameTypeClosure = # we do the initialization lazily for performance (avoids memory allocations) discard - + proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool = result = not isNil(c.s) and c.s.contains((a.id, b.id)) if not result: @@ -700,17 +700,17 @@ proc sameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool = if a == nil or b == nil: result = false else: result = sameType(a, b, flags) -proc equalParam(a, b: PSym): TParamsEquality = +proc equalParam(a, b: PSym): TParamsEquality = if sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}) and exprStructuralEquivalent(a.constraint, b.constraint): - if a.ast == b.ast: + if a.ast == b.ast: result = paramsEqual - elif a.ast != nil and b.ast != nil: + elif a.ast != nil and b.ast != nil: if exprStructuralEquivalent(a.ast, b.ast): result = paramsEqual else: result = paramsIncompatible - elif a.ast != nil: + elif a.ast != nil: result = paramsEqual - elif b.ast != nil: + elif b.ast != nil: result = paramsIncompatible else: result = paramsNotEqual @@ -723,70 +723,70 @@ proc sameConstraints(a, b: PNode): bool = return false return true -proc equalParams(a, b: PNode): TParamsEquality = +proc equalParams(a, b: PNode): TParamsEquality = result = paramsEqual var length = sonsLen(a) - if length != sonsLen(b): + if length != sonsLen(b): result = paramsNotEqual - else: - for i in countup(1, length - 1): + else: + for i in countup(1, length - 1): var m = a.sons[i].sym var n = b.sons[i].sym assert((m.kind == skParam) and (n.kind == skParam)) case equalParam(m, n) - of paramsNotEqual: + of paramsNotEqual: return paramsNotEqual - of paramsEqual: + of paramsEqual: discard - of paramsIncompatible: + of paramsIncompatible: result = paramsIncompatible - if (m.name.id != n.name.id): + if (m.name.id != n.name.id): # BUGFIX return paramsNotEqual # paramsIncompatible; # continue traversal! If not equal, we can return immediately; else # it stays incompatible if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}): - if (a.sons[0].typ == nil) or (b.sons[0].typ == nil): + if (a.sons[0].typ == nil) or (b.sons[0].typ == nil): result = paramsNotEqual # one proc has a result, the other not is OK - else: + else: result = paramsIncompatible # overloading by different # result types does not work - -proc sameLiteral(x, y: PNode): bool = - if x.kind == y.kind: + +proc sameLiteral(x, y: PNode): bool = + if x.kind == y.kind: case x.kind of nkCharLit..nkInt64Lit: result = x.intVal == y.intVal of nkFloatLit..nkFloat64Lit: result = x.floatVal == y.floatVal of nkNilLit: result = true else: assert(false) - -proc sameRanges(a, b: PNode): bool = + +proc sameRanges(a, b: PNode): bool = result = sameLiteral(a.sons[0], b.sons[0]) and sameLiteral(a.sons[1], b.sons[1]) -proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = +proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = # two tuples are equivalent iff the names, types and positions are the same; # however, both types may not have any field names (t.n may be nil) which # complicates the matter a bit. if sonsLen(a) == sonsLen(b): result = true - for i in countup(0, sonsLen(a) - 1): + for i in countup(0, sonsLen(a) - 1): var x = a.sons[i] var y = b.sons[i] if IgnoreTupleFields in c.flags: - x = skipTypes(x, {tyRange}) - y = skipTypes(y, {tyRange}) - + x = skipTypes(x, {tyRange, tyGenericInst}) + y = skipTypes(y, {tyRange, tyGenericInst}) + result = sameTypeAux(x, y, c) - if not result: return + if not result: return if a.n != nil and b.n != nil and IgnoreTupleFields notin c.flags: - for i in countup(0, sonsLen(a.n) - 1): - # check field names: + for i in countup(0, sonsLen(a.n) - 1): + # check field names: if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym: var x = a.n.sons[i].sym var y = b.n.sons[i].sym result = x.name.id == y.name.id - if not result: break + if not result: break else: internalError(a.n.info, "sameTuple") template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} = @@ -797,7 +797,7 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} = # expensive structural equality test; however due to the way generic and # objects work, if one of the types does **not** contain tfFromGeneric, # they cannot be equal. The check ``a.sym.id == b.sym.id`` checks - # for the same origin and is essential because we don't want "pure" + # for the same origin and is essential because we don't want "pure" # structural type equivalence: # # type @@ -835,9 +835,9 @@ proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool = of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkEmpty, nkNilLit, nkType: result = true else: - if sonsLen(a) == sonsLen(b): - for i in countup(0, sonsLen(a) - 1): - if not sameObjectTree(a.sons[i], b.sons[i], c): return + if sonsLen(a) == sonsLen(b): + for i in countup(0, sonsLen(a) - 1): + if not sameObjectTree(a.sons[i], b.sons[i], c): return result = true proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool = @@ -853,7 +853,7 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool = result = true for i in countup(0, sonsLen(a) - 1): result = sameTypeOrNilAux(a.sons[i], b.sons[i], c) - if not result: return + if not result: return proc isGenericAlias*(t: PType): bool = return t.kind == tyGenericInst and t.lastSon.kind == tyGenericInst @@ -866,7 +866,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = # believe it or not, the direct check for ``containsOrIncl(c, a, b)`` # increases bootstrapping time from 2.4s to 3.3s on my laptop! So we cheat # again: Since the recursion check is only to not get caught in an endless - # recursion, we use a counter and only if it's value is over some + # recursion, we use a counter and only if it's value is over some # threshold we perform the expensive exact cycle check: if c.recCheck < 3: inc c.recCheck @@ -874,11 +874,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = if containsOrIncl(c, a, b): return true proc sameFlags(a, b: PType): bool {.inline.} = - result = eqTypeFlags*a.flags == eqTypeFlags*b.flags + result = eqTypeFlags*a.flags == eqTypeFlags*b.flags if x == y: return true var a = skipTypes(x, {tyGenericInst}) - var b = skipTypes(y, {tyGenericInst}) + var b = skipTypes(y, {tyGenericInst}) assert(a != nil) assert(b != nil) if a.kind != b.kind: @@ -891,7 +891,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = of dcEqOrDistinctOf: while a.kind == tyDistinct: a = a.sons[0] if a.kind != b.kind: return false - + if x.kind == tyGenericInst: let lhs = x.skipGenericAlias @@ -916,11 +916,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameObjectStructures(a, b, c) and sameFlags(a, b) of tyDistinct: cycleCheck() - if c.cmp == dcEq: + if c.cmp == dcEq: if sameFlags(a, b): ifFastObjectTypeCheckFailed(a, b): - result = sameTypeAux(a.sons[0], b.sons[0], c) - else: + result = sameTypeAux(a.sons[0], b.sons[0], c) + else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b) of tyEnum, tyForward: # XXX generic enums do not make much sense, but require structural checking @@ -957,13 +957,13 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = sameValue(a.n.sons[0], b.n.sons[0]) and sameValue(a.n.sons[1], b.n.sons[1]) of tyGenericInst: discard - of tyNone: result = false + of tyNone: result = false proc sameBackendType*(x, y: PType): bool = var c = initSameTypeClosure() c.flags.incl IgnoreTupleFields result = sameTypeAux(x, y, c) - + proc compareTypes*(x, y: PType, cmp: TDistinctCompare = dcEq, flags: TTypeCmpFlags = {}): bool = @@ -972,8 +972,8 @@ proc compareTypes*(x, y: PType, c.cmp = cmp c.flags = flags result = sameTypeAux(x, y, c) - -proc inheritanceDiff*(a, b: PType): int = + +proc inheritanceDiff*(a, b: PType): int = # | returns: 0 iff `a` == `b` # | returns: -x iff `a` is the x'th direct superclass of `b` # | returns: +x iff `a` is the x'th direct subclass of `b` @@ -985,14 +985,14 @@ proc inheritanceDiff*(a, b: PType): int = result = 0 while x != nil: x = skipTypes(x, skipPtrs) - if sameObjectTypes(x, b): return + if sameObjectTypes(x, b): return x = x.sons[0] dec(result) var y = b result = 0 while y != nil: y = skipTypes(y, skipPtrs) - if sameObjectTypes(y, a): return + if sameObjectTypes(y, a): return y = y.sons[0] inc(result) result = high(int) @@ -1066,7 +1066,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if kind == skConst: return t var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}) case t2.kind - of tyVar: + of tyVar: if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap of tyOpenArray: if kind != skParam: result = t @@ -1075,9 +1075,9 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if kind notin {skParam, skResult}: result = t else: result = typeAllowedAux(marker, t2, kind, flags) of tyProc: - for i in countup(1, sonsLen(t) - 1): + for i in countup(1, sonsLen(t) - 1): result = typeAllowedAux(marker, t.sons[i], skParam, flags) - if result != nil: break + if result != nil: break if result.isNil and t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skResult, flags) of tyExpr, tyStmt, tyTypeDesc, tyStatic: @@ -1092,7 +1092,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = t of tyNil: if kind != skConst: result = t - of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: + of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: result = nil of tyOrdinal: if kind != skParam: result = t @@ -1132,13 +1132,13 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, # prevent cascading errors: result = nil -proc typeAllowed*(t: PType, kind: TSymKind): PType = +proc typeAllowed*(t: PType, kind: TSymKind): PType = # returns 'nil' on success and otherwise the part of the type that is # wrong! var marker = initIntSet() result = typeAllowedAux(marker, t, kind, {}) -proc align(address, alignment: BiggestInt): BiggestInt = +proc align(address, alignment: BiggestInt): BiggestInt = result = (address + (alignment - 1)) and not (alignment - 1) const @@ -1147,17 +1147,17 @@ const szUnknownSize* = -1 proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt -proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = +proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = var maxAlign, maxSize, b, res: BiggestInt case n.kind - of nkRecCase: + of nkRecCase: assert(n.sons[0].kind == nkSym) result = computeRecSizeAux(n.sons[0], a, currOffset) maxSize = 0 maxAlign = 1 - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): case n.sons[i].kind - of nkOfBranch, nkElse: + of nkOfBranch, nkElse: res = computeRecSizeAux(lastSon(n.sons[i]), b, currOffset) if res < 0: return res maxSize = max(maxSize, res) @@ -1166,17 +1166,17 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = currOffset = align(currOffset, maxAlign) + maxSize result = align(result, maxAlign) + maxSize a = maxAlign - of nkRecList: + of nkRecList: result = 0 maxAlign = 1 - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): res = computeRecSizeAux(n.sons[i], b, currOffset) if res < 0: return res currOffset = align(currOffset, b) + res result = align(result, b) + res if b > maxAlign: maxAlign = b a = maxAlign - of nkSym: + of nkSym: result = computeSizeAux(n.sym.typ, a) n.sym.offset = int(currOffset) else: @@ -1193,31 +1193,31 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = # size already computed result = typ.size a = typ.align - return + return typ.size = szIllegalRecursion # mark as being computed case typ.kind - of tyInt, tyUInt: + of tyInt, tyUInt: result = intSize a = result - of tyInt8, tyUInt8, tyBool, tyChar: + of tyInt8, tyUInt8, tyBool, tyChar: result = 1 a = result - of tyInt16, tyUInt16: + of tyInt16, tyUInt16: result = 2 a = result - of tyInt32, tyUInt32, tyFloat32: + of tyInt32, tyUInt32, tyFloat32: result = 4 a = result - of tyInt64, tyUInt64, tyFloat64: + of tyInt64, tyUInt64, tyFloat64: result = 8 a = result of tyFloat128: result = 16 a = result - of tyFloat: + of tyFloat: result = floatSize a = result - of tyProc: + of tyProc: if typ.callConv == ccClosure: result = 2 * ptrSize else: result = ptrSize a = ptrSize @@ -1232,17 +1232,17 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = let elemSize = computeSizeAux(typ.sons[1], a) if elemSize < 0: return elemSize result = lengthOrd(typ.sons[0]) * elemSize - of tyEnum: - if firstOrd(typ) < 0: + of tyEnum: + if firstOrd(typ) < 0: result = 4 # use signed int32 - else: + else: length = lastOrd(typ) # BUGFIX: use lastOrd! if length + 1 < `shl`(1, 8): result = 1 elif length + 1 < `shl`(1, 16): result = 2 elif length + 1 < `shl`(BiggestInt(1), 32): result = 4 else: result = 8 a = result - of tySet: + of tySet: length = lengthOrd(typ.sons[0]) if length <= 8: result = 1 elif length <= 16: result = 2 @@ -1251,32 +1251,32 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = elif align(length, 8) mod 8 == 0: result = align(length, 8) div 8 else: result = align(length, 8) div 8 + 1 a = result - of tyRange: + of tyRange: result = computeSizeAux(typ.sons[0], a) - of tyTuple: + of tyTuple: result = 0 maxAlign = 1 - for i in countup(0, sonsLen(typ) - 1): + for i in countup(0, sonsLen(typ) - 1): res = computeSizeAux(typ.sons[i], a) if res < 0: return res maxAlign = max(maxAlign, a) result = align(result, a) + res result = align(result, maxAlign) a = maxAlign - of tyObject: - if typ.sons[0] != nil: + of tyObject: + if typ.sons[0] != nil: result = computeSizeAux(typ.sons[0], a) - if result < 0: return + if result < 0: return maxAlign = a - elif isObjectWithTypeFieldPredicate(typ): + elif isObjectWithTypeFieldPredicate(typ): result = intSize maxAlign = result - else: + else: result = 0 maxAlign = 1 currOffset = result result = computeRecSizeAux(typ.n, a, currOffset) - if result < 0: return + if result < 0: return if a < maxAlign: a = maxAlign result = align(result, a) of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter: @@ -1290,7 +1290,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = typ.size = result typ.align = int16(a) -proc computeSize(typ: PType): BiggestInt = +proc computeSize(typ: PType): BiggestInt = var a: BiggestInt = 1 result = computeSizeAux(typ, a) @@ -1299,7 +1299,7 @@ proc getReturnType*(s: PSym): PType = assert s.kind in skProcKinds result = s.typ.sons[0] -proc getSize(typ: PType): BiggestInt = +proc getSize(typ: PType): BiggestInt = result = computeSize(typ) if result < 0: internalError("getSize: " & $typ.kind) @@ -1317,7 +1317,7 @@ proc containsGenericTypeIter(t: PType, closure: RootRef): bool = return false -proc containsGenericType*(t: PType): bool = +proc containsGenericType*(t: PType): bool = result = iterOverType(t, containsGenericTypeIter, nil) proc baseOfDistinct*(t: PType): PType = @@ -1336,7 +1336,7 @@ proc baseOfDistinct*(t: PType): PType = proc safeInheritanceDiff*(a, b: PType): int = # same as inheritanceDiff but checks for tyError: - if a.kind == tyError or b.kind == tyError: + if a.kind == tyError or b.kind == tyError: result = -1 else: result = inheritanceDiff(a, b) @@ -1356,7 +1356,7 @@ proc compatibleEffects*(formal, actual: PType): bool = assert formal.kind == tyProc and actual.kind == tyProc internalAssert formal.n.sons[0].kind == nkEffectList internalAssert actual.n.sons[0].kind == nkEffectList - + var spec = formal.n.sons[0] if spec.len != 0: var real = actual.n.sons[0] diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim new file mode 100644 index 000000000..960e2aae9 --- /dev/null +++ b/tests/ccgbugs/tuple_canon.nim @@ -0,0 +1,80 @@ +# bug #2250 + +import + math, strutils + +type + Meters = float + Point2[T] = tuple[x, y: T] + + HexState* = enum + hsOn, hsOff + + Index = uint16 + + HexGrid* = object + w, h: int ## Width and height of the hex grid. + radius: Meters ## Radius of circle that circumscribes a hexagon. + grid: seq[HexState] ## Information on what hexes are drawn. + + HexVtxIndex = enum + hiA, hiB, hiC, hiD, hiE, hiF + + HexCoord* = Point2[int] + +const + HexDY = sqrt(1.0 - (0.5 * 0.5)) # dy from center to midpoint of 1-2 + HexDX = sqrt(1.0 - (HexDY * HexDY)) # dx from center to midpoint of 1-5 (0.5) + + +let + hexOffsets : array[HexVtxIndex, Point2[float]] = [ + (-1.0, 0.0), + (-HexDX, -HexDY), + (HexDX, -HexDY), + (1.0, 0.0), + (HexDX, HexDY), + (-HexDX, HexDY)] + + evenSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [ + ((0,0), hiA), + ((0,0), hiB), + ((1,-1), hiA), + ((1,0), hiB), + ((1,0), hiA), + ((0,1), hiB)] + + oddSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [ + ((0,0), hiA), + ((0,0), hiB), + ((1,0), hiA), + ((1,1), hiB), + ((1,1), hiA), + ((0,1), hiB)] + +template odd*(i: int) : expr = + (i and 1) != 0 + +proc vidx(hg: HexGrid; col, row: int; i: HexVtxIndex) : Index = + #NOTE: this variation compiles + #var offset : type(evenSharingOffsets[i]) + # + #if odd(col): + # offset = oddSharingOffsets[i] + #else: + # offset = evenSharingOffsets[i] + + let + #NOTE: this line generates the bad code + offset = (if odd(col): oddSharingOffsets[i] else: evenSharingOffsets[i]) + x = col + 1 + offset.hc.x + y = row + 1 + offset.hc.y + + result = Index(x*2 + y * (hg.w + 2)*2 + int(offset.idx)) + +proc go() = + var hg : HexGrid + + echo "vidx ", $vidx(hg, 1, 2, hiC) + +go() diff --git a/tests/overload/tsymtabchange_during_or.nim b/tests/overload/tsymtabchange_during_or.nim new file mode 100644 index 000000000..b5551bcc7 --- /dev/null +++ b/tests/overload/tsymtabchange_during_or.nim @@ -0,0 +1,24 @@ + +# bug #2229 + +type Type1 = object + id: int + +type Type2 = object + id: int + +proc init(self: var Type1, a: int, b: ref Type2) = + echo "1" + +proc init(self: var Type2, a: int) = + echo """ + Works when this proc commented out + Otherwise error: + test.nim(14, 4) Error: ambiguous call; both test.init(self: var Type1, a: int, b: ref Type2) and test.init(self: var Type1, a: int, b: ref Type2) match for: (Type1, int literal(1), ref Type2) + """ + +var a: Type1 +init(a, 1, ( + var b = new(Type2); + b +)) |