static params: expr[T] is now static[T]

This introduces tyStatic and successfully bootstraps and handles
few simple test cases.  Static params within macros are no longer
treated as PNimrodNodes - they are now equivalent to constants
of the designated type.
This commit is contained in:
Zahary Karadjov 2013-12-19 01:06:38 +02:00
commit 027f30610e
22 changed files with 135 additions and 110 deletions

View file

@ -192,6 +192,7 @@ type
nkObjectTy, # object body nkObjectTy, # object body
nkTupleTy, # tuple body nkTupleTy, # tuple body
nkTypeClassTy, # user-defined type class nkTypeClassTy, # user-defined type class
nkStaticTy, # ``static[T]``
nkRecList, # list of object parts nkRecList, # list of object parts
nkRecCase, # case section of object nkRecCase, # case section of object
nkRecWhen, # when section of object nkRecWhen, # when section of object
@ -336,12 +337,13 @@ type
tyIter, # unused tyIter, # unused
tyProxy # used as errornous type (for idetools) tyProxy # used as errornous type (for idetools)
tyTypeClass tyTypeClass
tyParametricTypeClass # structured similarly to tyGenericInst
# lastSon is the body of the type class
tyAnd tyAnd
tyOr tyOr
tyNot tyNot
tyAnything tyAnything
tyParametricTypeClass # structured similarly to tyGenericInst tyStatic
# lastSon is the body of the type class
const const
tyPureObject* = tyTuple tyPureObject* = tyTuple
@ -1232,7 +1234,7 @@ proc propagateToOwner*(owner, elem: PType) =
if tfShared in elem.flags: if tfShared in elem.flags:
owner.flags.incl tfHasShared owner.flags.incl tfHasShared
if elem.kind in {tyExpr, tyTypeDesc}: if elem.kind in {tyExpr, tyStatic, tyTypeDesc}:
owner.flags.incl tfHasMeta owner.flags.incl tfHasMeta
elif elem.kind in {tyString, tyRef, tySequence} or elif elem.kind in {tyString, tyRef, tySequence} or
elem.kind == tyProc and elem.callConv == ccClosure: elem.kind == tyProc and elem.callConv == ccClosure:

View file

@ -88,7 +88,7 @@ proc GetUniqueType*(key: PType): PType =
result = key result = key
of tyTypeDesc, tyTypeClasses: of tyTypeDesc, tyTypeClasses:
InternalError("value expected, but got a type") InternalError("value expected, but got a type")
of tyGenericParam: of tyGenericParam, tyStatic:
InternalError("GetUniqueType") InternalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter: of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
result = GetUniqueType(lastSon(key)) result = GetUniqueType(lastSon(key))

View file

@ -194,7 +194,7 @@ when compileTimeRopeFmt:
if i - 1 >= start: if i - 1 >= start:
yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0) yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0)
macro rfmt(m: BModule, fmt: expr[string], args: varargs[PRope]): expr = macro rfmt(m: BModule, fmt: static[string], args: varargs[PRope]): expr =
## Experimental optimized rope-formatting operator ## Experimental optimized rope-formatting operator
## The run-time code it produces will be very fast, but will it speed up ## The run-time code it produces will be very fast, but will it speed up
## the compilation of nimrod itself or will the macro execution time ## the compilation of nimrod itself or will the macro execution time
@ -209,7 +209,7 @@ when compileTimeRopeFmt:
of ffParam: of ffParam:
result.add(args[frag.intValue]) result.add(args[frag.intValue])
else: else:
template rfmt(m: BModule, fmt: expr[string], args: varargs[PRope]): expr = template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
ropecg(m, fmt, args) ropecg(m, fmt, args)
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr, proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,

View file

@ -78,7 +78,7 @@ proc mapType(t: ast.PType): ptr libffi.TType =
of tyFloat, tyFloat64: result = addr libffi.type_double of tyFloat, tyFloat64: result = addr libffi.type_double
of tyFloat32: result = addr libffi.type_float of tyFloat32: result = addr libffi.type_float
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr, of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyNil: tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyStatic, tyNil:
result = addr libffi.type_pointer result = addr libffi.type_pointer
of tyDistinct: of tyDistinct:
result = mapType(t.sons[0]) result = mapType(t.sons[0])

View file

@ -91,6 +91,7 @@ proc evalMacroCall*(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode = proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
if defined(debug): writeStackTrace()
result = newNodeI(nkExceptBranch, info) result = newNodeI(nkExceptBranch, info)
# creating a nkExceptBranch without sons # creating a nkExceptBranch without sons
# means that it could not be evaluated # means that it could not be evaluated
@ -263,8 +264,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
result = newNodeIT(nkUIntLit, info, t) result = newNodeIT(nkUIntLit, info, t)
of tyFloat..tyFloat128: of tyFloat..tyFloat128:
result = newNodeIt(nkFloatLit, info, t) result = newNodeIt(nkFloatLit, info, t)
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr, of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyProc: tyStmt, tyTypeDesc, tyStatic, tyProc:
result = newNodeIT(nkNilLit, info, t) result = newNodeIT(nkNilLit, info, t)
of tyObject: of tyObject:
result = newNodeIT(nkPar, info, t) result = newNodeIT(nkPar, info, t)
@ -358,7 +359,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
proc aliasNeeded(n: PNode, flags: TEvalFlags): bool = proc aliasNeeded(n: PNode, flags: TEvalFlags): bool =
result = efLValue in flags or n.typ == nil or result = efLValue in flags or n.typ == nil or
n.typ.kind in {tyExpr, tyStmt, tyTypeDesc} n.typ.kind in {tyExpr, tyStatic, tyStmt, tyTypeDesc}
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode = proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
# We need to return a node to the actual value, # We need to return a node to the actual value,

View file

@ -130,7 +130,7 @@ proc mapType(typ: PType): TJSTypeKind =
result = etyObject result = etyObject
of tyNil: result = etyNull of tyNil: result = etyNull
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone, of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone,
tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc, tyTypeClasses: tyForward, tyEmpty, tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
result = etyNone result = etyNone
of tyProc: result = etyProc of tyProc: result = etyProc
of tyCString: result = etyString of tyCString: result = etyString

View file

@ -965,14 +965,18 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
of tkTuple: result = parseTuple(p, mode == pmTypeDef) of tkTuple: result = parseTuple(p, mode == pmTypeDef)
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}) of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
of tkIterator: of tkIterator:
if mode in {pmTypeDesc, pmTypeDef}: when true:
result = parseProcExpr(p, false) if mode in {pmTypeDesc, pmTypeDef}:
result.kind = nkIteratorTy result = parseProcExpr(p, false)
result.kind = nkIteratorTy
else:
# no anon iterators for now:
parMessage(p, errExprExpected, p.tok)
getTok(p) # we must consume a token here to prevend endless loops!
result = ast.emptyNode
else: else:
# no anon iterators for now: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
parMessage(p, errExprExpected, p.tok) result.kind = nkIteratorTy
getTok(p) # we must consume a token here to prevend endless loops!
result = ast.emptyNode
of tkEnum: of tkEnum:
if mode == pmTypeDef: if mode == pmTypeDef:
result = parseEnum(p) result = parseEnum(p)
@ -995,9 +999,13 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
getTokNoInd(p) getTokNoInd(p)
addSon(result, primary(p, pmNormal)) addSon(result, primary(p, pmNormal))
of tkStatic: of tkStatic:
result = newNodeP(nkStaticExpr, p) let info = parLineInfo(p)
getTokNoInd(p) getTokNoInd(p)
addSon(result, primary(p, pmNormal)) let next = primary(p, pmNormal)
if next.kind == nkBracket and next.sonsLen == 1:
result = newNode(nkStaticTy, info, @[next.sons[0]])
else:
result = newNode(nkStaticExpr, info, @[next])
of tkBind: of tkBind:
result = newNodeP(nkBind, p) result = newNodeP(nkBind, p)
getTok(p) getTok(p)

View file

