This commit is contained in:
Andreas Rumpf 2016-09-01 13:01:22 +02:00
commit 3a13706d7d
19 changed files with 74 additions and 31 deletions

View file

@ -46,7 +46,8 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
case a.kind case a.kind
of tyObject: 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) if result == arNo: result = isPartOfAux(a.n, b, marker)
of tyGenericInst, tyDistinct: of tyGenericInst, tyDistinct:
result = isPartOfAux(lastSon(a), b, marker) result = isPartOfAux(lastSon(a), b, marker)

View file

@ -726,6 +726,7 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope): PSym =
var ty = ty var ty = ty
assert r != nil assert r != nil
while ty != nil: while ty != nil:
ty = ty.skipTypes(skipPtrs)
assert(ty.kind in {tyTuple, tyObject}) assert(ty.kind in {tyTuple, tyObject})
result = lookupInRecord(ty.n, field.name) result = lookupInRecord(ty.n, field.name)
if result != nil: break if result != nil: break
@ -1257,7 +1258,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
if not p.module.compileToCpp: if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil: while t.kind == tyObject and t.sons[0] != nil:
add(r, ~".Sup") add(r, ~".Sup")
t = skipTypes(t.sons[0], typedescInst) t = skipTypes(t.sons[0], skipPtrs)
if isObjLackingTypeField(t): if isObjLackingTypeField(t):
globalError(x.info, errGenerated, globalError(x.info, errGenerated,
"no 'of' operator available for pure objects") "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: if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil: while t.kind == tyObject and t.sons[0] != nil:
add(r, ".Sup") add(r, ".Sup")
t = skipTypes(t.sons[0], abstractInst) t = skipTypes(t.sons[0], skipPtrs)
if nilCheck != nil: if nilCheck != nil:
linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n", linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
nilCheck, r, genTypeInfo(p.module, dest)) nilCheck, r, genTypeInfo(p.module, dest))

View file

@ -73,7 +73,9 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) =
lineF(p, cpsStmts, "}$n", []) lineF(p, cpsStmts, "}$n", [])
of tyObject: of tyObject:
for i in countup(0, sonsLen(typ) - 1): 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) if typ.n != nil: genTraverseProc(c, accessor, typ.n)
of tyTuple: of tyTuple:
let typ = getUniqueType(typ) let typ = getUniqueType(typ)

View file

@ -475,11 +475,11 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
hasField = true hasField = true
elif m.compileToCpp: elif m.compileToCpp:
appcg(m, result, " : public $1 {$n", appcg(m, result, " : public $1 {$n",
[getTypeDescAux(m, typ.sons[0], check)]) [getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
hasField = true hasField = true
else: else:
appcg(m, result, " {$n $1 Sup;$n", appcg(m, result, " {$n $1 Sup;$n",
[getTypeDescAux(m, typ.sons[0], check)]) [getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
hasField = true hasField = true
else: else:
addf(result, " {$n", [name]) 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]) addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
var t = typ.sons[0] var t = typ.sons[0]
while t != nil: while t != nil:
t = t.skipTypes(abstractInst) t = t.skipTypes(skipPtrs)
t.flags.incl tfObjHasKids t.flags.incl tfObjHasKids
t = t.sons[0] t = t.sons[0]

View file

@ -246,7 +246,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
if not p.module.compileToCpp: if not p.module.compileToCpp:
while (s.kind == tyObject) and (s.sons[0] != nil): while (s.kind == tyObject) and (s.sons[0] != nil):
add(r, ".Sup") 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)) linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t))
of frEmbedded: of frEmbedded:
# worst case for performance: # worst case for performance:

View file

@ -1364,7 +1364,7 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v
if output.len > 0: output.add(", ") if output.len > 0: output.add(", ")
addf(output, "m_type: $1" | "'m_type' => $#", [genTypeInfo(p, t)]) addf(output, "m_type: $1" | "'m_type' => $#", [genTypeInfo(p, t)])
while t != nil: while t != nil:
createRecordVarAux(p, t.n, excludedFieldIDs, output) createRecordVarAux(p, t.skipTypes(skipPtrs).n, excludedFieldIDs, output)
t = t.sons[0] t = t.sons[0]
proc arrayTypeForElemType(typ: PType): string = proc arrayTypeForElemType(typ: PType): string =

View file

@ -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)]) addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
if (typ.kind == tyObject) and (typ.sons[0] != nil): if (typ.kind == tyObject) and (typ.sons[0] != nil):
addf(p.g.typeInfo, "$1.base = $2;$n", 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 = proc genTupleFields(p: PProc, typ: PType): Rope =
var s: Rope = nil var s: Rope = nil

View file

@ -172,7 +172,7 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode =
if field != nil: break if field != nil: break
t = t.sons[0] t = t.sons[0]
if t == nil: break if t == nil: break
t = t.skipTypes(abstractInst) t = t.skipTypes(skipPtrs)
#if field == nil: #if field == nil:
# echo "FIELD ", b # echo "FIELD ", b
# debug deref.typ # debug deref.typ
@ -193,7 +193,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym =
if result != nil: break if result != nil: break
t = t.sons[0] t = t.sons[0]
if t == nil: break if t == nil: break
t = t.skipTypes(abstractInst) t = t.skipTypes(skipPtrs)
proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode = proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
# returns a[].b as a node # returns a[].b as a node

View file

@ -203,7 +203,8 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)
of tyObject, tyDistinct: of tyObject, tyDistinct:
if not considerOverloadedOp(c, t, body, x, y): 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) if t.kind == tyObject: liftBodyObj(c, t.n, body, x, y)
of tyTuple: of tyTuple:
liftBodyTup(c, t, body, x, y) liftBodyTup(c, t, body, x, y)

View file

@ -1070,7 +1070,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result = check result = check
return result return result
if ty.sons[0] == nil: break 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: # old code, not sure if it's live code:
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(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) f = lookupInRecordAndBuildCheck(c, n, ty.n, i, check)
if f != nil: break if f != nil: break
if ty.sons[0] == nil: break if ty.sons[0] == nil: break
ty = skipTypes(ty.sons[0], {tyGenericInst}) ty = skipTypes(ty.sons[0], skipPtrs)
if f != nil: if f != nil:
if fieldVisible(c, f): if fieldVisible(c, f):
# is the access to a public field or in the same module or in a friend? # 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) f = lookupInRecordAndBuildCheck(c, it, t.n, id, check)
if f != nil: break if f != nil: break
if t.sons[0] == 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): if f != nil and fieldVisible(c, f):
it.sons[0] = newSymNode(f) it.sons[0] = newSymNode(f)
e = fitNode(c, f.typ, e) e = fitNode(c, f.typ, e)

View file

@ -152,7 +152,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
while t.kind == tyObject: while t.kind == tyObject:
semForObjectFields(fc, t.n, n, stmts) semForObjectFields(fc, t.n, n, stmts)
if t.sons[0] == nil: break if t.sons[0] == nil: break
t = skipTypes(t.sons[0], abstractPtrs) t = skipTypes(t.sons[0], skipPtrs)
dec(c.p.nestedLoopCounter) dec(c.p.nestedLoopCounter)
# for TR macros this 'while true: ...; break' loop is pretty bad, so # for TR macros this 'while true: ...; break' loop is pretty bad, so
# we avoid it now if we can: # we avoid it now if we can:

View file

@ -47,7 +47,7 @@ proc rawHandleSelf(c: PContext; owner: PSym) =
while t.kind == tyObject: while t.kind == tyObject:
addObjFieldsToLocalScope(c, t.n) addObjFieldsToLocalScope(c, t.n)
if t.sons[0] == nil: break if t.sons[0] == nil: break
t = t.sons[0].skipTypes(abstractPtrs) t = t.sons[0].skipTypes(skipPtrs)
proc pushProcCon*(c: PContext; owner: PSym) = proc pushProcCon*(c: PContext; owner: PSym) =
rawPushProcCon(c, owner) rawPushProcCon(c, owner)

View file

@ -131,7 +131,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
if field != nil: break if field != nil: break
ty = ty.sons[0] ty = ty.sons[0]
if ty == nil: break if ty == nil: break
ty = ty.skipTypes(abstractPtrs) ty = ty.skipTypes(skipPtrs)
if field == nil: if field == nil:
localError(n.info, errGenerated, "invalid guard field: " & g.name.s) localError(n.info, errGenerated, "invalid guard field: " & g.name.s)
return return

View file

@ -659,7 +659,7 @@ proc semRaise(c: PContext, n: PNode): PNode =
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
n.sons[0] = semExprWithType(c, n.sons[0]) n.sons[0] = semExprWithType(c, n.sons[0])
var typ = n.sons[0].typ 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) localError(n.info, errExprCannotBeRaised)
proc addGenericParamListToScope(c: PContext, n: PNode) = proc addGenericParamListToScope(c: PContext, n: PNode) =

View file

