the foundations of a type traits module; better error messages for expr, typedesc and typeclasses params

This commit is contained in:
Zahary Karadjov
2012-04-06 05:02:48 +03:00
parent 98b7bdaa50
commit efb53233cb
8 changed files with 65 additions and 12 deletions

View File

@@ -243,8 +243,13 @@ const
sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
sfNoInit* = sfMainModule # don't generate code to init the variable
sfImmediate* = sfDeadCodeElim # macro or template is immediately expanded
# 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
# getting ready for the future expr/stmt merge
@@ -358,7 +363,8 @@ const
type
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,
mParseExprToAst, mParseStmtToAst, mExpandToAst,
mUnaryLt, mSucc,

View File

@@ -490,7 +490,7 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode =
proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
var s = n.sym
case s.kind
of skProc, skConverter, skMacro:
of skProc, skConverter, skMacro, skType:
result = n
#result = s.getBody
of skVar, skLet, skForVar, skTemp, skResult:
@@ -891,7 +891,24 @@ proc evalTemplate*(n: PNode, sym: PSym): PNode =
result = evalTemplateAux(sym.getBody, args, sym)
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 =
var
n = original.copyTree
@@ -941,6 +958,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mParseExprToAst: result = evalParseExpr(c, n)
of mParseStmtToAst: result = evalParseStmt(c, n)
of mExpandToAst: result = evalExpandToAst(c, n)
of mTypeTrait: result = evalTypeTrait(n, c.module)
of mNLen:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return

View File

@@ -667,3 +667,6 @@ template AssertNotNil*(e: expr): expr =
if(e == nil): InternalError($InstantiationInfo())
e
template InternalAssert*(e: bool): stmt =
if not e: InternalError($InstantiationInfo())

View File

@@ -1314,11 +1314,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
Message(n.info, warnDeprecated, "bind")
result = semExpr(c, n.sons[0], flags)
of nkTypeOfExpr:
var typ = semTypeNode(c, n, nil)
if typ.sym == nil:
typ = copyType(typ, typ.owner, true)
typ.linkTo(newSym(skType, getIdent"typedesc", typ.owner))
result = newSymNode(typ.sym, n.info)
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
typ = makeTypedesc(c, typ)
var sym = newSym(skType, getIdent"TypeOfExpr", typ.owner).linkTo(typ)
sym.flags.incl(sfAnon)
result = newSymNode(sym, n.info)
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
# check if it is an expression macro:
checkMinSonsLen(n, 1)

View File

@@ -206,7 +206,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mNewString, mNewStringOfCap,
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
mParseExprToAst, mParseStmtToAst, mExpandToAst,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
mNLen..mNError, mEqRef:
nil
of mRand:

View File

@@ -8,6 +8,7 @@
#
# This include file implements the semantic checking for magics.
# included from sem.nim
proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
var r = isPartOf(n[1], n[2])
@@ -43,11 +44,21 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result.add(filename)
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,
flags: TExprFlags): PNode =
case n[0].sym.magic
of mSlurp: result = semSlurp(c, n, flags)
of mIsPartOf: result = semIsPartOf(c, n, flags)
of mTypeTrait: result = semTypeTraits(c, n)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
result.typ = getSysType(tyString)

View File

@@ -583,8 +583,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
break addImplicitGeneric
var s = newSym(skType, paramTypId, getCurrOwner())
s.typ = typeClass
s.typ.sym = s
s.flags.incl(sfAnon)
s.linkTo(typeClass)
s.position = genericParams.len
genericParams.addSon(newSymNode(s))
endingType = typeClass
@@ -693,7 +693,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkTypeOfExpr:
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
checkSonsLen(n, 1)
result = semExprWithType(c, n.sons[0], {efInTypeof}).typ
result = semExprWithType(c, n.sons[0], {efInTypeof, efAllowType}).typ
of nkPar:
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
else: GlobalError(n.info, errTypeExpected)

View File

@@ -372,6 +372,13 @@ proc rangeToStr(n: PNode): string =
assert(n.kind == nkRange)
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 =
const
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
@@ -387,7 +394,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
var t = typ
result = ""
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
case t.Kind
of tyGenericBody, tyGenericInst, tyGenericInvokation:
@@ -396,6 +403,14 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if i > 1: add(result, ", ")
add(result, typeToString(t.sons[i]))
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:
if t.sons[0].kind == tyRange:
result = "array[" & rangeToStr(t.sons[0].n) & ", " &