@ -282,13 +282,16 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
app(result, substr(frmt, start, i - 1)) app(result, substr(frmt, start, i - 1))
assert(RopeInvariant(result)) assert(RopeInvariant(result))
{.push stack_trace: off, line_trace: off.} when true:
proc `~`*(r: expr[string]): PRope = template `~`*(r: string): PRope = r.ropef
# this is the new optimized "to rope" operator else:
# the mnemonic is that `~` looks a bit like a rope :) {.push stack_trace: off, line_trace: off.}
var r {.global.} = r.ropef proc `~`*(r: static[string]): PRope =
return r # this is the new optimized "to rope" operator
{.pop.} # the mnemonic is that `~` looks a bit like a rope :)
var r {.global.} = r.ropef
return r
{.pop.}
proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) = proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
app(c, ropef(frmt, args)) app(c, ropef(frmt, args))

View file

@ -102,7 +102,7 @@ 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 a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags: if sfGlobal in s.flags:
incl(c.p.owner.flags, sfSideEffect) incl(c.p.owner.flags, sfSideEffect)
elif s.kind == skParam and s.typ.kind == tyExpr and s.typ.n != nil: elif s.kind == skParam and s.typ.kind == tyStatic and s.typ.n != nil:
# XXX see the hack in sigmatch.nim ... # XXX see the hack in sigmatch.nim ...
return s.typ.n return s.typ.n
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
@ -111,7 +111,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
# var len = 0 # but won't be called # var len = 0 # but won't be called
# genericThatUsesLen(x) # marked as taking a closure? # genericThatUsesLen(x) # marked as taking a closure?
of skGenericParam: of skGenericParam:
if s.typ.kind == tyExpr: if s.typ.kind == tyStatic:
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
result.typ = s.typ result.typ = s.typ
elif s.ast != nil: elif s.ast != nil:
@ -668,6 +668,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
else: else:
result = semOverloadedCall(c, n, nOrig, result = semOverloadedCall(c, n, nOrig,
{skProc, skMethod, skConverter, skMacro, skTemplate}) {skProc, skMethod, skConverter, skMacro, skTemplate})
if result != nil: if result != nil:
if result.sons[0].kind != nkSym: if result.sons[0].kind != nkSym:
InternalError("semOverloadedCallAnalyseEffects") InternalError("semOverloadedCallAnalyseEffects")
@ -937,7 +938,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
let tParam = tbody.sons[s] let tParam = tbody.sons[s]
if tParam.sym.name == i: if tParam.sym.name == i:
let rawTyp = ty.sons[s + 1] let rawTyp = ty.sons[s + 1]
if rawTyp.kind == tyExpr: if rawTyp.kind == tyStatic:
return rawTyp.n return rawTyp.n
else: else:
let foundTyp = makeTypeDesc(c, rawTyp) let foundTyp = makeTypeDesc(c, rawTyp)
@ -1882,7 +1883,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkBind: of nkBind:
Message(n.info, warnDeprecated, "bind") Message(n.info, warnDeprecated, "bind")
result = semExpr(c, n.sons[0], flags) result = semExpr(c, n.sons[0], flags)
of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy: of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy, nkStaticTy:
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc}) var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
result.typ = makeTypeDesc(c, typ) result.typ = makeTypeDesc(c, typ)
#result = symNodeFromType(c, typ, n.info) #result = symNodeFromType(c, typ, n.info)

View file

@ -587,7 +587,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of skType: of skType:
result = newSymNodeTypeDesc(s, n.info) result = newSymNodeTypeDesc(s, n.info)
of skGenericParam: of skGenericParam:
if s.typ.kind == tyExpr: if s.typ.kind == tyStatic:
result = s.typ.n result = s.typ.n
result.typ = s.typ.sons[0] result.typ = s.typ.sons[0]
else: else:

View file

@ -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, tyExpr}+tyTypeClasses: if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses:
continue continue
var s = newSym(skType, q.name, getCurrOwner(), q.info) var s = newSym(skType, q.name, getCurrOwner(), q.info)
s.flags = s.flags + {sfUsed, sfFromGeneric} s.flags = s.flags + {sfUsed, sfFromGeneric}
@ -145,11 +145,11 @@ proc lateInstantiateGeneric(c: PContext, invocation: PType, info: TLineInfo): PT
pushInfoContext(info) pushInfoContext(info)
for i in 0 .. <s.typ.n.sons.len: for i in 0 .. <s.typ.n.sons.len:
let genericParam = s.typ.n[i].sym let genericParam = s.typ.n[i].sym
let symKind = if genericParam.typ.kind == tyExpr: skConst let symKind = if genericParam.typ.kind == tyStatic: skConst
else: skType else: skType
var boundSym = newSym(symKind, s.typ.n[i].sym.name, s, info) var boundSym = newSym(symKind, s.typ.n[i].sym.name, s, info)
boundSym.typ = invocation.sons[i+1].skipTypes({tyExpr}) boundSym.typ = invocation.sons[i+1].skipTypes({tyStatic})
boundSym.ast = invocation.sons[i+1].n boundSym.ast = invocation.sons[i+1].n
addDecl(c, boundSym) addDecl(c, boundSym)
# XXX: copyTree would have been unnecessary here if semTypeNode # XXX: copyTree would have been unnecessary here if semTypeNode
@ -200,7 +200,7 @@ proc fixupProcType(c: PContext, genericType: PType,
result = inst.concreteTypes[genericType.sym.position] result = inst.concreteTypes[genericType.sym.position]
if tfUnresolved in genericType.flags: if tfUnresolved in genericType.flags:
result = result.sons[0] result = result.sons[0]
of tyExpr: of tyStatic:
result = inst.concreteTypes[genericType.sym.position] result = inst.concreteTypes[genericType.sym.position]
of tyOpenArray, tyArray, tySet, tySequence, tyTuple, tyProc, of tyOpenArray, tyArray, tySet, tySequence, tyTuple, tyProc,
tyPtr, tyVar, tyRef, tyOrdinal, tyRange, tyVarargs: tyPtr, tyVar, tyRef, tyOrdinal, tyRange, tyVarargs:

View file

@ -88,7 +88,7 @@ proc semLocals(c: PContext, n: PNode): PNode =
#if it.owner != c.p.owner: return result #if it.owner != c.p.owner: return result
if it.kind in skLocalVars and if it.kind in skLocalVars and
it.typ.skipTypes({tyGenericInst, tyVar}).kind notin it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
{tyVarargs, tyOpenArray, tyTypeDesc, tyExpr, tyStmt, tyEmpty}: {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
var field = newSym(skField, it.name, getCurrOwner(), n.info) var field = newSym(skField, it.name, getCurrOwner(), n.info)
field.typ = it.typ.skipTypes({tyGenericInst, tyVar}) field.typ = it.typ.skipTypes({tyGenericInst, tyVar})

View file

@ -196,7 +196,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
let e = semExprWithType(c, n.sons[1], {efDetermineType}) let e = semExprWithType(c, n.sons[1], {efDetermineType})
if e.kind in {nkIntLit..nkUInt64Lit}: if e.kind in {nkIntLit..nkUInt64Lit}:
indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ) indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
elif e.kind == nkSym and e.typ.kind == tyExpr: elif e.kind == nkSym and e.typ.kind == tyStatic:
if e.sym.ast != nil: return semArray(c, e.sym.ast, nil) if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
InternalAssert c.InGenericContext > 0 InternalAssert c.InGenericContext > 0
if not isOrdinalType(e.typ.lastSon): if not isOrdinalType(e.typ.lastSon):
@ -206,7 +206,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
indx = e.typ.skipTypes({tyTypeDesc}) indx = e.typ.skipTypes({tyTypeDesc})
addSonSkipIntLit(result, indx) addSonSkipIntLit(result, indx)
if indx.kind == tyGenericInst: indx = lastSon(indx) if indx.kind == tyGenericInst: indx = lastSon(indx)
if indx.kind notin {tyGenericParam, tyExpr}: if indx.kind notin {tyGenericParam, tyStatic}:
if not isOrdinalType(indx): if not isOrdinalType(indx):
LocalError(n.sons[1].info, errOrdinalTypeExpected) LocalError(n.sons[1].info, errOrdinalTypeExpected)
elif enumHasHoles(indx): elif enumHasHoles(indx):
@ -577,9 +577,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
pragma(c, s, n.sons[0], typePragmas) pragma(c, s, n.sons[0], typePragmas)
if base == nil and tfInheritable notin result.flags: if base == nil and tfInheritable notin result.flags:
incl(result.flags, tfFinal) incl(result.flags, tfFinal)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
if kind == skMacro and param.typ.kind != tyTypeDesc: if kind == skMacro and param.typ.kind notin {tyTypeDesc, tyStatic}:
# within a macro, every param has the type PNimrodNode! # within a macro, every param has the type PNimrodNode!
# and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}: # and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
let nn = getSysSym"PNimrodNode" let nn = getSysSym"PNimrodNode"
@ -629,15 +629,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
addImplicitGenericImpl(e, paramTypId) addImplicitGenericImpl(e, paramTypId)
case paramType.kind: case paramType.kind:
of tyExpr: of tyAnything:
if paramType.sonsLen == 0: result = addImplicitGeneric(newTypeS(tyGenericParam, c))
# proc(a, b: expr) of tyStatic:
# no constraints, treat like generic param # proc(a: expr{string}, b: expr{nkLambda})
result = addImplicitGeneric(newTypeS(tyGenericParam, c)) # overload on compile time values and AST trees
else: result = addImplicitGeneric(c.newTypeWithSons(tyStatic, paramType.sons))
# proc(a: expr{string}, b: expr{nkLambda})
# overload on compile time values and AST trees
result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons))
of tyTypeDesc: of tyTypeDesc:
if tfUnresolved notin paramType.flags: if tfUnresolved notin paramType.flags:
# naked typedescs are not bindOnce types # naked typedescs are not bindOnce types
@ -743,8 +740,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if not containsGenericType(typ): if not containsGenericType(typ):
def = fitNode(c, typ, def) def = fitNode(c, typ, def)
if not (hasType or hasDefault): if not (hasType or hasDefault):
typ = newTypeS(tyExpr, c) let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
typ = newTypeS(tdef, c)
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 = newSymG(skParam, a.sons[j], c) var arg = newSymG(skParam, a.sons[j], c)
@ -1000,6 +998,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev) of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
of nkVarTy: result = semVarType(c, n, prev) of nkVarTy: result = semVarType(c, n, prev)
of nkDistinctTy: result = semDistinct(c, n, prev) of nkDistinctTy: result = semDistinct(c, n, prev)
of nkStaticTy:
result = newOrPrevType(tyStatic, prev, c)
var base = semTypeNode(c, n.sons[0], nil)
result.rawAddSon(base)
of nkProcTy, nkIteratorTy: of nkProcTy, nkIteratorTy:
if n.sonsLen == 0: if n.sonsLen == 0:
result = newConstraint(c, tyProc) result = newConstraint(c, tyProc)
@ -1105,7 +1107,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
if constraint.kind != nkEmpty: if constraint.kind != nkEmpty:
typ = semTypeNode(c, constraint, nil) typ = semTypeNode(c, constraint, nil)
if typ.kind != tyExpr or typ.len == 0: if typ.kind != tyStatic or typ.len == 0:
if typ.kind == tyTypeDesc: if typ.kind == tyTypeDesc:
if typ.len == 0: if typ.len == 0:
typ = newTypeS(tyTypeDesc, c) typ = newTypeS(tyTypeDesc, c)
@ -1116,7 +1118,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
def = semConstExpr(c, def) def = semConstExpr(c, def)
if typ == nil: if typ == nil:
if def.typ.kind != tyTypeDesc: if def.typ.kind != tyTypeDesc:
typ = newTypeWithSons(c, tyExpr, @[def.typ]) typ = newTypeWithSons(c, tyStatic, @[def.typ])
else: else:
if not containsGenericType(def.typ): if not containsGenericType(def.typ):
def = fitNode(c, typ, def) def = fitNode(c, typ, def)
@ -1132,7 +1134,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
# of the parameter will be stored in the # of the parameter will be stored in the
# attached symbol. # attached symbol.
var s = case finalType.kind var s = case finalType.kind
of tyExpr: of tyStatic:
newSymG(skGenericParam, a.sons[j], c).linkTo(finalType) newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
else: else:
newSymG(skType, a.sons[j], c).linkTo(finalType) newSymG(skType, a.sons[j], c).linkTo(finalType)

View file

@ -201,7 +201,7 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result = lookupTypeVar(cl, t) result = lookupTypeVar(cl, t)
if result.kind == tyGenericInvokation: if result.kind == tyGenericInvokation:
result = handleGenericInvokation(cl, result) result = handleGenericInvokation(cl, result)
of tyExpr: of tyStatic:
if t.sym != nil and t.sym.kind == skGenericParam: if t.sym != nil and t.sym.kind == skGenericParam:
result = lookupTypeVar(cl, t) result = lookupTypeVar(cl, t)
of tyGenericInvokation: of tyGenericInvokation:
@ -215,7 +215,7 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
else: else:
if t.kind == tyArray: if t.kind == tyArray:
let idxt = t.sons[0] let idxt = t.sons[0]
if idxt.kind == tyExpr and if idxt.kind == tyStatic and
idxt.sym != nil and idxt.sym.kind == skGenericParam: idxt.sym != nil and idxt.sym.kind == skGenericParam:
let value = lookupTypeVar(cl, idxt).n let value = lookupTypeVar(cl, idxt).n
t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info) t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)

View file

@ -124,7 +124,7 @@ proc sumGeneric(t: PType): int =
result = ord(t.kind == tyGenericInvokation) result = ord(t.kind == tyGenericInvokation)
for i in 0 .. <t.len: result += t.sons[i].sumGeneric for i in 0 .. <t.len: result += t.sons[i].sumGeneric
break break
of tyGenericParam, tyExpr, tyStmt, tyTypeDesc, tyTypeClass: break of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc, tyTypeClass: break
else: return 0 else: return 0
proc complexDisambiguation(a, b: PType): int = proc complexDisambiguation(a, b: PType): int =
@ -894,40 +894,39 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
arg = argSemantized arg = argSemantized
let let
a = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc}) a0 = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc})
else: argType else: argType
fMaybeExpr = f.skipTypes({tyDistinct}) a = if a0 != nil: a0.skipTypes({tyStatic}) else: a0
fMaybeStatic = f.skipTypes({tyDistinct})
case fMaybeExpr.kind case fMaybeStatic.kind
of tyExpr: of tyStatic:
if fMaybeExpr.sonsLen == 0: if a.kind == tyStatic:
r = isGeneric InternalAssert a.len > 0
r = typeRel(m, f.lastSon, a.lastSon)
else: else:
if a.kind == tyExpr: let match = matchTypeClass(m.bindings, fMaybeStatic, a)
InternalAssert a.len > 0 if not match: r = isNone
r = typeRel(m, f.lastSon, a.lastSon)
else: else:
let match = matchTypeClass(m.bindings, fMaybeExpr, a) # XXX: Ideally, this should happen much earlier somewhere near
if not match: r = isNone # semOpAux, but to do that, we need to be able to query the
else: # overload set to determine whether compile-time value is expected
# XXX: Ideally, this should happen much earlier somewhere near # for the param before entering the full-blown sigmatch algorithm.
# semOpAux, but to do that, we need to be able to query the # This is related to the immediate pragma since querying the
# overload set to determine whether compile-time value is expected # overload set could help there too.
# for the param before entering the full-blown sigmatch algorithm. var evaluated = c.semConstExpr(c, arg)
# This is related to the immediate pragma since querying the if evaluated != nil:
# overload set could help there too. r = isGeneric
var evaluated = c.semConstExpr(c, arg) arg.typ = newTypeS(tyStatic, c)
if evaluated != nil: arg.typ.sons = @[evaluated.typ]
r = isGeneric arg.typ.n = evaluated
arg.typ = newTypeS(tyExpr, c)
arg.typ.sons = @[evaluated.typ]
arg.typ.n = evaluated
if r == isGeneric: if r == isGeneric:
put(m.bindings, f, arg.typ) put(m.bindings, f, arg.typ)
of tyTypeClass, tyParametricTypeClass: of tyTypeClass, tyParametricTypeClass:
if fMaybeExpr.n != nil: if fMaybeStatic.n != nil:
let match = matchUserTypeClass(c, m, arg, fMaybeExpr, a) let match = matchUserTypeClass(c, m, arg, fMaybeStatic, a)
if match != nil: if match != nil:
r = isGeneric r = isGeneric
arg = match arg = match
@ -935,6 +934,9 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
r = isNone r = isNone
else: else:
r = typeRel(m, f, a) r = typeRel(m, f, a)
of tyExpr:
r = isGeneric
put(m.bindings, f, arg.typ)
else: else:
r = typeRel(m, f, a) r = typeRel(m, f, a)
@ -961,6 +963,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
result = argOrig[bodyPos] result = argOrig[bodyPos]
elif f.kind == tyTypeDesc: elif f.kind == tyTypeDesc:
result = arg result = arg
elif f.kind == tyStatic:
result = arg.typ.n
else: else:
result = argOrig result = argOrig
else: else:

View file

@ -409,7 +409,7 @@ const
"uint", "uint8", "uint16", "uint32", "uint64", "uint", "uint8", "uint16", "uint32", "uint64",
"bignum", "const ", "bignum", "const ",
"!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass", "!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass",
"ParametricTypeClass", "and", "or", "not", "any"] "ParametricTypeClass", "and", "or", "not", "any", "static"]
proc consToStr(t: PType): string = proc consToStr(t: PType): string =
if t.len > 0: result = t.typeToString if t.len > 0: result = t.typeToString
@ -445,6 +445,9 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
of tyTypeDesc: of tyTypeDesc:
if t.len == 0: result = "typedesc" if t.len == 0: result = "typedesc"
else: result = "typedesc[" & constraintsToStr(t) & "]" else: result = "typedesc[" & constraintsToStr(t) & "]"
of tyStatic:
InternalAssert t.len > 0
result = "static[" & constraintsToStr(t) & "]"
of tyTypeClass: of tyTypeClass:
if t.n != nil: return t.sym.owner.name.s if t.n != nil: return t.sym.owner.name.s
case t.len case t.len
@ -828,9 +831,9 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
if a.kind != b.kind: return false if a.kind != b.kind: return false
case a.Kind case a.Kind
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
tyInt..tyBigNum, tyStmt: tyInt..tyBigNum, tyStmt, tyExpr:
result = sameFlags(a, b) result = sameFlags(a, b)
of tyExpr: of tyStatic:
result = ExprStructuralEquivalent(a.n, b.n) and sameFlags(a, b) result = ExprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
of tyObject: of tyObject:
IfFastObjectTypeCheckFailed(a, b): IfFastObjectTypeCheckFailed(a, b):
@ -1038,7 +1041,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
if not result: break if not result: break
if result and t.sons[0] != nil: if result and t.sons[0] != nil:
result = typeAllowedAux(marker, t.sons[0], skResult, flags) result = typeAllowedAux(marker, t.sons[0], skResult, flags)
of tyExpr, tyStmt, tyTypeDesc: of tyExpr, tyStmt, tyTypeDesc, tyStatic:
result = true result = true
# XXX er ... no? these should not be allowed! # XXX er ... no? these should not be allowed!
of tyEmpty: of tyEmpty:
@ -1314,7 +1317,7 @@ proc compatibleEffects*(formal, actual: PType): bool =
result = true result = true
proc isCompileTimeOnly*(t: PType): bool {.inline.} = proc isCompileTimeOnly*(t: PType): bool {.inline.} =
result = t.kind in {tyTypedesc, tyExpr} result = t.kind in {tyTypedesc, tyStatic}
proc containsCompileTimeOnly*(t: PType): bool = proc containsCompileTimeOnly*(t: PType): bool =
if isCompileTimeOnly(t): return true if isCompileTimeOnly(t): return true

