mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-01 02:42:05 +00:00
typedesc and expr params
types are now valid proc/template/macro params and you can overload over them:
proc foo(T: typedesc) # accept any type
proc foo(T: typedesc{int}) # overload specifically for int
proc foo(T: typedesc{int or float or Callable}) # overload for any type matching the constraints
expr{type} is a param expecting compile time value of the designated type (or type class).
when typedesc or expr params are used with a proc, the proc will be instantiated once
for each unique type/value used as parameter.
This commit is contained in:
@@ -711,6 +711,15 @@ proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||
var emptyNode* = newNode(nkEmpty)
|
||||
# There is a single empty node that is shared! Do not overwrite it!
|
||||
|
||||
proc linkTo*(t: PType, s: PSym): PType {.discardable.} =
|
||||
t.sym = s
|
||||
s.typ = t
|
||||
result = t
|
||||
|
||||
proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
|
||||
t.sym = s
|
||||
s.typ = t
|
||||
result = s
|
||||
|
||||
const # for all kind of hash tables:
|
||||
GrowthFactor* = 2 # must be power of 2, > 0
|
||||
|
||||
@@ -130,6 +130,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var length = sonsLen(ri)
|
||||
for i in countup(1, length - 1):
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
if ri.sons[i].typ.isCompileTimeOnly: continue
|
||||
if i < sonsLen(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym))
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# included from cgen.nim
|
||||
|
||||
# ------------------------- Name Mangling --------------------------------
|
||||
|
||||
proc mangle(name: string): string =
|
||||
@@ -48,6 +50,9 @@ proc mangleName(s: PSym): PRope =
|
||||
app(result, toRope(s.id))
|
||||
s.loc.r = result
|
||||
|
||||
proc isCompileTimeOnly(t: PType): bool =
|
||||
result = t.kind in {tyTypedesc, tyExpr}
|
||||
|
||||
proc getTypeName(typ: PType): PRope =
|
||||
if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and
|
||||
(gCmd != cmdCompileToLLVM):
|
||||
@@ -187,6 +192,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
for i in countup(1, sonsLen(t.n) - 1):
|
||||
if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams")
|
||||
var param = t.n.sons[i].sym
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
fillLoc(param.loc, locParam, param.typ, mangleName(param), OnStack)
|
||||
app(params, getParamTypeDesc(m, param.typ, check))
|
||||
if ccgIntroducedPtr(param):
|
||||
@@ -206,8 +212,8 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
arr = arr.sons[0]
|
||||
if i < sonsLen(t.n) - 1: app(params, ", ")
|
||||
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
|
||||
if params != nil: app(params, ", ")
|
||||
var arr = t.sons[0]
|
||||
if params != nil: app(params, ", ")
|
||||
app(params, getTypeDescAux(m, arr, check))
|
||||
if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM):
|
||||
app(params, "*")
|
||||
|
||||
@@ -606,6 +606,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
res.loc.s = OnUnknown
|
||||
for i in countup(1, sonsLen(prc.typ.n) - 1):
|
||||
var param = prc.typ.n.sons[i].sym
|
||||
if param.typ.isCompileTimeOnly: continue
|
||||
assignParam(p, param)
|
||||
closureSetup(p, prc)
|
||||
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
|
||||
|
||||
@@ -663,7 +663,7 @@ proc InternalError*(errMsg: string) =
|
||||
writeContext(UnknownLineInfo())
|
||||
rawMessage(errInternal, errMsg)
|
||||
|
||||
template AssertNotNull*(e: expr): expr =
|
||||
template AssertNotNil*(e: expr): expr =
|
||||
if(e == nil): InternalError($InstantiationInfo())
|
||||
e
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc semAndEvalConstExpr(c: PContext, n: PNode): PNode =
|
||||
result = semConstExpr(c, n)
|
||||
|
||||
|
||||
include seminst, semcall
|
||||
|
||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
||||
|
||||
@@ -180,14 +180,16 @@ proc addToLib(lib: PLib, sym: PSym) =
|
||||
sym.annex = lib
|
||||
|
||||
proc makePtrType(c: PContext, baseType: PType): PType =
|
||||
if (baseType == nil): InternalError("makePtrType")
|
||||
result = newTypeS(tyPtr, c)
|
||||
addSon(result, baseType)
|
||||
addSon(result, baseType.AssertNotNil)
|
||||
|
||||
proc makeVarType(c: PContext, baseType: PType): PType =
|
||||
if (baseType == nil): InternalError("makeVarType")
|
||||
result = newTypeS(tyVar, c)
|
||||
addSon(result, baseType)
|
||||
addSon(result, baseType.AssertNotNil)
|
||||
|
||||
proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||
result = newTypeS(tyTypeDesc, c)
|
||||
result.addSon(typ.AssertNotNil)
|
||||
|
||||
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
||||
result = newType(kind, getCurrOwner())
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
# this module does the semantic checking for expressions
|
||||
# included from sem.nim
|
||||
|
||||
proc semExprOrTypedesc(c: PContext, n: PNode): PNode
|
||||
|
||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
||||
markUsed(n, s)
|
||||
pushInfoContext(n.info)
|
||||
@@ -93,6 +95,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
# if a proc accesses a global variable, it is not side effect free:
|
||||
if sfGlobal in s.flags:
|
||||
incl(c.p.owner.flags, sfSideEffect)
|
||||
elif s.kind == skParam and s.typ.kind == tyExpr:
|
||||
return s.typ.n
|
||||
elif s.owner != c.p.owner and s.owner.kind != skModule and
|
||||
c.p.owner.typ != nil and not IsGenericRoutine(s.owner):
|
||||
c.p.owner.typ.callConv = ccClosure
|
||||
@@ -111,7 +115,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
else:
|
||||
markUsed(n, s)
|
||||
result = newSymNode(s, n.info)
|
||||
|
||||
|
||||
proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
|
||||
var diff = inheritanceDiff(castDest, src)
|
||||
if diff == high(int):
|
||||
@@ -247,16 +251,31 @@ proc semIs(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
GlobalError(n.info, errXExpectsTwoArguments, "is")
|
||||
|
||||
proc semExprOrTypedesc(c: PContext, n: PNode): PNode =
|
||||
# XXX: Currently, semExprWithType will return the same type
|
||||
# for nodes such as (100) or (int).
|
||||
# This is inappropriate. The type of the first expression
|
||||
# should be "int", while the type of the second one should
|
||||
# be typeDesc(int).
|
||||
# Ideally, this should be fixed in semExpr, but right now
|
||||
# there are probably users that depend on the present behavior.
|
||||
# XXX: Investigate current uses of efAllowType and fix them to
|
||||
# work with tyTypeDesc.
|
||||
result = semExprWithType(c, n, {efAllowType})
|
||||
if result.kind == nkSym and result.sym.kind == skType and
|
||||
result.typ.kind != tyTypeDesc:
|
||||
result.typ = makeTypeDesc(c, result.typ)
|
||||
|
||||
proc semOpAux(c: PContext, n: PNode) =
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
|
||||
var info = a.sons[0].info
|
||||
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
|
||||
a.sons[1] = semExprWithType(c, a.sons[1], {efAllowType})
|
||||
a.sons[1] = semExprOrTypedesc(c, a.sons[1])
|
||||
a.typ = a.sons[1].typ
|
||||
else:
|
||||
n.sons[i] = semExprWithType(c, a, {efAllowType})
|
||||
n.sons[i] = semExprOrTypedesc(c, a)
|
||||
|
||||
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
||||
# quick check if there is *any* () operator overloaded:
|
||||
@@ -822,7 +841,7 @@ proc semDeref(c: PContext, n: PNode): PNode =
|
||||
of tyRef, tyPtr: n.typ = t.sons[0]
|
||||
else: result = nil
|
||||
#GlobalError(n.sons[0].info, errCircumNeedsPointer)
|
||||
|
||||
|
||||
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
## returns nil if not a built-in subscript operator; also called for the
|
||||
## checking of assignments
|
||||
@@ -833,7 +852,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result.add(x[0])
|
||||
return
|
||||
checkMinSonsLen(n, 2)
|
||||
n.sons[0] = semExprWithType(c, n.sons[0], flags - {efAllowType})
|
||||
n.sons[0] = semExprOrTypedesc(c, n.sons[0])
|
||||
var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
case arr.kind
|
||||
of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString:
|
||||
@@ -848,6 +867,11 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = n
|
||||
result.typ = elemType(arr)
|
||||
#GlobalError(n.info, errIndexTypesDoNotMatch)
|
||||
of tyTypeDesc:
|
||||
result = n.sons[0] # The result so far is a tyTypeDesc bound to
|
||||
# a tyGenericBody. The line below will substitute
|
||||
# it with the instantiated type.
|
||||
result.typ.sons[0] = semTypeNode(c, n, nil).linkTo(result.sym)
|
||||
of tyTuple:
|
||||
checkSonsLen(n, 2)
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
@@ -1024,7 +1048,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||
markUsed(n, expandedSym)
|
||||
|
||||
for i in countup(1, macroCall.len-1):
|
||||
macroCall.sons[i] = semExprWithType(c, macroCall[i], {efAllowType})
|
||||
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
|
||||
|
||||
# Preserve the magic symbol in order to be handled in evals.nim
|
||||
n.sons[0] = newSymNode(magicSym, n.info)
|
||||
@@ -1287,6 +1311,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkBind:
|
||||
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)
|
||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||
# check if it is an expression macro:
|
||||
checkMinSonsLen(n, 1)
|
||||
|
||||
@@ -20,7 +20,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
if a.kind != nkSym:
|
||||
InternalError(a.info, "instantiateGenericParamList; no symbol")
|
||||
var q = a.sym
|
||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass}: continue
|
||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass, tyExpr}: continue
|
||||
var s = newSym(skType, q.name, getCurrOwner())
|
||||
s.info = q.info
|
||||
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||
|
||||
@@ -180,6 +180,8 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
|
||||
if result != nil:
|
||||
markUsed(n, result)
|
||||
if result.kind == skParam and result.typ.kind == tyTypeDesc:
|
||||
return result.typ.sons[0].sym
|
||||
if result.kind != skType: GlobalError(n.info, errTypeExpected)
|
||||
if result.typ.kind != tyGenericParam:
|
||||
# XXX get rid of this hack!
|
||||
@@ -490,9 +492,20 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
||||
# if id is not nil, the generic param will bind just once (see below)
|
||||
case paramType.kind:
|
||||
of tyExpr:
|
||||
# proc(a, b: expr)
|
||||
if procKind notin {skTemplate, skMacro}:
|
||||
result.typ = newTypeS(tyGenericParam, c)
|
||||
if paramType.sonsLen == 0:
|
||||
# proc(a, b: expr)
|
||||
# no constraints, treat like generic param
|
||||
result.typ = newTypeS(tyGenericParam, c)
|
||||
else:
|
||||
# proc(a: expr{string}, b: expr{nkLambda})
|
||||
# overload on compile time values and AST trees
|
||||
result.typ = newTypeS(tyExpr, c)
|
||||
result.typ.sons = paramType.sons
|
||||
of tyTypeDesc:
|
||||
if procKind notin {skTemplate, skMacro}:
|
||||
result.typ = newTypeS(tyTypeDesc, c)
|
||||
result.typ.sons = paramType.sons
|
||||
of tyDistinct:
|
||||
# type T1 = distinct expr
|
||||
# type S1 = distinct Sortable
|
||||
@@ -565,7 +578,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
if genericParams == nil:
|
||||
# genericParams is nil when the proc is being instantiated
|
||||
# the resolved type will be in scope then
|
||||
endingType = SymtabGet(c.tab, paramTypId).AssertNotNull.typ
|
||||
endingType = SymtabGet(c.tab, paramTypId).AssertNotNil.typ
|
||||
else:
|
||||
block addImplicitGeneric:
|
||||
# is this a bindOnce type class already present in the param list?
|
||||
@@ -664,9 +677,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
|
||||
result = instGenericContainer(c, n, result)
|
||||
|
||||
proc semExpandToType(c: PContext, n: PNode, sym: PSym): PType =
|
||||
proc semTypeFromMacro(c: PContext, n: PNode): PType =
|
||||
# Expands a macro or template until a type is returned
|
||||
# results in GlobalError if the macro expands to something different
|
||||
var sym = expectMacroOrTemplateCall(c, n)
|
||||
markUsed(n, sym)
|
||||
case sym.kind
|
||||
of skMacro:
|
||||
@@ -676,7 +690,7 @@ proc semExpandToType(c: PContext, n: PNode, sym: PSym): PType =
|
||||
else:
|
||||
GlobalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
|
||||
|
||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = nil
|
||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||
case n.kind
|
||||
@@ -703,9 +717,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result.addSon(t2)
|
||||
result.flags.incl(if op == ord(wAnd): tfAll else: tfAny)
|
||||
else:
|
||||
# expand macros and templates
|
||||
var expandedSym = expectMacroOrTemplateCall(c, n)
|
||||
result = semExpandToType(c, n, expandedSym)
|
||||
result = semTypeFromMacro(c, n)
|
||||
of nkCurlyExpr:
|
||||
result = semTypeNode(c, n.sons[0], nil)
|
||||
if result != nil:
|
||||
result = copyType(result, getCurrOwner(), false)
|
||||
for i in countup(1, n.len - 1):
|
||||
result.addSon(semTypeNode(c, n.sons[i], nil))
|
||||
of nkWhenStmt:
|
||||
var whenResult = semWhen(c, n, false)
|
||||
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
||||
|
||||
@@ -35,7 +35,7 @@ type
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
isNone, isConvertible, isIntConv, isSubtype,
|
||||
isGeneric,
|
||||
isGeneric
|
||||
isEqual
|
||||
|
||||
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||
@@ -208,16 +208,32 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
var y = a.n.sons[i].sym
|
||||
if x.name.id != y.name.id: return isNone
|
||||
|
||||
proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
result = isNone
|
||||
let son = f.sons[0]
|
||||
if son.kind == a.kind:
|
||||
result = isGeneric
|
||||
elif son.kind == tyGenericBody:
|
||||
if a.kind == tyGenericInst and a.sons[0] == son:
|
||||
result = isGeneric
|
||||
put(mapping, f, a)
|
||||
proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
for i in countup(0, f.sonsLen - 1):
|
||||
let son = f.sons[i]
|
||||
var match = son.kind == a.kind
|
||||
|
||||
if not match:
|
||||
case son.kind
|
||||
of tyGenericBody:
|
||||
if a.kind == tyGenericInst and a.sons[0] == son:
|
||||
match = true
|
||||
put(mapping, f, a)
|
||||
of tyTypeClass:
|
||||
match = matchTypeClass(mapping, son, a) == isGeneric
|
||||
else: nil
|
||||
|
||||
if tfAny in f.flags:
|
||||
if match == true:
|
||||
return isGeneric
|
||||
else:
|
||||
if match == false:
|
||||
return isNone
|
||||
|
||||
# if the loop finished without returning, either all constraints matched
|
||||
# or none of them matched.
|
||||
result = if tfAny in f.flags: isNone else: isGeneric
|
||||
|
||||
proc procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
||||
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
||||
@@ -347,8 +363,6 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
result = typeRel(mapping, f.sons[0], a.sons[0])
|
||||
if result < isGeneric: result = isNone
|
||||
else: nil
|
||||
of tyTypeClass:
|
||||
result = matchTypeClass(mapping, f, a)
|
||||
of tyOrdinal:
|
||||
if isOrdinalType(a):
|
||||
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
||||
@@ -469,7 +483,19 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
result = isGeneric
|
||||
else:
|
||||
result = typeRel(mapping, x, a) # check if it fits
|
||||
of tyExpr, tyStmt, tyTypeDesc:
|
||||
of tyTypeClass:
|
||||
result = matchTypeClass(mapping, f, a)
|
||||
if result == isGeneric: put(mapping, f, a)
|
||||
of tyTypeDesc:
|
||||
if a.kind == tyTypeDesc:
|
||||
if f.sonsLen == 0:
|
||||
result = isGeneric
|
||||
else:
|
||||
result = matchTypeClass(mapping, f, a.sons[0])
|
||||
if result == isGeneric: put(mapping, f, a)
|
||||
else:
|
||||
result = isNone
|
||||
of tyExpr, tyStmt:
|
||||
result = isGeneric
|
||||
else: internalError("typeRel(" & $f.kind & ')')
|
||||
|
||||
@@ -512,9 +538,34 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
inc(m.convMatches)
|
||||
return
|
||||
|
||||
|
||||
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||
arg, argOrig: PNode): PNode =
|
||||
var r = typeRel(m.bindings, f, a)
|
||||
var r: TTypeRelation
|
||||
if f.kind == tyExpr:
|
||||
if f.sonsLen == 0:
|
||||
r = isGeneric
|
||||
else:
|
||||
let match = matchTypeClass(m.bindings, f, a)
|
||||
if match != isGeneric: r = isNone
|
||||
else:
|
||||
# XXX: Ideally, this should happen much earlier somewhere near
|
||||
# semOpAux, but to do that, we need to be able to query the
|
||||
# overload set to determine whether compile-time value is expected
|
||||
# for the param before entering the full-blown sigmatch algorithm.
|
||||
# This is related to the immediate pragma since querying the
|
||||
# overload set could help there too.
|
||||
var evaluated = c.semConstExpr(c, arg)
|
||||
if evaluated != nil:
|
||||
r = isGeneric
|
||||
arg.typ = newTypeS(tyExpr, c)
|
||||
arg.typ.n = evaluated
|
||||
|
||||
if r == isGeneric:
|
||||
put(m.bindings, f, arg.typ)
|
||||
else:
|
||||
r = typeRel(m.bindings, f, a)
|
||||
|
||||
case r
|
||||
of isConvertible:
|
||||
inc(m.convMatches)
|
||||
|
||||
@@ -48,15 +48,15 @@ proc equalParams*(a, b: PNode): TParamsEquality
|
||||
proc isOrdinalType*(t: PType): bool
|
||||
proc enumHasHoles*(t: PType): bool
|
||||
const
|
||||
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct,
|
||||
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
|
||||
tyConst, tyMutable}
|
||||
abstractVar* = {tyVar, tyGenericInst, tyDistinct,
|
||||
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
|
||||
tyConst, tyMutable}
|
||||
abstractRange* = {tyGenericInst, tyRange, tyDistinct,
|
||||
abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal,
|
||||
tyConst, tyMutable}
|
||||
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct,
|
||||
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
|
||||
tyConst, tyMutable}
|
||||
abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable}
|
||||
abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal}
|
||||
|
||||
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable}
|
||||
|
||||
@@ -142,7 +142,7 @@ proc skipTypes(t: PType, kinds: TTypeKinds): PType =
|
||||
proc isOrdinalType(t: PType): bool =
|
||||
assert(t != nil)
|
||||
result = (t.Kind in {tyChar, tyInt..tyInt64, tyBool, tyEnum}) or
|
||||
(t.Kind in {tyRange, tyConst, tyMutable, tyGenericInst}) and
|
||||
(t.Kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and
|
||||
isOrdinalType(t.sons[0])
|
||||
|
||||
proc enumHasHoles(t: PType): bool =
|
||||
@@ -730,8 +730,10 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
if a.kind != b.kind: return false
|
||||
case a.Kind
|
||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||
tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc, tyOrdinal:
|
||||
tyInt..tyBigNum, tyStmt:
|
||||
result = true
|
||||
of tyExpr:
|
||||
result = ExprStructuralEquivalent(a.n, b.n)
|
||||
of tyObject:
|
||||
IfFastObjectTypeCheckFailed(a, b):
|
||||
CycleCheck()
|
||||
@@ -740,7 +742,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
CycleCheck()
|
||||
if c.cmp == dcEq: result = sameDistinctTypes(a, b)
|
||||
else: result = sameTypeAux(a.sons[0], b.sons[0], c)
|
||||
of tyEnum, tyForward, tyProxy, tyTypeClass:
|
||||
of tyEnum, tyForward, tyProxy:
|
||||
# XXX generic enums do not make much sense, but require structural checking
|
||||
result = a.id == b.id
|
||||
of tyTuple:
|
||||
@@ -749,7 +751,8 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c)
|
||||
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
|
||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
||||
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter:
|
||||
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
||||
tyOrdinal, tyTypeDesc, tyTypeClass:
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
CycleCheck()
|
||||
result = true
|
||||
|
||||
17
tests/run/tmemoization.nim
Normal file
17
tests/run/tmemoization.nim
Normal file
@@ -0,0 +1,17 @@
|
||||
discard """
|
||||
msg: "test 1\ntest 2"
|
||||
output: "TEST 1\nTEST 2\nTEST 2"
|
||||
"""
|
||||
|
||||
import strutils
|
||||
|
||||
proc foo(s: expr{string}): string =
|
||||
static: echo s
|
||||
|
||||
const R = s.toUpper
|
||||
return R
|
||||
|
||||
echo foo("test 1")
|
||||
echo foo("test 2")
|
||||
echo foo("test " & $2)
|
||||
|
||||
35
tests/run/ttypedesc1.nim
Normal file
35
tests/run/ttypedesc1.nim
Normal file
@@ -0,0 +1,35 @@
|
||||
import unittest
|
||||
|
||||
type
|
||||
TFoo[T, U] = object
|
||||
x: T
|
||||
y: U
|
||||
|
||||
proc foo(T: typedesc{float}, a: expr): string =
|
||||
result = "float " & $(a.len > 5)
|
||||
|
||||
proc foo(T: typedesc{TFoo}, a: int): string =
|
||||
result = "TFoo " & $(a)
|
||||
|
||||
proc foo(T: typedesc{int or bool}): string =
|
||||
var a: T
|
||||
a = 10
|
||||
result = "int or bool " & ($a)
|
||||
|
||||
template foo(T: typedesc{seq}): expr = "seq"
|
||||
|
||||
test "types can be used as proc params":
|
||||
check foo(TFoo[int, float], 1000) == "TFoo 1000"
|
||||
|
||||
var f = 10.0
|
||||
check foo(float, "long string") == "float true"
|
||||
check foo(type(f), [1, 2, 3]) == "float false"
|
||||
|
||||
check foo(int) == "int or bool 10"
|
||||
|
||||
check foo(seq[int]) == "seq"
|
||||
check foo(seq[TFoo[bool, string]]) == "seq"
|
||||
|
||||
when false:
|
||||
proc foo(T: typedesc{seq}, s: T) = nil
|
||||
|
||||
Reference in New Issue
Block a user