mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-30 09:54:49 +00:00
refactoring: suggest can import sigmatch for type matching
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
98
rod/semcall.nim
Normal 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
|
||||
|
||||
@@ -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}))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
138
rod/seminst.nim
138
rod/seminst.nim
@@ -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()
|
||||
|
||||
|
||||
@@ -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
147
rod/semtypinst.nim
Normal 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()
|
||||
|
||||
121
rod/sigmatch.nim
121
rod/sigmatch.nim
@@ -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
|
||||
|
||||
|
||||
@@ -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
57
tests/accept/run/tgenerics1.nim
Executable 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)
|
||||
|
||||
|
||||
32
tests/accept/run/tmacros1.nim
Normal file
32
tests/accept/run/tmacros1.nim
Normal 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user