refactoring: suggest can import sigmatch for type matching

This commit is contained in:
Araq
2011-02-21 20:06:34 +01:00
parent 4e7a22cac3
commit fdde4d3a92
12 changed files with 445 additions and 266 deletions

View File

@@ -51,16 +51,18 @@ type
TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash
proc InitTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc NextIter*(ti: var TTabIter, tab: TStrTable): PSym
# usage:
# var i: TTabIter; s: PSym;
# s := InitTabIter(i, table);
# while s <> nil do begin
# var
# i: TTabIter
# s: PSym
# s = InitTabIter(i, table)
# while s != nil:
# ...
# s := NextIter(i, table);
# end;
# s = NextIter(i, table)
#
type
TIdentIter*{.final.} = object # iterator over all syms with the same identifier
h*: THash # current hash

View File

@@ -13,7 +13,7 @@ import
strutils, nhashes, lists, options, scanner, ast, astalgo, trees, treetab,
wordrecg, ropes, msgs, os, condsyms, idents, rnimsyn, types, platform, math,
magicsys, pnimsyn, nversion, nimsets, semdata, evals, semfold, importer,
procfind, lookups, rodread, pragmas, passes, suggest
procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest
proc semPass*(): TPass
# implementation
@@ -34,10 +34,6 @@ proc isTopLevel(c: PContext): bool =
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerAcc(n), getCurrOwner())
result.info = n.info
proc markUsed(n: PNode, s: PSym) =
incl(s.flags, sfUsed)
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym
# identifier with visability
@@ -115,7 +111,7 @@ proc semMacroExpr(c: PContext, n: PNode, sym: PSym,
if semCheck: result = semAfterMacroCall(c, result, sym)
dec(evalTemplateCounter)
include seminst, sigmatch
include seminst, semcall
proc CheckBool(t: PNode) =
if (t.Typ == nil) or

98
rod/semcall.nim Normal file
View File

@@ -0,0 +1,98 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements semantic checking for calls.
proc sameMethodDispatcher(a, b: PSym): bool =
result = false
if a.kind == skMethod and b.kind == skMethod:
var aa = lastSon(a.ast)
var bb = lastSon(b.ast)
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
result = true
proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
initialBinding: PNode): PNode =
var
o: TOverloadIter
x, y, z: TCandidate
#Message(n.info, warnUser, renderTree(n))
var sym = initOverloadIter(o, c, f)
result = nil
if sym == nil: return
initCandidate(x, sym, initialBinding)
initCandidate(y, sym, initialBinding)
while sym != nil:
if sym.kind in filter:
initCandidate(z, sym, initialBinding)
z.calleeSym = sym
matches(c, n, z)
if z.state == csMatch:
case x.state
of csEmpty, csNoMatch: x = z
of csMatch:
var cmp = cmpCandidates(x, z)
if cmp < 0: x = z # z is better than x
elif cmp == 0: y = z # z is as good as x
else: nil
sym = nextOverloadIter(o, c, f)
if x.state == csEmpty:
# no overloaded proc found
# do not generate an error yet; the semantic checking will check for
# an overloaded () operator
elif y.state == csMatch and cmpCandidates(x, y) == 0 and
not sameMethodDispatcher(x.calleeSym, y.calleeSym):
if x.state != csMatch:
InternalError(n.info, "x.state is not csMatch")
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(x.calleeSym), getProcHeader(y.calleeSym),
x.calleeSym.Name.s])
else:
# only one valid interpretation found:
markUsed(n, x.calleeSym)
if x.calleeSym.ast == nil:
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
if x.calleeSym.ast.sons[genericParamsPos].kind != nkEmpty:
# a generic proc!
x.calleeSym = generateInstance(c, x.calleeSym, x.bindings, n.info)
x.callee = x.calleeSym.typ
result = x.call
result.sons[0] = newSymNode(x.calleeSym)
result.typ = x.callee.sons[0]
proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
# process the bindings once:
var initialBinding: PNode
var f = n.sons[0]
if f.kind == nkBracketExpr:
# fill in the bindings:
initialBinding = f
f = f.sons[0]
else:
initialBinding = nil
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
proc explictGenericInstantiation(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 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

View File

@@ -166,6 +166,10 @@ proc makeRangeType(c: PContext, first, last: biggestInt,
result.n = n
addSon(result, getSysType(tyInt)) # basetype of range
proc markUsed*(n: PNode, s: PSym) =
incl(s.flags, sfUsed)
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
proc illFormedAst*(n: PNode) =
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))

View File

@@ -12,8 +12,7 @@ const
ConstAbstractTypes = {tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
tyArrayConstr, tyTuple, tySet}
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
semCheck: bool = true): PNode =
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
markUsed(n, s)
pushInfoContext(n.info)
result = evalTemplate(c, n, s)
@@ -122,9 +121,9 @@ proc checkConvertible(info: TLineInfo, castDest, src: PType) =
proc isCastable(dst, src: PType): bool =
#const
# castableTypeKinds = {@set}[tyInt, tyPtr, tyRef, tyCstring, tyString,
# tySequence, tyPointer, tyNil, tyOpenArray,
# tyProc, tySet, tyEnum, tyBool, tyChar];
# castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
# tySequence, tyPointer, tyNil, tyOpenArray,
# tyProc, tySet, tyEnum, tyBool, tyChar}
var ds, ss: biggestInt
# this is very unrestrictive; cast is allowed if castDest.size >= src.size
ds = computeSize(dst)
@@ -232,7 +231,8 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
proc changeType(n: PNode, newType: PType) =
case n.kind
of nkCurly, nkBracket:
for i in countup(0, sonsLen(n) - 1): changeType(n.sons[i], elemType(newType))
for i in countup(0, sonsLen(n) - 1):
changeType(n.sons[i], elemType(newType))
of nkPar:
if newType.kind != tyTuple:
InternalError(n.info, "changeType: no tuple type for constructor")
@@ -350,8 +350,6 @@ proc isAssignable(n: PNode): TAssignableResult =
result = isAssignable(n.sons[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
# Object and tuple conversions are still addressable, so we skip them
#if skipPtrsGeneric(n.sons[1].typ).kind in [tyOpenArray,
# tyTuple, tyObject] then
if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}:
result = isAssignable(n.sons[1])
of nkHiddenDeref, nkDerefExpr:
@@ -643,6 +641,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
checkSonsLen(n, 2)
n.sons[0] = semExprWithType(c, n.sons[0], {efAllowType} + flags)
if gCmd == cmdSuggest:
suggestFieldAccess(c, n.sons[0])
var i = considerAcc(n.sons[1])
var ty = n.sons[0].Typ
var f: PSym = nil

View File

@@ -7,35 +7,11 @@
# distribution, for details about the copyright.
#
# This module does the instantiation of generic procs and types.
# This module does the instantiation of generic procs.
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym
# generates an instantiated proc
proc searchInstTypes(tab: TIdTable, key: PType): PType =
# returns nil if we need to declare this type
result = PType(IdTableGet(tab, key))
if (result == nil) and (tab.counter > 0):
# we have to do a slow linear search because types may need
# to be compared by their structure:
for h in countup(0, high(tab.data)):
var t = PType(tab.data[h].key)
if t != nil:
if key.containerId == t.containerID:
var match = true
for j in countup(0, sonsLen(t) - 1):
# XXX sameType is not really correct for nested generics?
if not sameType(t.sons[j], key.sons[j]):
match = false
break
if match:
return PType(tab.data[h].val)
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
result = t.kind in GenericTypes
proc containsGenericType(t: PType): bool =
result = iterOverType(t, containsGenericTypeIter, nil)
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
if (n.kind != nkGenericParams):
@@ -129,106 +105,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
c.p = oldP # restore
c.module = oldMod
dec(c.InstCounter)
proc checkConstructedType(info: TLineInfo, t: PType) =
if (tfAcyclic in t.flags) and (skipTypes(t, abstractInst).kind != tyObject):
LocalError(info, errInvalidPragmaX, "acyclic")
elif computeSize(t) < 0:
LocalError(info, errIllegalRecursionInTypeX, typeToString(t))
elif (t.kind == tyVar) and (t.sons[0].kind == tyVar):
LocalError(info, errVarVarTypeNotAllowed)
type
TReplTypeVars{.final.} = object
c*: PContext
typeMap*: TIdTable # map PType to PType
symMap*: TIdTable # map PSym to PSym
info*: TLineInfo
proc ReplaceTypeVarsT(cl: var TReplTypeVars, t: PType): PType
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
if n != nil:
result = copyNode(n)
result.typ = ReplaceTypeVarsT(cl, n.typ)
case n.kind
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
nil
of nkSym:
result.sym = ReplaceTypeVarsS(cl, n.sym)
else:
var length = sonsLen(n)
if length > 0:
newSons(result, length)
for i in countup(0, length - 1):
result.sons[i] = ReplaceTypeVarsN(cl, n.sons[i])
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
if s == nil: return nil
result = PSym(idTableGet(cl.symMap, s))
if result == nil:
result = copySym(s, false)
incl(result.flags, sfFromGeneric)
idTablePut(cl.symMap, s, result)
result.typ = ReplaceTypeVarsT(cl, s.typ)
result.owner = s.owner
result.ast = ReplaceTypeVarsN(cl, s.ast)
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t))
if result == nil:
GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
elif result.kind == tyGenericParam:
InternalError(cl.info, "substitution with generic parameter")
proc ReplaceTypeVarsT(cl: var TReplTypeVars, t: PType): PType =
var body, newbody, x, header: PType
result = t
if t == nil: return
case t.kind
of tyGenericParam:
result = lookupTypeVar(cl, t)
of tyGenericInvokation:
body = t.sons[0]
if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
header = nil
for i in countup(1, sonsLen(t) - 1):
if t.sons[i].kind == tyGenericParam:
x = lookupTypeVar(cl, t.sons[i])
if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x
else:
x = t.sons[i]
idTablePut(cl.typeMap, body.sons[i - 1], x)
if header == nil: header = t
result = searchInstTypes(gInstTypes, header)
if result != nil: return
result = newType(tyGenericInst, t.sons[0].owner)
for i in countup(0, sonsLen(t) - 1):
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
addSon(result, header.sons[i])
idTablePut(gInstTypes, header, result)
newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
addSon(result, newbody)
#writeln(output, ropeToStr(Typetoyaml(newbody)));
checkConstructedType(cl.info, newbody)
of tyGenericBody:
InternalError(cl.info, "ReplaceTypeVarsT: tyGenericBody")
result = ReplaceTypeVarsT(cl, lastSon(t))
else:
if containsGenericType(t):
result = copyType(t, t.owner, false)
for i in countup(0, sonsLen(result) - 1):
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
result.n = ReplaceTypeVarsN(cl, result.n)
if result.Kind in GenericTypes:
LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
#writeln(output, ropeToStr(Typetoyaml(result)))
#checkConstructedType(cl.info, result)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
var cl: TReplTypeVars
InitIdTable(cl.symMap)
@@ -237,14 +114,3 @@ proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
cl.c = c
result = ReplaceTypeVarsT(cl, header)
proc generateTypeInstance(p: PContext, pt: TIdTable, arg: PNode,
t: PType): PType =
var cl: TReplTypeVars
InitIdTable(cl.symMap)
copyIdTable(cl.typeMap, pt)
cl.info = arg.info
cl.c = p
pushInfoContext(arg.info)
result = ReplaceTypeVarsT(cl, t)
popInfoContext()

