Skip to content

Commit

Permalink
tuples now support default values for fields
Browse files Browse the repository at this point in the history
  • Loading branch information
ringabout committed Aug 18, 2022
1 parent 6041db3 commit f0424ff
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 30 deletions.
61 changes: 36 additions & 25 deletions compiler/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,35 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode

const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink, tyDistinct}

proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): seq[PNode] =
case recNode.kind
of nkRecList:
for field in recNode:
result.add defaultFieldsForTuple(c, field, hasDefault)
of nkSym:
let field = recNode.sym
let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes)
if field.ast != nil: #Try to use default value
hasDefault = true
result.add newTree(nkExprColonExpr, recNode, field.ast)
elif recType.kind in {tyObject, tyArray, tyTuple}:
let asgnExpr = defaultNodeField(c, recNode, recNode.typ)
if asgnExpr != nil:
hasDefault = true
asgnExpr.flags.incl nfUseDefaultField
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), recType.owner)
rawAddSon(asgnType, recType)
let asgnExpr = newTree(nkCall,
newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)),
newNodeIT(nkType, recNode.info, asgnType)
)
asgnExpr.flags.incl nfUseDefaultField
asgnExpr.typ = recType
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
doAssert false

proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
case recNode.kind
Expand Down Expand Up @@ -617,31 +646,13 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode =
result.flags.incl nfUseDefaultField
elif aTypSkip.kind == tyTuple:
var hasDefault = false
var children: seq[PNode]
for s in aTypSkip.sons:
let child = defaultNodeField(c, a, s)
if child != nil:
hasDefault = true
children.add child
if hasDefault:
result = newNodeI(nkTupleConstr, a.info)
result.typ = aTyp
var i = 0
while i < children.len:
let s = children[i]
if s != nil:
result.add s
else:
let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), aTypSkip[i].owner)
rawAddSon(asgnType, aTypSkip[i])
let asgnExpr = newTree(nkCall,
newSymNode(getSysMagic(c.graph, a.info, "zeroDefault", mZeroDefault)),
newNodeIT(nkType, a.info, asgnType)
)
asgnExpr.flags.incl nfUseDefaultField
asgnExpr.typ = aTypSkip[i]
result.add asgnExpr
inc i
if aTypSkip.n != nil:
let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault)
if hasDefault and children.len > 0:
result = newNodeI(nkTupleConstr, a.info)
result.typ = aTyp
result.flags.incl nfUseDefaultField
result.sons.add children

proc defaultNodeField(c: PContext, a: PNode): PNode =
result = defaultNodeField(c, a, a.typ)
Expand Down
19 changes: 14 additions & 5 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const
errXExpectsOneTypeParam = "'$1' expects one type parameter"
errArrayExpectsTwoTypeParams = "array expects two type parameters"
errInvalidVisibilityX = "invalid visibility: '$1'"
errInitHereNotAllowed = "initialization not allowed here"
errXCannotBeAssignedTo = "'$1' cannot be assigned to"
errIteratorNotAllowed = "iterators can only be defined at the module's top level"
errXNeedsReturnType = "$1 needs a return type"
Expand Down Expand Up @@ -460,13 +459,19 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
var a = n[i]
if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
checkMinSonsLen(a, 3, c.config)
if a[^2].kind != nkEmpty:
var hasDefaultField = a[^1].kind != nkEmpty
if hasDefaultField:
a[^1] = semConstExpr(c, a[^1])
typ = a[^1].typ
elif a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
a[^1] = newIntNode(nkIntLit, firstOrd(c.config, typ))
a[^1].typ = typ
hasDefaultField = true
else:
localError(c.config, a.info, errTypeExpected)
typ = errorType(c)
if a[^1].kind != nkEmpty:
localError(c.config, a[^1].info, errInitHereNotAllowed)
for j in 0..<a.len - 2:
var field = newSymG(skField, a[j], c)
field.typ = typ
Expand All @@ -475,7 +480,11 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
if containsOrIncl(check, field.name.id):
localError(c.config, a[j].info, "attempt to redefine: '" & field.name.s & "'")
else:
result.n.add newSymNode(field)
let fSym = newSymNode(field)
if hasDefaultField:
fSym.sym.ast = a[^1]
fSym.sym.ast.flags.incl nfUseDefaultField
result.n.add fSym
addSonSkipIntLit(result, typ, c.idgen)
styleCheckDef(c, a[j].info, field)
onDef(field.info, field)
Expand Down
11 changes: 11 additions & 0 deletions tests/objects/tobject_default_value.nim
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,17 @@ template main =

doAssert hello[Default]()[^1].id == 1

block:
type
Default = tuple
id: int = 1

Default2 = tuple[id: int = 1]

var x: Default
proc hello(): Default2 = discard
doAssert hello().id == x.id


proc main1 =
var my = @[1, 2, 3, 4, 5]
Expand Down

0 comments on commit f0424ff

Please sign in to comment.