the foundations of a type traits module; better error messages for expr, typedesc and typeclasses params
This commit is contained in:
parent
98b7bdaa50
commit
efb53233cb
8 changed files with 65 additions and 12 deletions
|
|
@ -243,8 +243,13 @@ const
|
||||||
sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section
|
sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section
|
||||||
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
|
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
|
||||||
sfNoInit* = sfMainModule # don't generate code to init the variable
|
sfNoInit* = sfMainModule # don't generate code to init the variable
|
||||||
|
|
||||||
sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded
|
sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded
|
||||||
# without considering any possible overloads
|
# without considering any possible overloads
|
||||||
|
|
||||||
|
sfAnon* = sfCompilerProc # symbol name that was generated by the compiler
|
||||||
|
# the compiler will avoid printing such names
|
||||||
|
# in user messages.
|
||||||
|
|
||||||
const
|
const
|
||||||
# getting ready for the future expr/stmt merge
|
# getting ready for the future expr/stmt merge
|
||||||
|
|
@ -358,7 +363,8 @@ const
|
||||||
|
|
||||||
type
|
type
|
||||||
TMagic* = enum # symbols that require compiler magic:
|
TMagic* = enum # symbols that require compiler magic:
|
||||||
mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mIs, mOf,
|
mNone,
|
||||||
|
mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
||||||
mEcho, mShallowCopy, mSlurp,
|
mEcho, mShallowCopy, mSlurp,
|
||||||
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
||||||
mUnaryLt, mSucc,
|
mUnaryLt, mSucc,
|
||||||
|
|
|
||||||
|
|
@ -490,7 +490,7 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode =
|
||||||
proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||||
var s = n.sym
|
var s = n.sym
|
||||||
case s.kind
|
case s.kind
|
||||||
of skProc, skConverter, skMacro:
|
of skProc, skConverter, skMacro, skType:
|
||||||
result = n
|
result = n
|
||||||
#result = s.getBody
|
#result = s.getBody
|
||||||
of skVar, skLet, skForVar, skTemp, skResult:
|
of skVar, skLet, skForVar, skTemp, skResult:
|
||||||
|
|
@ -891,7 +891,24 @@ proc evalTemplate*(n: PNode, sym: PSym): PNode =
|
||||||
result = evalTemplateAux(sym.getBody, args, sym)
|
result = evalTemplateAux(sym.getBody, args, sym)
|
||||||
|
|
||||||
dec(evalTemplateCounter)
|
dec(evalTemplateCounter)
|
||||||
|
|
||||||
|
proc evalTypeTrait*(n: PNode, context: PSym): PNode =
|
||||||
|
## XXX: This should be pretty much guaranteed to be true
|
||||||
|
# by the type traits procs' signitures, but until the
|
||||||
|
# code is more mature it doesn't hurt to be extra safe
|
||||||
|
internalAssert n.sons.len >= 2 and
|
||||||
|
n.sons[1].sym.typ.kind == tyTypeDesc
|
||||||
|
|
||||||
|
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
|
||||||
|
case n.sons[0].sym.name.s
|
||||||
|
of "name":
|
||||||
|
result = newStrNode(nkStrLit, typ.typeToString)
|
||||||
|
result.typ = newType(tyString, context)
|
||||||
|
result.info = n.info
|
||||||
|
|
||||||
|
else:
|
||||||
|
internalAssert false
|
||||||
|
|
||||||
proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
|
proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
|
||||||
var
|
var
|
||||||
n = original.copyTree
|
n = original.copyTree
|
||||||
|
|
@ -941,6 +958,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
of mParseExprToAst: result = evalParseExpr(c, n)
|
of mParseExprToAst: result = evalParseExpr(c, n)
|
||||||
of mParseStmtToAst: result = evalParseStmt(c, n)
|
of mParseStmtToAst: result = evalParseStmt(c, n)
|
||||||
of mExpandToAst: result = evalExpandToAst(c, n)
|
of mExpandToAst: result = evalExpandToAst(c, n)
|
||||||
|
of mTypeTrait: result = evalTypeTrait(n, c.module)
|
||||||
of mNLen:
|
of mNLen:
|
||||||
result = evalAux(c, n.sons[1], {efLValue})
|
result = evalAux(c, n.sons[1], {efLValue})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
|
|
|
||||||
|
|
@ -667,3 +667,6 @@ template AssertNotNil*(e: expr): expr =
|
||||||
if(e == nil): InternalError($InstantiationInfo())
|
if(e == nil): InternalError($InstantiationInfo())
|
||||||
e
|
e
|
||||||
|
|
||||||
|
template InternalAssert*(e: bool): stmt =
|
||||||
|
if not e: InternalError($InstantiationInfo())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1314,11 +1314,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
Message(n.info, warnDeprecated, "bind")
|
Message(n.info, warnDeprecated, "bind")
|
||||||
result = semExpr(c, n.sons[0], flags)
|
result = semExpr(c, n.sons[0], flags)
|
||||||
of nkTypeOfExpr:
|
of nkTypeOfExpr:
|
||||||
var typ = semTypeNode(c, n, nil)
|
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
|
||||||
if typ.sym == nil:
|
typ = makeTypedesc(c, typ)
|
||||||
typ = copyType(typ, typ.owner, true)
|
var sym = newSym(skType, getIdent"TypeOfExpr", typ.owner).linkTo(typ)
|
||||||
typ.linkTo(newSym(skType, getIdent"typedesc", typ.owner))
|
sym.flags.incl(sfAnon)
|
||||||
result = newSymNode(typ.sym, n.info)
|
result = newSymNode(sym, n.info)
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||||
# check if it is an expression macro:
|
# check if it is an expression macro:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||||
of mNewString, mNewStringOfCap,
|
of mNewString, mNewStringOfCap,
|
||||||
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
|
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
|
||||||
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
||||||
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
|
||||||
mNLen..mNError, mEqRef:
|
mNLen..mNError, mEqRef:
|
||||||
nil
|
nil
|
||||||
of mRand:
|
of mRand:
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# This include file implements the semantic checking for magics.
|
# This include file implements the semantic checking for magics.
|
||||||
|
# included from sem.nim
|
||||||
|
|
||||||
proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
var r = isPartOf(n[1], n[2])
|
var r = isPartOf(n[1], n[2])
|
||||||
|
|
@ -43,11 +44,21 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
|
||||||
result.add(filename)
|
result.add(filename)
|
||||||
result.add(line)
|
result.add(line)
|
||||||
|
|
||||||
|
proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||||
|
checkMinSonsLen(n, 2)
|
||||||
|
internalAssert n.sons[1].kind == nkSym
|
||||||
|
if n.sons[1].sym.kind == skType:
|
||||||
|
result = evalTypeTrait(n, GetCurrOwner())
|
||||||
|
else:
|
||||||
|
# pass unmodified to evals
|
||||||
|
result = n
|
||||||
|
|
||||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
case n[0].sym.magic
|
case n[0].sym.magic
|
||||||
of mSlurp: result = semSlurp(c, n, flags)
|
of mSlurp: result = semSlurp(c, n, flags)
|
||||||
of mIsPartOf: result = semIsPartOf(c, n, flags)
|
of mIsPartOf: result = semIsPartOf(c, n, flags)
|
||||||
|
of mTypeTrait: result = semTypeTraits(c, n)
|
||||||
of mAstToStr:
|
of mAstToStr:
|
||||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
||||||
result.typ = getSysType(tyString)
|
result.typ = getSysType(tyString)
|
||||||
|
|
|
||||||
|
|
@ -583,8 +583,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
break addImplicitGeneric
|
break addImplicitGeneric
|
||||||
|
|
||||||
var s = newSym(skType, paramTypId, getCurrOwner())
|
var s = newSym(skType, paramTypId, getCurrOwner())
|
||||||
s.typ = typeClass
|
s.flags.incl(sfAnon)
|
||||||
s.typ.sym = s
|
s.linkTo(typeClass)
|
||||||
s.position = genericParams.len
|
s.position = genericParams.len
|
||||||
genericParams.addSon(newSymNode(s))
|
genericParams.addSon(newSymNode(s))
|
||||||
endingType = typeClass
|
endingType = typeClass
|
||||||
|
|
@ -693,7 +693,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkTypeOfExpr:
|
of nkTypeOfExpr:
|
||||||
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
result = semExprWithType(c, n.sons[0], {efInTypeof}).typ
|
result = semExprWithType(c, n.sons[0], {efInTypeof, efAllowType}).typ
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||||
else: GlobalError(n.info, errTypeExpected)
|
else: GlobalError(n.info, errTypeExpected)
|
||||||
|
|
|
||||||
|
|
@ -372,6 +372,13 @@ proc rangeToStr(n: PNode): string =
|
||||||
assert(n.kind == nkRange)
|
assert(n.kind == nkRange)
|
||||||
result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1])
|
result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1])
|
||||||
|
|
||||||
|
proc constraintsToStr(t: PType): string =
|
||||||
|
let sep = if tfAny in t.flags: " or " else: " and "
|
||||||
|
result = ""
|
||||||
|
for i in countup(0, t.sons.len - 1):
|
||||||
|
if i > 0: result.add(sep)
|
||||||
|
result.add(t.sons[i].typeToString)
|
||||||
|
|
||||||
proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
const
|
const
|
||||||
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
|
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
|
||||||
|
|
@ -387,7 +394,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
var t = typ
|
var t = typ
|
||||||
result = ""
|
result = ""
|
||||||
if t == nil: return
|
if t == nil: return
|
||||||
if prefer == preferName and t.sym != nil:
|
if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags:
|
||||||
return t.sym.Name.s
|
return t.sym.Name.s
|
||||||
case t.Kind
|
case t.Kind
|
||||||
of tyGenericBody, tyGenericInst, tyGenericInvokation:
|
of tyGenericBody, tyGenericInst, tyGenericInvokation:
|
||||||
|
|
@ -396,6 +403,14 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
if i > 1: add(result, ", ")
|
if i > 1: add(result, ", ")
|
||||||
add(result, typeToString(t.sons[i]))
|
add(result, typeToString(t.sons[i]))
|
||||||
add(result, ']')
|
add(result, ']')
|
||||||
|
of tyTypeDesc:
|
||||||
|
if t.sons.len == 0: result = "typedesc"
|
||||||
|
else: result = "typedesc{" & constraintsToStr(t) & "}"
|
||||||
|
of tyTypeClass:
|
||||||
|
result = constraintsToStr(t)
|
||||||
|
of tyExpr:
|
||||||
|
if t.sons.len == 0: result = "expr"
|
||||||
|
else: result = "expr{" & constraintsToStr(t) & "}"
|
||||||
of tyArray:
|
of tyArray:
|
||||||
if t.sons[0].kind == tyRange:
|
if t.sons[0].kind == tyRange:
|
||||||
result = "array[" & rangeToStr(t.sons[0].n) & ", " &
|
result = "array[" & rangeToStr(t.sons[0].n) & ", " &
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue