diff --git a/compiler/ast.nim b/compiler/ast.nim index 27e4fab63374b..50e8438f0b8dd 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -503,6 +503,7 @@ type nfLastRead # this node is a last read nfFirstWrite# this node is a first write nfHasComment # node has a comment + nfUseDefaultField TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45) @@ -1433,6 +1434,17 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = result.intVal = intVal result.typ = typ +proc newFloatTypeNode*(floatVal: BiggestFloat, typ: PType): PNode = + let kind = skipTypes(typ, abstractVarRange).kind + case kind + of tyFloat32: + result = newNode(nkFloat32Lit) + of tyFloat64, tyFloat: + result = newNode(nkFloatLit) + else: doAssert false, $kind + result.floatVal = floatVal + result.typ = typ + proc newIntTypeNode*(intVal: Int128, typ: PType): PNode = # XXX: introduce range check newIntTypeNode(castToInt64(intVal), typ) diff --git a/compiler/parser.nim b/compiler/parser.nim index 52466d9fa0f04..2f89efc560d7c 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1963,11 +1963,7 @@ proc parseObjectCase(p: var Parser): PNode = #| | IND{=} objectBranches) result = newNodeP(nkRecCase, p) getTokNoInd(p) - var a = newNodeP(nkIdentDefs, p) - a.add(identWithPragma(p)) - eat(p, tkColon) - a.add(parseTypeDesc(p)) - a.add(p.emptyNode) + var a = parseIdentColonEquals(p, {withPragma}) result.add(a) if p.tok.tokType == tkColon: getTok(p) flexComment(p, result) diff --git a/compiler/sem.nim b/compiler/sem.nim index 70c57864c5d09..3ecadf3fc5c68 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -535,6 +535,164 @@ proc setGenericParamsMisc(c: PContext; n: PNode) = else: n[miscPos][1] = orig +proc caseBranchMatchesExpr(branch, matched: PNode): bool = + for i in 0 ..< branch.len-1: + if branch[i].kind == nkRange: + if overlap(branch[i], matched): return true + elif exprStructuralEquivalent(branch[i], matched): + return true + +proc pickCaseBranchIndex(caseExpr, matched: PNode): int = + let endsWithElse = caseExpr[^1].kind == nkElse + for i in 1..= 4: a = newNodeI(nkRecList, n.info) else: a = newNodeI(nkEmpty, n.info) - if n[^1].kind != nkEmpty: - localError(c.config, n[^1].info, errInitHereNotAllowed) var typ: PType - if n[^2].kind == nkEmpty: + var hasDefaultField = n[^1].kind != nkEmpty + if hasDefaultField: + n[^1] = semConstExpr(c, n[^1]) + typ = n[^1].typ + propagateToOwner(rectype, typ) + elif n[^2].kind == nkEmpty: localError(c.config, n.info, errTypeExpected) typ = errorType(c) else: typ = semTypeNode(c, n[^2], nil) + if c.graph.config.isDefined("nimRangeDefault") and typ.skipTypes(abstractInst).kind in {tyRange, tyOrdinal}: + n[^1] = newIntNode(nkIntLit, firstOrd(c.config, typ)) + n[^1].typ = typ + hasDefaultField = true propagateToOwner(rectype, typ) var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner else: rectype.sym @@ -806,8 +813,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, inc(pos) if containsOrIncl(check, f.name.id): localError(c.config, info, "attempt to redefine: '" & f.name.s & "'") - if a.kind == nkEmpty: father.add newSymNode(f) - else: a.add newSymNode(f) + let fSym = newSymNode(f) + if hasDefaultField: + fSym.sym.ast = n[^1] + fSym.sym.ast.flags.incl nfUseDefaultField + if a.kind == nkEmpty: father.add fSym + else: a.add fSym styleCheckDef(c, f) onDef(f.info, f) if a.kind != nkEmpty: father.add a diff --git a/compiler/transf.nim b/compiler/transf.nim index bdd7c680ccd51..b44c45a6b659a 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -46,7 +46,7 @@ type module: PSym transCon: PTransCon # top of a TransCon stack inlining: int # > 0 if we are in inlining context (copy vars) - nestedProcs: int # > 0 if we are in a nested proc + genResult: bool contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' deferDetected, tooEarly: bool graph: ModuleGraph @@ -935,6 +935,21 @@ proc transform(c: PTransf, n: PNode): PNode = nkBlockStmt, nkBlockExpr}: oldDeferAnchor = c.deferAnchor c.deferAnchor = n + + # if c.genResult: + # c.genResult = false + # result = newNodeIT(nkStmtList, n.info, nil) + # let toInit = c.getCurrOwner().ast[resultPos] + + # if toInit.typ != nil: + # let field = defaultNodeField(c.graph, toInit) + + # if field != nil: + # result.add newTree(nkAsgn, toInit, field) + + # result.add transform(c, n) + # return result + case n.kind of nkSym: result = transformSym(c, n) @@ -1052,6 +1067,13 @@ proc transform(c: PTransf, n: PNode): PNode = result = n of nkExceptBranch: result = transformExceptBranch(c, n) + of nkObjConstr: + result = n + if result.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject or + result.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyRef and result.typ.skipTypes({tyGenericInst, tyAlias, tySink})[0].kind == tyObject: + result.sons.add result[0].sons + result[0] = newNodeIT(nkType, result.info, result.typ) + result = transformSons(c, result) of nkCheckedFieldExpr: result = transformSons(c, n) if result[0].kind != nkDotExpr: @@ -1079,6 +1101,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode = # nodes into an empty node. if nfTransf in n.flags: return n pushTransCon(c, newTransCon(owner)) + c.genResult = c.getCurrOwner().kind in routineKinds and c.transCon.owner.ast.len > resultPos and c.transCon.owner.ast[resultPos] != nil result = transform(c, n) popTransCon(c) incl(result.flags, nfTransf) diff --git a/lib/system.nim b/lib/system.nim index 738666e8da32e..faf79f6a91770 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -573,6 +573,11 @@ when notJSnotNims and not defined(nimSeqsV2): template space(s: PGenericSeq): int {.dirty.} = s.reserved and not (seqShallowFlag or strlitFlag) + +proc newDefaultArray*[T](N: static int, y: T): array[N, T] = + for i in 0..N-1: + result[i] = y + when notJSnotNims: include "system/hti" diff --git a/tests/objects/mobject_default_value.nim b/tests/objects/mobject_default_value.nim new file mode 100644 index 0000000000000..2245495015075 --- /dev/null +++ b/tests/objects/mobject_default_value.nim @@ -0,0 +1,15 @@ +type + Clean = object + mem: int + Default* = object + poi: int = 12 + clc: Clean + se*: range[0'i32 .. high(int32)] + + NonDefault* = object + poi: int + + PrellDeque*[T] = object + pendingTasks*: range[0'i32 .. high(int32)] + head: T + tail: T diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim new file mode 100644 index 0000000000000..82e1275edacdc --- /dev/null +++ b/tests/objects/tobject_default_value.nim @@ -0,0 +1,238 @@ +discard """ + matrix: "-d:nimRangeDefault" + targets: "c cpp js" +""" + +import times + +type + Guess = object + poi: DateTime + +block: + var x: Guess + discard x + + discard Guess() + +import mobject_default_value + +block: + let x = Default() + doAssert x.se == 0'i32 +# echo Default(poi: 12) +# echo Default(poi: 17) + +# echo NonDefault(poi: 77) + +block: + var x: Default + doAssert x.se == 0'i32 + +type + ObjectBase = object of RootObj + value = 12 + + Object = object of ObjectBase + time: float = 1.2 + date: int + scale: range[1..10] + + Object2 = object + name: Object + + Object3 = object + obj: Object2 + + ObjectTuple = tuple + base: ObjectBase + typ: int + obj: Object + + Ref = ref object of ObjectBase + + RefInt = ref object of Ref + data = 73 + +var t {.threadvar.}: Default +# var m1, m2 {.threadvar.}: Default + +block: + doAssert t.se == 0'i32 + +block: + var x: ObjectBase + doAssert x.value == 12 + let y = default(ObjectBase) + doAssert y.value == 12 + +block: + var x: Object + doAssert x.value == 12 + doAssert x.time == 1.2 + doAssert x.scale == 1 + let y = default(Object) + doAssert y.value == 12 + doAssert y.time == 1.2 + doAssert y.scale == 1 + + var x1, x2, x3: Object + doAssert x1.value == 12 + doAssert x1.time == 1.2 + doAssert x1.scale == 1 + doAssert x2.value == 12 + doAssert x2.time == 1.2 + doAssert x2.scale == 1 + doAssert x3.value == 12 + doAssert x3.time == 1.2 + doAssert x3.scale == 1 + +block: + var x: Ref + new(x) + doAssert x.value == 12, "Ref.value = " & $x.value + + var y: RefInt + new(y) + doAssert y.value == 12 + doAssert y.data == 73 + +# block: # object array +# var x: ObjectArray +# echo x + +block: + var x: Object2 + doAssert x.name.value == 12 + doAssert x.name.time == 1.2 + doAssert x.name.scale == 1 + +block: + var x: Object3 + doAssert x.obj.name.value == 12 + doAssert x.obj.name.time == 1.2 + doAssert x.obj.name.scale == 1 + +# block: #seq +# var x = newSeq[Object](10) +# echo x + +block: # array + var x: array[10, Object] + let y = x[0] + doAssert y.value == 12 + doAssert y.time == 1.2 + doAssert y.scale == 1 + +block: # array + var x {.noinit.}: array[10, Object] + discard x + +# block: # tuple +# var x: ObjectTuple +# doAssert x.base.value == 12 +# doAssert x.typ == 0 +# doAssert x.obj.time == 1.2 +# doAssert x.obj.date == 0 +# doAssert x.obj.scale == 1 +# doAssert x.obj.value == 12 + +type + ObjectArray = object + data: array[10, Object] + +block: + var x: ObjectArray + let y = x.data[0] + doAssert y.value == 12 + doAssert y.time == 1.2 + doAssert y.scale == 1 + + +block: + var x: PrellDeque[int] + doAssert x.pendingTasks == 0 + +type + Color = enum + Red, Blue, Yellow + + ObjectVarint = object + case kind: Color + of Red: + data: int = 10 + of Blue: + fill = "123" + of Yellow: + time = 1.8'f32 + + ObjectVarint1 = object + case kind: Color = Blue + of Red: + data1: int = 10 + of Blue: + fill2 = "123" + cry: float + of Yellow: + time3 = 1.8'f32 + him: int + +block: + var x = ObjectVarint(kind: Red) + doAssert x.kind == Red + doAssert x.data == 10 + +block: + var x = ObjectVarint(kind: Blue) + doAssert x.kind == Blue + doAssert x.fill == "123" + +block: + var x = ObjectVarint(kind: Yellow) + doAssert x.kind == Yellow + doAssert typeof(x.time) is float32 + +block: + var x: ObjectVarint1 + doAssert x.kind == Blue + doAssert x.fill2 == "123" + x.cry = 326 + + +type + ObjectVarint2 = object + case kind: Color + of Red: + data: int = 10 + of Blue: + fill = "123" + of Yellow: + time = 1.8'f32 + + ObjectVarint3 = object + case kind: Color = Blue + of Red: + data1: int = 10 + of Blue: + case name: Color = Blue + of Blue: + go = 12 + else: + temp = 66 + fill2 = "123" + cry: float + of Yellow: + time3 = 1.8'f32 + him: int + +block: + var x: ObjectVarint3 + doAssert x.kind == Blue + doAssert x.name == Blue + doAssert x.go == 12 + +block: + var x = ObjectVarint3(kind: Blue, name: Red, temp: 99) + doAssert x.kind == Blue + doAssert x.name == Red + doAssert x.temp == 99