From 0b32c96e3d266cbee52c0f984286937b4f35de36 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 6 May 2022 21:56:49 +0800 Subject: [PATCH] fix range type --- compiler/ast.nim | 1 + compiler/parser.nim | 6 +--- compiler/semexprs.nim | 10 ++++-- compiler/semmagic.nim | 10 ++++++ compiler/semobjconstr.nim | 63 +++++++++++++++++++++--------------- compiler/semstmts.nim | 25 +++++++++++++++ compiler/semtypes.nim | 21 +++++++++--- compiler/transf.nim | 67 ++++++++++++++++++++++++++++++++++++++- 8 files changed, 164 insertions(+), 39 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index d1e5ae2bfe655..f6a27d4da8f01 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -502,6 +502,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) 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/semexprs.nim b/compiler/semexprs.nim index 702b47929c7c4..f03605b61cc05 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -897,8 +897,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, rawAddSon(typ, result.typ) result.typ = typ -proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode - proc resolveIndirectCall(c: PContext; n, nOrig: PNode; t: PType): TCandidate = initCandidate(c, result, t) @@ -2380,6 +2378,14 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mSizeOf: markUsed(c, n.info, s) result = semSizeof(c, setMs(n, s)) + of mDefault: + result = semDirectOp(c, n, flags) + let typ = result[^1].typ.skipTypes({tyTypeDesc}) + if typ.skipTypes(abstractInst).kind == tyObject: + var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[^1].info, typ)) + asgnExpr.typ = typ + asgnExpr.sons.add defaultFieldsForTheUninitialized(c.graph.config, typ.skipTypes({tyGenericInst, tyAlias, tySink}).n) + result = semObjConstr(c, asgnExpr, flags) else: result = semDirectOp(c, n, flags) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index ed1826fd4ea9b..918fd39c71739 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -10,6 +10,8 @@ # This include file implements the semantic checking for magics. # included from sem.nim +proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode + proc semAddrArg(c: PContext; n: PNode): PNode = let x = semExprWithType(c, n) if x.kind == nkSym: @@ -512,6 +514,14 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result = n else: result = plugin(c, n) + of mNew: + result = n + let typ = result[^1].typ + if typ.skipTypes(abstractInst).kind == tyRef and typ.skipTypes(abstractInst)[0].kind == tyObject: + var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[^1].info, typ)) + asgnExpr.typ = typ + asgnExpr.sons.add defaultFieldsForTheUninitialized(c.graph.config, typ.skipTypes(abstractInst)[0].n) + result = newTree(nkAsgn, result[^1], semObjConstr(c, asgnExpr, flags)) of mNewFinalize: # Make sure the finalizer procedure refers to a procedure if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}: diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 6d11d321ec24d..0e28587e5aa7a 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -29,6 +29,10 @@ type initNone # None of the fields have been initialized initConflict # Fields from different branches have been initialized + +proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, + flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] + proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) = case newStatus of initConflict: @@ -72,7 +76,9 @@ proc semConstrField(c: PContext, flags: TExprFlags, let assignment = locateFieldInInitExpr(c, field, initExpr) if assignment != nil: if nfSem in assignment.flags: return assignment[1] - if not fieldVisible(c, field): + if nfUseDefaultField in assignment[1].flags: + discard + elif not fieldVisible(c, field): localError(c.config, initExpr.info, "the field '$1' is not accessible." % [field.name.s]) return @@ -155,18 +161,14 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode, if assignment == nil: constrCtx.missingFields.add r.sym - -proc semConstructFields(c: PContext, n: PNode, - constrCtx: var ObjConstrContext, - flags: TExprFlags): InitStatus = - result = initUnknown - +proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, + flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] = case n.kind of nkRecList: for field in n: - let status = semConstructFields(c, field, constrCtx, flags) - mergeInitStatus(result, status) - + let (subSt, subDf) = semConstructFields(c, field, constrCtx, flags) + result.status.mergeInitStatus subSt + result.defaults.add subDf of nkRecCase: template fieldsPresentInBranch(branchIdx: int): string = let branch = n[branchIdx] @@ -184,9 +186,10 @@ proc semConstructFields(c: PContext, n: PNode, 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 typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind in {tyRange, tyOrdinal}: + n[^1] = semConstExpr(c, 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.config, f) onDef(f.info, f) if a.kind != nkEmpty: father.add a diff --git a/compiler/transf.nim b/compiler/transf.nim index bdd7c680ccd51..ace4c6fd679ac 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 @@ -927,6 +927,49 @@ proc commonOptimizations*(g: ModuleGraph; idgen: IdGenerator; c: PSym, n: PNode) else: result = n +proc defaultFieldsForTheUninitialized*(c: ConfigRef, recNode: PNode): seq[PNode] = + case recNode.kind + of nkRecList: + for field in recNode: + result.add defaultFieldsForTheUninitialized(c, field) + of nkRecCase: + discard + # let discriminator = recNode[0] + # var selectedBranch: int + # let defaultValue = discriminator.sym.ast + # if defaultValue == nil: + # # None of the branches were explicitly selected by the user and no value + # # was given to the discrimator. We can assume that it will be initialized + # # to zero and this will select a particular branch as a result: + # selectedBranch = recNode.pickCaseBranch newIntNode(nkIntLit#[c.graph]#, 0) + # else: # Try to use default value + # selectedBranch = recNode.pickCaseBranch defaultValue + # result.add newTree(nkExprColonExpr, discriminator, defaultValue) + # result.add defaultFieldsForTheUninitialized(recNode[selectedBranch][^1]) + of nkSym: + let field = recNode.sym + if field.ast != nil: #Try to use default value + result.add newTree(nkExprColonExpr, recNode, field.ast) + elif recNode.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject: + var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, recNode.info, recNode.typ)) + asgnExpr.typ = recNode.typ + asgnExpr.flags.incl nfUseDefaultField + asgnExpr.sons.add defaultFieldsForTheUninitialized(c, recNode.typ.skipTypes({tyGenericInst, tyAlias, tySink}).n) + result.add newTree(nkExprColonExpr, recNode, asgnExpr) + elif recNode.typ.kind == tyArray and recNode.typ[1].skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject: + var asgnExpr = newNodeI(nkBracket, recNode.info) + asgnExpr.typ = recNode.typ + asgnExpr.flags.incl nfUseDefaultField + let defaults = defaultFieldsForTheUninitialized(c, recNode.typ[1].skipTypes({tyGenericInst, tyAlias, tySink}).n) + for i in 0.. resultPos and c.transCon.owner.ast[resultPos] != nil result = transform(c, n) popTransCon(c) incl(result.flags, nfTransf)