working code for simple cases of user-defined type classes
This commit is contained in:
parent
03577bc936
commit
6378fbd66e
7 changed files with 135 additions and 41 deletions
|
|
@ -689,6 +689,7 @@ type
|
||||||
# for enum types a list of symbols
|
# for enum types a list of symbols
|
||||||
# for tyInt it can be the int literal
|
# for tyInt it can be the int literal
|
||||||
# for procs and tyGenericBody, it's the
|
# for procs and tyGenericBody, it's the
|
||||||
|
# the body of the user-defined type class
|
||||||
# formal param list
|
# formal param list
|
||||||
# else: unused
|
# else: unused
|
||||||
destructor*: PSym # destructor. warning: nil here may not necessary
|
destructor*: PSym # destructor. warning: nil here may not necessary
|
||||||
|
|
@ -701,6 +702,7 @@ type
|
||||||
# -1 means that the size is unkwown
|
# -1 means that the size is unkwown
|
||||||
align*: int # the type's alignment requirements
|
align*: int # the type's alignment requirements
|
||||||
loc*: TLoc
|
loc*: TLoc
|
||||||
|
testeeName*: PIdent # the test variable in user-defined type classes
|
||||||
|
|
||||||
TPair*{.final.} = object
|
TPair*{.final.} = object
|
||||||
key*, val*: PObject
|
key*, val*: PObject
|
||||||
|
|
@ -1075,6 +1077,7 @@ proc assignType(dest, src: PType) =
|
||||||
dest.size = src.size
|
dest.size = src.size
|
||||||
dest.align = src.align
|
dest.align = src.align
|
||||||
dest.destructor = src.destructor
|
dest.destructor = src.destructor
|
||||||
|
dest.testeeName = src.testeeName
|
||||||
# this fixes 'type TLock = TSysLock':
|
# this fixes 'type TLock = TSysLock':
|
||||||
if src.sym != nil:
|
if src.sym != nil:
|
||||||
if dest.sym != nil:
|
if dest.sym != nil:
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,8 @@ type
|
||||||
features: TSandboxFlags
|
features: TSandboxFlags
|
||||||
globals*: TIdNodeTable # state of global vars
|
globals*: TIdNodeTable # state of global vars
|
||||||
getType*: proc(n: PNode): PNode {.closure.}
|
getType*: proc(n: PNode): PNode {.closure.}
|
||||||
|
handleIsOperator*: proc(n: PNode): PNode {.closure.}
|
||||||
|
|
||||||
PEvalContext* = ref TEvalContext
|
PEvalContext* = ref TEvalContext
|
||||||
|
|
||||||
TEvalFlag = enum
|
TEvalFlag = enum
|
||||||
|
|
@ -916,33 +917,6 @@ proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
proc evalIsOp*(n: PNode): PNode =
|
|
||||||
InternalAssert n.sonsLen == 3 and
|
|
||||||
n[1].kind == nkSym and n[1].sym.kind == skType and
|
|
||||||
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
|
||||||
|
|
||||||
let t1 = n[1].sym.typ
|
|
||||||
|
|
||||||
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
|
||||||
case n[2].strVal.normalize
|
|
||||||
of "closure":
|
|
||||||
let t = skipTypes(t1, abstractRange)
|
|
||||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
|
||||||
t.callConv == ccClosure and
|
|
||||||
tfIterator notin t.flags))
|
|
||||||
of "iterator":
|
|
||||||
let t = skipTypes(t1, abstractRange)
|
|
||||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
|
||||||
t.callConv == ccClosure and
|
|
||||||
tfIterator in t.flags))
|
|
||||||
else:
|
|
||||||
let t2 = n[2].typ
|
|
||||||
var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
|
|
||||||
else: sameType(t1, t2)
|
|
||||||
result = newIntNode(nkIntLit, ord(match))
|
|
||||||
|
|
||||||
result.typ = n.typ
|
|
||||||
|
|
||||||
proc expectString(n: PNode) =
|
proc expectString(n: PNode) =
|
||||||
if n.kind notin nkStrKinds:
|
if n.kind notin nkStrKinds:
|
||||||
GlobalError(n.info, errStringLiteralExpected)
|
GlobalError(n.info, errStringLiteralExpected)
|
||||||
|
|
@ -1038,7 +1012,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
result = evalTypeTrait(n[0], operand, c.module)
|
result = evalTypeTrait(n[0], operand, c.module)
|
||||||
of mIs:
|
of mIs:
|
||||||
n.sons[1] = evalAux(c, n.sons[1], {})
|
n.sons[1] = evalAux(c, n.sons[1], {})
|
||||||
result = evalIsOp(n)
|
result = c.handleIsOperator(n)
|
||||||
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
|
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
|
||||||
of mStaticExec:
|
of mStaticExec:
|
||||||
let cmd = evalAux(c, n.sons[1], {})
|
let cmd = evalAux(c, n.sons[1], {})
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
|
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
|
||||||
dec(evalTemplateCounter)
|
dec(evalTemplateCounter)
|
||||||
|
|
||||||
|
proc IsOpImpl(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
semCheck: bool = true): PNode =
|
semCheck: bool = true): PNode =
|
||||||
markUsed(n, sym)
|
markUsed(n, sym)
|
||||||
|
|
@ -215,6 +217,9 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
else:
|
else:
|
||||||
result = symNodeFromType(c, e.typ, n.info)
|
result = symNodeFromType(c, e.typ, n.info)
|
||||||
|
|
||||||
|
c.evalContext.handleIsOperator = proc (n: PNode): PNode =
|
||||||
|
result = IsOpImpl(c, n)
|
||||||
|
|
||||||
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
||||||
if semCheck: result = semAfterMacroCall(c, result, sym)
|
if semCheck: result = semAfterMacroCall(c, result, sym)
|
||||||
|
|
||||||
|
|
@ -250,6 +255,7 @@ proc myOpen(module: PSym): PPassContext =
|
||||||
if c.p != nil: InternalError(module.info, "sem.myOpen")
|
if c.p != nil: InternalError(module.info, "sem.myOpen")
|
||||||
c.semConstExpr = semConstExpr
|
c.semConstExpr = semConstExpr
|
||||||
c.semExpr = semExpr
|
c.semExpr = semExpr
|
||||||
|
c.semTryExpr = tryExpr
|
||||||
c.semOperand = semOperand
|
c.semOperand = semOperand
|
||||||
c.semConstBoolExpr = semConstBoolExpr
|
c.semConstBoolExpr = semConstBoolExpr
|
||||||
c.semOverloadedCall = semOverloadedCall
|
c.semOverloadedCall = semOverloadedCall
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ type
|
||||||
libs*: TLinkedList # all libs used by this module
|
libs*: TLinkedList # all libs used by this module
|
||||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
|
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||||
|
|
@ -204,6 +205,11 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||||
result = newTypeS(tyTypeDesc, c)
|
result = newTypeS(tyTypeDesc, c)
|
||||||
result.addSonSkipIntLit(typ.AssertNotNil)
|
result.addSonSkipIntLit(typ.AssertNotNil)
|
||||||
|
|
||||||
|
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
|
||||||
|
let typedesc = makeTypeDesc(c, typ)
|
||||||
|
let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
|
||||||
|
return newSymNode(sym, info)
|
||||||
|
|
||||||
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
||||||
result = newType(kind, getCurrOwner())
|
result = newType(kind, getCurrOwner())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -295,6 +295,39 @@ proc semOf(c: PContext, n: PNode): PNode =
|
||||||
n.typ = getSysType(tyBool)
|
n.typ = getSysType(tyBool)
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
|
proc IsOpImpl(c: PContext, n: PNode): PNode =
|
||||||
|
InternalAssert n.sonsLen == 3 and
|
||||||
|
n[1].kind == nkSym and n[1].sym.kind == skType and
|
||||||
|
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||||
|
|
||||||
|
let t1 = n[1].sym.typ.skipTypes({tyTypeDesc})
|
||||||
|
|
||||||
|
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
||||||
|
case n[2].strVal.normalize
|
||||||
|
of "closure":
|
||||||
|
let t = skipTypes(t1, abstractRange)
|
||||||
|
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||||
|
t.callConv == ccClosure and
|
||||||
|
tfIterator notin t.flags))
|
||||||
|
of "iterator":
|
||||||
|
let t = skipTypes(t1, abstractRange)
|
||||||
|
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||||
|
t.callConv == ccClosure and
|
||||||
|
tfIterator in t.flags))
|
||||||
|
else:
|
||||||
|
var match: bool
|
||||||
|
let t2 = n[2].typ
|
||||||
|
if t2.kind == tyTypeClass:
|
||||||
|
var m: TCandidate
|
||||||
|
InitCandidate(m, t2)
|
||||||
|
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
|
||||||
|
else:
|
||||||
|
match = sameType(t1, t2)
|
||||||
|
|
||||||
|
result = newIntNode(nkIntLit, ord(match))
|
||||||
|
|
||||||
|
result.typ = n.typ
|
||||||
|
|
||||||
proc semIs(c: PContext, n: PNode): PNode =
|
proc semIs(c: PContext, n: PNode): PNode =
|
||||||
if sonsLen(n) != 3:
|
if sonsLen(n) != 3:
|
||||||
LocalError(n.info, errXExpectsTwoArguments, "is")
|
LocalError(n.info, errXExpectsTwoArguments, "is")
|
||||||
|
|
@ -303,21 +336,21 @@ proc semIs(c: PContext, n: PNode): PNode =
|
||||||
n.typ = getSysType(tyBool)
|
n.typ = getSysType(tyBool)
|
||||||
|
|
||||||
n.sons[1] = semExprWithType(c, n[1], {efDetermineType})
|
n.sons[1] = semExprWithType(c, n[1], {efDetermineType})
|
||||||
if n[1].typ.kind != tyTypeDesc:
|
|
||||||
LocalError(n[0].info, errTypeExpected)
|
|
||||||
|
|
||||||
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
|
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
|
||||||
let t2 = semTypeNode(c, n[2], nil)
|
let t2 = semTypeNode(c, n[2], nil)
|
||||||
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
|
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
|
||||||
|
|
||||||
if n[1].typ.sonsLen == 0:
|
if n[1].typ.kind != tyTypeDesc:
|
||||||
|
n.sons[1] = makeTypeSymNode(c, n[1].typ, n[1].info)
|
||||||
|
elif n[1].typ.sonsLen == 0:
|
||||||
# this is a typedesc variable, leave for evals
|
# this is a typedesc variable, leave for evals
|
||||||
return
|
return
|
||||||
else:
|
|
||||||
let t1 = n[1].typ.sons[0]
|
let t1 = n[1].typ.sons[0]
|
||||||
# BUGFIX: don't evaluate this too early: ``T is void``
|
# BUGFIX: don't evaluate this too early: ``T is void``
|
||||||
if not containsGenericType(t1): result = evalIsOp(n)
|
if not containsGenericType(t1): result = IsOpImpl(c, n)
|
||||||
|
|
||||||
proc semOpAux(c: PContext, n: PNode) =
|
proc semOpAux(c: PContext, n: PNode) =
|
||||||
const flags = {efDetermineType}
|
const flags = {efDetermineType}
|
||||||
for i in countup(1, n.sonsLen-1):
|
for i in countup(1, n.sonsLen-1):
|
||||||
|
|
|
||||||
|
|
@ -871,6 +871,21 @@ proc freshType(res, prev: PType): PType {.inline.} =
|
||||||
else:
|
else:
|
||||||
result = res
|
result = res
|
||||||
|
|
||||||
|
proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
||||||
|
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
||||||
|
result = newOrPrevType(tyTypeClass, prev, c)
|
||||||
|
result.testeeName = considerAcc(n[0])
|
||||||
|
result.n = n[3]
|
||||||
|
|
||||||
|
let
|
||||||
|
pragmas = n[1]
|
||||||
|
inherited = n[2]
|
||||||
|
|
||||||
|
if inherited.kind != nkEmpty:
|
||||||
|
for n in inherited.sons:
|
||||||
|
let typ = semTypeNode(c, n, nil)
|
||||||
|
result.sons.safeAdd(typ)
|
||||||
|
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = nil
|
result = nil
|
||||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
|
|
@ -973,6 +988,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
of nkObjectTy: result = semObjectNode(c, n, prev)
|
of nkObjectTy: result = semObjectNode(c, n, prev)
|
||||||
of nkTupleTy: result = semTuple(c, n, prev)
|
of nkTupleTy: result = semTuple(c, n, prev)
|
||||||
|
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
||||||
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
||||||
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
||||||
of nkVarTy: result = semVarType(c, n, prev)
|
of nkVarTy: result = semVarType(c, n, prev)
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,9 @@ type
|
||||||
# be instantiated
|
# be instantiated
|
||||||
typedescMatched: bool
|
typedescMatched: bool
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
errors*: seq[string] # additional clarifications to be displayed to the
|
||||||
|
# user if overload resolution fails
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
isNone, isConvertible,
|
isNone, isConvertible,
|
||||||
isIntConv,
|
isIntConv,
|
||||||
|
|
@ -750,11 +752,55 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
result.typ = getInstantiatedType(c, arg, m, base(f))
|
result.typ = getInstantiatedType(c, arg, m, base(f))
|
||||||
m.baseTypeMatch = true
|
m.baseTypeMatch = true
|
||||||
|
|
||||||
|
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
|
arg: PNode, f, a: PType): PNode =
|
||||||
|
if f.n == nil:
|
||||||
|
let r = typeRel(m, f, a)
|
||||||
|
return if r == isGeneric: arg else: nil
|
||||||
|
|
||||||
|
var prev = PType(idTableGet(m.bindings, f))
|
||||||
|
if prev != nil:
|
||||||
|
if sameType(prev, a): return arg
|
||||||
|
else: return nil
|
||||||
|
|
||||||
|
# pushInfoContext(arg.info)
|
||||||
|
openScope(c)
|
||||||
|
|
||||||
|
var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info)
|
||||||
|
testee.typ = a
|
||||||
|
addDecl(c, testee)
|
||||||
|
|
||||||
|
for stmt in f.n:
|
||||||
|
var e = c.semTryExpr(c, copyTree(stmt))
|
||||||
|
if e == nil:
|
||||||
|
let expStr = renderTree(stmt, {renderNoComments})
|
||||||
|
m.errors.safeAdd("can't compile " & expStr & " for " & a.typeToString)
|
||||||
|
return nil
|
||||||
|
case e.kind
|
||||||
|
of nkReturnStmt:
|
||||||
|
nil
|
||||||
|
of nkTypeSection: nil
|
||||||
|
of nkConstDef: nil
|
||||||
|
else:
|
||||||
|
if e.typ.kind == tyBool:
|
||||||
|
let verdict = c.semConstExpr(c, e)
|
||||||
|
if verdict.intVal == 0:
|
||||||
|
let expStr = renderTree(stmt, {renderNoComments})
|
||||||
|
m.errors.safeAdd(expStr & " doesn't hold for " & a.typeToString)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
closeScope(c)
|
||||||
|
|
||||||
|
result = arg
|
||||||
|
put(m.bindings, f, a)
|
||||||
|
|
||||||
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
arg, argOrig: PNode): PNode =
|
argSemantized, argOrig: PNode): PNode =
|
||||||
|
var arg = argSemantized
|
||||||
var r: TTypeRelation
|
var r: TTypeRelation
|
||||||
let fMaybeExpr = f.skipTypes({tyDistinct})
|
let fMaybeExpr = f.skipTypes({tyDistinct})
|
||||||
if fMaybeExpr.kind == tyExpr:
|
case fMaybeExpr.kind
|
||||||
|
of tyExpr:
|
||||||
if fMaybeExpr.sonsLen == 0:
|
if fMaybeExpr.sonsLen == 0:
|
||||||
r = isGeneric
|
r = isGeneric
|
||||||
else:
|
else:
|
||||||
|
|
@ -776,6 +822,16 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
|
|
||||||
if r == isGeneric:
|
if r == isGeneric:
|
||||||
put(m.bindings, f, arg.typ)
|
put(m.bindings, f, arg.typ)
|
||||||
|
of tyTypeClass:
|
||||||
|
if fMaybeExpr.n != nil:
|
||||||
|
let match = matchUserTypeClass(c, m, arg, fMaybeExpr, a)
|
||||||
|
if match != nil:
|
||||||
|
r = isGeneric
|
||||||
|
arg = match
|
||||||
|
else:
|
||||||
|
r = isNone
|
||||||
|
else:
|
||||||
|
r = typeRel(m, f, a)
|
||||||
else:
|
else:
|
||||||
r = typeRel(m, f, a)
|
r = typeRel(m, f, a)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue