generic types can be used like type classes. distinct can be applied to type classes.
This commit is contained in:
parent
296ef07955
commit
bc2eb0ea9b
11 changed files with 147 additions and 79 deletions
|
|
@ -310,6 +310,8 @@ type
|
||||||
tfFromGeneric # type is an instantiation of a generic; this is needed
|
tfFromGeneric # type is an instantiation of a generic; this is needed
|
||||||
# because for instantiations of objects, structural
|
# because for instantiations of objects, structural
|
||||||
# type equality has to be used
|
# type equality has to be used
|
||||||
|
tfAll # type class requires all constraints to be met (default)
|
||||||
|
tfAny # type class requires any constraint to be met
|
||||||
|
|
||||||
TTypeFlags* = set[TTypeFlag]
|
TTypeFlags* = set[TTypeFlag]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -662,3 +662,8 @@ proc InternalError*(info: TLineInfo, errMsg: string) =
|
||||||
proc InternalError*(errMsg: string) =
|
proc InternalError*(errMsg: string) =
|
||||||
writeContext(UnknownLineInfo())
|
writeContext(UnknownLineInfo())
|
||||||
rawMessage(errInternal, errMsg)
|
rawMessage(errInternal, errMsg)
|
||||||
|
|
||||||
|
template AssertNotNull*(e: expr): expr =
|
||||||
|
if(e == nil): InternalError($InstantiationInfo())
|
||||||
|
e
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -219,3 +219,6 @@ proc binaryStrSearch*(x: openarray[string], y: string): int =
|
||||||
return mid
|
return mid
|
||||||
result = - 1
|
result = - 1
|
||||||
|
|
||||||
|
# Can we keep this? I'm using it all the time
|
||||||
|
template nimdbg*: expr = c.filename.endsWith"nimdbg.nim"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
if a.kind != nkSym:
|
if a.kind != nkSym:
|
||||||
InternalError(a.info, "instantiateGenericParamList; no symbol")
|
InternalError(a.info, "instantiateGenericParamList; no symbol")
|
||||||
var q = a.sym
|
var q = a.sym
|
||||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam}: continue
|
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass}: continue
|
||||||
var s = newSym(skType, q.name, getCurrOwner())
|
var s = newSym(skType, q.name, getCurrOwner())
|
||||||
s.info = q.info
|
s.info = q.info
|
||||||
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||||
|
|
@ -107,8 +107,6 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||||
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
||||||
c.threadEntries.add(s)
|
c.threadEntries.add(s)
|
||||||
|
|
||||||
template nimdbg: expr = c.filename.endsWith"nimdbg.nim"
|
|
||||||
|
|
||||||
proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType =
|
proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType =
|
||||||
# XXX: This is intended to replace the use of semParamList in generateInstance.
|
# XXX: This is intended to replace the use of semParamList in generateInstance.
|
||||||
# The results of semParamList's analysis are already encoded in the original
|
# The results of semParamList's analysis are already encoded in the original
|
||||||
|
|
|
||||||
|
|
@ -475,42 +475,6 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result.n = newNodeI(nkRecList, n.info)
|
result.n = newNodeI(nkRecList, n.info)
|
||||||
semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym)
|
semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym)
|
||||||
|
|
||||||
proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
|
|
||||||
cl: var TIntSet): PType =
|
|
||||||
result = t
|
|
||||||
if t == nil: return
|
|
||||||
if ContainsOrIncl(cl, t.id): return
|
|
||||||
case t.kind
|
|
||||||
of tyGenericBody:
|
|
||||||
result = newTypeS(tyGenericInvokation, c)
|
|
||||||
addSon(result, t)
|
|
||||||
for i in countup(0, sonsLen(t) - 2):
|
|
||||||
if t.sons[i].kind != tyGenericParam:
|
|
||||||
InternalError("addTypeVarsOfGenericBody")
|
|
||||||
# do not declare ``TKey`` twice:
|
|
||||||
#if not ContainsOrIncl(cl, t.sons[i].sym.ident.id):
|
|
||||||
var s = copySym(t.sons[i].sym)
|
|
||||||
s.position = sonsLen(genericParams)
|
|
||||||
if s.typ == nil or s.typ.kind != tyGenericParam:
|
|
||||||
InternalError("addTypeVarsOfGenericBody 2")
|
|
||||||
addDecl(c, s)
|
|
||||||
addSon(genericParams, newSymNode(s))
|
|
||||||
addSon(result, t.sons[i])
|
|
||||||
of tyGenericInst:
|
|
||||||
var L = sonsLen(t) - 1
|
|
||||||
t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl)
|
|
||||||
of tyGenericInvokation:
|
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
|
||||||
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
|
|
||||||
else:
|
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
|
||||||
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
|
|
||||||
|
|
||||||
proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
|
|
||||||
result = semTypeNode(c, n, nil)
|
|
||||||
if genericParams != nil and sonsLen(genericParams) == 0:
|
|
||||||
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
|
|
||||||
|
|
||||||
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
||||||
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
|
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
|
||||||
let nn = getSysSym"PNimrodNode"
|
let nn = getSysSym"PNimrodNode"
|
||||||
|
|
@ -520,11 +484,31 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
||||||
else:
|
else:
|
||||||
addDecl(c, param)
|
addDecl(c, param)
|
||||||
|
|
||||||
proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind): PType =
|
proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
||||||
|
tuple[typ: PType, id: PIdent] =
|
||||||
|
# if typ is not-nil, the param should be turned into a generic param
|
||||||
|
# if id is not nil, the generic param will bind just once (see below)
|
||||||
case paramType.kind:
|
case paramType.kind:
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
|
# proc(a, b: expr)
|
||||||
if procKind notin {skTemplate, skMacro}:
|
if procKind notin {skTemplate, skMacro}:
|
||||||
result = newTypeS(tyGenericParam, c)
|
result.typ = newTypeS(tyGenericParam, c)
|
||||||
|
of tyDistinct:
|
||||||
|
# type T1 = distinct expr
|
||||||
|
# type S1 = distinct Sortable
|
||||||
|
# proc x(a, b: T1, c, d: S1)
|
||||||
|
# This forces bindOnce behavior for the type class, equivalent to
|
||||||
|
# proc x[T, S](a, b: T, c, d: S)
|
||||||
|
result = paramTypeClass(c, paramType.lastSon, procKind)
|
||||||
|
result.id = paramType.sym.name
|
||||||
|
of tyGenericBody:
|
||||||
|
# type Foo[T] = object
|
||||||
|
# proc x(a: Foo, b: Foo)
|
||||||
|
result.typ = newTypeS(tyTypeClass, c)
|
||||||
|
result.typ.addSon(paramType)
|
||||||
|
result.id = paramType.sym.name # bindOnce by default
|
||||||
|
of tyTypeClass:
|
||||||
|
result.typ = copyType(paramType, getCurrOwner(), false)
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
|
|
@ -555,14 +539,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
hasDefault = a.sons[length-1].kind != nkEmpty
|
hasDefault = a.sons[length-1].kind != nkEmpty
|
||||||
|
|
||||||
if hasType:
|
if hasType:
|
||||||
typ = paramType(c, a.sons[length-2], genericParams, cl)
|
typ = semTypeNode(c, a.sons[length-2], nil)
|
||||||
if c.filename.endsWith"nimdbg.nim" and typ != nil:
|
|
||||||
echo("PARAM TYPE ", typ.kind, " ")
|
|
||||||
if genericParams != nil:
|
|
||||||
echo genericParams.info.toFileLineCol
|
|
||||||
debug typ
|
|
||||||
#if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
|
|
||||||
# debug a.sons[length-2][0][1]
|
|
||||||
if hasDefault:
|
if hasDefault:
|
||||||
def = semExprWithType(c, a.sons[length-1])
|
def = semExprWithType(c, a.sons[length-1])
|
||||||
# check type compability between def.typ and typ:
|
# check type compability between def.typ and typ:
|
||||||
|
|
@ -580,42 +558,46 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var arg = newSymS(skParam, a.sons[j], c)
|
var arg = newSymS(skParam, a.sons[j], c)
|
||||||
let typeClass = paramTypeClass(c, typ, kind)
|
var endingType = typ
|
||||||
|
var (typeClass, paramTypId) = paramTypeClass(c, typ, kind)
|
||||||
if typeClass != nil:
|
if typeClass != nil:
|
||||||
let typeClassParamId = getIdent(arg.name.s & ":type")
|
if paramTypId == nil: paramTypId = getIdent(arg.name.s & ":type")
|
||||||
if genericParams == nil:
|
if genericParams == nil:
|
||||||
# genericParams is nil when the proc is being instantiated
|
# genericParams is nil when the proc is being instantiated
|
||||||
# the resolved type will be in scope then
|
# the resolved type will be in scope then
|
||||||
var s = SymtabGet(c.tab, typeClassParamId)
|
endingType = SymtabGet(c.tab, paramTypId).AssertNotNull.typ
|
||||||
arg.typ = s.typ
|
|
||||||
else:
|
else:
|
||||||
var s = newSym(skType, typeClassParamId, getCurrOwner())
|
block addImplicitGeneric:
|
||||||
|
# is this a bindOnce type class already present in the param list?
|
||||||
|
for i in countup(0, genericParams.len - 1):
|
||||||
|
if genericParams.sons[i].sym.name == paramTypId:
|
||||||
|
endingType = genericParams.sons[i].typ
|
||||||
|
break addImplicitGeneric
|
||||||
|
|
||||||
|
var s = newSym(skType, paramTypId, getCurrOwner())
|
||||||
s.typ = typeClass
|
s.typ = typeClass
|
||||||
s.typ.sym = s
|
s.typ.sym = s
|
||||||
s.position = genericParams.len
|
s.position = genericParams.len
|
||||||
genericParams.addSon(newSymNode(s))
|
genericParams.addSon(newSymNode(s))
|
||||||
arg.typ = s.typ
|
endingType = typeClass
|
||||||
else:
|
|
||||||
arg.typ = typ
|
|
||||||
|
|
||||||
|
arg.typ = endingType
|
||||||
arg.position = counter
|
arg.position = counter
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||||
if ContainsOrIncl(check, arg.name.id):
|
if ContainsOrIncl(check, arg.name.id):
|
||||||
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
||||||
addSon(result.n, newSymNode(arg))
|
addSon(result.n, newSymNode(arg))
|
||||||
addSon(result, typ)
|
addSon(result, endingType)
|
||||||
addParamOrResult(c, arg, kind)
|
addParamOrResult(c, arg, kind)
|
||||||
|
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
var r = paramType(c, n.sons[0], genericParams, cl)
|
var r = semTypeNode(c, n.sons[0], nil)
|
||||||
# turn explicit 'void' return type into 'nil' because the rest of the
|
# turn explicit 'void' return type into 'nil' because the rest of the
|
||||||
# compiler only checks for 'nil':
|
# compiler only checks for 'nil':
|
||||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||||
result.sons[0] = r
|
result.sons[0] = r
|
||||||
res.typ = result.sons[0]
|
res.typ = result.sons[0]
|
||||||
#if matchType(result, [(tyProc, 1), (tyVar, 0)], tyGenericInvokation):
|
|
||||||
# debug result
|
|
||||||
|
|
||||||
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
|
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
|
|
@ -707,6 +689,20 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
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)
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
|
let op = n.sons[0].ident.id
|
||||||
|
if op in {ord(wAnd), ord(wOr)}:
|
||||||
|
var
|
||||||
|
t1 = semTypeNode(c, n.sons[1], nil)
|
||||||
|
t2 = semTypeNode(c, n.sons[2], nil)
|
||||||
|
|
||||||
|
if t1 == nil: GlobalError(n.sons[1].info, errTypeExpected)
|
||||||
|
elif t2 == nil: GlobalError(n.sons[2].info, errTypeExpected)
|
||||||
|
else:
|
||||||
|
result = newTypeS(tyTypeClass, c)
|
||||||
|
result.addSon(t1)
|
||||||
|
result.addSon(t2)
|
||||||
|
result.flags.incl(if op == ord(wAnd): tfAll else: tfAny)
|
||||||
|
else:
|
||||||
# expand macros and templates
|
# expand macros and templates
|
||||||
var expandedSym = expectMacroOrTemplateCall(c, n)
|
var expandedSym = expectMacroOrTemplateCall(c, n)
|
||||||
result = semExpandToType(c, n, expandedSym)
|
result = semExpandToType(c, n, expandedSym)
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = t
|
result = t
|
||||||
if t == nil: return
|
if t == nil: return
|
||||||
case t.kind
|
case t.kind
|
||||||
|
of tyTypeClass: nil
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
result = lookupTypeVar(cl, t)
|
result = lookupTypeVar(cl, t)
|
||||||
if result.kind == tyGenericInvokation:
|
if result.kind == tyGenericInvokation:
|
||||||
|
|
|
||||||
|
|
@ -208,9 +208,15 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
var y = a.n.sons[i].sym
|
var y = a.n.sons[i].sym
|
||||||
if x.name.id != y.name.id: return isNone
|
if x.name.id != y.name.id: return isNone
|
||||||
|
|
||||||
proc constraintRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
result = isNone
|
result = isNone
|
||||||
if f.kind == a.kind: result = isGeneric
|
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 procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
proc procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
||||||
|
|
@ -261,7 +267,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
assert(a != nil)
|
assert(a != nil)
|
||||||
if a.kind == tyGenericInst and
|
if a.kind == tyGenericInst and
|
||||||
skipTypes(f, {tyVar}).kind notin {
|
skipTypes(f, {tyVar}).kind notin {
|
||||||
tyGenericBody, tyGenericInvokation, tyGenericParam}:
|
tyGenericBody, tyGenericInvokation,
|
||||||
|
tyGenericParam, tyTypeClass }:
|
||||||
return typeRel(mapping, f, lastSon(a))
|
return typeRel(mapping, f, lastSon(a))
|
||||||
if a.kind == tyVar and f.kind != tyVar:
|
if a.kind == tyVar and f.kind != tyVar:
|
||||||
return typeRel(mapping, f, a.sons[0])
|
return typeRel(mapping, f, a.sons[0])
|
||||||
|
|
@ -341,7 +348,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
else: nil
|
else: nil
|
||||||
of tyTypeClass:
|
of tyTypeClass:
|
||||||
result = constraintRel(mapping, f.sons[0], a)
|
result = matchTypeClass(mapping, f, a)
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if isOrdinalType(a):
|
if isOrdinalType(a):
|
||||||
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
||||||
|
|
|
||||||
|
|
@ -409,7 +409,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
of tySequence:
|
of tySequence:
|
||||||
result = "seq[" & typeToString(t.sons[0]) & ']'
|
result = "seq[" & typeToString(t.sons[0]) & ']'
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
result = "ordinal"
|
result = "ordinal[" & typeToString(t.sons[0]) & ']'
|
||||||
of tySet:
|
of tySet:
|
||||||
result = "set[" & typeToString(t.sons[0]) & ']'
|
result = "set[" & typeToString(t.sons[0]) & ']'
|
||||||
of tyOpenArray:
|
of tyOpenArray:
|
||||||
|
|
|
||||||
|
|
@ -2173,7 +2173,7 @@ proc InstantiationInfo*(index = -1): tuple[filename: string, line: int] {.
|
||||||
## This is only useful for advanced meta programming. See the implementation
|
## This is only useful for advanced meta programming. See the implementation
|
||||||
## of `assert` for an example.
|
## of `assert` for an example.
|
||||||
|
|
||||||
proc raiseAssert(msg: string) {.noinline.} =
|
proc raiseAssert*(msg: string) {.noinline.} =
|
||||||
raise newException(EAssertionFailed, msg)
|
raise newException(EAssertionFailed, msg)
|
||||||
|
|
||||||
template assert*(cond: bool, msg = "") =
|
template assert*(cond: bool, msg = "") =
|
||||||
|
|
@ -2182,7 +2182,7 @@ template assert*(cond: bool, msg = "") =
|
||||||
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
||||||
## not generate any code at all for ``assert`` if it is advised to do so.
|
## not generate any code at all for ``assert`` if it is advised to do so.
|
||||||
## Use ``assert`` for debugging purposes only.
|
## Use ``assert`` for debugging purposes only.
|
||||||
bind raiseAssert, InstantiationInfo
|
bind InstantiationInfo
|
||||||
when compileOption("assertions"):
|
when compileOption("assertions"):
|
||||||
{.line.}:
|
{.line.}:
|
||||||
if not cond:
|
if not cond:
|
||||||
|
|
@ -2191,11 +2191,33 @@ template assert*(cond: bool, msg = "") =
|
||||||
template doAssert*(cond: bool, msg = "") =
|
template doAssert*(cond: bool, msg = "") =
|
||||||
## same as `assert` but is always turned on and not affected by the
|
## same as `assert` but is always turned on and not affected by the
|
||||||
## ``--assertions`` command line switch.
|
## ``--assertions`` command line switch.
|
||||||
bind raiseAssert, InstantiationInfo
|
bind InstantiationInfo
|
||||||
{.line: InstantiationInfo().}:
|
{.line: InstantiationInfo().}:
|
||||||
if not cond:
|
if not cond:
|
||||||
raiseAssert(astToStr(cond) & ' ' & msg)
|
raiseAssert(astToStr(cond) & ' ' & msg)
|
||||||
|
|
||||||
|
template onFailedAssert*(msg: expr, code: stmt): stmt =
|
||||||
|
## Sets an assertion failure handler that will intercept any assert statements
|
||||||
|
## following `onFailedAssert` in the current lexical scope.
|
||||||
|
## Can be defined multiple times in a single function.
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
##
|
||||||
|
## proc example(x: int): TErrorCode =
|
||||||
|
## onFailedAssert(msg):
|
||||||
|
## log msg
|
||||||
|
## return E_FAIL
|
||||||
|
##
|
||||||
|
## assert(...)
|
||||||
|
##
|
||||||
|
## onFailedAssert(msg):
|
||||||
|
## raise newException(EMyException, msg)
|
||||||
|
##
|
||||||
|
## assert(...)
|
||||||
|
##
|
||||||
|
template raiseAssert(msgIMPL: string): stmt =
|
||||||
|
let `msg` = msgIMPL
|
||||||
|
code
|
||||||
|
|
||||||
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
||||||
## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
|
## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
|
||||||
|
|
|
||||||
34
tests/compile/ttypeclasses.nim
Normal file
34
tests/compile/ttypeclasses.nim
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
type
|
||||||
|
TFoo[T] = object
|
||||||
|
val: T
|
||||||
|
|
||||||
|
T1 = distinct expr
|
||||||
|
T2 = distinct expr
|
||||||
|
|
||||||
|
proc takesExpr(x, y) =
|
||||||
|
echo x, y
|
||||||
|
|
||||||
|
proc same(x, y: T1) =
|
||||||
|
echo x, y
|
||||||
|
|
||||||
|
proc takesFoo(x, y: TFoo) =
|
||||||
|
echo x.val, y.val
|
||||||
|
|
||||||
|
proc takes2Types(x,y: T1, z: T2) =
|
||||||
|
echo x, y, z
|
||||||
|
|
||||||
|
takesExpr(1, 2)
|
||||||
|
takesExpr(1, "xxx")
|
||||||
|
takesExpr[bool, int](true, 0)
|
||||||
|
|
||||||
|
same(1, 2)
|
||||||
|
same("test", "test")
|
||||||
|
|
||||||
|
var f: TFoo[int]
|
||||||
|
f.val = 10
|
||||||
|
|
||||||
|
takesFoo(f, f)
|
||||||
|
|
||||||
|
takes2Types(1, 1, "string")
|
||||||
|
takes2Types[string, int]("test", "test", 1)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue