diff --git a/compiler/sem.nim b/compiler/sem.nim index 5593f8b02..bb42b5c1b 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -485,11 +485,31 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode = if result.kind != nkIntLit: localError(c.config, n.info, errConstExprExpected) - proc semGenericStmt(c: PContext, n: PNode): PNode proc semConceptBody(c: PContext, n: PNode): PNode -include semtypes, semtempl, semgnrc, semstmts, semexprs +include semtypes + +proc setGenericParamsMisc(c: PContext; n: PNode) = + ## used by call defs (procs, templates, macros, ...) to analyse their generic + ## params, and store the originals in miscPos for better error reporting. + 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 + +include semtempl, semgnrc, semstmts, semexprs proc addCodeForGenerics(c: PContext, n: PNode) = for i in c.lastGenericIdx..=", ">", "incl", "excl", "in", "notin", "isnot"] @@ -608,26 +610,23 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = s.owner.name.s == "vm" and s.name.s == "stackTrace": incl(s.flags, sfCallsite) + s.ast = n + styleCheckDef(c.config, s) - onDef(n[0].info, s) + onDef(n[namePos].info, s) # check parameter list: #s.scope = c.currentScope pushOwner(c, s) openScope(c) - n[namePos] = newSymNode(s, n[namePos].info) - if n[pragmasPos].kind != nkEmpty: - pragma(c, s, n[pragmasPos], templatePragmas) + n[namePos] = newSymNode(s) + pragmaCallable(c, s, n, templatePragmas) + implicitPragmas(c, s, n.info, templatePragmas) - var gp: PNode - if n[genericParamsPos].kind != nkEmpty: - n[genericParamsPos] = semGenericParamList(c, n[genericParamsPos]) - gp = n[genericParamsPos] - else: - gp = newNodeI(nkGenericParams, n.info) + setGenericParamsMisc(c, n) # process parameters: var allUntyped = true if n[paramsPos].kind != nkEmpty: - semParamList(c, n[paramsPos], gp, s) + semParamList(c, n[paramsPos], n[genericParamsPos], s) # a template's parameters are not gensym'ed even if that was originally the # case as we determine whether it's a template parameter in the template # body by the absence of the sfGenSym flag: @@ -636,18 +635,21 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = param.flags.incl sfTemplateParam param.flags.excl sfGenSym if param.typ.kind != tyUntyped: allUntyped = false - if gp.len > 0 and n[genericParamsPos].kind == nkEmpty: - # we have a list of implicit type parameters: - n[genericParamsPos] = gp else: s.typ = newTypeS(tyProc, c) # XXX why do we need tyTyped as a return type again? s.typ.n = newNodeI(nkFormalParams, n.info) rawAddSon(s.typ, newTypeS(tyTyped, c)) s.typ.n.add newNodeIT(nkType, n.info, s.typ[0]) + if n[genericParamsPos].safeLen == 0: + # restore original generic type params as no explicit or implicit were found + n[genericParamsPos] = n[miscPos][1] + n[miscPos] = c.graph.emptyNode if allUntyped: incl(s.flags, sfAllUntyped) + if n[patternPos].kind != nkEmpty: n[patternPos] = semPattern(c, n[patternPos]) + var ctx: TemplCtx ctx.toBind = initIntSet() ctx.toMixin = initIntSet() @@ -662,8 +664,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = semIdeForTemplateOrGeneric(c, n[bodyPos], ctx.cursorInBody) closeScope(c) popOwner(c) - s.ast = n - result = n if sfCustomPragma in s.flags: if n[bodyPos].kind != nkEmpty: localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s) diff --git a/tests/template/t17433.nim b/tests/template/t17433.nim index 121f3c471..053d33ff0 100644 --- a/tests/template/t17433.nim +++ b/tests/template/t17433.nim @@ -7,10 +7,10 @@ from std/macros import expandMacros proc bar(a: typedesc): a = default(a) -assert bar(float) == 0.0 -assert bar(string) == "" +doAssert bar(float) == 0.0 +doAssert bar(string) == "" template main = proc baz(a: typedesc): a = default(a) - assert baz(float) == 0.0 + doAssert baz(float) == 0.0 main()