mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
Restore the Nim's 0.14 proper handling of generic aliases
A more efficient implementation is possible by restoring the old lifting ot tyGenericInvocation to tyGenericInst in liftTypeParam, but this fix will suffice for now. fixes #5087 fixes #5602 fixes #5641 fixes #5570
This commit is contained in:
@@ -1346,6 +1346,9 @@ proc initIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc newIdTable*: TIdTable =
|
||||
initIdTable(result)
|
||||
|
||||
proc resetIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
# clear and set to old initial size:
|
||||
|
||||
@@ -351,8 +351,8 @@ when false:
|
||||
for i in 0 ..< n.safeLen:
|
||||
resetSemFlag(n[i])
|
||||
|
||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags): PNode =
|
||||
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
s: PSym, flags: TExprFlags): PNode =
|
||||
## Semantically check the output of a macro.
|
||||
## This involves processes such as re-checking the macro output for type
|
||||
## coherence, making sure that variables declared with 'let' aren't
|
||||
@@ -363,8 +363,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
globalError(s.info, errTemplateInstantiationTooNested)
|
||||
c.friendModules.add(s.owner.getModule)
|
||||
|
||||
result = n
|
||||
excl(n.flags, nfSem)
|
||||
result = macroResult
|
||||
excl(result.flags, nfSem)
|
||||
#resetSemFlag n
|
||||
if s.typ.sons[0] == nil:
|
||||
result = semStmt(c, result)
|
||||
@@ -378,13 +378,26 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
of tyStmt:
|
||||
result = semStmt(c, result)
|
||||
of tyTypeDesc:
|
||||
if n.kind == nkStmtList: result.kind = nkStmtListType
|
||||
if result.kind == nkStmtList: result.kind = nkStmtListType
|
||||
var typ = semTypeNode(c, result, nil)
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
#result = symNodeFromType(c, typ, n.info)
|
||||
else:
|
||||
var retType = s.typ.sons[0]
|
||||
if s.ast[genericParamsPos] != nil and retType.isMetaType:
|
||||
# The return type may depend on the Macro arguments
|
||||
# e.g. template foo(T: typedesc): seq[T]
|
||||
# We will instantiate the return type here, because
|
||||
# we now know the supplied arguments
|
||||
var paramTypes = newIdTable()
|
||||
for param, value in genericParamsInMacroCall(s, call):
|
||||
idTablePut(paramTypes, param.typ, value.typ)
|
||||
|
||||
retType = generateTypeInstance(c, paramTypes,
|
||||
macroResult.info, retType)
|
||||
|
||||
result = semExpr(c, result, flags)
|
||||
result = fitNode(c, s.typ.sons[0], result, result.info)
|
||||
result = fitNode(c, retType, result, result.info)
|
||||
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
|
||||
dec(evalTemplateCounter)
|
||||
discard c.friendModules.pop()
|
||||
@@ -409,7 +422,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
# c.evalContext = c.createEvalContext(emStatic)
|
||||
result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
|
||||
if efNoSemCheck notin flags:
|
||||
result = semAfterMacroCall(c, result, sym, flags)
|
||||
result = semAfterMacroCall(c, n, result, sym, flags)
|
||||
result = wrapInComesFrom(nOrig.info, result)
|
||||
popInfoContext()
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||
styleCheckUse(n.info, s)
|
||||
pushInfoContext(n.info)
|
||||
result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags)
|
||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
|
||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
|
||||
popInfoContext()
|
||||
|
||||
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
|
||||
@@ -36,7 +36,8 @@ proc rawPushProcCon(c: PContext, owner: PSym) =
|
||||
c.p = x
|
||||
|
||||
proc rawHandleSelf(c: PContext; owner: PSym) =
|
||||
if c.selfName != nil and owner.kind in {skProc, skMethod, skConverter, skIterator, skMacro} and owner.typ != nil:
|
||||
const callableSymbols = {skProc, skMethod, skConverter, skIterator, skMacro}
|
||||
if c.selfName != nil and owner.kind in callableSymbols and owner.typ != nil:
|
||||
let params = owner.typ.n
|
||||
if params.len > 1:
|
||||
let arg = params[1].sym
|
||||
|
||||
@@ -1177,7 +1177,8 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
var objB = t.sons[2]
|
||||
while true:
|
||||
if objB.kind == tyGenericBody: objB = objB.lastSon
|
||||
elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
|
||||
elif objB.kind in {tyGenericInvocation, tyGenericInst}:
|
||||
objB = objB.sons[0]
|
||||
else: break
|
||||
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
|
||||
if obj.assignment.isNil:
|
||||
|
||||
@@ -307,31 +307,32 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
rawAddSon(result, newbody)
|
||||
checkPartialConstructedType(cl.info, newbody)
|
||||
let dc = newbody.deepCopy
|
||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
|
||||
attachedDeepCopy, 1)
|
||||
if bodyIsNew and newbody.typeInst == nil:
|
||||
#doassert newbody.typeInst == nil
|
||||
newbody.typeInst = result
|
||||
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
|
||||
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
|
||||
# need to look into this issue later
|
||||
assert newbody.kind in {tyRef, tyPtr}
|
||||
assert newbody.lastSon.typeInst == nil
|
||||
newbody.lastSon.typeInst = result
|
||||
let asgn = newbody.assignment
|
||||
if asgn != nil and sfFromGeneric notin asgn.flags:
|
||||
# '=' needs to be instantiated for generics when the type is constructed:
|
||||
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
|
||||
attachedAsgn, 1)
|
||||
let methods = skipTypes(bbody, abstractPtrs).methods
|
||||
for col, meth in items(methods):
|
||||
# we instantiate the known methods belonging to that type, this causes
|
||||
# them to be registered and that's enough, so we 'discard' the result.
|
||||
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
|
||||
attachedAsgn, col)
|
||||
if cl.allowMetaTypes == false:
|
||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
|
||||
attachedDeepCopy, 1)
|
||||
if bodyIsNew and newbody.typeInst == nil:
|
||||
#doassert newbody.typeInst == nil
|
||||
newbody.typeInst = result
|
||||
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
|
||||
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
|
||||
# need to look into this issue later
|
||||
assert newbody.kind in {tyRef, tyPtr}
|
||||
assert newbody.lastSon.typeInst == nil
|
||||
newbody.lastSon.typeInst = result
|
||||
let asgn = newbody.assignment
|
||||
if asgn != nil and sfFromGeneric notin asgn.flags:
|
||||
# '=' needs to be instantiated for generics when the type is constructed:
|
||||
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
|
||||
attachedAsgn, 1)
|
||||
let methods = skipTypes(bbody, abstractPtrs).methods
|
||||
for col, meth in items(methods):
|
||||
# we instantiate the known methods belonging to that type, this causes
|
||||
# them to be registered and that's enough, so we 'discard' the result.
|
||||
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
|
||||
attachedAsgn, col)
|
||||
|
||||
proc eraseVoidParams*(t: PType) =
|
||||
# transform '(): void' into '()' because old parts of the compiler really
|
||||
@@ -526,6 +527,14 @@ proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||
result = replaceTypeVarsT(cl, t)
|
||||
popInfoContext()
|
||||
|
||||
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||
t: PType): PType =
|
||||
var cl = initTypeVars(p, pt, info, nil)
|
||||
cl.allowMetaTypes = true
|
||||
pushInfoContext(info)
|
||||
result = replaceTypeVarsT(cl, t)
|
||||
popInfoContext()
|
||||
|
||||
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
|
||||
t: PType): untyped =
|
||||
generateTypeInstance(p, pt, arg.info, t)
|
||||
|
||||
@@ -26,7 +26,7 @@ type
|
||||
sym*: PSym
|
||||
unmatchedVarParam*: int
|
||||
diagnostics*: seq[string]
|
||||
|
||||
|
||||
CandidateErrors* = seq[CandidateError]
|
||||
|
||||
TCandidate* = object
|
||||
@@ -68,7 +68,7 @@ type
|
||||
# future.
|
||||
mutabilityProblem*: uint8 # tyVar mismatch
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
isNone, isConvertible,
|
||||
isIntConv,
|
||||
@@ -639,7 +639,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
makeTypeDesc(c, typ)
|
||||
|
||||
typeParams.safeAdd((param, typ))
|
||||
|
||||
|
||||
addDecl(c, param)
|
||||
|
||||
for param in typeClass.n[0]:
|
||||
@@ -676,7 +676,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
flags: TExprFlags = {}
|
||||
collectDiagnostics = m.diagnostics != nil or
|
||||
sfExplain in typeClass.sym.flags
|
||||
|
||||
|
||||
if collectDiagnostics:
|
||||
oldWriteHook = writelnHook
|
||||
# XXX: we can't write to m.diagnostics directly, because
|
||||
@@ -688,13 +688,13 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
let msg = s.replace("Error:", errorPrefix)
|
||||
if oldWriteHook != nil: oldWriteHook msg
|
||||
diagnostics.add msg
|
||||
|
||||
|
||||
var checkedBody = c.semTryExpr(c, body.copyTree, flags)
|
||||
|
||||
if collectDiagnostics:
|
||||
writelnHook = oldWriteHook
|
||||
for msg in diagnostics: m.diagnostics.safeAdd msg
|
||||
|
||||
|
||||
if checkedBody == nil: return nil
|
||||
|
||||
# The inferrable type params have been identified during the semTryExpr above.
|
||||
@@ -746,7 +746,7 @@ proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
|
||||
#
|
||||
# Preconditions:
|
||||
#
|
||||
# * The input of this proc must be semantized
|
||||
# * The input of this proc must be semantized
|
||||
# - all templates should be expanded
|
||||
# - aby constant folding possible should already be performed
|
||||
#
|
||||
@@ -769,13 +769,13 @@ proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
|
||||
return inferStaticParam(lhs[2], rhs - lhs[1].intVal)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs - lhs[2].intVal)
|
||||
|
||||
|
||||
of mDec, mSubI, mSubU, mPred:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[2], lhs[1].intVal - rhs)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs + lhs[2].intVal)
|
||||
|
||||
|
||||
of mMulI, mMulU:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
if rhs mod lhs[1].intVal == 0:
|
||||
@@ -783,34 +783,34 @@ proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
if rhs mod lhs[2].intVal == 0:
|
||||
return inferStaticParam(lhs[1], rhs div lhs[2].intVal)
|
||||
|
||||
|
||||
of mDivI, mDivU:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
if lhs[1].intVal mod rhs == 0:
|
||||
return inferStaticParam(lhs[2], lhs[1].intVal div rhs)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], lhs[2].intVal * rhs)
|
||||
|
||||
|
||||
of mShlI:
|
||||
if lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs shr lhs[2].intVal)
|
||||
|
||||
|
||||
of mShrI:
|
||||
if lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs shl lhs[2].intVal)
|
||||
|
||||
|
||||
of mUnaryMinusI:
|
||||
return inferStaticParam(lhs[1], -rhs)
|
||||
|
||||
|
||||
of mUnaryPlusI, mToInt, mToBiggestInt:
|
||||
return inferStaticParam(lhs[1], rhs)
|
||||
|
||||
|
||||
else: discard
|
||||
|
||||
|
||||
elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil:
|
||||
lhs.typ.n = newIntNode(nkIntLit, rhs)
|
||||
return lhs.typ
|
||||
|
||||
|
||||
return nil
|
||||
|
||||
proc failureToInferStaticParam(n: PNode) =
|
||||
@@ -825,7 +825,7 @@ proc inferStaticsInRange(c: var TCandidate,
|
||||
allowUnresolved = true)
|
||||
let upperBound = tryResolvingStaticExpr(c, inferred.n[1],
|
||||
allowUnresolved = true)
|
||||
|
||||
|
||||
template doInferStatic(c: var TCandidate, e: PNode, r: BiggestInt) =
|
||||
var exp = e
|
||||
var rhs = r
|
||||
@@ -1049,7 +1049,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
result = typeRel(c, f.sons[1].skipTypes({tyTypeDesc}),
|
||||
a.sons[1].skipTypes({tyTypeDesc}))
|
||||
if result < isGeneric: return isNone
|
||||
|
||||
|
||||
if fRange.rangeHasUnresolvedStatic:
|
||||
return inferStaticsInRange(c, fRange, a)
|
||||
elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
|
||||
@@ -1204,9 +1204,49 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
of tyEmpty, tyVoid:
|
||||
if a.kind == f.kind: result = isEqual
|
||||
|
||||
of tyGenericInst, tyAlias:
|
||||
of tyAlias:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
|
||||
of tyGenericInst:
|
||||
var prev = PType(idTableGet(c.bindings, f))
|
||||
var f = if prev == nil: f else: prev
|
||||
|
||||
let roota = a.skipGenericAlias
|
||||
let rootf = f.skipGenericAlias
|
||||
|
||||
var m = c
|
||||
if a.kind == tyGenericInst:
|
||||
if roota.base == rootf.base:
|
||||
for i in 1 .. rootf.sonsLen-2:
|
||||
let ff = rootf.sons[i]
|
||||
let aa = roota.sons[i]
|
||||
result = typeRel(c, ff, aa)
|
||||
if result notin {isEqual, isGeneric}: return isNone
|
||||
# if ff.kind == tyRange and result != isEqual: return isNone
|
||||
|
||||
if prev == nil: put(c, f, a)
|
||||
result = isGeneric
|
||||
else:
|
||||
var aAsObject = roota.lastSon
|
||||
if rootf.lastSon.kind in {tyAnd, tyOr}:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
if result != isNone: put(c, f, a)
|
||||
return
|
||||
|
||||
if rootf.lastSon.kind == tyRef and aAsObject.kind == tyRef:
|
||||
aAsObject = aAsObject.base
|
||||
|
||||
if aAsObject.kind == tyObject:
|
||||
let baseType = aAsObject.base
|
||||
if baseType != nil:
|
||||
c.inheritancePenalty += 1
|
||||
return typeRel(c, f, baseType)
|
||||
|
||||
result = isNone
|
||||
else:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
if result != isNone: put(c, f, a)
|
||||
|
||||
of tyGenericBody:
|
||||
considerPreviousT:
|
||||
if a.kind == tyGenericInst and a.sons[0] == f:
|
||||
@@ -1217,6 +1257,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
|
||||
of tyGenericInvocation:
|
||||
var x = a.skipGenericAlias
|
||||
|
||||
# XXX: This is very hacky. It should be moved back into liftTypeParam
|
||||
if x.kind == tyGenericInst and c.calleeSym != nil and c.calleeSym.kind == skProc:
|
||||
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
|
||||
return typeRel(c, inst, a)
|
||||
|
||||
var depth = 0
|
||||
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
|
||||
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
||||
@@ -2086,6 +2132,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
|
||||
return nil
|
||||
var f = dc.typ.sons[col]
|
||||
|
||||
if op == attachedDeepCopy:
|
||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||
else:
|
||||
|
||||
@@ -1606,6 +1606,12 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||
n.typ = x.typ
|
||||
result.node = n
|
||||
|
||||
iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
|
||||
let gp = macroSym.ast[genericParamsPos]
|
||||
for i in 0 .. <gp.len:
|
||||
let idx = macroSym.typ.len + i
|
||||
yield (gp[i].sym, call.sons[idx])
|
||||
|
||||
var evalMacroCounter: int
|
||||
|
||||
proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
|
||||
|
||||
27
tests/generics/t5570.nim
Normal file
27
tests/generics/t5570.nim
Normal file
@@ -0,0 +1,27 @@
|
||||
discard """
|
||||
nimout: "type uint32\ntype uint32"
|
||||
output: "(weight: 17.0, color: 100)"
|
||||
"""
|
||||
|
||||
import macros
|
||||
|
||||
type
|
||||
BaseFruit[T] = object of RootObj
|
||||
color: T
|
||||
|
||||
Banana[T] = object of BaseFruit[uint32]
|
||||
weight: T
|
||||
|
||||
macro printTypeName(typ: typed): untyped =
|
||||
echo "type ", getType(typ).repr
|
||||
|
||||
proc setColor[K](self: var BaseFruit[K], c: int) =
|
||||
printTypeName(self.color)
|
||||
self.color = uint32(c)
|
||||
|
||||
var x: Banana[float64]
|
||||
x.weight = 17
|
||||
printTypeName(x.color)
|
||||
x.setColor(100)
|
||||
echo x
|
||||
|
||||
18
tests/generics/t5602_inheritence.nim
Normal file
18
tests/generics/t5602_inheritence.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
discard """
|
||||
output: "seq[float]\n0"
|
||||
"""
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/5602
|
||||
|
||||
import typetraits
|
||||
|
||||
type
|
||||
Foo[T] = object of RootObj
|
||||
Bar[T] = object of Foo[seq[T]]
|
||||
|
||||
proc p[T](f: Foo[T]): T =
|
||||
echo T.name
|
||||
|
||||
var s: Bar[float]
|
||||
echo p(s).len # the bug was: p(s) should return seq[float], but returns float instead
|
||||
|
||||
28
tests/generics/tmapping_generic_alias.nim
Normal file
28
tests/generics/tmapping_generic_alias.nim
Normal file
@@ -0,0 +1,28 @@
|
||||
discard """
|
||||
output: '''type(c) = GenAlias[system.int]
|
||||
T = int
|
||||
seq[int]
|
||||
'''
|
||||
"""
|
||||
|
||||
import typetraits
|
||||
|
||||
type
|
||||
Gen[T] = object
|
||||
x: T
|
||||
|
||||
GenAlias[T] = Gen[seq[T]]
|
||||
|
||||
proc f1[T](x: Gen[T]) =
|
||||
echo T.name
|
||||
|
||||
proc f2[T](x: GenAlias[T]) =
|
||||
echo "type(c) = ", type(x).name
|
||||
echo "T = ", T.name
|
||||
f1 x
|
||||
|
||||
let
|
||||
y = Gen[seq[int]](x: @[10])
|
||||
|
||||
f2 y
|
||||
|
||||
28
tests/generics/tparam_binding.nim
Normal file
28
tests/generics/tparam_binding.nim
Normal file
@@ -0,0 +1,28 @@
|
||||
discard """
|
||||
errormsg: "got (ref Matrix[2, 2, system.float], ref Matrix[2, 1, system.float])"
|
||||
line: 27
|
||||
"""
|
||||
|
||||
type
|
||||
Matrix[M,N: static[int]; T: SomeReal] = distinct array[0..(M*N - 1), T]
|
||||
|
||||
let a = new Matrix[2,2,float]
|
||||
let b = new Matrix[2,1,float]
|
||||
|
||||
proc foo[M,N: static[int],T](a: ref Matrix[M, N, T], b: ref Matrix[M, N, T])=
|
||||
discard
|
||||
|
||||
foo(a, a)
|
||||
|
||||
proc bar[M,N: static[int],T](a: ref Matrix[M, M, T], b: ref Matrix[M, N, T])=
|
||||
discard
|
||||
|
||||
bar(a, b)
|
||||
bar(a, a)
|
||||
|
||||
proc baz[M,N: static[int],T](a: ref Matrix[N, N, T], b: ref Matrix[M, N, T])=
|
||||
discard
|
||||
|
||||
baz(a, a)
|
||||
baz(a, b)
|
||||
|
||||
Reference in New Issue
Block a user