Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
1d842e8b75
21 changed files with 174 additions and 55 deletions
|
|
@ -624,6 +624,7 @@ type
|
|||
loc*: TLoc
|
||||
annex*: PLib # additional fields (seldom used, so we use a
|
||||
# reference to another object to safe space)
|
||||
constraint*: PNode # additional constraints like 'lit|result'
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TType* = object of TIdObj # types are identical iff they have the
|
||||
|
|
@ -650,7 +651,6 @@ type
|
|||
align*: int # the type's alignment requirements
|
||||
containerID*: int # used for type checking of generics
|
||||
loc*: TLoc
|
||||
constraint*: PNode # additional constraints like 'lit|result'
|
||||
|
||||
TPair*{.final.} = object
|
||||
key*, val*: PObject
|
||||
|
|
|
|||
|
|
@ -145,6 +145,9 @@ proc isVisible(n: PNode): bool =
|
|||
var v = n.sons[0].ident
|
||||
result = v.id == ord(wStar) or v.id == ord(wMinus)
|
||||
elif n.kind == nkSym:
|
||||
# we cannot generate code for forwarded symbols here as we have no
|
||||
# exception tracking information here. Instead we copy over the comment
|
||||
# from the proc header.
|
||||
result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
|
||||
elif n.kind == nkPragmaExpr:
|
||||
result = isVisible(n.sons[0])
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
|
|||
add(code, chr(ord(op)))
|
||||
|
||||
proc whichAlias*(p: PSym): TAliasRequest =
|
||||
if p.typ.constraint != nil:
|
||||
result = TAliasRequest(p.typ.constraint.strVal[0].ord)
|
||||
if p.constraint != nil:
|
||||
result = TAliasRequest(p.constraint.strVal[0].ord)
|
||||
|
||||
proc compileConstraints(p: PNode, result: var TPatternCode) =
|
||||
case p.kind
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ proc inSymChoice(sc, x: PNode): bool =
|
|||
|
||||
proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
|
||||
# check param constraints first here as this is quite optimized:
|
||||
if p.typ.constraint != nil:
|
||||
result = matchNodeKinds(p.typ.constraint, n)
|
||||
if p.constraint != nil:
|
||||
result = matchNodeKinds(p.constraint, n)
|
||||
if not result: return
|
||||
if isNil(n.typ):
|
||||
result = p.typ.kind in {tyEmpty, tyStmt}
|
||||
|
|
|
|||
|
|
@ -330,9 +330,6 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
|||
if r.s[r.pos] == '@':
|
||||
inc(r.pos)
|
||||
result.containerID = decodeVInt(r.s, r.pos)
|
||||
if r.s[r.pos] == '`':
|
||||
inc(r.pos)
|
||||
result.constraint = decodeNode(r, UnknownLineInfo())
|
||||
decodeLoc(r, result.loc, info)
|
||||
while r.s[r.pos] == '^':
|
||||
inc(r.pos)
|
||||
|
|
@ -423,6 +420,9 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
|
|||
result.offset = - 1
|
||||
decodeLoc(r, result.loc, result.info)
|
||||
result.annex = decodeLib(r, info)
|
||||
if r.s[r.pos] == '#':
|
||||
inc(r.pos)
|
||||
result.constraint = decodeNode(r, UnknownLineInfo())
|
||||
if r.s[r.pos] == '(':
|
||||
if result.kind in routineKinds:
|
||||
result.ast = decodeNodeLazyBody(r, result.info, result)
|
||||
|
|
|
|||
|
|
@ -233,9 +233,6 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
|||
if t.containerID != 0:
|
||||
add(result, '@')
|
||||
encodeVInt(t.containerID, result)
|
||||
if t.constraint != nil:
|
||||
add(result, '`')
|
||||
encodeNode(w, UnknownLineInfo(), t.constraint, result)
|
||||
encodeLoc(w, t.loc, result)
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
if t.sons[i] == nil:
|
||||
|
|
@ -295,6 +292,9 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
|||
encodeVInt(s.offset, result)
|
||||
encodeLoc(w, s.loc, result)
|
||||
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
|
||||
if s.constraint != nil:
|
||||
add(result, '#')
|
||||
encodeNode(w, UnknownLineInfo(), s.constraint, result)
|
||||
# lazy loading will soon reload the ast lazily, so the ast needs to be
|
||||
# the last entry of a symbol:
|
||||
if s.ast != nil:
|
||||
|
|
|
|||
|
|
@ -84,6 +84,16 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
||||
args])
|
||||
|
||||
proc instantiateGenericConverters(c: PContext, n: PNode, x: TCandidate) {.
|
||||
noinline.}=
|
||||
for i in 1 .. <n.len:
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym and
|
||||
isGenericRoutine(a.sons[0].sym):
|
||||
let finalCallee = generateInstance(c, a.sons[0].sym, x.bindings, n.info)
|
||||
a.sons[0].sym = finalCallee
|
||||
a.sons[0].typ = finalCallee.typ
|
||||
|
||||
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||
assert x.state == csMatch
|
||||
var finalCallee = x.calleeSym
|
||||
|
|
@ -101,6 +111,8 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
|||
if ContainsGenericType(result.typ): result.typ = errorType(c)
|
||||
return
|
||||
result = x.call
|
||||
if x.genericConverter:
|
||||
instantiateGenericConverters(c, result, x)
|
||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||
result.typ = finalCallee.typ.sons[0]
|
||||
|
||||
|
|
|
|||
|
|
@ -780,6 +780,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
|
||||
if n.sons[namePos].kind != nkSym: InternalError(n.info, "semProcAux")
|
||||
n.sons[namePos].sym = proto
|
||||
if gCmd == cmdDoc and not isNil(proto.ast.comment):
|
||||
n.comment = proto.ast.comment
|
||||
proto.ast = n # needed for code generation
|
||||
popOwner()
|
||||
pushOwner(s)
|
||||
|
|
@ -869,8 +871,6 @@ proc semMethod(c: PContext, n: PNode): PNode =
|
|||
proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||
LocalError(n.info, errNoGenericParamsAllowedForX, "converter")
|
||||
result = semProcAux(c, n, skConverter, converterPragmas)
|
||||
var s = result.sons[namePos].sym
|
||||
var t = s.typ
|
||||
|
|
|
|||
|
|
@ -635,6 +635,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
genericParams.addSon(newSymNode(s))
|
||||
result = typeClass
|
||||
|
||||
proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
|
||||
if n.kind == nkCurlyExpr:
|
||||
result = semTypeNode(c, n.sons[0], nil)
|
||||
constraint = semNodeKindConstraints(n)
|
||||
else:
|
||||
result = semTypeNode(c, n, nil)
|
||||
|
||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
prev: PType, kind: TSymKind): PType =
|
||||
var
|
||||
|
|
@ -660,13 +667,14 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
checkMinSonsLen(a, 3)
|
||||
var
|
||||
typ: PType = nil
|
||||
def: PNode = nil
|
||||
def: PNode = nil
|
||||
constraint: PNode = nil
|
||||
length = sonsLen(a)
|
||||
hasType = a.sons[length-2].kind != nkEmpty
|
||||
hasDefault = a.sons[length-1].kind != nkEmpty
|
||||
|
||||
if hasType:
|
||||
typ = semTypeNode(c, a.sons[length-2], nil)
|
||||
typ = semParamType(c, a.sons[length-2], constraint)
|
||||
|
||||
if hasDefault:
|
||||
def = semExprWithType(c, a.sons[length-1])
|
||||
|
|
@ -689,6 +697,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
arg.name.s, arg.info).skipIntLit
|
||||
arg.typ = finalType
|
||||
arg.position = counter
|
||||
arg.constraint = constraint
|
||||
inc(counter)
|
||||
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||
if ContainsOrIncl(check, arg.name.id):
|
||||
|
|
@ -787,6 +796,12 @@ proc semTypeExpr(c: PContext, n: PNode): PType =
|
|||
else:
|
||||
LocalError(n.info, errTypeExpected, n.renderTree)
|
||||
|
||||
proc freshType(res, prev: PType): PType {.inline.} =
|
||||
if prev.isNil:
|
||||
result = copyType(result, result.owner, keepId=false)
|
||||
else:
|
||||
result = res
|
||||
|
||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = nil
|
||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||
|
|
@ -825,7 +840,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
checkSonsLen(n, 3)
|
||||
result = semTypeNode(c, n.sons[1], prev)
|
||||
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
|
||||
# XXX this is wrong for tyString at least
|
||||
result = freshType(result, prev)
|
||||
result.flags.incl(tfNotNil)
|
||||
else:
|
||||
LocalError(n.info, errGenerated, "invalid type")
|
||||
|
|
@ -833,11 +848,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = semTypeExpr(c, n)
|
||||
else:
|
||||
result = semTypeExpr(c, n)
|
||||
of nkCurlyExpr:
|
||||
result = semTypeNode(c, n.sons[0], nil)
|
||||
if result != nil:
|
||||
result = copyType(result, getCurrOwner(), true)
|
||||
result.constraint = semNodeKindConstraints(n)
|
||||
of nkWhenStmt:
|
||||
var whenResult = semWhen(c, n, false)
|
||||
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
||||
|
|
@ -920,6 +930,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
of nkSharedTy:
|
||||
checkSonsLen(n, 1)
|
||||
result = semTypeNode(c, n.sons[0], prev)
|
||||
result = freshType(result, prev)
|
||||
result.flags.incl(tfShared)
|
||||
else:
|
||||
LocalError(n.info, errTypeExpected)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ type
|
|||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||
# for example
|
||||
proxyMatch*: bool # to prevent instantiations
|
||||
genericConverter*: bool # true if a generic converter needs to
|
||||
# be instantiated
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
|
|
@ -57,6 +59,7 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
|||
c.callee = callee
|
||||
c.call = nil
|
||||
c.baseTypeMatch = false
|
||||
c.genericConverter = false
|
||||
c.inheritancePenalty = 0
|
||||
|
||||
proc initCandidate*(c: var TCandidate, callee: PType) =
|
||||
|
|
@ -571,16 +574,26 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
|||
for i in countup(0, len(c.converters) - 1):
|
||||
var src = c.converters[i].typ.sons[1]
|
||||
var dest = c.converters[i].typ.sons[0]
|
||||
if (typeRel(m, f, dest) == isEqual) and
|
||||
(typeRel(m, src, a) == isEqual):
|
||||
# for generic type converters we need to check 'src <- a' before
|
||||
# 'f <- dest' in order to not break the unification:
|
||||
# see tests/tgenericconverter:
|
||||
let srca = typeRel(m, src, a)
|
||||
if srca notin {isEqual, isGeneric}: continue
|
||||
|
||||
let destIsGeneric = containsGenericType(dest)
|
||||
if destIsGeneric:
|
||||
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
||||
let fdest = typeRel(m, f, dest)
|
||||
if fdest in {isEqual, isGeneric}:
|
||||
markUsed(arg, c.converters[i])
|
||||
var s = newSymNode(c.converters[i])
|
||||
s.typ = c.converters[i].typ
|
||||
s.info = arg.info
|
||||
result = newNodeIT(nkHiddenCallConv, arg.info, s.typ.sons[0])
|
||||
result = newNodeIT(nkHiddenCallConv, arg.info, dest)
|
||||
addSon(result, s)
|
||||
addSon(result, copyTree(arg))
|
||||
inc(m.convMatches)
|
||||
m.genericConverter = srca == isGeneric or destIsGeneric
|
||||
return
|
||||
|
||||
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
|
|
@ -837,10 +850,10 @@ proc matchesAux*(c: PContext, n, nOrig: PNode,
|
|||
m.baseTypeMatch = false
|
||||
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a], nOrig.sons[a])
|
||||
if arg == nil:
|
||||
if arg == nil:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
if m.baseTypeMatch:
|
||||
return
|
||||
if m.baseTypeMatch:
|
||||
assert(container == nil)
|
||||
container = newNodeI(nkBracket, n.sons[a].info)
|
||||
addSon(container, arg)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue