Skip to content

Commit

Permalink
fix(sem): errors in lambdas no longer crash
Browse files Browse the repository at this point in the history
Summary
---------

Errors in lambdas requiring inference (`proc(e: auto) echo e`), no
longer crash the compiler. Instead errors within the lambda body are
reported and lambda inference fails as it should.

Details
-------

`semInferredLambda` failed to wrap its output when there were errors.
This would reach `transf` and result in a compiler crash by hitting an
`unreachable` assertion.

Now errors in the body are reported immediately (to provide context for
inference failure) and AST output from the inference attempt is
correctly wrapped such that inference appropriately fails.
  • Loading branch information
saem committed Aug 28, 2024
1 parent 17f96a1 commit 0ddf173
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 21 deletions.
49 changes: 28 additions & 21 deletions compiler/sem/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2182,45 +2182,52 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} =
## used for resolving 'auto' in lambdas based on their callsite
addInNimDebugUtils(c.config, "semInferredLambda", n, result)
var n = n
let original = n[namePos].sym
let s = original #copySym(original, false)
#incl(s.flags, sfFromGeneric)
#s.owner = original

n = instantiateTypesInBody(c, pt, n, original)
result = n
result = instantiateTypesInBody(c, pt, n, original)
s.ast = result
n[namePos].sym = s
n[genericParamsPos] = c.graph.emptyNode
result[namePos].sym = s
result[genericParamsPos] = c.graph.emptyNode
# for LL we need to avoid wrong aliasing
n[paramsPos] = newNodeI(nkFormalParams, n[paramsPos].info, n.typ.n.len)
for i, p in n.typ.n.pairs:
n[paramsPos][i] =
result[paramsPos] = newNodeI(nkFormalParams, result[paramsPos].info,
result.typ.n.len)
for i, p in result.typ.n.pairs:
result[paramsPos][i] =
case i
of 0: # return type
newNodeIT(nkType, n.info, n.typ[0])
newNodeIT(nkType, n.info, result.typ[0])
else: # copy instantiated parameters
n.typ.n[i]
s.typ = n.typ
let params = n.typ.n
for i in 1..<params.len:
if params[i].typ.kind in {tyTypeDesc, tyGenericParam,
tyFromExpr}+tyTypeClasses:
localReport(c.config, params[i].info, reportSym(
rsemCannotInferTypeOfParameter, params[i].sym))
#params[i].sym.owner = s
if p.typ.kind in {tyTypeDesc, tyGenericParam,
tyFromExpr}+tyTypeClasses:
localReport(c.config, p.info, reportSym(
rsemCannotInferTypeOfParameter, p.sym))
#params[i].sym.owner = s
result.typ.n[i]
s.typ = result.typ
openScope(c)
pushOwner(c, s)
addParams(c, params)
addParams(c, result.typ.n)
pushProcCon(c, s)
addResult(c, n, n.typ[0])
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
addResult(c, result, result.typ[0])
result[bodyPos] = semProcBody(c, result[bodyPos])
if result[bodyPos].kind == nkError:
# output the error now otherwise we'll just get an inferred lambda failure
# without an explanation, ideally this should be explained/added context of
# the inferred lambda error itself.
c.config.localReport(result[bodyPos])
s.ast[bodyPos] = hloBody(c, result[bodyPos])
s.ast[bodyPos] = foldInAst(c.module, s.ast[bodyPos], c.idgen, c.graph)
trackProc(c, s, s.ast[bodyPos])
popProcCon(c)
popOwner(c)
closeScope(c)
# wrap in an error if there were issues along the way
for k in result.items:
if k.kind == nkError:
result = c.config.wrapError(result)
# alternative variant (not quite working):
# var prc = arg[0].sym
# let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
discard """
description: "Fail lambda inference due to error without the body."
errormsg: "undeclared identifier: 'i'"
line: 11
"""

# This is a regression test, ensure we report errors inside lambdas during
# inference

var x: seq[proc(i: int)]
x.add proc(e: auto) = echo i

0 comments on commit 0ddf173

Please sign in to comment.