View File

@@ -245,7 +245,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
elif (sfMinus in allowed) and (v.id == ord(wMinus)):
incl(result.flags, sfMinus)
else:
GlobalError(n.sons[0].info, errInvalidVisibilityX, v.s)
LocalError(n.sons[0].info, errInvalidVisibilityX, v.s)
else:
illFormedAst(n)
else:

147
rod/semtypinst.nim Normal file
View File

@@ -0,0 +1,147 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module does the instantiation of generic procs and types.
import ast, astalgo, msgs, types, semdata
proc checkConstructedType*(info: TLineInfo, t: PType) =
if (tfAcyclic in t.flags) and (skipTypes(t, abstractInst).kind != tyObject):
LocalError(info, errInvalidPragmaX, "acyclic")
elif computeSize(t) < 0:
LocalError(info, errIllegalRecursionInTypeX, typeToString(t))
elif (t.kind == tyVar) and (t.sons[0].kind == tyVar):
LocalError(info, errVarVarTypeNotAllowed)
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
result = t.kind in GenericTypes
proc containsGenericType*(t: PType): bool =
result = iterOverType(t, containsGenericTypeIter, nil)
proc searchInstTypes(tab: TIdTable, key: PType): PType =
# returns nil if we need to declare this type
result = PType(IdTableGet(tab, key))
if (result == nil) and (tab.counter > 0):
# we have to do a slow linear search because types may need
# to be compared by their structure:
for h in countup(0, high(tab.data)):
var t = PType(tab.data[h].key)
if t != nil:
if key.containerId == t.containerID:
var match = true
for j in countup(0, sonsLen(t) - 1):
# XXX sameType is not really correct for nested generics?
if not sameType(t.sons[j], key.sons[j]):
match = false
break
if match:
return PType(tab.data[h].val)
type
TReplTypeVars* {.final.} = object
c*: PContext
typeMap*: TIdTable # map PType to PType
symMap*: TIdTable # map PSym to PSym
info*: TLineInfo
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
if n != nil:
result = copyNode(n)
result.typ = ReplaceTypeVarsT(cl, n.typ)
case n.kind
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
nil
of nkSym:
result.sym = ReplaceTypeVarsS(cl, n.sym)
else:
var length = sonsLen(n)
if length > 0:
newSons(result, length)
for i in countup(0, length - 1):
result.sons[i] = ReplaceTypeVarsN(cl, n.sons[i])
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
if s == nil: return nil
result = PSym(idTableGet(cl.symMap, s))
if result == nil:
result = copySym(s, false)
incl(result.flags, sfFromGeneric)
idTablePut(cl.symMap, s, result)
result.typ = ReplaceTypeVarsT(cl, s.typ)
result.owner = s.owner
result.ast = ReplaceTypeVarsN(cl, s.ast)
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t))
if result == nil:
GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
elif result.kind == tyGenericParam:
InternalError(cl.info, "substitution with generic parameter")
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
var body, newbody, x, header: PType
result = t
if t == nil: return
case t.kind
of tyGenericParam:
result = lookupTypeVar(cl, t)
of tyGenericInvokation:
body = t.sons[0]
if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
header = nil
for i in countup(1, sonsLen(t) - 1):
if t.sons[i].kind == tyGenericParam:
x = lookupTypeVar(cl, t.sons[i])
if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x
else:
x = t.sons[i]
idTablePut(cl.typeMap, body.sons[i - 1], x)
if header == nil: header = t
result = searchInstTypes(gInstTypes, header)
if result != nil: return
result = newType(tyGenericInst, t.sons[0].owner)
for i in countup(0, sonsLen(t) - 1):
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
addSon(result, header.sons[i])
idTablePut(gInstTypes, header, result)
newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
addSon(result, newbody)
#writeln(output, ropeToStr(Typetoyaml(newbody)));
checkConstructedType(cl.info, newbody)
of tyGenericBody:
InternalError(cl.info, "ReplaceTypeVarsT: tyGenericBody")
result = ReplaceTypeVarsT(cl, lastSon(t))
else:
if containsGenericType(t):
result = copyType(t, t.owner, false)
for i in countup(0, sonsLen(result) - 1):
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
result.n = ReplaceTypeVarsN(cl, result.n)
if result.Kind in GenericTypes:
LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
#writeln(output, ropeToStr(Typetoyaml(result)))
#checkConstructedType(cl.info, result)
proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): PType =
var cl: TReplTypeVars
InitIdTable(cl.symMap)
copyIdTable(cl.typeMap, pt)
cl.info = arg.info
cl.c = p
pushInfoContext(arg.info)
result = ReplaceTypeVarsT(cl, t)
popInfoContext()

