mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-15 21:50:55 +00:00
various bugfixes for generics; added generic sort proc
This commit is contained in:
11
rod/ast.nim
11
rod/ast.nim
@@ -750,6 +750,12 @@ proc newSymNode(sym: PSym): PNode =
|
||||
result.typ = sym.typ
|
||||
result.info = sym.info
|
||||
|
||||
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
result = newNode(nkSym)
|
||||
result.sym = sym
|
||||
result.typ = sym.typ
|
||||
result.info = info
|
||||
|
||||
proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode =
|
||||
result = newNode(kind)
|
||||
result.info = info
|
||||
@@ -869,6 +875,11 @@ proc len*(n: PNode): int {.inline.} =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc safeLen*(n: PNode): int {.inline.} =
|
||||
## works even for leaves.
|
||||
if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc add*(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
|
||||
@@ -79,20 +79,42 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
|
||||
initialBinding = nil
|
||||
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
|
||||
|
||||
proc explictGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
proc explicitGenericInstError(n: PNode): PNode =
|
||||
LocalError(n.info, errCannotInstantiateX, renderTree(n))
|
||||
result = n
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
for i in 1..sonsLen(n)-1:
|
||||
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
|
||||
# we cannot check for the proper number of type parameters because in
|
||||
# `f[a,b](x, y)` `f` is not resolved yet properly.
|
||||
# XXX: BUG this should be checked somehow!
|
||||
assert n.sons[0].kind == nkSym
|
||||
var s = s
|
||||
var a = n.sons[0]
|
||||
if a.kind == nkSym:
|
||||
# common case; check the only candidate has the right
|
||||
# number of generic type parameters:
|
||||
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
|
||||
return explicitGenericInstError(n)
|
||||
elif a.kind == nkSymChoice:
|
||||
# choose the generic proc with the proper number of type parameters.
|
||||
# XXX I think this could be improved by reusing sigmatch.ParamTypesMatch.
|
||||
# It's good enough for now.
|
||||
var candidateCount = 0
|
||||
for i in countup(0, len(a)-1):
|
||||
var candidate = a.sons[i].sym
|
||||
if candidate.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||
# if suffices that the candidate has the proper number of generic
|
||||
# type parameters:
|
||||
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
|
||||
s = candidate
|
||||
inc(candidateCount)
|
||||
if candidateCount != 1: return explicitGenericInstError(n)
|
||||
else:
|
||||
assert false
|
||||
|
||||
var x: TCandidate
|
||||
initCandidate(x, s, n)
|
||||
var newInst = generateInstance(c, s, x.bindings, n.info)
|
||||
|
||||
markUsed(n, s)
|
||||
result = newSymNode(newInst)
|
||||
result.info = n.info
|
||||
result = newSymNode(newInst, n.info)
|
||||
|
||||
|
||||
@@ -61,24 +61,22 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
if s.typ.kind in ConstAbstractTypes:
|
||||
result = copyTree(s.ast)
|
||||
result.typ = s.typ
|
||||
result.info = n.info
|
||||
else:
|
||||
result = newSymNode(s)
|
||||
result.info = n.info
|
||||
result = newSymNode(s, n.info)
|
||||
of skMacro: result = semMacroExpr(c, n, s)
|
||||
of skTemplate: result = semTemplateExpr(c, n, s)
|
||||
of skVar:
|
||||
markUsed(n, s)
|
||||
# if a proc accesses a global variable, it is not side effect free:
|
||||
if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
|
||||
result = newSymNode(s)
|
||||
result.info = n.info
|
||||
result = newSymNode(s, n.info)
|
||||
of skGenericParam:
|
||||
if s.ast == nil: InternalError(n.info, "no default for")
|
||||
result = semExpr(c, s.ast)
|
||||
else:
|
||||
markUsed(n, s)
|
||||
result = newSymNode(s)
|
||||
result.info = n.info
|
||||
result = newSymNode(s, n.info)
|
||||
|
||||
proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
|
||||
var diff = inheritanceDiff(castDest, src)
|
||||
@@ -645,23 +643,22 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
var ty = n.sons[0].Typ
|
||||
var f: PSym = nil
|
||||
result = nil
|
||||
if ty.kind == tyEnum:
|
||||
# look up if the identifier belongs to the enum:
|
||||
while ty != nil:
|
||||
f = getSymFromList(ty.n, i)
|
||||
if f != nil: break
|
||||
ty = ty.sons[0] # enum inheritance
|
||||
if f != nil:
|
||||
result = newSymNode(f)
|
||||
result.info = n.info
|
||||
result.typ = ty
|
||||
markUsed(n, f)
|
||||
else:
|
||||
GlobalError(n.sons[1].info, errEnumHasNoValueX, i.s)
|
||||
return
|
||||
elif not (efAllowType in flags) and isTypeExpr(n.sons[0]):
|
||||
GlobalError(n.sons[0].info, errATypeHasNoValue)
|
||||
return
|
||||
if isTypeExpr(n.sons[0]):
|
||||
if ty.kind == tyEnum:
|
||||
# look up if the identifier belongs to the enum:
|
||||
while ty != nil:
|
||||
f = getSymFromList(ty.n, i)
|
||||
if f != nil: break
|
||||
ty = ty.sons[0] # enum inheritance
|
||||
if f != nil:
|
||||
result = newSymNode(f)
|
||||
result.info = n.info
|
||||
result.typ = ty
|
||||
markUsed(n, f)
|
||||
return
|
||||
elif efAllowType notin flags:
|
||||
GlobalError(n.sons[0].info, errATypeHasNoValue)
|
||||
return
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
var check: PNode = nil
|
||||
if ty.kind == tyObject:
|
||||
@@ -1027,7 +1024,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
|
||||
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||
# type parameters: partial generic specialization
|
||||
result = explictGenericInstantiation(c, n, s)
|
||||
n.sons[0] = semSym(c, n.sons[0], s, flags)
|
||||
result = explicitGenericInstantiation(c, n, s)
|
||||
else:
|
||||
result = semArrayAccess(c, n, flags)
|
||||
of nkPragmaExpr:
|
||||
|
||||
@@ -40,13 +40,15 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||
of skMacro:
|
||||
result = semMacroExpr(c, n, s, false)
|
||||
of skGenericParam:
|
||||
result = newSymNode(s)
|
||||
result = newSymNode(s, n.info)
|
||||
of skParam:
|
||||
result = n
|
||||
of skType:
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam): result = newSymNode(s)
|
||||
else: result = n
|
||||
else: result = newSymNode(s)
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||
result = newSymNode(s, n.info)
|
||||
else:
|
||||
result = n
|
||||
else: result = newSymNode(s, n.info)
|
||||
|
||||
proc getIdentNode(n: PNode): PNode =
|
||||
case n.kind
|
||||
@@ -101,12 +103,12 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||
of skProc, skMethod, skIterator, skConverter:
|
||||
n.sons[0] = symChoice(c, n.sons[0], s)
|
||||
of skGenericParam:
|
||||
n.sons[0] = newSymNode(s)
|
||||
n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||
of skType:
|
||||
# bad hack for generics:
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||
n.sons[0] = newSymNode(s)
|
||||
else: n.sons[0] = newSymNode(s)
|
||||
n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||
else: n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
n.sons[i] = semGenericStmt(c, n.sons[i], flags)
|
||||
of nkMacroStmt:
|
||||
@@ -221,9 +223,9 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||
if (a.kind != nkIdentDefs): IllFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
L = sonsLen(a)
|
||||
a.sons[L - 1] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc})
|
||||
a.sons[L - 1] = semGenericStmt(c, a.sons[L - 1])
|
||||
for j in countup(0, L - 3):
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc})
|
||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1])
|
||||
for j in countup(0, L-3):
|
||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef, nkLambda:
|
||||
|
||||
@@ -522,11 +522,15 @@ proc SemTypeSection(c: PContext, n: PNode): PNode =
|
||||
InternalError(a.info, "semTypeSection: containerID")
|
||||
s.typ.containerID = getID()
|
||||
a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
|
||||
addSon(s.typ, nil) # to be filled out later
|
||||
|
||||
# we fill it out later. For magic generics like 'seq', it won't be filled
|
||||
# so we use tyEmpty instead of nil to not crash for strange conversions
|
||||
# like: mydata.seq
|
||||
addSon(s.typ, newTypeS(tyEmpty, c))
|
||||
s.ast = a
|
||||
body = semTypeNode(c, a.sons[2], nil)
|
||||
if body != nil: body.sym = s
|
||||
s.typ.sons[sonsLen(s.typ) - 1] = body #debug(s.typ);
|
||||
s.typ.sons[sonsLen(s.typ) - 1] = body
|
||||
popOwner()
|
||||
closeScope(c.tab)
|
||||
elif a.sons[2].kind != nkEmpty:
|
||||
|
||||
@@ -488,7 +488,8 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
|
||||
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
|
||||
#if result.kind == tyGenericInvokation: debug(result)
|
||||
|
||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
|
||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
prev: PType): PType =
|
||||
var
|
||||
def, res: PNode
|
||||
typ: PType
|
||||
@@ -515,12 +516,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
|
||||
if a.sons[length - 1].kind != nkEmpty:
|
||||
def = semExprWithType(c, a.sons[length - 1])
|
||||
# check type compability between def.typ and typ:
|
||||
if typ != nil:
|
||||
if cmpTypes(typ, def.typ) < isConvertible:
|
||||
typeMismatch(a.sons[length - 1], typ, def.typ)
|
||||
def = fitNode(c, typ, def)
|
||||
else:
|
||||
if typ == nil:
|
||||
typ = def.typ
|
||||
elif def != nil and def.typ != nil and def.typ.kind != tyNone:
|
||||
# example code that triggers it:
|
||||
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
||||
def = fitNode(c, typ, def)
|
||||
else:
|
||||
def = ast.emptyNode
|
||||
for j in countup(0, length - 3):
|
||||
|
||||
@@ -130,8 +130,11 @@ proc concreteType(mapping: TIdTable, t: PType): PType =
|
||||
result = t
|
||||
while true:
|
||||
result = PType(idTableGet(mapping, t))
|
||||
if result == nil: InternalError("lookup failed")
|
||||
if result.kind != tyGenericParam: break
|
||||
if result == nil:
|
||||
break # it's ok, no match
|
||||
# example code that triggers it:
|
||||
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
||||
if result.kind != tyGenericParam: break
|
||||
else:
|
||||
result = t # Note: empty is valid here
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ proc suggestFieldAccess(c: PContext, n: PNode) =
|
||||
else:
|
||||
# fallback:
|
||||
suggestEverything(c, n)
|
||||
elif typ.kind == tyEnum:
|
||||
elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType:
|
||||
# look up if the identifier belongs to the enum:
|
||||
var t = typ
|
||||
while t != nil:
|
||||
|
||||
Reference in New Issue
Block a user