support the full range of type modifiers when declaring concept vars and testing proc signatures
This commit is contained in:
parent
0a9a878bd3
commit
815724db71
6 changed files with 100 additions and 44 deletions
|
|
@ -235,6 +235,13 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||||
of nkStmtList, nkStmtListExpr:
|
of nkStmtList, nkStmtListExpr:
|
||||||
if n.typ != nil:
|
if n.typ != nil:
|
||||||
result = isAssignable(owner, n.lastSon, isUnsafeAddr)
|
result = isAssignable(owner, n.lastSon, isUnsafeAddr)
|
||||||
|
of nkVarTy:
|
||||||
|
# XXX: The fact that this is here is a bit of a hack.
|
||||||
|
# The goal is to allow the use of checks such as "foo(var T)"
|
||||||
|
# within concepts. Semantically, it's not correct to say that
|
||||||
|
# nkVarTy denotes an lvalue, but the example above is the only
|
||||||
|
# possible code which will get us here
|
||||||
|
result = arLValue
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1793,8 +1793,16 @@ proc parseObject(p: var TParser): PNode =
|
||||||
addSon(result, parseObjectPart(p))
|
addSon(result, parseObjectPart(p))
|
||||||
|
|
||||||
proc parseTypeClassParam(p: var TParser): PNode =
|
proc parseTypeClassParam(p: var TParser): PNode =
|
||||||
if p.tok.tokType in {tkOut, tkVar}:
|
let modifier = case p.tok.tokType
|
||||||
result = newNodeP(nkVarTy, p)
|
of tkOut, tkVar: nkVarTy
|
||||||
|
of tkPtr: nkPtrTy
|
||||||
|
of tkRef: nkRefTy
|
||||||
|
of tkStatic: nkStaticTy
|
||||||
|
of tkType: nkTypeOfExpr
|
||||||
|
else: nkEmpty
|
||||||
|
|
||||||
|
if modifier != nkEmpty:
|
||||||
|
result = newNodeP(modifier, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
result.addSon(p.parseSymbol)
|
result.addSon(p.parseSymbol)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,17 @@ proc makePtrType*(c: PContext, baseType: PType): PType =
|
||||||
result = newTypeS(tyPtr, c)
|
result = newTypeS(tyPtr, c)
|
||||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||||
|
|
||||||
|
proc makeTypeWithModifier*(c: PContext,
|
||||||
|
modifier: TTypeKind,
|
||||||
|
baseType: PType): PType =
|
||||||
|
assert modifier in {tyVar, tyPtr, tyRef, tyStatic, tyTypeDesc}
|
||||||
|
|
||||||
|
if modifier in {tyVar, tyTypeDesc} and baseType.kind == modifier:
|
||||||
|
result = baseType
|
||||||
|
else:
|
||||||
|
result = newTypeS(modifier, c)
|
||||||
|
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||||
|
|
||||||
proc makeVarType*(c: PContext, baseType: PType): PType =
|
proc makeVarType*(c: PContext, baseType: PType): PType =
|
||||||
if baseType.kind == tyVar:
|
if baseType.kind == tyVar:
|
||||||
result = baseType
|
result = baseType
|
||||||
|
|
@ -238,8 +249,11 @@ proc makeVarType*(c: PContext, baseType: PType): PType =
|
||||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||||
|
|
||||||
proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||||
result = newTypeS(tyTypeDesc, c)
|
if typ.kind == tyTypeDesc:
|
||||||
result.addSonSkipIntLit(typ.assertNotNil)
|
result = typ
|
||||||
|
else:
|
||||||
|
result = newTypeS(tyTypeDesc, c)
|
||||||
|
result.addSonSkipIntLit(typ.assertNotNil)
|
||||||
|
|
||||||
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
|
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
|
||||||
let typedesc = makeTypeDesc(c, typ)
|
let typedesc = makeTypeDesc(c, typ)
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||||
let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
|
let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
|
||||||
let n = if n[0].kind == nkBracket: n[0] else: n
|
let n = if n[0].kind == nkBracket: n[0] else: n
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
var base = semTypeNode(c, n.lastSon, nil)
|
var base = semTypeNode(c, n.lastSon, nil).skipTypes({tyTypeDesc})
|
||||||
result = newOrPrevType(kind, prev, c)
|
result = newOrPrevType(kind, prev, c)
|
||||||
var isNilable = false
|
var isNilable = false
|
||||||
# check every except the last is an object:
|
# check every except the last is an object:
|
||||||
|
|
@ -155,7 +155,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if sonsLen(n) == 1:
|
if sonsLen(n) == 1:
|
||||||
result = newOrPrevType(tyVar, prev, c)
|
result = newOrPrevType(tyVar, prev, c)
|
||||||
var base = semTypeNode(c, n.sons[0], nil)
|
var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
|
||||||
if base.kind == tyVar:
|
if base.kind == tyVar:
|
||||||
localError(n.info, errVarVarTypeNotAllowed)
|
localError(n.info, errVarVarTypeNotAllowed)
|
||||||
base = base.sons[0]
|
base = base.sons[0]
|
||||||
|
|
@ -1404,7 +1404,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkDistinctTy: result = semDistinct(c, n, prev)
|
of nkDistinctTy: result = semDistinct(c, n, prev)
|
||||||
of nkStaticTy:
|
of nkStaticTy:
|
||||||
result = newOrPrevType(tyStatic, prev, c)
|
result = newOrPrevType(tyStatic, prev, c)
|
||||||
var base = semTypeNode(c, n.sons[0], nil)
|
var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
|
||||||
result.rawAddSon(base)
|
result.rawAddSon(base)
|
||||||
result.flags.incl tfHasStatic
|
result.flags.incl tfHasStatic
|
||||||
of nkIteratorTy:
|
of nkIteratorTy:
|
||||||
|
|
|
||||||
|
|
@ -622,17 +622,27 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
dummyName: PNode
|
dummyName: PNode
|
||||||
dummyType: PType
|
dummyType: PType
|
||||||
|
|
||||||
if param.kind == nkVarTy:
|
let modifier = case param.kind
|
||||||
|
of nkVarTy: tyVar
|
||||||
|
of nkRefTy: tyRef
|
||||||
|
of nkPtrTy: tyPtr
|
||||||
|
of nkStaticTy: tyStatic
|
||||||
|
of nkTypeOfExpr: tyTypeDesc
|
||||||
|
else: tyNone
|
||||||
|
|
||||||
|
if modifier != tyNone:
|
||||||
dummyName = param[0]
|
dummyName = param[0]
|
||||||
dummyType = if a.kind != tyVar: makeVarType(c, a) else: a
|
dummyType = c.makeTypeWithModifier(modifier, a)
|
||||||
else:
|
else:
|
||||||
dummyName = param
|
dummyName = param
|
||||||
dummyType = a
|
dummyType = a
|
||||||
|
|
||||||
internalAssert dummyName.kind == nkIdent
|
internalAssert dummyName.kind == nkIdent
|
||||||
var dummyParam = newSym(skVar, dummyName.ident, body.sym, body.sym.info)
|
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
|
||||||
|
dummyName.ident, body.sym, body.sym.info)
|
||||||
dummyParam.typ = dummyType
|
dummyParam.typ = dummyType
|
||||||
addDecl(c, dummyParam)
|
addDecl(c, dummyParam)
|
||||||
|
|
||||||
#echo "B ", dummyName.ident.s, " ", typeToString(dummyType), " ", dummyparam.kind
|
#echo "B ", dummyName.ident.s, " ", typeToString(dummyType), " ", dummyparam.kind
|
||||||
|
|
||||||
var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
|
var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
|
||||||
|
|
@ -1411,12 +1421,12 @@ proc inferTypeClassParam*(m: var TCandidate, f, a: PType): bool =
|
||||||
if inferrableType == nil: return false
|
if inferrableType == nil: return false
|
||||||
|
|
||||||
var inferAs = f
|
var inferAs = f
|
||||||
|
|
||||||
case f.kind
|
case f.kind
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
var prev = PType(idTableGet(m.bindings, f))
|
var prev = PType(idTableGet(m.bindings, f))
|
||||||
if prev != nil: inferAs = prev
|
if prev != nil: inferAs = prev
|
||||||
|
|
||||||
of tyFromExpr:
|
of tyFromExpr:
|
||||||
let computedType = tryResolvingStaticExpr(m, f.n).typ
|
let computedType = tryResolvingStaticExpr(m, f.n).typ
|
||||||
case computedType.kind
|
case computedType.kind
|
||||||
|
|
@ -1426,10 +1436,10 @@ proc inferTypeClassParam*(m: var TCandidate, f, a: PType): bool =
|
||||||
inferAs = computedType
|
inferAs = computedType
|
||||||
else:
|
else:
|
||||||
localError(f.n.info, errTypeExpected)
|
localError(f.n.info, errTypeExpected)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
inferrableType.assignType inferAs
|
inferrableType.assignType inferAs
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
@ -1470,7 +1480,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
argType = arg.typ
|
argType = arg.typ
|
||||||
|
|
||||||
var
|
var
|
||||||
useTypeLoweringRuleInTypeClass = c.inTypeClass > 0 and
|
useTypeLoweringRuleInTypeClass = argType != nil and
|
||||||
|
c.inTypeClass > 0 and
|
||||||
not m.isNoCall and
|
not m.isNoCall and
|
||||||
f.kind != tyTypeDesc
|
f.kind != tyTypeDesc
|
||||||
|
|
||||||
|
|
@ -1478,9 +1489,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
argType.skipTypes({tyTypeDesc, tyFieldAccessor})
|
argType.skipTypes({tyTypeDesc, tyFieldAccessor})
|
||||||
else:
|
else:
|
||||||
argType
|
argType
|
||||||
|
|
||||||
r = typeRel(m, f, a)
|
r = typeRel(m, f, a)
|
||||||
|
|
||||||
if r != isNone and m.calleeSym != nil and
|
if r != isNone and m.calleeSym != nil and
|
||||||
m.calleeSym.kind in {skMacro, skTemplate}:
|
m.calleeSym.kind in {skMacro, skTemplate}:
|
||||||
# XXX: duplicating this is ugly, but we cannot (!) move this
|
# XXX: duplicating this is ugly, but we cannot (!) move this
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,13 @@ discard """
|
||||||
output: '''Sortable
|
output: '''Sortable
|
||||||
Sortable
|
Sortable
|
||||||
Container
|
Container
|
||||||
true
|
|
||||||
true
|
|
||||||
false
|
|
||||||
false
|
|
||||||
false
|
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import typetraits
|
import typetraits
|
||||||
|
|
||||||
|
template reject(expr) = assert(not compiles(x))
|
||||||
|
|
||||||
type
|
type
|
||||||
TObj = object
|
TObj = object
|
||||||
x: int
|
x: int
|
||||||
|
|
@ -36,33 +33,52 @@ foo(@[TObj(x: 10), TObj(x: 20)])
|
||||||
|
|
||||||
proc intval(x: int): int = 10
|
proc intval(x: int): int = 10
|
||||||
|
|
||||||
# check real and virtual fields
|
|
||||||
type
|
type
|
||||||
TFoo = concept T
|
TFoo = concept o, type T, ref r, var v, ptr p, static s
|
||||||
T.x
|
o.x
|
||||||
y(T)
|
y(o) is int
|
||||||
|
|
||||||
|
var str: string
|
||||||
|
var intref: ref int
|
||||||
|
|
||||||
|
refproc(ref T, ref int)
|
||||||
|
varproc(var T)
|
||||||
|
ptrproc(ptr T, str)
|
||||||
|
|
||||||
|
staticproc(static[T])
|
||||||
|
|
||||||
|
typeproc o.type
|
||||||
|
o.type.typeproc
|
||||||
|
|
||||||
|
refproc(r, intref)
|
||||||
|
varproc(v)
|
||||||
|
p.ptrproc(string)
|
||||||
|
staticproc s
|
||||||
|
typeproc(T)
|
||||||
|
|
||||||
|
const TypeName = T.name
|
||||||
|
type MappedType = type(T.y)
|
||||||
|
|
||||||
intval T.y
|
intval T.y
|
||||||
let z = intval(T.y)
|
let z = intval(o.y)
|
||||||
|
|
||||||
|
static:
|
||||||
|
assert T.name.len == 4
|
||||||
|
reject o.name
|
||||||
|
reject o.typeproc
|
||||||
|
reject staticproc(o)
|
||||||
|
reject o.varproc
|
||||||
|
reject T.staticproc
|
||||||
|
reject p.staticproc
|
||||||
|
|
||||||
proc y(x: TObj): int = 10
|
proc y(x: TObj): int = 10
|
||||||
|
|
||||||
|
proc varproc(x: var TObj) = discard
|
||||||
|
proc refproc(x: ref TObj, y: ref int) = discard
|
||||||
|
proc ptrproc(x: ptr TObj, y: string) = discard
|
||||||
|
proc staticproc(x: static[TObj]) = discard
|
||||||
|
proc typeproc(t: type TObj) = discard
|
||||||
|
|
||||||
proc testFoo(x: TFoo) = discard
|
proc testFoo(x: TFoo) = discard
|
||||||
testFoo(TObj(x: 10))
|
testFoo(TObj(x: 10))
|
||||||
|
|
||||||
type
|
|
||||||
Matrix[Rows, Cols: static[int]; T] = concept M
|
|
||||||
M.M == Rows
|
|
||||||
M.N == Cols
|
|
||||||
M.T is T
|
|
||||||
|
|
||||||
MyMatrix[M, N: static[int]; T] = object
|
|
||||||
data: array[M*N, T]
|
|
||||||
|
|
||||||
var x: MyMatrix[3, 3, int]
|
|
||||||
|
|
||||||
echo x is Matrix
|
|
||||||
echo x is Matrix[3, 3, int]
|
|
||||||
echo x is Matrix[3, 3, float]
|
|
||||||
echo x is Matrix[4, 3, int]
|
|
||||||
echo x is Matrix[3, 4, int]
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue