Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

recursively skip invocations for generic ref object types #336

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 19 additions & 53 deletions src/nimony/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1372,12 +1372,9 @@ proc findObjField(t: Cursor; name: StrId; level = 0): ObjField =
if baseType.kind == DotToken:
result = ObjField(level: -1)
else:
if baseType.typeKind in {RefT, PtrT}:
inc baseType
if baseType.typeKind == InvokeT:
inc baseType # get to root symbol
if baseType.kind == Symbol:
result = findObjField(objtypeImpl(baseType.symId), name, level+1)
baseType = rootObjtypeImpl(baseType)
if baseType.typeKind == ObjectT:
result = findObjField(baseType, name, level+1)
else:
# maybe error
result = ObjField(level: -1)
Expand Down Expand Up @@ -1426,27 +1423,18 @@ proc tryBuiltinDot(c: var SemContext; it: var Item; lhs: Item; fieldName: StrId;
result = InvalidDot
else:
let t = skipModifier(lhs.typ)
var root = t
if root.typeKind in {RefT, PtrT}:
inc root
if root.typeKind == InvokeT:
inc root
if root.kind == Symbol:
let objType = objtypeImpl(root.symId)
if objType.typeKind == ObjectT:
let field = findObjField(objType, fieldName)
if field.level >= 0:
c.dest.add symToken(field.sym, info)
c.dest.add intToken(pool.integers.getOrIncl(field.level), info)
it.typ = field.typ # will be fit later with commonType
it.kind = FldY
result = MatchedDotField
else:
c.dest.add identToken(fieldName, info)
c.buildErr info, "undeclared field: " & pool.strings[fieldName]
let objType = rootObjtypeImpl(t)
if objType.typeKind == ObjectT:
let field = findObjField(objType, fieldName)
if field.level >= 0:
c.dest.add symToken(field.sym, info)
c.dest.add intToken(pool.integers.getOrIncl(field.level), info)
it.typ = field.typ # will be fit later with commonType
it.kind = FldY
result = MatchedDotField
else:
c.dest.add identToken(fieldName, info)
c.buildErr info, "object type expected"
c.buildErr info, "undeclared field: " & pool.strings[fieldName]
elif lhs.kind == ModuleY:
# this is a qualified identifier, i.e. module.name
# consider matched even if undeclared
Expand Down Expand Up @@ -3557,27 +3545,11 @@ proc buildObjConstrField(c: var SemContext; field: Local; setFields: Table[SymId
proc buildDefaultObjConstr(c: var SemContext; typ: Cursor; setFields: Table[SymId, Cursor]; info: PackedLineInfo) =
c.dest.addParLe(OconstrX, info)
c.dest.addSubtree typ
var objImpl = typ
if objImpl.typeKind in {RefT, PtrT}:
inc objImpl
if objImpl.typeKind == InvokeT:
inc objImpl
if objImpl.kind == Symbol:
objImpl = objtypeImpl(objImpl.symId)
var objImpl = rootObjtypeImpl(typ)
var obj = asObjectDecl(objImpl)
# same field order as old nim VM: starting with most shallow base type
while obj.parentType.kind != DotToken:
var parentImpl = obj.parentType
if parentImpl.typeKind in {RefT, PtrT}:
inc parentImpl
if parentImpl.kind == Symbol:
parentImpl = objtypeImpl(parentImpl.symId)
elif parentImpl.typeKind == InvokeT:
inc parentImpl # get to symbol
parentImpl = objtypeImpl(parentImpl.symId)
else:
# should not be possible
discard
var parentImpl = rootObjtypeImpl(obj.parentType)
let parent = asObjectDecl(parentImpl)
obj.parentType = parent.parentType
var currentField = parent.firstField
Expand All @@ -3599,16 +3571,10 @@ proc semObjConstr(c: var SemContext, it: var Item) =
inc it.n
it.typ = semLocalType(c, it.n)
c.dest.shrink exprStart
var objType = it.typ
if objType.typeKind in {RefT, PtrT}:
inc objType
if objType.typeKind == InvokeT:
inc objType
if objType.kind == Symbol:
objType = objtypeImpl(objType.symId)
if objType.typeKind != ObjectT:
c.buildErr info, "expected object type for object constructor"
return
var objType = rootObjtypeImpl(it.typ)
if objType.typeKind != ObjectT:
c.buildErr info, "expected object type for object constructor"
return
var fieldBuf = createTokenBuf(16)
var setFieldPositions = initTable[SymId, int]()
while it.n.kind != ParRi:
Expand Down
29 changes: 29 additions & 0 deletions src/nimony/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,35 @@ proc objtypeImpl*(s: SymId): Cursor =
if k in {RefT, PtrT}:
inc result

proc rootObjtypeImpl*(c: Cursor): Cursor =
## get root object type impl from any combination of type symbols,
## generic invocations and a single layer of `ref`/`ptr` indirection
result = c
var ptrs = 0
while true:
if result.kind == Symbol:
let res = tryLoadSym(result.symId)
if res.status != LacksNothing or res.decl.stmtKind != TypeS:
break
result = asTypeDecl(res.decl).body
else:
let kind = result.typeKind
case kind
of RefT, PtrT:
if ptrs != 0:
break
inc ptrs
inc result
of InvokeT:
# get to base sym
inc result
of ObjectT:
# match
break
else:
# not an object type
break

proc getTypeSection*(s: SymId): TypeDecl =
let res = tryLoadSym(s)
assert res.status == LacksNothing
Expand Down
21 changes: 21 additions & 0 deletions tests/nimony/basics/tgenericbinarytree.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type int* {.magic: Int.}

type
NodeObj[T] = object
data: T
left, right: ref NodeObj[T]
Node[T] = ref NodeObj[T]

var x = Node[int](data: 123, left: nil, right: nil)
x.data = 456
x.left = Node[int](data: 123, left: nil, right: nil)
x.right = nil
x.left.right = nil
var y = Node[int](data: 987, left: nil, right: nil)
x.left.left = Node[int](data: -123, left: y, right: y)

proc foo[T](data: T): Node[T] =
result = Node[T](data: data, left: nil, right: nil)
result.data = data
let a = foo(123)
x = a
Loading