diff options
author | Araq <rumpf_a@web.de> | 2011-02-21 20:06:34 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-02-21 20:06:34 +0100 |
commit | fdde4d3a9266e8a393f0303b1982a2dc9ca7ca6e (patch) | |
tree | a076ec612bb98d6dd1a8eff18505f2b3c90610f7 /rod | |
parent | 4e7a22cac31a0a703c080c7fe0d2569f56ab16a0 (diff) | |
download | Nim-fdde4d3a9266e8a393f0303b1982a2dc9ca7ca6e.tar.gz |
refactoring: suggest can import sigmatch for type matching
Diffstat (limited to 'rod')
-rwxr-xr-x | rod/astalgo.nim | 14 | ||||
-rwxr-xr-x | rod/sem.nim | 8 | ||||
-rw-r--r-- | rod/semcall.nim | 98 | ||||
-rwxr-xr-x | rod/semdata.nim | 4 | ||||
-rwxr-xr-x | rod/semexprs.nim | 16 | ||||
-rwxr-xr-x | rod/seminst.nim | 138 | ||||
-rwxr-xr-x | rod/semtypes.nim | 2 | ||||
-rw-r--r-- | rod/semtypinst.nim | 147 | ||||
-rwxr-xr-x | rod/sigmatch.nim | 121 | ||||
-rw-r--r-- | rod/suggest.nim | 74 |
10 files changed, 356 insertions, 266 deletions
diff --git a/rod/astalgo.nim b/rod/astalgo.nim index 9c9719b35..bb5a6cf56 100755 --- a/rod/astalgo.nim +++ b/rod/astalgo.nim @@ -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 diff --git a/rod/sem.nim b/rod/sem.nim index 0518dc423..66fc66cbe 100755 --- a/rod/sem.nim +++ b/rod/sem.nim @@ -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 diff --git a/rod/semcall.nim b/rod/semcall.nim new file mode 100644 index 000000000..1b31558ca --- /dev/null +++ b/rod/semcall.nim @@ -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 + diff --git a/rod/semdata.nim b/rod/semdata.nim index 5b7425a96..702e00059 100755 --- a/rod/semdata.nim +++ b/rod/semdata.nim @@ -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})) diff --git a/rod/semexprs.nim b/rod/semexprs.nim index 58c358021..b16bf11dc 100755 --- a/rod/semexprs.nim +++ b/rod/semexprs.nim @@ -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 diff --git a/rod/seminst.nim b/rod/seminst.nim index f2acdba60..d32aff15e 100755 --- a/rod/seminst.nim +++ b/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() - diff --git a/rod/semtypes.nim b/rod/semtypes.nim index 08c64384e..e6aab393b 100755 --- a/rod/semtypes.nim +++ b/rod/semtypes.nim @@ -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: diff --git a/rod/semtypinst.nim b/rod/semtypinst.nim new file mode 100644 index 000000000..6427d7858 --- /dev/null +++ b/rod/semtypinst.nim @@ -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() + diff --git a/rod/sigmatch.nim b/rod/sigmatch.nim index cddfc89cb..dc0b1bbc4 100755 --- a/rod/sigmatch.nim +++ b/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 - diff --git a/rod/suggest.nim b/rod/suggest.nim index 377c988bd..5eaa2bd9e 100644 --- a/rod/suggest.nim +++ b/rod/suggest.nim @@ -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) |