From e03b3bdde75f5e82f9c5512fcd00033704de4a34 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 6 Jun 2018 23:41:19 +0100 Subject: [PATCH 1/4] fixes 7980 --- compiler/hlo.nim | 50 +++++++++++++--------- tests/template/tpattern_with_converter.nim | 27 ++++++++++++ 2 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 tests/template/tpattern_with_converter.nim diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 8251e3179c..511712b541 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -36,27 +36,35 @@ proc applyPatterns(c: PContext, n: PNode): PNode = # we apply the last pattern first, so that pattern overriding is possible; # however the resulting AST would better not trigger the old rule then # anymore ;-) - for i in countdown(c.patterns.len-1, 0): - let pattern = c.patterns[i] - if not isNil(pattern): - let x = applyRule(c, pattern, result) - if not isNil(x): - assert x.kind in {nkStmtList, nkCall} - # better be safe than sorry, so check evalTemplateCounter too: - inc(evalTemplateCounter) - if evalTemplateCounter > evalTemplateLimit: - globalError(c.config, n.info, "template instantiation too nested") - # deactivate this pattern: - c.patterns[i] = nil - if x.kind == nkStmtList: - assert x.len == 3 - x.sons[1] = evalPattern(c, x.sons[1], result) - result = flattenStmts(x) - else: - result = evalPattern(c, x, result) - dec(evalTemplateCounter) - # activate this pattern again: - c.patterns[i] = pattern + if c.patterns.len > 0: + + # temporary disable converters + var ctx_converters: TSymSeq + shallowCopy(ctx_converters, c.converters) + c.converters = @[] + defer: shallowCopy(c.converters, ctx_converters) + + for i in countdown(c.patterns.len-1, 0): + let pattern = c.patterns[i] + if not isNil(pattern): + let x = applyRule(c, pattern, result) + if not isNil(x): + assert x.kind in {nkStmtList, nkCall} + # better be safe than sorry, so check evalTemplateCounter too: + inc(evalTemplateCounter) + if evalTemplateCounter > evalTemplateLimit: + globalError(c.config, n.info, "template instantiation too nested") + # deactivate this pattern: + c.patterns[i] = nil + if x.kind == nkStmtList: + assert x.len == 3 + x.sons[1] = evalPattern(c, x.sons[1], result) + result = flattenStmts(x) + else: + result = evalPattern(c, x, result) + dec(evalTemplateCounter) + # activate this pattern again: + c.patterns[i] = pattern proc hlo(c: PContext, n: PNode): PNode = inc(c.hloLoopDetector) diff --git a/tests/template/tpattern_with_converter.nim b/tests/template/tpattern_with_converter.nim new file mode 100644 index 0000000000..e0632552bf --- /dev/null +++ b/tests/template/tpattern_with_converter.nim @@ -0,0 +1,27 @@ +discard """ + output: 10.0 +""" + +type + MyFloat = object + val: float + +converter to_myfloat*(x: float): MyFloat {.inline.} = + MyFloat(val: x) + +proc `+`(x1, x2: MyFloat): MyFloat = + MyFloat(val: x1.val + x2.val) + +proc `*`(x1, x2: MyFloat): MyFloat = + MyFloat(val: x1.val * x2.val) + +template optMul{`*`(a, 2.0)}(a: MyFloat): MyFloat = + a + a + +func floatMyFloat(x: MyFloat): MyFloat = + result = x * 2.0 + +func floatDouble(x: float): float = + result = x * 2.0 + +echo floatDouble(5) \ No newline at end of file From 1b7cf3df5192ab1d7612ba0b349117a8960156e3 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 12 Jun 2018 00:20:08 +0100 Subject: [PATCH 2/4] New approach --- compiler/hlo.nim | 50 ++++++++++++++++++------------------------- compiler/patterns.nim | 2 +- compiler/sigmatch.nim | 7 ++++-- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 511712b541..8251e3179c 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -36,35 +36,27 @@ proc applyPatterns(c: PContext, n: PNode): PNode = # we apply the last pattern first, so that pattern overriding is possible; # however the resulting AST would better not trigger the old rule then # anymore ;-) - if c.patterns.len > 0: - - # temporary disable converters - var ctx_converters: TSymSeq - shallowCopy(ctx_converters, c.converters) - c.converters = @[] - defer: shallowCopy(c.converters, ctx_converters) - - for i in countdown(c.patterns.len-1, 0): - let pattern = c.patterns[i] - if not isNil(pattern): - let x = applyRule(c, pattern, result) - if not isNil(x): - assert x.kind in {nkStmtList, nkCall} - # better be safe than sorry, so check evalTemplateCounter too: - inc(evalTemplateCounter) - if evalTemplateCounter > evalTemplateLimit: - globalError(c.config, n.info, "template instantiation too nested") - # deactivate this pattern: - c.patterns[i] = nil - if x.kind == nkStmtList: - assert x.len == 3 - x.sons[1] = evalPattern(c, x.sons[1], result) - result = flattenStmts(x) - else: - result = evalPattern(c, x, result) - dec(evalTemplateCounter) - # activate this pattern again: - c.patterns[i] = pattern + for i in countdown(c.patterns.len-1, 0): + let pattern = c.patterns[i] + if not isNil(pattern): + let x = applyRule(c, pattern, result) + if not isNil(x): + assert x.kind in {nkStmtList, nkCall} + # better be safe than sorry, so check evalTemplateCounter too: + inc(evalTemplateCounter) + if evalTemplateCounter > evalTemplateLimit: + globalError(c.config, n.info, "template instantiation too nested") + # deactivate this pattern: + c.patterns[i] = nil + if x.kind == nkStmtList: + assert x.len == 3 + x.sons[1] = evalPattern(c, x.sons[1], result) + result = flattenStmts(x) + else: + result = evalPattern(c, x, result) + dec(evalTemplateCounter) + # activate this pattern again: + c.patterns[i] = pattern proc hlo(c: PContext, n: PNode): PNode = inc(c.hloLoopDetector) diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 5409a48112..8c1017a95d 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -77,7 +77,7 @@ proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool = if isNil(n.typ): result = p.typ.kind in {tyVoid, tyStmt} else: - result = sigmatch.argtypeMatches(c.c, p.typ, n.typ) + result = sigmatch.argtypeMatches(c.c, p.typ, n.typ, from_hlo = true) proc isPatternParam(c: PPatternContext, p: PNode): bool {.inline.} = result = p.kind == nkSym and p.sym.kind == skParam and p.sym.owner == c.owner diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index fcfdda8bbe..dd0270443f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2359,14 +2359,17 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = for t in m.inferredTypes: if t.sonsLen > 1: t.sons.setLen 1 -proc argtypeMatches*(c: PContext, f, a: PType): bool = +proc argtypeMatches*(c: PContext, f, a: PType, from_hlo = false): bool = var m: TCandidate initCandidate(c, m, f) let res = paramTypesMatch(m, f, a, ast.emptyNode, nil) #instantiateGenericConverters(c, res, m) # XXX this is used by patterns.nim too; I think it's better to not # instantiate generic converters for that - result = res != nil + if not from_hlo: + res != nil + else: + res != nil and m.convMatches == 0 and m.intConvMatches in [0, 256] proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; op: TTypeAttachedOp; col: int): PSym {.procvar.} = From 746da12d74028a0f5c1cfcc0eb14bc157df79837 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 12 Jun 2018 00:22:11 +0100 Subject: [PATCH 3/4] add comment --- compiler/sigmatch.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index dd0270443f..f5a8d225aa 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2369,6 +2369,7 @@ proc argtypeMatches*(c: PContext, f, a: PType, from_hlo = false): bool = if not from_hlo: res != nil else: + # pattern templates do not allow for conversions except from int literal res != nil and m.convMatches == 0 and m.intConvMatches in [0, 256] proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; From 44d82d94927424ce643aecba5231adb698bf3965 Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 12 Jun 2018 09:17:24 +0100 Subject: [PATCH 4/4] style improvements --- compiler/patterns.nim | 2 +- compiler/sigmatch.nim | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 8c1017a95d..2d2aeba76a 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -77,7 +77,7 @@ proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool = if isNil(n.typ): result = p.typ.kind in {tyVoid, tyStmt} else: - result = sigmatch.argtypeMatches(c.c, p.typ, n.typ, from_hlo = true) + result = sigmatch.argtypeMatches(c.c, p.typ, n.typ, fromHlo = true) proc isPatternParam(c: PPatternContext, p: PNode): bool {.inline.} = result = p.kind == nkSym and p.sym.kind == skParam and p.sym.owner == c.owner diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index f5a8d225aa..bde3a5b1ec 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2359,14 +2359,14 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = for t in m.inferredTypes: if t.sonsLen > 1: t.sons.setLen 1 -proc argtypeMatches*(c: PContext, f, a: PType, from_hlo = false): bool = +proc argtypeMatches*(c: PContext, f, a: PType, fromHlo = false): bool = var m: TCandidate initCandidate(c, m, f) let res = paramTypesMatch(m, f, a, ast.emptyNode, nil) #instantiateGenericConverters(c, res, m) # XXX this is used by patterns.nim too; I think it's better to not # instantiate generic converters for that - if not from_hlo: + if not fromHlo: res != nil else: # pattern templates do not allow for conversions except from int literal