mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-03 03:32:32 +00:00
the foundations of a type traits module; better error messages for expr, typedesc and typeclasses params
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) & ", " &
|
||||
|
||||
Reference in New Issue
Block a user