From e4ac3def9ca65b5eeb45896bc71c206501eb6d6f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 18 Apr 2024 14:34:42 +0000 Subject: [PATCH] fixes #19833 #19833; transform `discardable` into discard statement --- compiler/semexprs.nim | 4 +-- compiler/semstmts.nim | 65 +++++++++++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 61d4687a36..1f2a0d46b0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1186,7 +1186,7 @@ proc semExprNoType(c: PContext, n: PNode): PNode = let isPush = c.config.hasHint(hintExtendedContext) if isPush: pushInfoContext(c.config, n.info) result = semExpr(c, n, {efWantStmt}) - discardCheck(c, result, {}) + result = discardCheck(c, result, {}) if isPush: popInfoContext(c.config) proc isTypeExpr(n: PNode): bool = @@ -2022,7 +2022,7 @@ proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode = a[1] = result result = semAsgn(c, a) else: - discardCheck(c, result, {}) + result = discardCheck(c, result, {}) if c.p.owner.kind notin {skMacro, skTemplate} and c.p.resultSym != nil and c.p.resultSym.typ.isMetaType: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f71fc9fa0d..61f2235f86 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -137,12 +137,25 @@ const nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr, nkHiddenStdConv, nkHiddenDeref} -proc implicitlyDiscardable(n: PNode): bool = +const skipForDiscardableStmt = skipForDiscardable - {nkHiddenStdConv, nkHiddenDeref} + +type + DiscardableKind = enum + No, LastBlock, Discardable + +proc implicitlyDiscardableClassifier(n: PNode): DiscardableKind = var n = n while n.kind in skipForDiscardable: n = n.lastSon - result = n.kind in nkLastBlockStmts or - (isCallExpr(n) and n[0].kind == nkSym and - sfDiscardable in n[0].sym.flags) + if n.kind in nkLastBlockStmts: + result = LastBlock + elif isCallExpr(n) and n[0].kind == nkSym and + sfDiscardable in n[0].sym.flags: + result = Discardable + else: + result = No + +proc implicitlyDiscardable(n: PNode): bool = + result = implicitlyDiscardableClassifier(n) in {LastBlock, Discardable} proc fixNilType(c: PContext; n: PNode) = if isAtom(n): @@ -153,13 +166,31 @@ proc fixNilType(c: PContext; n: PNode) = for it in n: fixNilType(c, it) n.typ = nil -proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) = +proc wrapDiscardableExpr(n: PNode): PNode = + result = n + var n = n + var parent = n + var hasWork = false + while n.kind in skipForDiscardableStmt: + parent = n + n = n.lastSon + if n.kind notin skipForDiscardableStmt: + parent[^1] = newTreeI(nkDiscardStmt, n.info, n) + hasWork = true + break + if not hasWork: + result = newTreeI(nkDiscardStmt, result.info, result) + +proc discardCheck(c: PContext, n: PNode, flags: TExprFlags): PNode = + result = n if c.matchedConcept != nil or efInTypeof in flags: return if result.typ != nil and result.typ.kind notin {tyTyped, tyVoid}: - if implicitlyDiscardable(result): - var n = newNodeI(nkDiscardStmt, result.info, 1) - n[0] = result + let kind = implicitlyDiscardableClassifier(result) + if kind == Discardable: + result = wrapDiscardableExpr(result) + elif kind == LastBlock: + discard elif result.typ.kind != tyError and c.config.cmd != cmdInteractive: if result.typ.kind == tyNone: localError(c.config, result.info, "expression has no type: " & @@ -207,7 +238,8 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): else: illFormedAst(it, c.config) if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped} or (not hasElse and efInTypeof notin flags): - for it in n: discardCheck(c, it.lastSon, flags) + for it in n: + it[^1] = discardCheck(c, it[^1], flags) result.transitionSonsKind(nkIfStmt) # propagate any enforced VoidContext: if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext @@ -314,12 +346,14 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil) closeScope(c) if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped}: - discardCheck(c, n[0], flags) - for i in 1..