Skip to content

fix #24912 #24913

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: devel
Choose a base branch
from
72 changes: 48 additions & 24 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -994,18 +994,18 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
let callee = result[0].sym
case callee.kind
of skMacro, skTemplate: discard
else:
if callee.kind == skIterator and callee.id == c.p.owner.id and
not isClosureIterator(c.p.owner.typ):
of skIterator:
if callee.id == c.p.owner.id and not isClosureIterator(c.p.owner.typ):
localError(c.config, n.info, errRecursiveDependencyIteratorX % callee.name.s)
# error correction, prevents endless for loop elimination in transf.
# See bug #2051:
result[0] = newSymNode(errorSym(c, n))
elif callee.kind == skIterator:
if efWantIterable in flags:
let typ = newTypeS(tyIterable, c)
rawAddSon(typ, result.typ)
result.typ() = typ
elif efWantIterable in flags:
let typ = newTypeS(tyIterable, c)
rawAddSon(typ, result.typ)
result.typ() = typ
else:
discard

proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
t: PType): TCandidate =
Expand Down Expand Up @@ -1075,6 +1075,16 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
# don't fold calls in concepts and typeof
result = evalAtCompileTime(c, result)

proc normalizeMethodCallSyntax(n: PNode): PNode =
# transforms A.b(C) to b(A, C)
# does not check if `b` is a field
result = n[0]
result.transitionSonsKind(nkCall)
for i in 1..<n.len: result.add n[i]
let tmp = result[1]
result[1] = result[0]
result[0] = tmp

proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = nil
checkMinSonsLen(n, 1, c.config)
Expand Down Expand Up @@ -1104,15 +1114,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
elif isSymChoice(n[0]) and nfDotField notin n.flags:
# overloaded generic procs e.g. newSeq[int] can end up here
return semDirectOp(c, n, flags, expectedType)

var t: PType = nil
if n[0].typ != nil:
t = skipTypes(n[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct})
if t != nil and t.kind == tyTypeDesc:
if n.len == 1: return semObjConstr(c, n, flags, expectedType)
return semConv(c, n, flags)

let nOrig = n.copyTree

var nOrig = n.copyTree
semOpAux(c, n)
if t != nil and t.kind == tyProc:
# This is a proc variable, apply normal overload resolution
Expand Down Expand Up @@ -1154,21 +1160,39 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType

else:
result = overloadedCallOpr(c, n) # this uses efNoUndeclared
# Now that nkSym does not imply an iteration over the proc/iterator space,
# the old ``prc`` (which is likely an nkIdent) has to be restored:
if result == nil or result.kind == nkEmpty:
# XXX: hmm, what kind of symbols will end up here?
# do we really need to try the overload resolution?
n[0] = prc
nOrig[0] = prc
n.flags.incl nfExprCall
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil: return errorNode(c, n)
var tcall = n.copyTree
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a helper proc here and document what the heck is actually does and why it needs to do it. The compiler code is already incomprehensible with all these arbitrary transformations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pulled out the part that is new. The rest is stuff that got re-positioned.

if n[0].kind == nkDotExpr and n[0].typ.kind notin {tyProc, tyGenericInst, tyOwned}:
tcall = normalizeMethodCallSyntax(tcall)
nOrig = tcall.copyTree
else:
# Now that nkSym does not imply an iteration over the proc/iterator space,
# the old ``prc`` (which is likely an nkIdent) has to be restored:
tcall[0] = prc
nOrig[0] = prc
tcall.flags.incl nfExprCall
let canspec = t != nil and t.kind in {tyFromExpr, tyTypeDesc}
var fflags = flags
if canspec:
fflags.incl efNoUndeclared
result = semOverloadedCallAnalyseEffects(c, tcall, nOrig, fflags)
if result == nil:
if canspec:
if n.len == 2:
return semConv(c, n, flags)
elif n.len == 1:
return semObjConstr(c, n, flags, expectedType)
elif result.kind notin nkCallKinds:
# the semExpr() in overloadedCallOpr can even break this condition!
# See bug #904 of how to trigger it:
return result
#result = afterCallActions(c, result, nOrig, flags)
if result == nil:
return errorNode(c, n)
if result.typ != nil and result.typ.kind == tyFromExpr and t != nil and t.kind == tyTypeDesc:
# this is wrong but tyFromExpr doesn't always seem to be a valid result
# anecdotally, this is what the compiler is trying to do but I think
# tyFromExpr needs to be handled elsewhere
return semObjConstr(c, n, flags, expectedType)
if result[0].kind == nkSym:
result = afterCallActions(c, result, nOrig, flags, expectedType)
else:
Expand Down
63 changes: 63 additions & 0 deletions tests/exprs/tdots.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
discard """
action: run
"""

#24913
block:
type
A = object
b: int
B = object
b: proc(x: float): int

proc b(T: typedesc[A]; s: float): int = 5
proc b(T: typedesc[B]; s: float): int = 7
proc testme(x: float): int = 3
doAssert A.b(1.0) == 5
doAssert B.b(1.0) == 7
doAssert B(b: testme).b(1.0) == 3

block:
type
Proc[T] = proc(text: T): int {.closure.}

Rule[T] = object
p: Proc[T]

proc p(x: Rule[int]; y: float): int = 5
proc sp(y: int): int = 3

proc spring[T](rule: Rule[T]) =
let p = proc (text: T) =
doAssert rule.p(text) == 3
p(default(T))

Rule[int](p: sp).spring()

block:
type
A = object

proc new(T: type A): ref A =
let c = (ref T)()
c

proc p[K](rng=A.new()) =
discard new(A)

p[int]()

# cant be in a block
type
Cont[T] = ref RootObj
Rule[T] = object
p: Cont[T]

proc p(x: Rule[int]; y: int): int = 5

proc spring[T](rule: Rule[T]) =
let p = proc (x: T) =
doAssert rule.p(x) == 5
p(default(T))

Rule[int]().spring()