mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
fixes #4673
This commit is contained in:
@@ -46,7 +46,8 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
|
||||
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
|
||||
case a.kind
|
||||
of tyObject:
|
||||
result = isPartOfAux(a.sons[0], b, marker)
|
||||
if a.sons[0] != nil:
|
||||
result = isPartOfAux(a.sons[0].skipTypes(skipPtrs), b, marker)
|
||||
if result == arNo: result = isPartOfAux(a.n, b, marker)
|
||||
of tyGenericInst, tyDistinct:
|
||||
result = isPartOfAux(lastSon(a), b, marker)
|
||||
|
||||
@@ -726,6 +726,7 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope): PSym =
|
||||
var ty = ty
|
||||
assert r != nil
|
||||
while ty != nil:
|
||||
ty = ty.skipTypes(skipPtrs)
|
||||
assert(ty.kind in {tyTuple, tyObject})
|
||||
result = lookupInRecord(ty.n, field.name)
|
||||
if result != nil: break
|
||||
@@ -1257,7 +1258,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||
if not p.module.compileToCpp:
|
||||
while t.kind == tyObject and t.sons[0] != nil:
|
||||
add(r, ~".Sup")
|
||||
t = skipTypes(t.sons[0], typedescInst)
|
||||
t = skipTypes(t.sons[0], skipPtrs)
|
||||
if isObjLackingTypeField(t):
|
||||
globalError(x.info, errGenerated,
|
||||
"no 'of' operator available for pure objects")
|
||||
@@ -1875,7 +1876,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
||||
if not p.module.compileToCpp:
|
||||
while t.kind == tyObject and t.sons[0] != nil:
|
||||
add(r, ".Sup")
|
||||
t = skipTypes(t.sons[0], abstractInst)
|
||||
t = skipTypes(t.sons[0], skipPtrs)
|
||||
if nilCheck != nil:
|
||||
linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
|
||||
nilCheck, r, genTypeInfo(p.module, dest))
|
||||
|
||||
@@ -73,7 +73,9 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
of tyObject:
|
||||
for i in countup(0, sonsLen(typ) - 1):
|
||||
genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
|
||||
var x = typ.sons[i]
|
||||
if x != nil: x = x.skipTypes(skipPtrs)
|
||||
genTraverseProc(c, accessor.parentObj(c.p.module), x)
|
||||
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
|
||||
of tyTuple:
|
||||
let typ = getUniqueType(typ)
|
||||
|
||||
@@ -475,11 +475,11 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||
hasField = true
|
||||
elif m.compileToCpp:
|
||||
appcg(m, result, " : public $1 {$n",
|
||||
[getTypeDescAux(m, typ.sons[0], check)])
|
||||
[getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
|
||||
hasField = true
|
||||
else:
|
||||
appcg(m, result, " {$n $1 Sup;$n",
|
||||
[getTypeDescAux(m, typ.sons[0], check)])
|
||||
[getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
|
||||
hasField = true
|
||||
else:
|
||||
addf(result, " {$n", [name])
|
||||
@@ -901,7 +901,7 @@ proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
|
||||
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
|
||||
var t = typ.sons[0]
|
||||
while t != nil:
|
||||
t = t.skipTypes(abstractInst)
|
||||
t = t.skipTypes(skipPtrs)
|
||||
t.flags.incl tfObjHasKids
|
||||
t = t.sons[0]
|
||||
|
||||
|
||||
@@ -246,7 +246,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||
if not p.module.compileToCpp:
|
||||
while (s.kind == tyObject) and (s.sons[0] != nil):
|
||||
add(r, ".Sup")
|
||||
s = skipTypes(s.sons[0], abstractInst)
|
||||
s = skipTypes(s.sons[0], skipPtrs)
|
||||
linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t))
|
||||
of frEmbedded:
|
||||
# worst case for performance:
|
||||
|
||||
@@ -1364,7 +1364,7 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v
|
||||
if output.len > 0: output.add(", ")
|
||||
addf(output, "m_type: $1" | "'m_type' => $#", [genTypeInfo(p, t)])
|
||||
while t != nil:
|
||||
createRecordVarAux(p, t.n, excludedFieldIDs, output)
|
||||
createRecordVarAux(p, t.skipTypes(skipPtrs).n, excludedFieldIDs, output)
|
||||
t = t.sons[0]
|
||||
|
||||
proc arrayTypeForElemType(typ: PType): string =
|
||||
|
||||
@@ -76,7 +76,7 @@ proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
|
||||
addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
|
||||
if (typ.kind == tyObject) and (typ.sons[0] != nil):
|
||||
addf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[name, genTypeInfo(p, typ.sons[0])])
|
||||
[name, genTypeInfo(p, typ.sons[0].skipTypes(skipPtrs))])
|
||||
|
||||
proc genTupleFields(p: PProc, typ: PType): Rope =
|
||||
var s: Rope = nil
|
||||
|
||||
@@ -172,7 +172,7 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode =
|
||||
if field != nil: break
|
||||
t = t.sons[0]
|
||||
if t == nil: break
|
||||
t = t.skipTypes(abstractInst)
|
||||
t = t.skipTypes(skipPtrs)
|
||||
#if field == nil:
|
||||
# echo "FIELD ", b
|
||||
# debug deref.typ
|
||||
@@ -193,7 +193,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym =
|
||||
if result != nil: break
|
||||
t = t.sons[0]
|
||||
if t == nil: break
|
||||
t = t.skipTypes(abstractInst)
|
||||
t = t.skipTypes(skipPtrs)
|
||||
|
||||
proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
|
||||
# returns a[].b as a node
|
||||
|
||||
@@ -203,7 +203,8 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyObject, tyDistinct:
|
||||
if not considerOverloadedOp(c, t, body, x, y):
|
||||
if t.sons[0] != nil: liftBodyAux(c, t.sons[0], body, x, y)
|
||||
if t.sons[0] != nil:
|
||||
liftBodyAux(c, t.sons[0].skipTypes(skipPtrs), body, x, y)
|
||||
if t.kind == tyObject: liftBodyObj(c, t.n, body, x, y)
|
||||
of tyTuple:
|
||||
liftBodyTup(c, t, body, x, y)
|
||||
|
||||
@@ -1070,7 +1070,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
result = check
|
||||
return result
|
||||
if ty.sons[0] == nil: break
|
||||
ty = skipTypes(ty.sons[0], {tyGenericInst})
|
||||
ty = skipTypes(ty.sons[0], skipPtrs)
|
||||
# old code, not sure if it's live code:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
@@ -1148,7 +1148,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
f = lookupInRecordAndBuildCheck(c, n, ty.n, i, check)
|
||||
if f != nil: break
|
||||
if ty.sons[0] == nil: break
|
||||
ty = skipTypes(ty.sons[0], {tyGenericInst})
|
||||
ty = skipTypes(ty.sons[0], skipPtrs)
|
||||
if f != nil:
|
||||
if fieldVisible(c, f):
|
||||
# is the access to a public field or in the same module or in a friend?
|
||||
@@ -2108,7 +2108,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
f = lookupInRecordAndBuildCheck(c, it, t.n, id, check)
|
||||
if f != nil: break
|
||||
if t.sons[0] == nil: break
|
||||
t = skipTypes(t.sons[0], {tyGenericInst})
|
||||
t = skipTypes(t.sons[0], skipPtrs)
|
||||
if f != nil and fieldVisible(c, f):
|
||||
it.sons[0] = newSymNode(f)
|
||||
e = fitNode(c, f.typ, e)
|
||||
|
||||
@@ -152,7 +152,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
while t.kind == tyObject:
|
||||
semForObjectFields(fc, t.n, n, stmts)
|
||||
if t.sons[0] == nil: break
|
||||
t = skipTypes(t.sons[0], abstractPtrs)
|
||||
t = skipTypes(t.sons[0], skipPtrs)
|
||||
dec(c.p.nestedLoopCounter)
|
||||
# for TR macros this 'while true: ...; break' loop is pretty bad, so
|
||||
# we avoid it now if we can:
|
||||
|
||||
@@ -47,7 +47,7 @@ proc rawHandleSelf(c: PContext; owner: PSym) =
|
||||
while t.kind == tyObject:
|
||||
addObjFieldsToLocalScope(c, t.n)
|
||||
if t.sons[0] == nil: break
|
||||
t = t.sons[0].skipTypes(abstractPtrs)
|
||||
t = t.sons[0].skipTypes(skipPtrs)
|
||||
|
||||
proc pushProcCon*(c: PContext; owner: PSym) =
|
||||
rawPushProcCon(c, owner)
|
||||
|
||||
@@ -131,7 +131,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
|
||||
if field != nil: break
|
||||
ty = ty.sons[0]
|
||||
if ty == nil: break
|
||||
ty = ty.skipTypes(abstractPtrs)
|
||||
ty = ty.skipTypes(skipPtrs)
|
||||
if field == nil:
|
||||
localError(n.info, errGenerated, "invalid guard field: " & g.name.s)
|
||||
return
|
||||
|
||||
@@ -659,7 +659,7 @@ proc semRaise(c: PContext, n: PNode): PNode =
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||
var typ = n.sons[0].typ
|
||||
if typ.kind != tyRef or typ.sons[0].kind != tyObject:
|
||||
if typ.kind != tyRef or typ.lastSon.kind != tyObject:
|
||||
localError(n.info, errExprCannotBeRaised)
|
||||
|
||||
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||
|
||||
@@ -661,11 +661,12 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
if n.sonsLen == 0: return newConstraint(c, tyObject)
|
||||
var check = initIntSet()
|
||||
var pos = 0
|
||||
var base: PType = nil
|
||||
var base, realBase: PType = nil
|
||||
# n.sons[0] contains the pragmas (if any). We process these later...
|
||||
checkSonsLen(n, 3)
|
||||
if n.sons[1].kind != nkEmpty:
|
||||
base = skipTypesOrNil(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
|
||||
realBase = semTypeNode(c, n.sons[1].sons[0], nil)
|
||||
base = skipTypesOrNil(realBase, skipPtrs)
|
||||
if base.isNil:
|
||||
localError(n.info, errIllegalRecursionInTypeX, "object")
|
||||
else:
|
||||
@@ -676,9 +677,10 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
if concreteBase.kind != tyError:
|
||||
localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
|
||||
base = nil
|
||||
realBase = nil
|
||||
if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
|
||||
result = newOrPrevType(tyObject, prev, c)
|
||||
rawAddSon(result, base)
|
||||
rawAddSon(result, realBase)
|
||||
if result.n.isNil:
|
||||
result.n = newNodeI(nkRecList, n.info)
|
||||
else:
|
||||
|
||||
@@ -352,18 +352,28 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||
else: result = isIntConv
|
||||
else: result = isNone
|
||||
|
||||
proc isObjectSubtype(a, f: PType): int =
|
||||
proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
|
||||
var t = a
|
||||
assert t.kind == tyObject
|
||||
var depth = 0
|
||||
var last = a
|
||||
while t != nil and not sameObjectTypes(f, t):
|
||||
assert t.kind == tyObject
|
||||
t = t.sons[0]
|
||||
if t == nil: break
|
||||
t = skipTypes(t, {tyGenericInst})
|
||||
last = t
|
||||
t = skipTypes(t, skipPtrs)
|
||||
inc depth
|
||||
if t != nil:
|
||||
if fGenericOrigin != nil and last.kind == tyGenericInst and
|
||||
last.len-1 == fGenericOrigin.len:
|
||||
for i in countup(1, sonsLen(fGenericOrigin) - 1):
|
||||
let x = PType(idTableGet(c.bindings, fGenericOrigin.sons[i]))
|
||||
if x == nil:
|
||||
put(c, fGenericOrigin.sons[i], last.sons[i])
|
||||
result = depth
|
||||
else:
|
||||
result = -1
|
||||
|
||||
type
|
||||
SkippedPtr = enum skippedNone, skippedRef, skippedPtr
|
||||
@@ -896,7 +906,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
result = isEqual
|
||||
# elif tfHasMeta in f.flags: result = recordRel(c, f, a)
|
||||
else:
|
||||
var depth = isObjectSubtype(a, f)
|
||||
var depth = isObjectSubtype(c, a, f, nil)
|
||||
if depth > 0:
|
||||
inc(c.inheritancePenalty, depth)
|
||||
result = isSubtype
|
||||
@@ -1012,6 +1022,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
result = isGeneric
|
||||
else:
|
||||
let genericBody = f.sons[0]
|
||||
var askip = skippedNone
|
||||
var fskip = skippedNone
|
||||
let aobj = x.skipToObject(askip)
|
||||
let fobj = genericBody.lastSon.skipToObject(fskip)
|
||||
if fobj != nil and aobj != nil and askip == fskip:
|
||||
let depth = isObjectSubtype(c, aobj, fobj, f)
|
||||
if depth >= 0:
|
||||
c.inheritancePenalty += depth
|
||||
return if depth == 0: isGeneric else: isSubtype
|
||||
result = typeRel(c, genericBody, x)
|
||||
if result != isNone:
|
||||
# see tests/generics/tgeneric3.nim for an example that triggers this
|
||||
|
||||
@@ -273,7 +273,7 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
|
||||
while true:
|
||||
suggestObject(c, t.n, outputs)
|
||||
if t.sons[0] == nil: break
|
||||
t = skipTypes(t.sons[0], {tyGenericInst})
|
||||
t = skipTypes(t.sons[0], skipPtrs)
|
||||
suggestOperations(c, n, typ, outputs)
|
||||
elif typ.kind == tyTuple and typ.n != nil:
|
||||
suggestSymList(c, typ.n, outputs)
|
||||
|
||||
@@ -94,7 +94,8 @@ proc invalidGenericInst(f: PType): bool =
|
||||
|
||||
proc isPureObject(typ: PType): bool =
|
||||
var t = typ
|
||||
while t.kind == tyObject and t.sons[0] != nil: t = t.sons[0]
|
||||
while t.kind == tyObject and t.sons[0] != nil:
|
||||
t = t.sons[0].skipTypes(skipPtrs)
|
||||
result = t.sym != nil and sfPure in t.sym.flags
|
||||
|
||||
proc getOrdValue(n: PNode): BiggestInt =
|
||||
@@ -228,7 +229,8 @@ proc searchTypeForAux(t: PType, predicate: TTypePredicate,
|
||||
if result: return
|
||||
case t.kind
|
||||
of tyObject:
|
||||
result = searchTypeForAux(t.sons[0], predicate, marker)
|
||||
if t.sons[0] != nil:
|
||||
result = searchTypeForAux(t.sons[0].skipTypes(skipPtrs), predicate, marker)
|
||||
if not result: result = searchTypeNodeForAux(t.n, predicate, marker)
|
||||
of tyGenericInst, tyDistinct:
|
||||
result = searchTypeForAux(lastSon(t), predicate, marker)
|
||||
@@ -265,7 +267,9 @@ proc analyseObjectWithTypeFieldAux(t: PType,
|
||||
if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
|
||||
return frEmbedded
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
|
||||
var x = t.sons[i]
|
||||
if x != nil: x = x.skipTypes(skipPtrs)
|
||||
res = analyseObjectWithTypeFieldAux(x, marker)
|
||||
if res == frEmbedded:
|
||||
return frEmbedded
|
||||
if res == frHeader: result = frHeader
|
||||
@@ -1293,7 +1297,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
|
||||
a = maxAlign
|
||||
of tyObject:
|
||||
if typ.sons[0] != nil:
|
||||
result = computeSizeAux(typ.sons[0], a)
|
||||
result = computeSizeAux(typ.sons[0].skipTypes(skipPtrs), a)
|
||||
if result < 0: return
|
||||
maxAlign = a
|
||||
elif isObjectWithTypeFieldPredicate(typ):
|
||||
|
||||
13
tests/objects/tinherit_from_generic.nim
Normal file
13
tests/objects/tinherit_from_generic.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
discard """
|
||||
output: '''true'''
|
||||
"""
|
||||
|
||||
# bug #4673
|
||||
type
|
||||
BaseObj[T] = ref object of RootObj
|
||||
SomeObj = ref object of BaseObj[int]
|
||||
|
||||
proc doSomething[T](o: BaseObj[T]) =
|
||||
echo "true"
|
||||
var o = new(SomeObj)
|
||||
o.doSomething() # Error: cannot instantiate: 'T'
|
||||
Reference in New Issue
Block a user