@ -661,11 +661,12 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
if n.sonsLen == 0: return newConstraint(c, tyObject) if n.sonsLen == 0: return newConstraint(c, tyObject)
var check = initIntSet() var check = initIntSet()
var pos = 0 var pos = 0
var base: PType = nil var base, realBase: PType = nil
# n.sons[0] contains the pragmas (if any). We process these later... # n.sons[0] contains the pragmas (if any). We process these later...
checkSonsLen(n, 3) checkSonsLen(n, 3)
if n.sons[1].kind != nkEmpty: 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: if base.isNil:
localError(n.info, errIllegalRecursionInTypeX, "object") localError(n.info, errIllegalRecursionInTypeX, "object")
else: else:
@ -676,9 +677,10 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
if concreteBase.kind != tyError: if concreteBase.kind != tyError:
localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects) localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
base = nil base = nil
realBase = nil
if n.kind != nkObjectTy: internalError(n.info, "semObjectNode") if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
result = newOrPrevType(tyObject, prev, c) result = newOrPrevType(tyObject, prev, c)
rawAddSon(result, base) rawAddSon(result, realBase)
if result.n.isNil: if result.n.isNil:
result.n = newNodeI(nkRecList, n.info) result.n = newNodeI(nkRecList, n.info)
else: else:

View file

@ -352,18 +352,28 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
else: result = isIntConv else: result = isIntConv
else: result = isNone else: result = isNone
proc isObjectSubtype(a, f: PType): int = proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
var t = a var t = a
assert t.kind == tyObject assert t.kind == tyObject
var depth = 0 var depth = 0
var last = a
while t != nil and not sameObjectTypes(f, t): while t != nil and not sameObjectTypes(f, t):
assert t.kind == tyObject assert t.kind == tyObject
t = t.sons[0] t = t.sons[0]
if t == nil: break if t == nil: break
t = skipTypes(t, {tyGenericInst}) last = t
t = skipTypes(t, skipPtrs)
inc depth inc depth
if t != nil: 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 result = depth
else:
result = -1
type type
SkippedPtr = enum skippedNone, skippedRef, skippedPtr SkippedPtr = enum skippedNone, skippedRef, skippedPtr
@ -896,7 +906,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = isEqual result = isEqual
# elif tfHasMeta in f.flags: result = recordRel(c, f, a) # elif tfHasMeta in f.flags: result = recordRel(c, f, a)
else: else:
var depth = isObjectSubtype(a, f) var depth = isObjectSubtype(c, a, f, nil)
if depth > 0: if depth > 0:
inc(c.inheritancePenalty, depth) inc(c.inheritancePenalty, depth)
result = isSubtype result = isSubtype
@ -1012,6 +1022,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = isGeneric result = isGeneric
else: else:
let genericBody = f.sons[0] 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) result = typeRel(c, genericBody, x)
if result != isNone: if result != isNone:
# see tests/generics/tgeneric3.nim for an example that triggers this # see tests/generics/tgeneric3.nim for an example that triggers this

View file

@ -273,7 +273,7 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
while true: while true:
suggestObject(c, t.n, outputs) suggestObject(c, t.n, outputs)
if t.sons[0] == nil: break if t.sons[0] == nil: break
t = skipTypes(t.sons[0], {tyGenericInst}) t = skipTypes(t.sons[0], skipPtrs)
suggestOperations(c, n, typ, outputs) suggestOperations(c, n, typ, outputs)
elif typ.kind == tyTuple and typ.n != nil: elif typ.kind == tyTuple and typ.n != nil:
suggestSymList(c, typ.n, outputs) suggestSymList(c, typ.n, outputs)

View file

@ -94,7 +94,8 @@ proc invalidGenericInst(f: PType): bool =
proc isPureObject(typ: PType): bool = proc isPureObject(typ: PType): bool =
var t = typ 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 result = t.sym != nil and sfPure in t.sym.flags
proc getOrdValue(n: PNode): BiggestInt = proc getOrdValue(n: PNode): BiggestInt =
@ -228,7 +229,8 @@ proc searchTypeForAux(t: PType, predicate: TTypePredicate,
if result: return if result: return
case t.kind case t.kind
of tyObject: 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) if not result: result = searchTypeNodeForAux(t.n, predicate, marker)
of tyGenericInst, tyDistinct: of tyGenericInst, tyDistinct:
result = searchTypeForAux(lastSon(t), predicate, marker) result = searchTypeForAux(lastSon(t), predicate, marker)
@ -265,7 +267,9 @@ proc analyseObjectWithTypeFieldAux(t: PType,
if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
return frEmbedded return frEmbedded
for i in countup(0, sonsLen(t) - 1): 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: if res == frEmbedded:
return frEmbedded return frEmbedded
if res == frHeader: result = frHeader if res == frHeader: result = frHeader
@ -1293,7 +1297,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
a = maxAlign a = maxAlign
of tyObject: of tyObject:
if typ.sons[0] != nil: if typ.sons[0] != nil:
result = computeSizeAux(typ.sons[0], a) result = computeSizeAux(typ.sons[0].skipTypes(skipPtrs), a)
if result < 0: return if result < 0: return
maxAlign = a maxAlign = a
elif isObjectWithTypeFieldPredicate(typ): elif isObjectWithTypeFieldPredicate(typ):

View 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'