mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-14 15:43:45 +00:00
IC: proctype handling
This commit is contained in:
@@ -618,6 +618,18 @@ proc genProcParams(m: BModule; t: PType, rettype: var Rope, params: var Builder,
|
||||
for i in 1..<t.n.len:
|
||||
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
|
||||
var param = t.n[i].sym
|
||||
# The hidden closure environment param (`:envP`) is not a real C parameter:
|
||||
# the environment is passed via the trailing `ClE_0` (added below) and
|
||||
# `closureSetup` materialises `:envP` as a local cast of it. In a from-source
|
||||
# build `:envP` only lives in the routine's AST params, never in the proc
|
||||
# *type's* `n`, so it never reaches here. Under IC `closureParams` re-shares
|
||||
# the AST param node with `typ.n`, so the lifted `:envP` leaks into `t.n`;
|
||||
# emitting it would produce a bogus extra parameter that collides with the
|
||||
# `closureSetup` local (the "redeclared as different kind of symbol" / env
|
||||
# pointer-type mismatch). We still must fill its name/loc (later passes such
|
||||
# as `assignParam` and `closureSetup` reference it), but it is omitted from
|
||||
# the C signature to match the from-source ABI.
|
||||
let isClosureEnv = t.callConv == ccClosure and param.name.s == ":envP"
|
||||
var descKind = dkParam
|
||||
if m.config.backend == backendCpp and optByRef in param.options:
|
||||
if param.typ.kind == tyGenericInst:
|
||||
@@ -629,6 +641,7 @@ proc genProcParams(m: BModule; t: PType, rettype: var Rope, params: var Builder,
|
||||
fillParamName(m, param)
|
||||
fillLoc(param.locImpl, locParam, t.n[i],
|
||||
param.paramStorageLoc)
|
||||
if isClosureEnv: continue # name/loc filled, but not part of the C signature
|
||||
var typ: Rope
|
||||
if ccgIntroducedPtr(m.config, param, t.returnType) and descKind == dkParam:
|
||||
typ = ptrType(getTypeDescWeak(m, param.typ, check, descKind))
|
||||
|
||||
@@ -261,12 +261,28 @@ proc typeKey(c: var Context; t: PType; flags: set[ConsiderFlag]; conf: ConfigRef
|
||||
c.typeKey(t.skipModifierB, flags, conf)
|
||||
of tyProc:
|
||||
withTree c.m, (if tfIterator in t.flagsImpl: "itertype" else: "proctype"):
|
||||
if CoProc in flags and t.nImpl != nil:
|
||||
# Proc parameter *types* are part of the type's identity. Under IC the
|
||||
# parameters live in `nImpl` (`sonsImpl` holds only the return type), so a
|
||||
# loaded proc type has an empty `sonsImpl[1..]`; reading params from there
|
||||
# would silently drop them and collide every same-return/same-callconv
|
||||
# closure onto one key (e.g. `proc(cb: proc())` onto bare `proc()`),
|
||||
# which made hook lookup resolve to the wrong `=copy`. Prefer `nImpl`
|
||||
# (consistent in-memory and after load); hash param types only, not their
|
||||
# symbols — parameter names do not affect type identity.
|
||||
if t.nImpl != nil and t.nImpl.kind == nkFormalParams:
|
||||
let params = t.nImpl
|
||||
for i in 1..<params.len:
|
||||
let param = params[i].sym
|
||||
c.symKey(param, conf)
|
||||
c.typeKey(param.typImpl, flags, conf)
|
||||
if params[i].kind == nkSym:
|
||||
# The param sym may be a lazily-loaded stub: force it in (as `symKey`
|
||||
# does) so its type is available, then hash the param *type* only —
|
||||
# parameter names are not part of the type's identity. Without the
|
||||
# load the type reads back nil at codegen and the key silently loses
|
||||
# its parameters (collapsing distinct closure types onto one key).
|
||||
let ps = params[i].sym
|
||||
if ps.state == Partial and c.sl != nil: c.sl(ps)
|
||||
c.typeKey(ps.typImpl, flags, conf)
|
||||
else:
|
||||
c.typeKey(params[i].typField, flags, conf)
|
||||
else:
|
||||
for i in 1..<t.sonsImpl.len:
|
||||
c.typeKey(t.sonsImpl[i], flags, conf)
|
||||
|
||||
Reference in New Issue
Block a user