semLambda removed, semProcAux reworked (#17379)
* simplified proc-like name ident to symbol code * wip - reworking generic param sem * wip - closer to removing nkEmpty generic params * it's hacky but tests pass * slowly tweaking semProcAux to take on semLambda * fix pragma superset check proto vs current * Set the symbol owner earlier * partial progress reworking proto found bug where default values between forward and impl lead to overload resolution issues. * simplified pragma handling and callConv checks Co-authored-by: Clyybber <Clyybber@users.noreply.github.com> * partially working * cgexprs issue * It works! * comment clean-up * clean-up asserts, comments, and other bits * add isGenericParams, inline isGeneric queries * seeing if this is sufficiently consistent * can use this approach or continue it in a further PR * commentary about nullary generics and clean-ups * fixed a mistake in PNode isGenericRoutine * Some small cleanups * Small cleanup * for func lambdas ensure we use lambda pragmas * add some basic compileTime func tests * [ci skip] remove comments Co-authored-by: Clyybber <Clyybber@users.noreply.github.com> Co-authored-by: Clyybber <darkmine956@gmail.com>
This commit is contained in:
parent
144e338abb
commit
72b89eff82
18 changed files with 286 additions and 212 deletions
|
|
@ -1040,6 +1040,7 @@ const
|
||||||
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
||||||
routineDefs* = declarativeDefs + {nkMacroDef, nkTemplateDef}
|
routineDefs* = declarativeDefs + {nkMacroDef, nkTemplateDef}
|
||||||
procDefs* = nkLambdaKinds + declarativeDefs
|
procDefs* = nkLambdaKinds + declarativeDefs
|
||||||
|
callableDefs* = nkLambdaKinds + routineDefs
|
||||||
|
|
||||||
nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}
|
nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}
|
||||||
nkStrKinds* = {nkStrLit..nkTripleStrLit}
|
nkStrKinds* = {nkStrLit..nkTripleStrLit}
|
||||||
|
|
@ -1760,12 +1761,32 @@ proc getStrOrChar*(a: PNode): string =
|
||||||
#internalError(a.info, "getStrOrChar")
|
#internalError(a.info, "getStrOrChar")
|
||||||
#result = ""
|
#result = ""
|
||||||
|
|
||||||
proc isGenericRoutine*(s: PSym): bool =
|
proc isGenericParams*(n: PNode): bool {.inline.} =
|
||||||
case s.kind
|
## used to judge whether a node is generic params.
|
||||||
of skProcKinds:
|
n != nil and n.kind == nkGenericParams
|
||||||
result = sfFromGeneric in s.flags or
|
|
||||||
(s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty)
|
proc isGenericRoutine*(n: PNode): bool {.inline.} =
|
||||||
else: discard
|
n != nil and n.kind in callableDefs and n[genericParamsPos].isGenericParams
|
||||||
|
|
||||||
|
proc isGenericRoutineStrict*(s: PSym): bool {.inline.} =
|
||||||
|
## determines if this symbol represents a generic routine
|
||||||
|
## the unusual name is so it doesn't collide and eventually replaces
|
||||||
|
## `isGenericRoutine`
|
||||||
|
s.kind in skProcKinds and s.ast.isGenericRoutine
|
||||||
|
|
||||||
|
proc isGenericRoutine*(s: PSym): bool {.inline.} =
|
||||||
|
## determines if this symbol represents a generic routine or an instance of
|
||||||
|
## one. This should be renamed accordingly and `isGenericRoutineStrict`
|
||||||
|
## should take this name instead.
|
||||||
|
##
|
||||||
|
## Warning/XXX: Unfortunately, it considers a proc kind symbol flagged with
|
||||||
|
## sfFromGeneric as a generic routine. Instead this should likely not be the
|
||||||
|
## case and the concepts should be teased apart:
|
||||||
|
## - generic definition
|
||||||
|
## - generic instance
|
||||||
|
## - either generic definition or instance
|
||||||
|
s.kind in skProcKinds and (sfFromGeneric in s.flags or
|
||||||
|
s.ast.isGenericRoutine)
|
||||||
|
|
||||||
proc skipGenericOwner*(s: PSym): PSym =
|
proc skipGenericOwner*(s: PSym): PSym =
|
||||||
## Generic instantiations are owned by their originating generic
|
## Generic instantiations are owned by their originating generic
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
|
||||||
|
|
||||||
proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
|
proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
|
||||||
var op = getAttachedOp(c.graph, t, kind)
|
var op = getAttachedOp(c.graph, t, kind)
|
||||||
if op == nil or op.ast[genericParamsPos].kind != nkEmpty:
|
if op == nil or op.ast.isGenericRoutine:
|
||||||
# give up and find the canonical type instead:
|
# give up and find the canonical type instead:
|
||||||
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
|
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
|
||||||
let canon = c.graph.canonTypes.getOrDefault(h)
|
let canon = c.graph.canonTypes.getOrDefault(h)
|
||||||
|
|
@ -278,7 +278,7 @@ proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode
|
||||||
#echo dest.typ.id
|
#echo dest.typ.id
|
||||||
globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] &
|
globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] &
|
||||||
"' operator not found for type " & typeToString(t))
|
"' operator not found for type " & typeToString(t))
|
||||||
elif op.ast[genericParamsPos].kind != nkEmpty:
|
elif op.ast.isGenericRoutine:
|
||||||
globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] &
|
globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] &
|
||||||
"' operator is generic")
|
"' operator is generic")
|
||||||
dbg:
|
dbg:
|
||||||
|
|
|
||||||
|
|
@ -354,7 +354,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||||
# markUsed(c.g.config, c.info, op, c.g.usageSym)
|
# markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||||
onUse(c.info, op)
|
onUse(c.info, op)
|
||||||
# We also now do generic instantiations in the destructor lifting pass:
|
# We also now do generic instantiations in the destructor lifting pass:
|
||||||
if op.ast[genericParamsPos].kind != nkEmpty:
|
if op.ast.isGenericRoutine:
|
||||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||||
field = op
|
field = op
|
||||||
#echo "trying to use ", op.ast
|
#echo "trying to use ", op.ast
|
||||||
|
|
@ -370,7 +370,7 @@ proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
|
||||||
var op = t.destructor
|
var op = t.destructor
|
||||||
|
|
||||||
if op != nil and sfOverriden in op.flags:
|
if op != nil and sfOverriden in op.flags:
|
||||||
if op.ast[genericParamsPos].kind != nkEmpty:
|
if op.ast.isGenericRoutine:
|
||||||
# patch generic destructor:
|
# patch generic destructor:
|
||||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||||
setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op)
|
setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op)
|
||||||
|
|
@ -394,7 +394,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||||
var op = t.destructor
|
var op = t.destructor
|
||||||
if op != nil and sfOverriden in op.flags:
|
if op != nil and sfOverriden in op.flags:
|
||||||
|
|
||||||
if op.ast[genericParamsPos].kind != nkEmpty:
|
if op.ast.isGenericRoutine:
|
||||||
# patch generic destructor:
|
# patch generic destructor:
|
||||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||||
setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op)
|
setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op)
|
||||||
|
|
@ -1021,7 +1021,7 @@ proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo; idgen: Id
|
||||||
|
|
||||||
let op = getAttachedOp(g, t, attachedDestructor)
|
let op = getAttachedOp(g, t, attachedDestructor)
|
||||||
if op != nil:
|
if op != nil:
|
||||||
if op.ast[genericParamsPos].kind != nkEmpty:
|
if op.ast.isGenericRoutine:
|
||||||
internalError(g.config, info, "resolved destructor is generic")
|
internalError(g.config, info, "resolved destructor is generic")
|
||||||
if op.magic == mDestroy:
|
if op.magic == mDestroy:
|
||||||
internalError(g.config, info, "patching mDestroy with mDestroy?")
|
internalError(g.config, info, "patching mDestroy with mDestroy?")
|
||||||
|
|
@ -1031,7 +1031,7 @@ proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo; idgen: Id
|
||||||
proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: IdGenerator;
|
proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: IdGenerator;
|
||||||
info: TLineInfo) =
|
info: TLineInfo) =
|
||||||
let op = getAttachedOp(g, t, kind)
|
let op = getAttachedOp(g, t, kind)
|
||||||
if op != nil and op.ast != nil and op.ast[genericParamsPos].kind != nkEmpty:
|
if op != nil and op.ast != nil and op.ast.isGenericRoutine:
|
||||||
if t.typeInst != nil:
|
if t.typeInst != nil:
|
||||||
var a: TLiftCtx
|
var a: TLiftCtx
|
||||||
a.info = info
|
a.info = info
|
||||||
|
|
|
||||||
|
|
@ -287,6 +287,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
|
||||||
|
|
||||||
proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
|
proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
|
||||||
conflictsWith: TLineInfo) =
|
conflictsWith: TLineInfo) =
|
||||||
|
## Emit a redefinition error if in non-interactive mode
|
||||||
if c.config.cmd != cmdInteractive:
|
if c.config.cmd != cmdInteractive:
|
||||||
localError(c.config, info,
|
localError(c.config, info,
|
||||||
"redefinition of '$1'; previous declaration here: $2" %
|
"redefinition of '$1'; previous declaration here: $2" %
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ const
|
||||||
wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
|
wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
|
||||||
wThread, wAsmNoStackFrame,
|
wThread, wAsmNoStackFrame,
|
||||||
wRaises, wLocks, wTags, wRequires, wEnsures,
|
wRaises, wLocks, wTags, wRequires, wEnsures,
|
||||||
wGcSafe, wCodegenDecl, wNoInit}
|
wGcSafe, wCodegenDecl, wNoInit, wCompileTime}
|
||||||
typePragmas* = declPragmas + {wMagic, wAcyclic,
|
typePragmas* = declPragmas + {wMagic, wAcyclic,
|
||||||
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
|
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
|
||||||
wIncompleteStruct, wCompleteStruct, wByCopy, wByRef,
|
wIncompleteStruct, wCompleteStruct, wByCopy, wByRef,
|
||||||
|
|
@ -1245,23 +1245,23 @@ proc mergePragmas(n, pragmas: PNode) =
|
||||||
else:
|
else:
|
||||||
for p in pragmas: n[pragmasPos].add p
|
for p in pragmas: n[pragmasPos].add p
|
||||||
|
|
||||||
proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
|
proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
|
||||||
validPragmas: TSpecialWords) =
|
validPragmas: TSpecialWords) =
|
||||||
if sym != nil and sym.kind != skModule:
|
if sym != nil and sym.kind != skModule:
|
||||||
for it in c.optionStack:
|
for it in c.optionStack:
|
||||||
let o = it.otherPragmas
|
let o = it.otherPragmas
|
||||||
if not o.isNil and sfFromGeneric notin sym.flags: # see issue #12985
|
if not o.isNil and sfFromGeneric notin sym.flags: # see issue #12985
|
||||||
pushInfoContext(c.config, n.info)
|
pushInfoContext(c.config, info)
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < o.len:
|
while i < o.len:
|
||||||
if singlePragma(c, sym, o, i, validPragmas, true, false):
|
if singlePragma(c, sym, o, i, validPragmas, true, false):
|
||||||
internalError(c.config, n.info, "implicitPragmas")
|
internalError(c.config, info, "implicitPragmas")
|
||||||
inc i
|
inc i
|
||||||
popInfoContext(c.config)
|
popInfoContext(c.config)
|
||||||
if sym.kind in routineKinds and sym.ast != nil: mergePragmas(sym.ast, o)
|
if sym.kind in routineKinds and sym.ast != nil: mergePragmas(sym.ast, o)
|
||||||
|
|
||||||
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
|
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
|
||||||
localError(c.config, n.info, ".dynlib requires .exportc")
|
localError(c.config, info, ".dynlib requires .exportc")
|
||||||
var lib = c.optionStack[^1].dynlib
|
var lib = c.optionStack[^1].dynlib
|
||||||
if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
|
if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
|
||||||
sfImportc in sym.flags and lib != nil:
|
sfImportc in sym.flags and lib != nil:
|
||||||
|
|
@ -1291,4 +1291,11 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords;
|
||||||
isStatement: bool) =
|
isStatement: bool) =
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
pragmaRec(c, sym, n, validPragmas, isStatement)
|
pragmaRec(c, sym, n, validPragmas, isStatement)
|
||||||
implicitPragmas(c, sym, n, validPragmas)
|
# XXX: in the case of a callable def, this should use its info
|
||||||
|
implicitPragmas(c, sym, n.info, validPragmas)
|
||||||
|
|
||||||
|
proc pragmaCallable*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords,
|
||||||
|
isStatement: bool = false) =
|
||||||
|
if n == nil: return
|
||||||
|
if n[pragmasPos].kind != nkEmpty:
|
||||||
|
pragmaRec(c, sym, n[pragmasPos], validPragmas, isStatement)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ proc semProcBody(c: PContext, n: PNode): PNode
|
||||||
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode
|
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode
|
||||||
proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
|
proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
|
||||||
|
|
||||||
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
|
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
|
||||||
proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode
|
proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode
|
||||||
proc semOpAux(c: PContext, n: PNode)
|
proc semOpAux(c: PContext, n: PNode)
|
||||||
|
|
|
||||||
|
|
@ -445,7 +445,7 @@ proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
|
||||||
let a = if a.kind == nkHiddenDeref: a[0] else: a
|
let a = if a.kind == nkHiddenDeref: a[0] else: a
|
||||||
if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
|
if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
|
||||||
let s = a[0].sym
|
let s = a[0].sym
|
||||||
if s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty:
|
if s.isGenericRoutineStrict:
|
||||||
let finalCallee = generateInstance(c, s, x.bindings, a.info)
|
let finalCallee = generateInstance(c, s, x.bindings, a.info)
|
||||||
a[0].sym = finalCallee
|
a[0].sym = finalCallee
|
||||||
a[0].typ = finalCallee.typ
|
a[0].typ = finalCallee.typ
|
||||||
|
|
@ -524,7 +524,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
|
||||||
if result.typ.kind == tyError: incl result.typ.flags, tfCheckedForDestructor
|
if result.typ.kind == tyError: incl result.typ.flags, tfCheckedForDestructor
|
||||||
return
|
return
|
||||||
let gp = finalCallee.ast[genericParamsPos]
|
let gp = finalCallee.ast[genericParamsPos]
|
||||||
if gp.kind != nkEmpty:
|
if gp.isGenericParams:
|
||||||
if x.calleeSym.kind notin {skMacro, skTemplate}:
|
if x.calleeSym.kind notin {skMacro, skTemplate}:
|
||||||
if x.calleeSym.magic in {mArrGet, mArrPut}:
|
if x.calleeSym.magic in {mArrGet, mArrPut}:
|
||||||
finalCallee = x.calleeSym
|
finalCallee = x.calleeSym
|
||||||
|
|
|
||||||
|
|
@ -2856,7 +2856,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkCurly: result = semSetConstr(c, n)
|
of nkCurly: result = semSetConstr(c, n)
|
||||||
of nkBracket: result = semArrayConstr(c, n, flags)
|
of nkBracket: result = semArrayConstr(c, n, flags)
|
||||||
of nkObjConstr: result = semObjConstr(c, n, flags)
|
of nkObjConstr: result = semObjConstr(c, n, flags)
|
||||||
of nkLambdaKinds: result = semLambda(c, n, flags)
|
of nkLambdaKinds: result = semProcAux(c, n, skProc, lambdaPragmas, flags)
|
||||||
of nkDerefExpr: result = semDeref(c, n)
|
of nkDerefExpr: result = semDeref(c, n)
|
||||||
of nkAddr:
|
of nkAddr:
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -358,7 +358,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
|
|
||||||
openScope(c)
|
openScope(c)
|
||||||
let gp = n[genericParamsPos]
|
let gp = n[genericParamsPos]
|
||||||
internalAssert c.config, gp.kind != nkEmpty
|
internalAssert c.config, gp.kind == nkGenericParams
|
||||||
n[namePos] = newSymNode(result)
|
n[namePos] = newSymNode(result)
|
||||||
pushInfoContext(c.config, info, fn.detailedInfo)
|
pushInfoContext(c.config, info, fn.detailedInfo)
|
||||||
var entry = TInstantiation.new
|
var entry = TInstantiation.new
|
||||||
|
|
|
||||||
|
|
@ -1523,75 +1523,9 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
proc setGenericParamsMisc(c: PContext; n: PNode): PNode =
|
|
||||||
let orig = n[genericParamsPos]
|
|
||||||
# we keep the original params around for better error messages, see
|
|
||||||
# issue https://github.com/nim-lang/Nim/issues/1713
|
|
||||||
result = semGenericParamList(c, orig)
|
|
||||||
if n[miscPos].kind == nkEmpty:
|
|
||||||
n[miscPos] = newTree(nkBracket, c.graph.emptyNode, orig)
|
|
||||||
else:
|
|
||||||
n[miscPos][1] = orig
|
|
||||||
n[genericParamsPos] = result
|
|
||||||
|
|
||||||
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|
||||||
# XXX semProcAux should be good enough for this now, we will eventually
|
|
||||||
# remove semLambda
|
|
||||||
result = semProcAnnotation(c, n, lambdaPragmas)
|
|
||||||
if result != nil: return result
|
|
||||||
result = n
|
|
||||||
checkSonsLen(n, bodyPos + 1, c.config)
|
|
||||||
var s: PSym
|
|
||||||
if n[namePos].kind != nkSym:
|
|
||||||
s = newSym(skProc, c.cache.idAnon, nextSymId c.idgen, getCurrOwner(c), n.info)
|
|
||||||
s.ast = n
|
|
||||||
n[namePos] = newSymNode(s)
|
|
||||||
else:
|
|
||||||
s = n[namePos].sym
|
|
||||||
pushOwner(c, s)
|
|
||||||
openScope(c)
|
|
||||||
var gp: PNode
|
|
||||||
if n[genericParamsPos].kind != nkEmpty:
|
|
||||||
gp = setGenericParamsMisc(c, n)
|
|
||||||
else:
|
|
||||||
gp = newNodeI(nkGenericParams, n.info)
|
|
||||||
|
|
||||||
if n[paramsPos].kind != nkEmpty:
|
|
||||||
semParamList(c, n[paramsPos], gp, s)
|
|
||||||
# paramsTypeCheck(c, s.typ)
|
|
||||||
if gp.len > 0 and n[genericParamsPos].kind == nkEmpty:
|
|
||||||
# we have a list of implicit type parameters:
|
|
||||||
n[genericParamsPos] = gp
|
|
||||||
else:
|
|
||||||
s.typ = newProcType(c, n.info)
|
|
||||||
if n[pragmasPos].kind != nkEmpty:
|
|
||||||
pragma(c, s, n[pragmasPos], lambdaPragmas)
|
|
||||||
s.options = c.config.options
|
|
||||||
if n[bodyPos].kind != nkEmpty:
|
|
||||||
if sfImportc in s.flags:
|
|
||||||
localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
|
|
||||||
#if efDetermineType notin flags:
|
|
||||||
# XXX not good enough; see tnamedparamanonproc.nim
|
|
||||||
if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags):
|
|
||||||
pushProcCon(c, s)
|
|
||||||
addResult(c, n, s.typ[0], skProc)
|
|
||||||
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
|
|
||||||
trackProc(c, s, s.ast[bodyPos])
|
|
||||||
popProcCon(c)
|
|
||||||
elif efOperand notin flags:
|
|
||||||
localError(c.config, n.info, errGenericLambdaNotAllowed)
|
|
||||||
sideEffectsCheck(c, s)
|
|
||||||
else:
|
|
||||||
localError(c.config, n.info, errImplOfXexpected % s.name.s)
|
|
||||||
closeScope(c) # close scope for parameters
|
|
||||||
popOwner(c)
|
|
||||||
result.typ = s.typ
|
|
||||||
if optOwnedRefs in c.config.globalOptions:
|
|
||||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
|
||||||
|
|
||||||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} =
|
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} =
|
||||||
|
## used for resolving 'auto' in lambdas based on their callsite
|
||||||
var n = n
|
var n = n
|
||||||
|
|
||||||
let original = n[namePos].sym
|
let original = n[namePos].sym
|
||||||
let s = original #copySym(original, false)
|
let s = original #copySym(original, false)
|
||||||
#incl(s.flags, sfFromGeneric)
|
#incl(s.flags, sfFromGeneric)
|
||||||
|
|
@ -1798,11 +1732,6 @@ proc cursorInProc(conf: ConfigRef; n: PNode): bool =
|
||||||
if n.info.fileIndex == conf.m.trackPos.fileIndex:
|
if n.info.fileIndex == conf.m.trackPos.fileIndex:
|
||||||
result = cursorInProcAux(conf, n)
|
result = cursorInProcAux(conf, n)
|
||||||
|
|
||||||
type
|
|
||||||
TProcCompilationSteps = enum
|
|
||||||
stepRegisterSymbol,
|
|
||||||
stepDetermineType,
|
|
||||||
|
|
||||||
proc hasObjParam(s: PSym): bool =
|
proc hasObjParam(s: PSym): bool =
|
||||||
var t = s.typ
|
var t = s.typ
|
||||||
for col in 1..<t.len:
|
for col in 1..<t.len:
|
||||||
|
|
@ -1814,7 +1743,7 @@ proc finishMethod(c: PContext, s: PSym) =
|
||||||
methodDef(c.graph, c.idgen, s)
|
methodDef(c.graph, c.idgen, s)
|
||||||
|
|
||||||
proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
|
proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
|
||||||
if isGenericRoutine(s):
|
if s.isGenericRoutine:
|
||||||
let tt = s.typ
|
let tt = s.typ
|
||||||
var foundObj = false
|
var foundObj = false
|
||||||
# we start at 1 for now so that tparsecombnum continues to compile.
|
# we start at 1 for now so that tparsecombnum continues to compile.
|
||||||
|
|
@ -1840,28 +1769,45 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
|
||||||
else:
|
else:
|
||||||
localError(c.config, n.info, "'method' needs a parameter that has an object type")
|
localError(c.config, n.info, "'method' needs a parameter that has an object type")
|
||||||
|
|
||||||
|
proc setGenericParamsMisc(c: PContext; n: PNode) =
|
||||||
|
let orig = n[genericParamsPos]
|
||||||
|
|
||||||
|
doAssert orig.kind in {nkEmpty, nkGenericParams}
|
||||||
|
|
||||||
|
if n[genericParamsPos].kind == nkEmpty:
|
||||||
|
n[genericParamsPos] = newNodeI(nkGenericParams, n.info)
|
||||||
|
else:
|
||||||
|
# we keep the original params around for better error messages, see
|
||||||
|
# issue https://github.com/nim-lang/Nim/issues/1713
|
||||||
|
n[genericParamsPos] = semGenericParamList(c, orig)
|
||||||
|
|
||||||
|
if n[miscPos].kind == nkEmpty:
|
||||||
|
n[miscPos] = newTree(nkBracket, c.graph.emptyNode, orig)
|
||||||
|
else:
|
||||||
|
n[miscPos][1] = orig
|
||||||
|
|
||||||
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
validPragmas: TSpecialWords,
|
validPragmas: TSpecialWords, flags: TExprFlags = {}): PNode =
|
||||||
phase = stepRegisterSymbol): PNode =
|
|
||||||
result = semProcAnnotation(c, n, validPragmas)
|
result = semProcAnnotation(c, n, validPragmas)
|
||||||
if result != nil: return result
|
if result != nil: return result
|
||||||
result = n
|
result = n
|
||||||
checkMinSonsLen(n, bodyPos + 1, c.config)
|
checkMinSonsLen(n, bodyPos + 1, c.config)
|
||||||
var s: PSym
|
|
||||||
var typeIsDetermined = false
|
|
||||||
var isAnon = false
|
|
||||||
if n[namePos].kind != nkSym:
|
|
||||||
assert phase == stepRegisterSymbol
|
|
||||||
|
|
||||||
if n[namePos].kind == nkEmpty:
|
let isAnon = n[namePos].kind == nkEmpty
|
||||||
s = newSym(kind, c.cache.idAnon, nextSymId c.idgen, getCurrOwner(c), n.info)
|
|
||||||
incl(s.flags, sfUsed)
|
var s: PSym
|
||||||
isAnon = true
|
|
||||||
else:
|
case n[namePos].kind
|
||||||
s = semIdentDef(c, n[0], kind)
|
of nkEmpty:
|
||||||
|
s = newSym(kind, c.cache.idAnon, nextSymId c.idgen, c.getCurrOwner, n.info)
|
||||||
|
s.flags.incl sfUsed
|
||||||
|
n[namePos] = newSymNode(s)
|
||||||
|
of nkSym:
|
||||||
|
s = n[namePos].sym
|
||||||
|
s.owner = c.getCurrOwner
|
||||||
|
else:
|
||||||
|
s = semIdentDef(c, n[namePos], kind)
|
||||||
n[namePos] = newSymNode(s)
|
n[namePos] = newSymNode(s)
|
||||||
s.ast = n
|
|
||||||
#s.scope = c.currentScope
|
|
||||||
when false:
|
when false:
|
||||||
# disable for now
|
# disable for now
|
||||||
if sfNoForward in c.module.flags and
|
if sfNoForward in c.module.flags and
|
||||||
|
|
@ -1869,37 +1815,50 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
addInterfaceOverloadableSymAt(c, c.currentScope, s)
|
addInterfaceOverloadableSymAt(c, c.currentScope, s)
|
||||||
s.flags.incl sfForward
|
s.flags.incl sfForward
|
||||||
return
|
return
|
||||||
else:
|
|
||||||
s = n[namePos].sym
|
|
||||||
s.owner = getCurrOwner(c)
|
|
||||||
typeIsDetermined = s.typ == nil
|
|
||||||
s.ast = n
|
|
||||||
#s.scope = c.currentScope
|
|
||||||
|
|
||||||
|
assert s.kind in skProcKinds
|
||||||
|
|
||||||
|
s.ast = n
|
||||||
s.options = c.config.options
|
s.options = c.config.options
|
||||||
|
#s.scope = c.currentScope
|
||||||
|
|
||||||
# before compiling the proc body, set as current the scope
|
# before compiling the proc params & body, set as current the scope
|
||||||
# where the proc was declared
|
# where the proc was declared
|
||||||
let oldScope = c.currentScope
|
let delcarationScope = c.currentScope
|
||||||
#c.currentScope = s.scope
|
|
||||||
pushOwner(c, s)
|
pushOwner(c, s)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
var gp: PNode
|
|
||||||
if n[genericParamsPos].kind != nkEmpty:
|
|
||||||
gp = setGenericParamsMisc(c, n)
|
|
||||||
else:
|
|
||||||
gp = newNodeI(nkGenericParams, n.info)
|
|
||||||
# process parameters:
|
# process parameters:
|
||||||
|
# generic parameters, parameters, and also the implicit generic parameters
|
||||||
|
# within are analysed. This is often the entirety of their semantic analysis
|
||||||
|
# but later we will have to do a check for forward declarations, which can by
|
||||||
|
# way of pragmas, default params, and so on invalidate this parsing.
|
||||||
|
# Nonetheless, we need to carry out this analysis to perform the search for a
|
||||||
|
# potential forward declaration.
|
||||||
|
setGenericParamsMisc(c, n)
|
||||||
|
|
||||||
if n[paramsPos].kind != nkEmpty:
|
if n[paramsPos].kind != nkEmpty:
|
||||||
semParamList(c, n[paramsPos], gp, s)
|
semParamList(c, n[paramsPos], n[genericParamsPos], s)
|
||||||
if gp.len > 0:
|
# we maybe have implicit type parameters:
|
||||||
if n[genericParamsPos].kind == nkEmpty:
|
|
||||||
# we have a list of implicit type parameters:
|
|
||||||
n[genericParamsPos] = gp
|
|
||||||
# check for semantics again:
|
|
||||||
# semParamList(c, n[ParamsPos], nil, s)
|
|
||||||
else:
|
else:
|
||||||
s.typ = newProcType(c, n.info)
|
s.typ = newProcType(c, n.info)
|
||||||
|
|
||||||
|
if n[genericParamsPos].safeLen == 0:
|
||||||
|
# if there exist no explicit or implicit generic parameters, then this is
|
||||||
|
# at most a nullary generic (generic with no type params). Regardless of
|
||||||
|
# whether it's a nullary generic or non-generic, we restore the original.
|
||||||
|
# In the case of `nkEmpty` it's non-generic and an empty `nkGeneircParams`
|
||||||
|
# is a nullary generic.
|
||||||
|
#
|
||||||
|
# Remarks about nullary generics vs non-generics:
|
||||||
|
# The difference between a non-generic and nullary generic is minor in
|
||||||
|
# most cases but there are subtle and significant differences as well.
|
||||||
|
# Due to instantiation that generic procs go through, a static echo in the
|
||||||
|
# body of a nullary generic will not be executed immediately, as it's
|
||||||
|
# instantiated and not immediately evaluated.
|
||||||
|
n[genericParamsPos] = n[miscPos][1]
|
||||||
|
n[miscPos] = c.graph.emptyNode
|
||||||
|
|
||||||
if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime)
|
if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime)
|
||||||
if n[patternPos].kind != nkEmpty:
|
if n[patternPos].kind != nkEmpty:
|
||||||
n[patternPos] = semPattern(c, n[patternPos])
|
n[patternPos] = semPattern(c, n[patternPos])
|
||||||
|
|
@ -1908,47 +1867,66 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
elif s.kind == skFunc:
|
elif s.kind == skFunc:
|
||||||
incl(s.flags, sfNoSideEffect)
|
incl(s.flags, sfNoSideEffect)
|
||||||
incl(s.typ.flags, tfNoSideEffect)
|
incl(s.typ.flags, tfNoSideEffect)
|
||||||
var (proto, comesFromShadowScope) = if isAnon: (nil, false)
|
|
||||||
else: searchForProc(c, oldScope, s)
|
var (proto, comesFromShadowScope) =
|
||||||
|
if isAnon: (nil, false)
|
||||||
|
else: searchForProc(c, delcarationScope, s)
|
||||||
if proto == nil and sfForward in s.flags:
|
if proto == nil and sfForward in s.flags:
|
||||||
#This is a definition that shares its sym with its forward declaration (generated by a macro),
|
## In cases such as a macro generating a proc with a gensymmed name we
|
||||||
#if the symbol is also gensymmed we won't find it with searchForProc, so we check here
|
## know `searchForProc` will not find it and sfForward will be set. In
|
||||||
|
## such scenarios the sym is shared between forward declaration and we
|
||||||
|
## can treat the `s` as the proto.
|
||||||
proto = s
|
proto = s
|
||||||
if proto == nil:
|
let hasProto = proto != nil
|
||||||
if s.kind == skIterator:
|
|
||||||
if s.typ.callConv != ccClosure:
|
# set the default calling conventions
|
||||||
s.typ.callConv = if isAnon: ccClosure else: ccInline
|
case s.kind
|
||||||
else:
|
of skIterator:
|
||||||
s.typ.callConv = lastOptionEntry(c).defaultCC
|
if s.typ.callConv != ccClosure:
|
||||||
# add it here, so that recursive procs are possible:
|
s.typ.callConv = if isAnon: ccClosure else: ccInline
|
||||||
if sfGenSym in s.flags:
|
of skMacro, skTemplate:
|
||||||
if s.owner == nil: s.owner = getCurrOwner(c)
|
# we don't bother setting calling conventions for macros and templates
|
||||||
elif kind in OverloadableSyms:
|
discard
|
||||||
if not typeIsDetermined:
|
|
||||||
addInterfaceOverloadableSymAt(c, oldScope, s)
|
|
||||||
else:
|
|
||||||
if not typeIsDetermined:
|
|
||||||
addInterfaceDeclAt(c, oldScope, s)
|
|
||||||
if n[pragmasPos].kind != nkEmpty:
|
|
||||||
pragma(c, s, n[pragmasPos], validPragmas)
|
|
||||||
else:
|
|
||||||
implicitPragmas(c, s, n, validPragmas)
|
|
||||||
styleCheckDef(c.config, s)
|
|
||||||
onDef(n[namePos].info, s)
|
|
||||||
else:
|
else:
|
||||||
if n[pragmasPos].kind != nkEmpty:
|
# NB: procs with a forward decl have theirs determined by the forward decl
|
||||||
pragma(c, s, n[pragmasPos], validPragmas)
|
if not hasProto:
|
||||||
# To ease macro generation that produce forwarded .async procs we now
|
# in this case we're either a forward declaration or we're an impl without
|
||||||
# allow a bit redundancy in the pragma declarations. The rule is
|
# a forward decl. We set the calling convention or will be set during
|
||||||
# a prototype's pragma list must be a superset of the current pragma
|
# pragma analysis further down.
|
||||||
# list.
|
s.typ.callConv = lastOptionEntry(c).defaultCC
|
||||||
# XXX This needs more checks eventually, for example that external
|
|
||||||
# linking names do agree:
|
if not hasProto and sfGenSym notin s.flags: #and not isAnon:
|
||||||
if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags:
|
if s.kind in OverloadableSyms:
|
||||||
localError(c.config, n[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
|
addInterfaceOverloadableSymAt(c, delcarationScope, s)
|
||||||
("'" & proto.name.s & "' from " & c.config$proto.info))
|
else:
|
||||||
styleCheckDef(c.config, s)
|
addInterfaceDeclAt(c, delcarationScope, s)
|
||||||
|
|
||||||
|
pragmaCallable(c, s, n, validPragmas)
|
||||||
|
if not hasProto:
|
||||||
|
implicitPragmas(c, s, n.info, validPragmas)
|
||||||
|
|
||||||
|
# To ease macro generation that produce forwarded .async procs we now
|
||||||
|
# allow a bit redundancy in the pragma declarations. The rule is
|
||||||
|
# a prototype's pragma list must be a superset of the current pragma
|
||||||
|
# list.
|
||||||
|
# XXX This needs more checks eventually, for example that external
|
||||||
|
# linking names do agree:
|
||||||
|
if hasProto and (
|
||||||
|
# calling convention mismatch
|
||||||
|
tfExplicitCallConv in s.typ.flags and proto.typ.callConv != s.typ.callConv or
|
||||||
|
# implementation has additional pragmas
|
||||||
|
proto.typ.flags < s.typ.flags):
|
||||||
|
localError(c.config, n[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
|
||||||
|
("'" & proto.name.s & "' from " & c.config$proto.info &
|
||||||
|
" '" & s.name.s & "' from " & c.config$s.info))
|
||||||
|
|
||||||
|
styleCheckDef(c.config, s)
|
||||||
|
if hasProto:
|
||||||
onDefResolveForward(n[namePos].info, proto)
|
onDefResolveForward(n[namePos].info, proto)
|
||||||
|
else:
|
||||||
|
onDef(n[namePos].info, s)
|
||||||
|
|
||||||
|
if hasProto:
|
||||||
if sfForward notin proto.flags and proto.magic == mNone:
|
if sfForward notin proto.flags and proto.magic == mNone:
|
||||||
wrongRedefinition(c, n.info, proto.name.s, proto.info)
|
wrongRedefinition(c, n.info, proto.name.s, proto.info)
|
||||||
if not comesFromShadowScope:
|
if not comesFromShadowScope:
|
||||||
|
|
@ -1957,7 +1935,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
suggestSym(c.graph, s.info, proto, c.graph.usageSym)
|
suggestSym(c.graph, s.info, proto, c.graph.usageSym)
|
||||||
closeScope(c) # close scope with wrong parameter symbols
|
closeScope(c) # close scope with wrong parameter symbols
|
||||||
openScope(c) # open scope for old (correct) parameter symbols
|
openScope(c) # open scope for old (correct) parameter symbols
|
||||||
if proto.ast[genericParamsPos].kind != nkEmpty:
|
if proto.ast[genericParamsPos].isGenericParams:
|
||||||
addGenericParamListToScope(c, proto.ast[genericParamsPos])
|
addGenericParamListToScope(c, proto.ast[genericParamsPos])
|
||||||
addParams(c, proto.typ.n, proto.kind)
|
addParams(c, proto.typ.n, proto.kind)
|
||||||
proto.info = s.info # more accurate line information
|
proto.info = s.info # more accurate line information
|
||||||
|
|
@ -1974,31 +1952,42 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
pushOwner(c, s)
|
pushOwner(c, s)
|
||||||
|
|
||||||
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
|
if not isAnon:
|
||||||
if s.name.s[0] in {'.', '('}:
|
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
|
||||||
if s.name.s in [".", ".()", ".="] and {Feature.destructor, dotOperators} * c.features == {}:
|
elif s.name.s[0] in {'.', '('}:
|
||||||
localError(c.config, n.info, "the overloaded " & s.name.s &
|
if s.name.s in [".", ".()", ".="] and {Feature.destructor, dotOperators} * c.features == {}:
|
||||||
" operator has to be enabled with {.experimental: \"dotOperators\".}")
|
localError(c.config, n.info, "the overloaded " & s.name.s &
|
||||||
elif s.name.s == "()" and callOperator notin c.features:
|
" operator has to be enabled with {.experimental: \"dotOperators\".}")
|
||||||
localError(c.config, n.info, "the overloaded " & s.name.s &
|
elif s.name.s == "()" and callOperator notin c.features:
|
||||||
" operator has to be enabled with {.experimental: \"callOperator\".}")
|
localError(c.config, n.info, "the overloaded " & s.name.s &
|
||||||
|
" operator has to be enabled with {.experimental: \"callOperator\".}")
|
||||||
|
|
||||||
if n[bodyPos].kind != nkEmpty and sfError notin s.flags:
|
if n[bodyPos].kind != nkEmpty and sfError notin s.flags:
|
||||||
# for DLL generation we allow sfImportc to have a body, for use in VM
|
# for DLL generation we allow sfImportc to have a body, for use in VM
|
||||||
if sfBorrow in s.flags:
|
if sfBorrow in s.flags:
|
||||||
localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
|
localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
|
||||||
let usePseudoGenerics = kind in {skMacro, skTemplate}
|
if c.config.ideCmd in {ideSug, ideCon} and s.kind notin {skMacro, skTemplate} and not
|
||||||
# Macros and Templates can have generic parameters, but they are
|
|
||||||
# only used for overload resolution (there is no instantiation of
|
|
||||||
# the symbol, so we must process the body now)
|
|
||||||
if not usePseudoGenerics and c.config.ideCmd in {ideSug, ideCon} and not
|
|
||||||
cursorInProc(c.config, n[bodyPos]):
|
cursorInProc(c.config, n[bodyPos]):
|
||||||
discard "speed up nimsuggest"
|
# speed up nimsuggest
|
||||||
if s.kind == skMethod: semMethodPrototype(c, s, n)
|
if s.kind == skMethod: semMethodPrototype(c, s, n)
|
||||||
|
elif isAnon:
|
||||||
|
let gp = n[genericParamsPos]
|
||||||
|
if gp.kind == nkEmpty or (gp.len == 1 and tfRetType in gp[0].typ.flags):
|
||||||
|
# absolutely no generics (empty) or a single generic return type are
|
||||||
|
# allowed, everything else, including a nullary generic is an error.
|
||||||
|
pushProcCon(c, s)
|
||||||
|
addResult(c, n, s.typ[0], skProc)
|
||||||
|
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
|
||||||
|
trackProc(c, s, s.ast[bodyPos])
|
||||||
|
popProcCon(c)
|
||||||
|
elif efOperand notin flags:
|
||||||
|
localError(c.config, n.info, errGenericLambdaNotAllowed)
|
||||||
else:
|
else:
|
||||||
pushProcCon(c, s)
|
pushProcCon(c, s)
|
||||||
if n[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
|
if n[genericParamsPos].kind == nkEmpty or s.kind in {skMacro, skTemplate}:
|
||||||
if not usePseudoGenerics and s.magic == mNone: paramsTypeCheck(c, s.typ)
|
# Macros and Templates can have generic parameters, but they are only
|
||||||
|
# used for overload resolution (there is no instantiation of the symbol)
|
||||||
|
if s.kind notin {skMacro, skTemplate} and s.magic == mNone: paramsTypeCheck(c, s.typ)
|
||||||
|
|
||||||
maybeAddResult(c, s, n)
|
maybeAddResult(c, s, n)
|
||||||
# semantic checking also needed with importc in case used in VM
|
# semantic checking also needed with importc in case used in VM
|
||||||
|
|
@ -2006,9 +1995,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
# unfortunately we cannot skip this step when in 'system.compiles'
|
# unfortunately we cannot skip this step when in 'system.compiles'
|
||||||
# context as it may even be evaluated in 'system.compiles':
|
# context as it may even be evaluated in 'system.compiles':
|
||||||
trackProc(c, s, s.ast[bodyPos])
|
trackProc(c, s, s.ast[bodyPos])
|
||||||
if s.kind == skMethod: semMethodPrototype(c, s, n)
|
|
||||||
else:
|
else:
|
||||||
if (s.typ[0] != nil and kind != skIterator) or kind == skMacro:
|
if (s.typ[0] != nil and s.kind != skIterator):
|
||||||
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextSymId c.idgen, nil, n.info))
|
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextSymId c.idgen, nil, n.info))
|
||||||
|
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -2016,20 +2004,17 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
if s.magic == mNone:
|
if s.magic == mNone:
|
||||||
fixupInstantiatedSymbols(c, s)
|
fixupInstantiatedSymbols(c, s)
|
||||||
if s.kind == skMethod: semMethodPrototype(c, s, n)
|
if s.kind == skMethod: semMethodPrototype(c, s, n)
|
||||||
if sfImportc in s.flags:
|
|
||||||
# don't ignore the body in case used in VM
|
|
||||||
# n[bodyPos] = c.graph.emptyNode
|
|
||||||
discard
|
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
else:
|
else:
|
||||||
if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyUntyped:
|
|
||||||
# `auto` is represented as `tyUntyped` at this point in compilation.
|
|
||||||
localError(c.config, n[paramsPos][0].info, "return type 'auto' cannot be used in forward declarations")
|
|
||||||
|
|
||||||
if s.kind == skMethod: semMethodPrototype(c, s, n)
|
if s.kind == skMethod: semMethodPrototype(c, s, n)
|
||||||
if proto != nil: localError(c.config, n.info, errImplOfXexpected % proto.name.s)
|
if hasProto: localError(c.config, n.info, errImplOfXexpected % proto.name.s)
|
||||||
if {sfImportc, sfBorrow, sfError} * s.flags == {} and s.magic == mNone:
|
if {sfImportc, sfBorrow, sfError} * s.flags == {} and s.magic == mNone:
|
||||||
|
# this is a forward declaration and we're building the prototype
|
||||||
|
if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyUntyped:
|
||||||
|
# `auto` is represented as `tyUntyped` at this point in compilation.
|
||||||
|
localError(c.config, n[paramsPos][0].info, "return type 'auto' cannot be used in forward declarations")
|
||||||
|
|
||||||
incl(s.flags, sfForward)
|
incl(s.flags, sfForward)
|
||||||
incl(s.flags, sfWasForwarded)
|
incl(s.flags, sfWasForwarded)
|
||||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||||
|
|
@ -2044,15 +2029,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
result.typ = s.typ
|
result.typ = s.typ
|
||||||
if optOwnedRefs in c.config.globalOptions:
|
if optOwnedRefs in c.config.globalOptions:
|
||||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
result.typ = makeVarType(c, result.typ, tyOwned)
|
||||||
if isTopLevel(c) and s.kind != skIterator and
|
elif isTopLevel(c) and s.kind != skIterator and s.typ.callConv == ccClosure:
|
||||||
s.typ.callConv == ccClosure:
|
|
||||||
localError(c.config, s.info, "'.closure' calling convention for top level routines is invalid")
|
localError(c.config, s.info, "'.closure' calling convention for top level routines is invalid")
|
||||||
|
|
||||||
proc determineType(c: PContext, s: PSym) =
|
proc determineType(c: PContext, s: PSym) =
|
||||||
if s.typ != nil: return
|
if s.typ != nil: return
|
||||||
#if s.magic != mNone: return
|
#if s.magic != mNone: return
|
||||||
#if s.ast.isNil: return
|
#if s.ast.isNil: return
|
||||||
discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType)
|
discard semProcAux(c, s.ast, s.kind, {})
|
||||||
|
|
||||||
proc semIterator(c: PContext, n: PNode): PNode =
|
proc semIterator(c: PContext, n: PNode): PNode =
|
||||||
# gensym'ed iterator?
|
# gensym'ed iterator?
|
||||||
|
|
@ -2086,7 +2070,9 @@ proc semProc(c: PContext, n: PNode): PNode =
|
||||||
result = semProcAux(c, n, skProc, procPragmas)
|
result = semProcAux(c, n, skProc, procPragmas)
|
||||||
|
|
||||||
proc semFunc(c: PContext, n: PNode): PNode =
|
proc semFunc(c: PContext, n: PNode): PNode =
|
||||||
result = semProcAux(c, n, skFunc, procPragmas)
|
let validPragmas = if n[namePos].kind != nkEmpty: procPragmas
|
||||||
|
else: lambdaPragmas
|
||||||
|
result = semProcAux(c, n, skFunc, validPragmas)
|
||||||
|
|
||||||
proc semMethod(c: PContext, n: PNode): PNode =
|
proc semMethod(c: PContext, n: PNode): PNode =
|
||||||
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "method")
|
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "method")
|
||||||
|
|
|
||||||
|
|
@ -636,10 +636,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||||
param.flags.incl sfTemplateParam
|
param.flags.incl sfTemplateParam
|
||||||
param.flags.excl sfGenSym
|
param.flags.excl sfGenSym
|
||||||
if param.typ.kind != tyUntyped: allUntyped = false
|
if param.typ.kind != tyUntyped: allUntyped = false
|
||||||
if gp.len > 0:
|
if gp.len > 0 and n[genericParamsPos].kind == nkEmpty:
|
||||||
if n[genericParamsPos].kind == nkEmpty:
|
# we have a list of implicit type parameters:
|
||||||
# we have a list of implicit type parameters:
|
n[genericParamsPos] = gp
|
||||||
n[genericParamsPos] = gp
|
|
||||||
else:
|
else:
|
||||||
s.typ = newTypeS(tyProc, c)
|
s.typ = newTypeS(tyProc, c)
|
||||||
# XXX why do we need tyTyped as a return type again?
|
# XXX why do we need tyTyped as a return type again?
|
||||||
|
|
|
||||||
|
|
@ -1233,7 +1233,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
if hasDefault:
|
if hasDefault:
|
||||||
def = a[^1]
|
def = a[^1]
|
||||||
block determineType:
|
block determineType:
|
||||||
if genericParams != nil and genericParams.len > 0:
|
if genericParams.isGenericParams:
|
||||||
def = semGenericStmt(c, def)
|
def = semGenericStmt(c, def)
|
||||||
if hasUnresolvedArgs(c, def):
|
if hasUnresolvedArgs(c, def):
|
||||||
def.typ = makeTypeFromExpr(c, def.copyTree)
|
def.typ = makeTypeFromExpr(c, def.copyTree)
|
||||||
|
|
@ -1361,7 +1361,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
result.flags.excl tfHasMeta
|
result.flags.excl tfHasMeta
|
||||||
result.n.typ = r
|
result.n.typ = r
|
||||||
|
|
||||||
if genericParams != nil and genericParams.len > 0:
|
if genericParams.isGenericParams:
|
||||||
for n in genericParams:
|
for n in genericParams:
|
||||||
if {sfUsed, sfAnon} * n.sym.flags == {}:
|
if {sfUsed, sfAnon} * n.sym.flags == {}:
|
||||||
result.flags.incl tfUnresolved
|
result.flags.incl tfUnresolved
|
||||||
|
|
@ -1666,7 +1666,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
|
||||||
# we construct a fake 'nkProcDef' for the 'mergePragmas' inside 'implicitPragmas'...
|
# we construct a fake 'nkProcDef' for the 'mergePragmas' inside 'implicitPragmas'...
|
||||||
s.ast = newTree(nkProcDef, newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info),
|
s.ast = newTree(nkProcDef, newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info),
|
||||||
newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info))
|
newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info))
|
||||||
implicitPragmas(c, s, n, {wTags, wRaises})
|
implicitPragmas(c, s, n.info, {wTags, wRaises})
|
||||||
when useEffectSystem: setEffectsForProcType(c.graph, result, s.ast[pragmasPos])
|
when useEffectSystem: setEffectsForProcType(c.graph, result, s.ast[pragmasPos])
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2265,7 +2265,7 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||||
genParams(c, s.typ.n)
|
genParams(c, s.typ.n)
|
||||||
|
|
||||||
# allocate additional space for any generically bound parameters
|
# allocate additional space for any generically bound parameters
|
||||||
if s.kind == skMacro and s.ast[genericParamsPos].kind != nkEmpty:
|
if s.kind == skMacro and s.isGenericRoutineStrict:
|
||||||
genGenericParams(c, s.ast[genericParamsPos])
|
genGenericParams(c, s.ast[genericParamsPos])
|
||||||
|
|
||||||
if tfCapturesEnv in s.typ.flags:
|
if tfCapturesEnv in s.typ.flags:
|
||||||
|
|
|
||||||
14
tests/constr/tnocompiletimefunc.nim
Normal file
14
tests/constr/tnocompiletimefunc.nim
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "request to generate code for .compileTime proc: foo"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ensure compileTime funcs can't be called from runtime
|
||||||
|
|
||||||
|
func foo(a: int): int {.compileTime.} =
|
||||||
|
a * a
|
||||||
|
|
||||||
|
proc doAThing(): int =
|
||||||
|
for i in 0..2:
|
||||||
|
result += foo(i)
|
||||||
|
|
||||||
|
echo doAThing()
|
||||||
6
tests/constr/tnocompiletimefunclambda.nim
Normal file
6
tests/constr/tnocompiletimefunclambda.nim
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "request to generate code for .compileTime proc: :anonymous"
|
||||||
|
"""
|
||||||
|
|
||||||
|
let a = func(a: varargs[int]) {.compileTime, closure.} =
|
||||||
|
discard a[0]
|
||||||
11
tests/converter/tconverter.nim
Normal file
11
tests/converter/tconverter.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
discard """
|
||||||
|
output: '''fooo fooo'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
converter intToString[T](i: T): string = "fooo"
|
||||||
|
|
||||||
|
let
|
||||||
|
foo: string = 1
|
||||||
|
bar: string = intToString(2)
|
||||||
|
|
||||||
|
echo foo, " ", bar
|
||||||
26
tests/generics/tnullary_generics.nim
Normal file
26
tests/generics/tnullary_generics.nim
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
discard """
|
||||||
|
nimout: '''
|
||||||
|
hah
|
||||||
|
hey
|
||||||
|
hey
|
||||||
|
hah
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# non-generic
|
||||||
|
proc foo(s: string) =
|
||||||
|
static: echo "hah"
|
||||||
|
echo s
|
||||||
|
|
||||||
|
static: echo "hey"
|
||||||
|
|
||||||
|
foo("hoo")
|
||||||
|
|
||||||
|
# nullary generic
|
||||||
|
proc bar[](s: string) =
|
||||||
|
static: echo "hah"
|
||||||
|
echo s
|
||||||
|
|
||||||
|
static: echo "hey"
|
||||||
|
|
||||||
|
bar("hoo")
|
||||||
|
|
@ -2,6 +2,8 @@ discard """
|
||||||
nimout: '''
|
nimout: '''
|
||||||
staticAlialProc instantiated with 358
|
staticAlialProc instantiated with 358
|
||||||
staticAlialProc instantiated with 368
|
staticAlialProc instantiated with 368
|
||||||
|
0: Foo
|
||||||
|
1: Bar
|
||||||
'''
|
'''
|
||||||
output: '''
|
output: '''
|
||||||
16
|
16
|
||||||
|
|
@ -289,8 +291,10 @@ macro fooParam(x: static array[2, string]): untyped =
|
||||||
echo i, ": ", val
|
echo i, ": ", val
|
||||||
|
|
||||||
macro barParam(x: static Table[int, string]): untyped =
|
macro barParam(x: static Table[int, string]): untyped =
|
||||||
for i, val in x:
|
let barParamInsides = proc(i: int, val: string): NimNode =
|
||||||
echo i, ": ", val
|
echo i, ": ", val
|
||||||
|
for i, val in x:
|
||||||
|
discard barParamInsides(i, val)
|
||||||
|
|
||||||
fooM()
|
fooM()
|
||||||
barM()
|
barM()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue