Skip to content

Commit aaba3c5

Browse files
authored
sem: fix crash due to incorrect error handling (#1372)
## Summary Wrap usage of erroneous symbols in quiet errors, so that error propagation works as expected. This fixes compiler/nimsuggest crashes when the iterable expression in `for` loops has an error. Fixes #1369. ## Details ### The Problem If the iterable slot of a `for` loop is an error, `tyError` is assigned as the forvars' type. When such forvar appears as an argument in a call expression, errors ### The Solution * add the `adWrappedSymError` diagnostic, which is a quiet diagnostic like `adWrappedError`, meaning that it's only used for error propagation and never reported * move `newSymNode2` from `ast` to `sem` and change it so that it creates `adWrappedSymError` error nodes for symbols where the definition has an error * rename `newSymNode2` to `newSymNodeOrError` * update the few usages of `newSymNode2` * add test for the `for`-loop-related compiler crash to the new `error_propagation` category The introduction of `adWrappedSymError` is meant to be a foundational work for changing `skError` to only represent errors (instead of both errors and symbols whose definition has an error).
1 parent bd3d3dc commit aaba3c5

File tree

9 files changed

+37
-40
lines changed

9 files changed

+37
-40
lines changed

compiler/ast/ast.nim

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -193,32 +193,6 @@ proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
193193
result.ident = ident
194194
result.info = info
195195

196-
proc newSymNode2*(sym: PSym): PNode =
197-
## creates a new `nkSym` node, unless sym.kind is an skError where an nkError
198-
## is extracted from the sym and returned instead.
199-
## NB: not a `newSymNode` replacement, it's for when symbol sem fails
200-
if sym.isError:
201-
result = sym.ast
202-
else:
203-
result = newNode(nkSym)
204-
result.sym = sym
205-
result.typ = sym.typ
206-
result.info = sym.info
207-
208-
proc newSymNode2*(sym: PSym, info: TLineInfo): PNode =
209-
## creates a new `nkSym` node, unless sym.kind is an skError where an nkError
210-
## is extracted from the sym and returned instead. In either case sets the
211-
## node info to the one provided
212-
## NB: not a `newSymNode` replacement, it's for when symbol sem fails
213-
if sym.isError:
214-
result = sym.ast
215-
result.info = info
216-
else:
217-
result = newNode(nkSym)
218-
result.sym = sym
219-
result.typ = sym.typ
220-
result.info = info
221-
222196
proc newSymNodeIT*(sym: PSym, info: TLineInfo, typ: PType): PNode =
223197
## create a new sym node with the supplied `info` and `typ`
224198
result = newNodeIT(nkSym, info, typ)

compiler/ast/ast_types.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,7 @@ type
10701070
AstDiagKind* = enum
10711071
# general
10721072
adWrappedError
1073+
adWrappedSymError
10731074
adCyclicTree
10741075
# type
10751076
adSemTypeMismatch
@@ -1279,7 +1280,7 @@ type
12791280
location*: TLineInfo # TODO: `wrongNode` already has this, move to
12801281
# variant or handle in display/rendering
12811282
case kind*: AstDiagKind
1282-
of adWrappedError:
1283+
of adWrappedError, adWrappedSymError:
12831284
discard
12841285
of adSemTypeMismatch,
12851286
adSemIllegalConversion,

compiler/ast/errorhandling.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ iterator walkErrors*(config: ConfigRef; n: PNode): PNode =
189189
for i in 0..<errNodes.len:
190190
# reverse index so we go from the innermost to outermost
191191
let e = errNodes[i]
192-
if e.diag.kind == adWrappedError:
192+
if e.diag.kind in {adWrappedError, adWrappedSymError}:
193193
continue
194194

195195
assert(

compiler/front/cli_reporter.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3143,7 +3143,7 @@ func astDiagToLegacyReport(conf: ConfigRef, diag: PAstDiag): Report {.inline.} =
31433143
vmRep: VMReport
31443144

31453145
case diag.kind
3146-
of adWrappedError:
3146+
of adWrappedError, adWrappedSymError:
31473147
semRep = SemReport(
31483148
location: some diag.location,
31493149
reportInst: diag.instLoc.toReportLineInfo,

compiler/front/msgs.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ func astDiagToLegacyReportKind*(
422422
## very broad categories and they'll no longer map to "reports".
423423
case diag
424424
of adWrappedError: rsemWrappedError
425+
of adWrappedSymError: rsemWrappedError
425426
of adSemTypeMismatch: rsemTypeMismatch
426427
of adSemTypeNotAllowed: rsemTypeNotAllowed
427428
of adSemTIsNotAConcreteType: rsemTIsNotAConcreteType

compiler/sem/sem.nim

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,20 @@ proc wrapErrorAndUpdate(c: ConfigRef, n: PNode, s: PSym): PNode =
151151
result = c.wrapError(n)
152152
s.ast = result
153153

154+
proc newSymNodeOrError(c: ConfigRef, sym: PSym, info: TLineInfo): PNode =
155+
## Creates a new `nkSym` node, unless `sym` either represents an error
156+
## itself or refers to an erroneous entity. In the latter two cases, an
157+
## error node is returned.
158+
## NB: not a `newSymNode` replacement, it's for when symbol sem fails
159+
if sym.isError:
160+
result = sym.ast
161+
result.info = info
162+
elif sym.ast.isError or (sym.typ != nil and sym.typ.kind == tyError):
163+
result = c.newError(newSymNode(sym, info),
164+
PAstDiag(kind: adWrappedSymError))
165+
else:
166+
result = newSymNode(sym, info)
167+
154168
template semIdeForTemplateOrGenericCheck(conf, n, cursorInBody) =
155169
# use only for idetools support; detecting cursor in generic or template body
156170
# if so call `semIdeForTemplateOrGeneric` for semantic checking

compiler/sem/semexprs.nim

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,7 +1631,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
16311631
localReport(c.config, n, reportSem rsemIllegalNimvmContext)
16321632

16331633
markUsed(c, n.info, s)
1634-
result = newSymNode2(s, n.info)
1634+
result = newSymNodeOrError(c.config, s, n.info)
16351635
# We cannot check for access to outer vars for example because it's still
16361636
# not sure the symbol really ends up being used:
16371637
# var len = 0 # but won't be called
@@ -1662,14 +1662,9 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
16621662
c.config.internalAssert s.owner != nil
16631663
result = newSymNode(s, n.info)
16641664
else:
1665-
if s.kind == skError and not s.ast.isNil and s.ast.kind == nkError:
1666-
# XXX: at the time of writing only `lookups.qualifiedlookup` sets up the
1667-
# PSym so the error is in the ast field
1668-
result = s.ast
1669-
else:
1670-
let info = getCallLineInfo(n)
1671-
markUsed(c, info, s)
1672-
result = newSymNode(s, info)
1665+
let info = getCallLineInfo(n)
1666+
markUsed(c, info, s)
1667+
result = newSymNodeOrError(c.config, s, info)
16731668

16741669
proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
16751670
case t.kind

compiler/sem/semstmts.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ proc semNormalizedLetOrVar(c: PContext, n: PNode, symkind: TSymKind): PNode =
839839
c.config.newError(r, PAstDiag(kind: adSemIllegalCompileTime))
840840

841841
if v.isError:
842-
producedDecl[i] = newSymNode2(v)
842+
producedDecl[i] = v.ast # ast is an error AST
843843
hasError = true
844844

845845
continue # refactor: remove the need to continue
@@ -1202,7 +1202,7 @@ proc semNormalizedConst(c: PContext, n: PNode): PNode =
12021202
localReport(c.config, defPart.info, reportSem(rsemResultShadowed))
12031203

12041204
if v.isError:
1205-
producedDecl[i] = newSymNode2(v)
1205+
producedDecl[i] = v.ast # ast is an error AST
12061206
hasError = true
12071207

12081208
continue # refactor: remove the need to continue
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
discard """
2+
description: '''
3+
Ensure for-loop vars are usable in call expressions when the iterable slot
4+
has an error.
5+
'''
6+
matrix: "--errorMax:100"
7+
errormsg: "undeclared identifier: 'unknown'"
8+
line: 11
9+
"""
10+
11+
for x in unknown:
12+
echo x

0 commit comments

Comments
 (0)