From 8f4b3743277119a0ec231738fdd3931476c186d9 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 19 Jun 2017 20:07:26 +0300 Subject: [PATCH] Fix #4020; Better handling of templates within concepts --- compiler/ast.nim | 4 +- compiler/astalgo.nim | 2 + compiler/evaltempl.nim | 2 + compiler/semstmts.nim | 3 +- tests/concepts/templatesinconcepts.nim | 56 ++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 tests/concepts/templatesinconcepts.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 63b656715..6e651ed00 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -453,6 +453,7 @@ type nfIsRef # this node is a 'ref' node; used for the VM nfPreventCg # this node should be ignored by the codegen nfBlockArg # this a stmtlist appearing in a call (e.g. a do block) + nfFromTemplate # a top-level node returned from a template TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that) @@ -956,7 +957,8 @@ const skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias} PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfDotSetter, nfDotField, - nfIsRef, nfPreventCg, nfLL} + nfIsRef, nfPreventCg, nfLL, + nfFromTemplate} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index ebe080468..e32fff181 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -407,6 +407,8 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int; var istr = rspaces(indent + 2) result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)] + when defined(useNodeIds): + addf(result, ",$N$1\"id\": $2", [istr, rope(n.id)]) addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) if maxRecDepth != 0: addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)]) diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index fda0b79dd..f088afcdb 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -155,5 +155,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = #if ctx.instLines: result.info = n.info for i in countup(0, safeLen(body) - 1): evalTemplateAux(body.sons[i], args, ctx, result) + result.flags.incl nfFromTemplate result = wrapInComesFrom(n.info, result) dec(evalTemplateCounter) + diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b00e9a9c0..8e019e4f6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1761,7 +1761,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = else: var expr = semExpr(c, n.sons[i], flags) n.sons[i] = expr - if c.matchedConcept != nil and expr.typ != nil: + if c.matchedConcept != nil and expr.typ != nil and + (nfFromTemplate notin n.flags or i != last): case expr.typ.kind of tyBool: if expr.kind == nkInfix and diff --git a/tests/concepts/templatesinconcepts.nim b/tests/concepts/templatesinconcepts.nim new file mode 100644 index 000000000..292b97ea6 --- /dev/null +++ b/tests/concepts/templatesinconcepts.nim @@ -0,0 +1,56 @@ +import typetraits + +template typeLen(x): int = x.type.name.len + +template bunchOfChecks(x) = + x.typeLen > 3 + x != 10 is bool + +template stmtListExprTmpl(x: untyped): untyped = + x is int + x + +type + Obj = object + x: int + + Gen[T] = object + x: T + + Eq = concept x, y + (x == y) is bool + + NotEq = concept x, y + (x != y) is bool + + ConceptUsingTemplate1 = concept x + echo x + sizeof(x) is int + bunchOfChecks x + + ConceptUsingTemplate2 = concept x + stmtListExprTmpl x + +template ok(x) = + static: assert(x) + +template no(x) = + static: assert(not(x)) + +ok int is Eq +ok int is NotEq +ok string is Eq +ok string is NotEq +ok Obj is Eq +ok Obj is NotEq +ok Gen[string] is Eq +ok Gen[int] is NotEq + +no int is ConceptUsingTemplate1 +ok float is ConceptUsingTemplate1 +no string is ConceptUsingTemplate1 + +ok int is ConceptUsingTemplate2 +no float is ConceptUsingTemplate2 +no string is ConceptUsingTemplate2 +