Templates will pick the candidate in the nearest scope when symbols are mixed-in

This commit is contained in:
Zahary Karadjov 2013-12-31 03:58:31 +02:00
commit 8f3d5a25a6
6 changed files with 32 additions and 16 deletions

View file

@ -1430,6 +1430,10 @@ proc skipGenericOwner*(s: PSym): PSym =
result = if sfFromGeneric in s.flags: s.owner.owner result = if sfFromGeneric in s.flags: s.owner.owner
else: s.owner else: s.owner
proc originatingModule*(s: PSym): PSym =
result = s.owner
while result.kind != skModule: result = result.owner
proc isRoutine*(s: PSym): bool {.inline.} = proc isRoutine*(s: PSym): bool {.inline.} =
result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod, result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod,
skConverter} skConverter}

View file

@ -1164,7 +1164,7 @@ proc semAsgn(c: PContext, n: PNode): PNode =
if lhsIsResult: {efAllowDestructor} else: {}) if lhsIsResult: {efAllowDestructor} else: {})
if lhsIsResult: if lhsIsResult:
n.typ = enforceVoidContext n.typ = enforceVoidContext
if lhs.sym.typ.isMetaType: if lhs.sym.typ.isMetaType and lhs.sym.typ.kind != tyTypeDesc:
if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric: if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric:
internalAssert c.p.resultSym != nil internalAssert c.p.resultSym != nil
lhs.typ = rhs.typ lhs.typ = rhs.typ

View file

@ -421,6 +421,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
else: else:
s = semIdentVis(c, skTemplate, n.sons[0], {}) s = semIdentVis(c, skTemplate, n.sons[0], {})
# check parameter list: # check parameter list:
s.scope = c.currentScope
pushOwner(s) pushOwner(s)
openScope(c) openScope(c)
n.sons[namePos] = newSymNode(s, n.sons[namePos].info) n.sons[namePos] = newSymNode(s, n.sons[namePos].info)

View file

@ -162,8 +162,9 @@ proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
elif result.kind == tyGenericParam and not cl.allowMetaTypes: elif result.kind == tyGenericParam and not cl.allowMetaTypes:
internalError(cl.info, "substitution with generic parameter") internalError(cl.info, "substitution with generic parameter")
proc instCopyType(t: PType): PType = proc instCopyType(cl: var TReplTypeVars, t: PType): PType =
result = copyType(t, t.owner, false) # XXX: relying on allowMetaTypes is a kludge
result = copyType(t, t.owner, cl.allowMetaTypes)
result.flags.incl tfFromGeneric result.flags.incl tfFromGeneric
result.flags.excl tfInstClearedFlags result.flags.excl tfInstClearedFlags
@ -184,7 +185,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
if x.kind == tyGenericParam: if x.kind == tyGenericParam:
x = lookupTypeVar(cl, x) x = lookupTypeVar(cl, x)
if x != nil: if x != nil:
if header == nil: header = instCopyType(t) if header == nil: header = instCopyType(cl, t)
header.sons[i] = x header.sons[i] = x
propagateToOwner(header, x) propagateToOwner(header, x)
@ -193,7 +194,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
result = searchInstTypes(header) result = searchInstTypes(header)
if result != nil: return if result != nil: return
else: else:
header = instCopyType(t) header = instCopyType(cl, t)
result = newType(tyGenericInst, t.sons[0].owner) result = newType(tyGenericInst, t.sons[0].owner)
# be careful not to propagate unnecessary flags here (don't use rawAddSon) # be careful not to propagate unnecessary flags here (don't use rawAddSon)
@ -295,7 +296,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result = lookup result = lookup
if tfUnresolved in t.flags: result = result.base if tfUnresolved in t.flags: result = result.base
of tyGenericInst: of tyGenericInst:
result = instCopyType(t) result = instCopyType(cl, t)
for i in 1 .. <result.sonsLen: for i in 1 .. <result.sonsLen:
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i]) result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
propagateToOwner(result, result.lastSon) propagateToOwner(result, result.lastSon)
@ -308,7 +309,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info) t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)
if containsGenericType(t): if containsGenericType(t):
result = instCopyType(t) result = instCopyType(cl, t)
result.size = -1 # needs to be recomputed result.size = -1 # needs to be recomputed
for i in countup(0, sonsLen(result) - 1): for i in countup(0, sonsLen(result) - 1):

View file

@ -31,7 +31,8 @@ type
state*: TCandidateState state*: TCandidateState
callee*: PType # may not be nil! callee*: PType # may not be nil!
calleeSym*: PSym # may be nil calleeSym*: PSym # may be nil
calleeScope: int # may be -1 for unknown scope calleeScope*: int # scope depth:
# is this a top-level symbol or a nested proc?
call*: PNode # modified call call*: PNode # modified call
bindings*: TIdTable # maps types to types bindings*: TIdTable # maps types to types
baseTypeMatch: bool # needed for conversions from T to openarray[T] baseTypeMatch: bool # needed for conversions from T to openarray[T]
@ -86,7 +87,15 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
binding: PNode, calleeScope = -1) = binding: PNode, calleeScope = -1) =
initCandidateAux(ctx, c, callee.typ) initCandidateAux(ctx, c, callee.typ)
c.calleeSym = callee c.calleeSym = callee
c.calleeScope = calleeScope if callee.kind in skProcKinds and calleeScope == -1:
if callee.originatingModule == ctx.module:
let rootSym = if sfFromGeneric notin callee.flags: callee
else: callee.owner
c.calleeScope = rootSym.scope.depthLevel
else:
c.calleeScope = 1
else:
c.calleeScope = calleeScope
initIdTable(c.bindings) initIdTable(c.bindings)
c.errors = nil c.errors = nil
if binding != nil and callee.kind in routineKinds: if binding != nil and callee.kind in routineKinds:
@ -166,9 +175,8 @@ proc cmpCandidates*(a, b: TCandidate): int =
if result != 0: return if result != 0: return
result = a.convMatches - b.convMatches result = a.convMatches - b.convMatches
if result != 0: return if result != 0: return
if (a.calleeScope != -1) and (b.calleeScope != -1): result = a.calleeScope - b.calleeScope
result = a.calleeScope - b.calleeScope if result != 0: return
if result != 0: return
# the other way round because of other semantics: # the other way round because of other semantics:
result = b.inheritancePenalty - a.inheritancePenalty result = b.inheritancePenalty - a.inheritancePenalty
if result != 0: return if result != 0: return
@ -566,8 +574,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if a.kind == tyTuple: result = recordRel(c, f, a) if a.kind == tyTuple: result = recordRel(c, f, a)
of tyObject: of tyObject:
if a.kind == tyObject: if a.kind == tyObject:
if sameObjectTypes(f, a): result = isEqual if sameObjectTypes(f, a):
elif tfHasMeta in f.flags: result = recordRel(c, f, a) result = isEqual
# elif tfHasMeta in f.flags: result = recordRel(c, f, a)
else: else:
var depth = isObjectSubtype(a, f) var depth = isObjectSubtype(a, f)
if depth > 0: if depth > 0:

View file

@ -875,6 +875,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
tyOrdinal, tyTypeClasses: tyOrdinal, tyTypeClasses:
cycleCheck() cycleCheck()
if a.kind == tyTypeClass and a.n != nil: return a.n == b.n
result = sameChildrenAux(a, b, c) and sameFlags(a, b) result = sameChildrenAux(a, b, c) and sameFlags(a, b)
if result and a.kind == tyProc: if result and a.kind == tyProc:
result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and