View File

@@ -10,24 +10,28 @@
# This module implements the signature matching for resolving
# the call to overloaded procs, generic procs and operators.
import
ast, astalgo, semdata, types, msgs, rnimsyn, lookups, semtypinst,
magicsys
type
TCandidateState = enum
TCandidateState* = enum
csEmpty, csMatch, csNoMatch
TCandidate{.final.} = object
TCandidate* {.final.} = object
exactMatches: int
subtypeMatches: int
intConvMatches: int # conversions to int are not as expensive
convMatches: int
genericMatches: int
state: TCandidateState
callee: PType # may not be nil!
calleeSym: PSym # may be nil
call: PNode # modified call
bindings: TIdTable # maps sym-ids to types
state*: TCandidateState
callee*: PType # may not be nil!
calleeSym*: PSym # may be nil
call*: PNode # modified call
bindings*: TIdTable # maps sym-ids to types
baseTypeMatch: bool # needed for conversions from T to openarray[T]
# for example
TTypeRelation = enum # order is important!
TTypeRelation* = enum # order is important!
isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
@@ -41,12 +45,12 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
c.call = nil
c.baseTypeMatch = false
proc initCandidate(c: var TCandidate, callee: PType) =
proc initCandidate*(c: var TCandidate, callee: PType) =
initCandidateAux(c, callee)
c.calleeSym = nil
initIdTable(c.bindings)
proc initCandidate(c: var TCandidate, callee: PSym, binding: PNode) =
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode) =
initCandidateAux(c, callee.typ)
c.calleeSym = callee
initIdTable(c.bindings)
@@ -70,7 +74,7 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) =
a.baseTypeMatch = b.baseTypeMatch
copyIdTable(a.bindings, b.bindings)
proc cmpCandidates(a, b: TCandidate): int =
proc cmpCandidates*(a, b: TCandidate): int =
result = a.exactMatches - b.exactMatches
if result != 0: return
result = a.genericMatches - b.genericMatches
@@ -88,7 +92,7 @@ proc writeMatches(c: TCandidate) =
Writeln(stdout, "intconv matches: " & $c.intConvMatches)
Writeln(stdout, "generic matches: " & $c.genericMatches)
proc getNotFoundError(c: PContext, n: PNode): string =
proc getNotFoundError*(c: PContext, n: PNode): string =
# Gives a detailed error message; this is separated from semDirectCall,
# as semDirectCall is already pretty slow (and we need this information only
# in case of an error).
@@ -425,7 +429,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
else: nil
else: internalError("typeRel(" & $f.kind & ')')
proc cmpTypes(f, a: PType): TTypeRelation =
proc cmpTypes*(f, a: PType): TTypeRelation =
var mapping: TIdTable
InitIdTable(mapping)
result = typeRel(mapping, f, a)
@@ -552,7 +556,7 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
markUsed(arg, arg.sons[best].sym)
result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best])
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode =
var m: TCandidate
initCandidate(m, f)
result = paramTypesMatch(c, m, f, a, arg)
@@ -561,7 +565,7 @@ proc setSon(father: PNode, at: int, son: PNode) =
if sonsLen(father) <= at: setlen(father.sons, at + 1)
father.sons[at] = son
proc matches(c: PContext, n: PNode, m: var TCandidate) =
proc matches*(c: PContext, n: PNode, m: var TCandidate) =
var f = 1 # iterates over formal parameters
var a = 1 # iterates over the actual given arguments
m.state = csMatch # until proven otherwise
@@ -670,90 +674,3 @@ proc matches(c: PContext, n: PNode, m: var TCandidate) =
setSon(m.call, formal.position + 1, copyTree(formal.ast))
inc(f)
proc sameMethodDispatcher(a, b: PSym): bool =
result = false
if a.kind == skMethod and b.kind == skMethod:
var aa = lastSon(a.ast)
var bb = lastSon(b.ast)
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
result = true
proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
initialBinding: PNode): PNode =
var
o: TOverloadIter
x, y, z: TCandidate
#Message(n.info, warnUser, renderTree(n))
var sym = initOverloadIter(o, c, f)
result = nil
if sym == nil: return
initCandidate(x, sym, initialBinding)
initCandidate(y, sym, initialBinding)
while sym != nil:
if sym.kind in filter:
initCandidate(z, sym, initialBinding)
z.calleeSym = sym
matches(c, n, z)
if z.state == csMatch:
case x.state
of csEmpty, csNoMatch: x = z
of csMatch:
var cmp = cmpCandidates(x, z)
if cmp < 0: x = z # z is better than x
elif cmp == 0: y = z # z is as good as x
else: nil
sym = nextOverloadIter(o, c, f)
if x.state == csEmpty:
# no overloaded proc found
# do not generate an error yet; the semantic checking will check for
# an overloaded () operator
elif y.state == csMatch and cmpCandidates(x, y) == 0 and
not sameMethodDispatcher(x.calleeSym, y.calleeSym):
if x.state != csMatch:
InternalError(n.info, "x.state is not csMatch")
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(x.calleeSym), getProcHeader(y.calleeSym),
x.calleeSym.Name.s])
else:
# only one valid interpretation found:
markUsed(n, x.calleeSym)
if x.calleeSym.ast == nil:
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
if x.calleeSym.ast.sons[genericParamsPos].kind != nkEmpty:
# a generic proc!
x.calleeSym = generateInstance(c, x.calleeSym, x.bindings, n.info)
x.callee = x.calleeSym.typ
result = x.call
result.sons[0] = newSymNode(x.calleeSym)
result.typ = x.callee.sons[0]
proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
# process the bindings once:
var initialBinding: PNode
var f = n.sons[0]
if f.kind == nkBracketExpr:
# fill in the bindings:
initialBinding = f
f = f.sons[0]
else:
initialBinding = nil
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
proc explictGenericInstantiation(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 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

View File

@@ -9,7 +9,7 @@
## This file implements features required for IDE support.
import scanner, ast, astalgo, semdata, msgs, types
import scanner, ast, astalgo, semdata, msgs, types, sigmatch
const
sep = '\t'
@@ -33,23 +33,83 @@ proc SymToStr(s: PSym, isLocal: bool): string =
result.add(sep)
result.add($ToColumn(s.info))
proc suggestSym(s: PSym): bool {.inline.} =
proc filterSym(s: PSym): bool {.inline.} =
result = s.name.s[0] in scanner.SymChars
proc suggestField(s: PSym) =
if filterSym(s):
MessageOut(SymToStr(s, isLocal=true))
proc suggestExpr*(c: PContext, n: PNode) =
if not msgs.inCheckpoint(n.info): return
for i in countdown(c.tab.tos-1, 0):
for it in items(c.tab.stack[i]):
if suggestSym(it):
MessageOut(SymToStr(it, i > ModuleTablePos))
if filterSym(it):
MessageOut(SymToStr(it, isLocal = i > ModuleTablePos))
quit(0)
proc suggestStmt*(c: PContext, n: PNode) =
suggestExpr(c, n)
suggestExpr(c, n)
proc suggestSymList(list: PNode) =
for i in countup(0, sonsLen(list) - 1):
if list.sons[i].kind != nkSym: InternalError(list.info, "getSymFromList")
suggestField(list.sons[i].sym)
proc suggestObject(n: PNode) =
case n.kind
of nkRecList:
for i in countup(0, sonsLen(n) - 1): suggestObject(n.sons[i])
of nkRecCase:
var L = sonsLen(n)
if L > 0:
suggestObject(n.sons[0])
for i in countup(1, L-1):
suggestObject(lastSon(n.sons[i]))
of nkSym: suggestField(n.sym)
else: nil
proc suggestOperations(c: PContext, n: PNode, typ: PType) =
nil
proc suggestFieldAccess*(c: PContext, n: PNode) =
suggestExpr(c, n)
# XXX provide a better implementation based on n[0].typ
# special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but
# ``myObj``.
var typ = n.Typ
if typ == nil:
# a module symbol has no type for example:
if n.kind == nkSym and n.sym.kind == skModule:
if n.sym == c.module:
# all symbols accessible, because we are in the current module:
for it in items(c.tab.stack[ModuleTablePos]):
if filterSym(it): MessageOut(SymToStr(it, isLocal=false))
else:
for it in items(n.sym.tab):
if filterSym(it): MessageOut(SymToStr(it, isLocal=false))
else:
# fallback:
suggestExpr(c, n)
elif typ.kind == tyEnum:
# look up if the identifier belongs to the enum:
var t = typ
while t != nil:
suggestSymList(t.n)
t = t.sons[0]
suggestOperations(c, n, typ)
else:
typ = skipTypes(typ, {tyGenericInst, tyVar, tyPtr, tyRef})
if typ.kind == tyObject:
var t = typ
while true:
suggestObject(t.n)
if t.sons[0] == nil: break
t = skipTypes(t.sons[0], {tyGenericInst})
suggestOperations(c, n, typ)
elif typ.kind == tyTuple and typ.n != nil:
suggestSymList(typ.n)
suggestOperations(c, n, typ)
else:
# fallback:
suggestExpr(c, n)

57
tests/accept/run/tgenerics1.nim Executable file
View File

@@ -0,0 +1,57 @@
discard """
output: "256 100"
"""
# A min-heap.
type
TNode[T] = tuple[priority: int, data: T]
TBinHeap[T] = object
heap: seq[TNode[T]]
last: int
PBinHeap[T] = ref TBinHeap[T]
proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
new(heap)
heap.last = 0
newSeq(heap.seq, size)
when false:
proc parent(elem: int): int =
return (elem-1) div 2
proc siftUp[T](heap: PBinHeap[T], elem: int) =
var idx = elem
while idx != 0:
var p = parent(idx)
if heap.heap[idx] < heap.heap[p]:
var tmp = heap.heap[idx]
heap.heap[idx] = heap.heap[p]
heap.heap[p] = tmp
idx = p
else:
break
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
var node: TNode
new(node)
node.priority = int
node.data = data
heap.heap[heap.last] = node
siftUp(heap, heap.last)
inc(heap.last)
proc print*[T](heap: PBinHeap[T]) =
for i in countup(0, heap.last):
echo($heap.heap[i])
var
heap: PBinHeap[int]
newBinHeap(heap, 256)
add(heap, 1, 100)
print(heap)

View File

@@ -0,0 +1,32 @@
discard """
output: "hellow"
"""
import
macros, strutils
macro outterMacro*(n: stmt): stmt =
var j : string = "hi"
proc innerProc(i: int): string =
echo "Using arg ! " & n.repr
result = "Got: '" & $n.kind & "' " & $j
if n.kind != TNimrodNodeKind.nnkMacroStmt:
error("Macro " & n[0].repr & " requires a block.")
var callNode = n[0]
expectKind(callNode, TNimrodNodeKind.nnkCall)
if callNode.len != 2 or callNode[1].kind != TNimrodNodeKind.nnkIdent:
error("Macro " & callNode.repr &
" requires the ident passed as parameter (eg: " & callNode.repr &
"(the_name_you_want)): statements.")
result = newNimNode(TNimrodNodeKind.nnkStmtList)
var ass : PNimrodNode = newNimNode(TNimrodNodeKind.nnkAsgn)
ass.add(newIdentNode(callNode[1].ident))
ass.add(newStrLitNode(innerProc(4)))
result.add(ass)
var str: string
outterMacro(str):
"hellow"
echo str