View file

@ -777,7 +777,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
const const
atomicTypes = {tyBool, tyChar, atomicTypes = {tyBool, tyChar,
tyExpr, tyStmt, tyTypeDesc, tyExpr, tyStmt, tyTypeDesc, tyStatic,
tyEnum, tyEnum,
tyOrdinal, tyOrdinal,
tyRange, tyRange,
@ -937,8 +937,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
result = newNodeIT(nkUIntLit, info, t) result = newNodeIT(nkUIntLit, info, t)
of tyFloat..tyFloat128: of tyFloat..tyFloat128:
result = newNodeIt(nkFloatLit, info, t) result = newNodeIt(nkFloatLit, info, t)
of tyVar, tyPointer, tyPtr, tyCString, tySequence, tyString, tyExpr, of tyVar, tyPointer, tyPtr, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyProc, tyRef: tyStmt, tyTypeDesc, tyStatic, tyProc, tyRef:
result = newNodeIT(nkNilLit, info, t) result = newNodeIT(nkNilLit, info, t)
of tyObject: of tyObject:
result = newNodeIT(nkPar, info, t) result = newNodeIT(nkPar, info, t)

View file

@ -59,7 +59,8 @@ type
nnkBindStmt, nnkMixinStmt, nnkUsingStmt, nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy, nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkTypeClassTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
nnkRecList, nnkRecCase, nnkRecWhen,
nnkRefTy, nnkPtrTy, nnkVarTy, nnkRefTy, nnkPtrTy, nnkVarTy,
nnkConstTy, nnkMutableTy, nnkConstTy, nnkMutableTy,
nnkDistinctTy, nnkDistinctTy,
@ -285,14 +286,15 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
## if not `ex`: ## if not `ex`:
## echo `info` & ": Check failed: " & `expString` ## echo `info` & ": Check failed: " & `expString`
template emit*(e: expr[string]): stmt = when not defined(booting):
## accepts a single string argument and treats it as nimrod code template emit*(e: static[string]): stmt =
## that should be inserted verbatim in the program ## accepts a single string argument and treats it as nimrod code
## Example: ## that should be inserted verbatim in the program
## ## Example:
## emit("echo " & '"' & "hello world".toUpper & '"') ##
## ## emit("echo " & '"' & "hello world".toUpper & '"')
eval: result = e.parseStmt ##
eval: result = e.parseStmt
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} = proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
## checks that `n` is of kind `k`. If this is not the case, ## checks that `n` is of kind `k`. If this is not the case,

View file

@ -2641,7 +2641,7 @@ when hostOS != "standalone":
x[j+i] = item[j] x[j+i] = item[j]
inc(j) inc(j)
proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} = proc compiles*(x): bool {.magic: "Compiles", noSideEffect.} =
## Special compile-time procedure that checks whether `x` can be compiled ## Special compile-time procedure that checks whether `x` can be compiled
## without any semantic error. ## without any semantic error.
## This can be used to check whether a type supports some operation: ## This can be used to check whether a type supports some operation:

View file

@ -5,7 +5,7 @@ discard """
import strutils import strutils
proc foo(s: expr[string]): string = proc foo(s: static[string]): string =
static: echo s static: echo s
const R = s.toUpper const R = s.toUpper

View file

@ -4,15 +4,15 @@ discard """
""" """
type type
TFoo[T; Val: expr[string]] = object TFoo[T; Val: static[string]] = object
data: array[4, T] data: array[4, T]
TBar[T; I: expr[int]] = object TBar[T; I: static[int]] = object
data: array[I, T] data: array[I, T]
TA1[T; I: expr[int]] = array[I, T] #TA1[T; I: static[int]] = array[I, T]
TA2[T; I: expr[int]] = array[0..I, T] #TA2[T; I: static[int]] = array[0..I, T]
TA3[T; I: expr[int]] = array[I-1, T] TA3[T; I: static[int]] = array[I-1, T]
proc takeFoo(x: TFoo) = proc takeFoo(x: TFoo) =
echo "abracadabra" echo "abracadabra"

View file

@ -38,7 +38,6 @@ version 0.9.x
- macros as type pragmas - macros as type pragmas
- implicit deref for parameter matching - implicit deref for parameter matching
- lazy overloading resolution: - lazy overloading resolution:
* get rid of ``expr[typ]``, use perhaps ``static[typ]`` instead
* special case ``tyStmt`` * special case ``tyStmt``
- FFI: - FFI:
* test libffi on windows * test libffi on windows