Merge branch 'upstream' into devel

Conflicts:
	compiler/ccgutils.nim
	compiler/msgs.nim
	compiler/sem.nim
	compiler/semexprs.nim
	compiler/seminst.nim
	compiler/semmagic.nim
	compiler/semstmts.nim
	compiler/semtypes.nim
	compiler/semtypinst.nim
	compiler/sigmatch.nim
	compiler/types.nim
	compiler/vmgen.nim
	lib/core/macros.nim
	lib/system.nim
	tests/reject/tenummix.nim
	web/news.txt
This commit is contained in:
Zahary Karadjov 2013-12-29 17:21:00 +02:00
commit afddae5aaf
41 changed files with 901 additions and 568 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,19 +337,26 @@ 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
tyBuiltInTypeClass
tyCompositeTypeClass
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
GcTypeKinds* = {tyRef, tySequence, tyString} GcTypeKinds* = {tyRef, tySequence, tyString}
tyError* = tyProxy # as an errornous node should match everything tyError* = tyProxy # as an errornous node should match everything
tyTypeClasses* = {tyTypeClass, tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass,
tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyStatic, tyExpr} + tyTypeClasses
type type
TTypeKinds* = set[TTypeKind] TTypeKinds* = set[TTypeKind]
@ -383,9 +391,6 @@ type
# proc foo(T: typedesc, list: seq[T]): var T # proc foo(T: typedesc, list: seq[T]): var T
tfRetType, # marks return types in proc (used to detect type classes tfRetType, # marks return types in proc (used to detect type classes
# used as return types for return type inference) # used as return types for return type inference)
tfAll, # type class requires all constraints to be met (default)
tfAny, # type class requires any constraint to be met
tfNot, # type class with a negative check
tfCapturesEnv, # whether proc really captures some environment tfCapturesEnv, # whether proc really captures some environment
tfByCopy, # pass object/tuple by copy (C backend) tfByCopy, # pass object/tuple by copy (C backend)
tfByRef, # pass object/tuple by reference (C backend) tfByRef, # pass object/tuple by reference (C backend)
@ -396,8 +401,11 @@ type
tfNeedsInit, # type constains a "not nil" constraint somewhere or some tfNeedsInit, # type constains a "not nil" constraint somewhere or some
# other type so that it requires inititalization # other type so that it requires inititalization
tfHasShared, # type constains a "shared" constraint modifier somewhere tfHasShared, # type constains a "shared" constraint modifier somewhere
tfHasMeta, # type has "typedesc" or "expr" somewhere; or uses '|' tfHasMeta, # type contains "wildcard" sub-types such as generic params
# or other type classes
tfHasGCedMem, # type contains GC'ed memory tfHasGCedMem, # type contains GC'ed memory
tfGenericTypeParam
tfHasStatic
TTypeFlags* = set[TTypeFlag] TTypeFlags* = set[TTypeFlag]
@ -774,9 +782,11 @@ const
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody, GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
tyGenericParam} tyGenericParam}
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray, StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray, tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
tyVarargs} tyVarargs}
ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in:: ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
# var x = expr # var x = expr
tyBool, tyChar, tyEnum, tyArray, tyObject, tyBool, tyChar, tyEnum, tyArray, tyObject,
@ -1219,7 +1229,7 @@ proc newSons(father: PNode, length: int) =
proc propagateToOwner*(owner, elem: PType) = proc propagateToOwner*(owner, elem: PType) =
const HaveTheirOwnEmpty = {tySequence, tySet} const HaveTheirOwnEmpty = {tySequence, tySet}
owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta, owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta,
tfHasGCedMem}) tfHasStatic, tfHasGCedMem})
if tfNotNil in elem.flags: if tfNotNil in elem.flags:
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}: if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}:
owner.flags.incl tfNotNil owner.flags.incl tfNotNil
@ -1232,10 +1242,14 @@ 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 tyMetaTypes:
owner.flags.incl tfHasMeta owner.flags.incl tfHasMeta
elif elem.kind in {tyString, tyRef, tySequence} or
if elem.kind == tyStatic:
owner.flags.incl tfHasStatic
if elem.kind in {tyString, tyRef, tySequence} or
elem.kind == tyProc and elem.callConv == ccClosure: elem.kind == tyProc and elem.callConv == ccClosure:
owner.flags.incl tfHasGCedMem owner.flags.incl tfHasGCedMem

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

@ -87,7 +87,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) and gVerbosity >= 3: 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,
@ -905,17 +906,15 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
result = parseString(code.getStrValue, code.info.toFilename, result = parseString(code.getStrValue, code.info.toFilename,
code.info.line.int) code.info.line.int)
#result.typ = newType(tyStmt, c.module) #result.typ = newType(tyStmt, c.module)
proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
InternalAssert operand.kind == nkSym
let typ = operand.sym.typ.skipTypes({tyTypeDesc}) proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
let typ = operand.typ.skipTypes({tyTypeDesc})
case trait.sym.name.s.normalize case trait.sym.name.s.normalize
of "name": of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferName)) result = newStrNode(nkStrLit, typ.typeToString(preferName))
result.typ = newType(tyString, context) result.typ = newType(tyString, context)
result.info = trait.info result.info = trait.info
of "arity": of "arity":
result = newIntNode(nkIntLit, typ.n.len-1) result = newIntNode(nkIntLit, typ.n.len-1)
result.typ = newType(tyInt, context) result.typ = newType(tyInt, context)
result.info = trait.info result.info = trait.info
@ -1329,7 +1328,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
if gNestedEvals <= 0: stackTrace(c, n.info, errTooManyIterations) if gNestedEvals <= 0: stackTrace(c, n.info, errTooManyIterations)
case n.kind case n.kind
of nkSym: result = evalSym(c, n, flags) of nkSym: result = evalSym(c, n, flags)
of nkType..nkNilLit: of nkType..nkNilLit, nkTypeOfExpr:
# nkStrLit is VERY common in the traces, so we should avoid # nkStrLit is VERY common in the traces, so we should avoid
# the 'copyNode' here. # the 'copyNode' here.
result = n #.copyNode result = n #.copyNode

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

@ -643,6 +643,8 @@ proc toFileLine*(info: TLineInfo): string {.inline.} =
proc toFileLineCol*(info: TLineInfo): string {.inline.} = proc toFileLineCol*(info: TLineInfo): string {.inline.} =
result = info.toFilename & "(" & $info.line & "," & $info.col & ")" result = info.toFilename & "(" & $info.line & "," & $info.col & ")"
template `$`*(info: TLineInfo): expr = toFileLineCol(info)
proc `??`* (info: TLineInfo, filename: string): bool = proc `??`* (info: TLineInfo, filename: string): bool =
# only for debugging purposes # only for debugging purposes
result = filename in info.toFilename result = filename in info.toFilename
@ -699,21 +701,20 @@ type
TErrorHandling = enum doNothing, doAbort, doRaise TErrorHandling = enum doNothing, doAbort, doRaise
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
template maybeTrace = template quit =
if defined(debug) or gVerbosity >= 3 or msg == errInternal: if defined(debug) or gVerbosity >= 3 or msg == errInternal:
writeStackTrace() writeStackTrace()
quit 1
if msg >= fatalMin and msg <= fatalMax: if msg >= fatalMin and msg <= fatalMax:
maybeTrace() quit()
quit(1)
if msg >= errMin and msg <= errMax: if msg >= errMin and msg <= errMax:
maybeTrace()
inc(gErrorCounter) inc(gErrorCounter)
options.gExitcode = 1'i8 options.gExitcode = 1'i8
if gErrorCounter >= gErrorMax: if gErrorCounter >= gErrorMax:
quit(1) quit()
elif eh == doAbort and gCmd != cmdIdeTools: elif eh == doAbort and gCmd != cmdIdeTools:
quit(1) quit()
elif eh == doRaise: elif eh == doRaise:
raiseRecoverableError(s) raiseRecoverableError(s)

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

@ -25,7 +25,7 @@ proc equalGenericParams(procA, procB: PNode): bool =
let a = procA.sons[i].sym let a = procA.sons[i].sym
let b = procB.sons[i].sym let b = procB.sons[i].sym
if a.name.id != b.name.id or if a.name.id != b.name.id or
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}): return
if a.ast != nil and b.ast != nil: if a.ast != nil and b.ast != nil:
if not exprStructuralEquivalent(a.ast, b.ast): return if not exprStructuralEquivalent(a.ast, b.ast): return
result = true result = true

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

@ -158,6 +158,16 @@ proc isOpImpl(c: PContext, n: PNode): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode semCheck: bool = true): PNode
proc symFromType(t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
result = newSym(skType, getIdent"AnonType", t.owner, info)
result.flags.incl sfAnon
result.typ = t
proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
result = newSymNode(symFromType(t, info), info)
result.typ = makeTypeDesc(c, t)
when false: when false:
proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext = proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
result = newEvalContext(c.module, mode) result = newEvalContext(c.module, mode)
@ -169,10 +179,37 @@ when false:
result = newSymNode(getSysSym"void") result = newSymNode(getSysSym"void")
else: else:
result.typ = makeTypeDesc(c, result.typ) result.typ = makeTypeDesc(c, result.typ)
result.handleIsOperator = proc (n: PNode): PNode = result.handleIsOperator = proc (n: PNode): PNode =
result = IsOpImpl(c, n) result = isOpImpl(c, n)
proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
# recompute the types as 'eval' isn't guaranteed to construct types nor
# that the types are sound:
result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case:
let arg = result
result = indexTypesMatch(c, eOrig.typ, arg.typ, arg)
if result == nil:
result = arg
# for 'tcnstseq' we support [] to become 'seq'
if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
arg.typ = eOrig.typ
proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil: return
result = getConstExpr(c.module, e)
if result != nil: return
result = evalConstExpr(c.module, e)
if result == nil or result.kind == nkEmpty:
return nil
result = fixupTypeAfterEval(c, result, e)
proc semConstExpr(c: PContext, n: PNode): PNode = proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n) var e = semExprWithType(c, n)
if e == nil: if e == nil:
@ -191,18 +228,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
# error correction: # error correction:
result = e result = e
else: else:
# recompute the types as 'eval' isn't guaranteed to construct types nor result = fixupTypeAfterEval(c, result, e)
# that the types are sound:
result = semExprWithType(c, result)
#result = fitNode(c, e.typ, result) inlined with special case:
let arg = result
result = indexTypesMatch(c, e.typ, arg.typ, arg)
if result == nil:
result = arg
# for 'tcnstseq' we support [] to become 'seq'
if e.typ.skipTypes(abstractInst).kind == tySequence and
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
arg.typ = e.typ
include hlo, seminst, semcall include hlo, seminst, semcall
@ -282,6 +308,7 @@ proc myOpen(module: PSym): PPassContext =
c.semConstExpr = semConstExpr c.semConstExpr = semConstExpr
c.semExpr = semExpr c.semExpr = semExpr
c.semTryExpr = tryExpr c.semTryExpr = tryExpr
c.semTryConstExpr = tryConstExpr
c.semOperand = semOperand c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall c.semOverloadedCall = semOverloadedCall

View file

@ -47,14 +47,14 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
var z: TCandidate var z: TCandidate
if sym == nil: return if sym == nil: return
initCandidate(best, sym, initialBinding, symScope) initCandidate(c, best, sym, initialBinding, symScope)
initCandidate(alt, sym, initialBinding, symScope) initCandidate(c, alt, sym, initialBinding, symScope)
best.state = csNoMatch best.state = csNoMatch
while sym != nil: while sym != nil:
if sym.kind in filter: if sym.kind in filter:
determineType(c, sym) determineType(c, sym)
initCandidate(z, sym, initialBinding, o.lastOverloadScope) initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
z.calleeSym = sym z.calleeSym = sym
matches(c, n, orig, z) matches(c, n, orig, z)
if errors != nil: if errors != nil:
@ -199,15 +199,15 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode = proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
var m: TCandidate var m: TCandidate
initCandidate(m, f) initCandidate(c, m, f)
result = paramTypesMatch(c, m, f, a, arg, nil) result = paramTypesMatch(m, f, a, arg, nil)
if m.genericConverter and result != nil: if m.genericConverter and result != nil:
instGenericConvertersArg(c, result, m) instGenericConvertersArg(c, result, m)
proc convertTo*(c: PContext, f: PType, n: PNode): PNode = proc convertTo*(c: PContext, f: PType, n: PNode): PNode =
var m: TCandidate var m: TCandidate
initCandidate(m, f) initCandidate(c, m, f)
result = paramTypesMatch(c, m, f, n.typ, n, nil) result = paramTypesMatch(m, f, n.typ, n, nil)
if m.genericConverter and result != nil: if m.genericConverter and result != nil:
instGenericConvertersArg(c, result, m) instGenericConvertersArg(c, result, m)
@ -243,9 +243,9 @@ proc explicitGenericInstError(n: PNode): PNode =
result = n result = n
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
var x: TCandidate var m: TCandidate
initCandidate(x, s, n) initCandidate(c, m, s, n)
var newInst = generateInstance(c, s, x.bindings, n.info) var newInst = generateInstance(c, s, m.bindings, n.info)
markUsed(n, s) markUsed(n, s)
result = newSymNode(newInst, n.info) result = newSymNode(newInst, n.info)

View file

@ -75,6 +75,7 @@ type
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}, semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
bufferErrors = false): PNode {.nimcall.} bufferErrors = false): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
@ -213,7 +214,24 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc) let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
return newSymNode(sym, info) return newSymNode(sym, info)
proc newTypeS(kind: TTypeKind, c: PContext): PType = proc makeAndType*(c: PContext, t1, t2: PType): PType =
result = newTypeS(tyAnd, c)
result.sons = @[t1, t2]
propagateToOwner(result, t1)
propagateToOwner(result, t2)
proc makeOrType*(c: PContext, t1, t2: PType): PType =
result = newTypeS(tyOr, c)
result.sons = @[t1, t2]
propagateToOwner(result, t1)
propagateToOwner(result, t2)
proc makeNotType*(c: PContext, t1: PType): PType =
result = newTypeS(tyNot, c)
result.sons = @[t1]
propagateToOwner(result, t1)
proc newTypeS(kind: TTypeKind, c: PContext): PType =
result = newType(kind, getCurrOwner()) result = newType(kind, getCurrOwner())
proc newTypeWithSons*(c: PContext, kind: TTypeKind, proc newTypeWithSons*(c: PContext, kind: TTypeKind,

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:
@ -142,7 +142,7 @@ proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus =
const const
IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64} IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
proc checkConvertible(castDest, src: PType): TConvStatus = proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
result = convOK result = convOK
if sameType(castDest, src) and castDest.sym == src.sym: if sameType(castDest, src) and castDest.sym == src.sym:
# don't annoy conversions that may be needed on another processor: # don't annoy conversions that may be needed on another processor:
@ -163,7 +163,7 @@ proc checkConvertible(castDest, src: PType): TConvStatus =
# accept conversion between integral types # accept conversion between integral types
else: else:
# we use d, s here to speed up that operation a bit: # we use d, s here to speed up that operation a bit:
case cmpTypes(d, s) case cmpTypes(c, d, s)
of isNone, isGeneric: of isNone, isGeneric:
if not compareTypes(castDest, src, dcEqIgnoreDistinct): if not compareTypes(castDest, src, dcEqIgnoreDistinct):
result = convNotLegal result = convNotLegal
@ -202,7 +202,7 @@ proc semConv(c: PContext, n: PNode): PNode =
var op = result.sons[1] var op = result.sons[1]
if not isSymChoice(op): if not isSymChoice(op):
let status = checkConvertible(result.typ, op.typ) let status = checkConvertible(c, result.typ, op.typ)
case status case status
of convOK: nil of convOK: nil
of convNotNeedeed: of convNotNeedeed:
@ -213,7 +213,7 @@ proc semConv(c: PContext, n: PNode): PNode =
else: else:
for i in countup(0, sonsLen(op) - 1): for i in countup(0, sonsLen(op) - 1):
let it = op.sons[i] let it = op.sons[i]
let status = checkConvertible(result.typ, it.typ) let status = checkConvertible(c, result.typ, it.typ)
if status == convOK: if status == convOK:
markUsed(n, it.sym) markUsed(n, it.sym)
markIndirect(c, it.sym) markIndirect(c, it.sym)
@ -301,7 +301,7 @@ proc semOf(c: PContext, n: PNode): PNode =
proc isOpImpl(c: PContext, n: PNode): PNode = proc isOpImpl(c: PContext, n: PNode): PNode =
internalAssert n.sonsLen == 3 and internalAssert n.sonsLen == 3 and
n[1].typ != nil and n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType} n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = n[1].typ.skipTypes({tyTypeDesc}) let t1 = n[1].typ.skipTypes({tyTypeDesc})
@ -324,15 +324,15 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
case t2.kind case t2.kind
of tyTypeClasses: of tyTypeClasses:
var m: TCandidate var m: TCandidate
initCandidate(m, t2) initCandidate(c, m, t2)
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
of tyOrdinal: of tyOrdinal:
var m: TCandidate var m: TCandidate
initCandidate(m, t2) initCandidate(c, m, t2)
match = isOrdinalType(t1) match = isOrdinalType(t1)
of tySequence, tyArray, tySet: of tySequence, tyArray, tySet:
var m: TCandidate var m: TCandidate
initCandidate(m, t2) initCandidate(c, m, t2)
match = typeRel(m, t2, t1) != isNone match = typeRel(m, t2, t1) != isNone
else: else:
match = sameType(t1, t2) match = sameType(t1, t2)
@ -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")
@ -706,7 +707,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
if t != nil and t.kind == tyProc: if t != nil and t.kind == tyProc:
# This is a proc variable, apply normal overload resolution # This is a proc variable, apply normal overload resolution
var m: TCandidate var m: TCandidate
initCandidate(m, t) initCandidate(c, m, t)
matches(c, n, nOrig, m) matches(c, n, nOrig, m)
if m.state != csMatch: if m.state != csMatch:
if c.inCompilesContext > 0: if c.inCompilesContext > 0:
@ -939,7 +940,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)
@ -1164,7 +1165,7 @@ proc semAsgn(c: PContext, n: PNode): PNode =
if lhsIsResult: if lhsIsResult:
n.typ = enforceVoidContext n.typ = enforceVoidContext
if lhs.sym.typ.kind == tyGenericParam: if lhs.sym.typ.kind == tyGenericParam:
if matchTypeClass(lhs.typ, rhs.typ): if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric:
internalAssert c.p.resultSym != nil internalAssert c.p.resultSym != nil
lhs.typ = rhs.typ lhs.typ = rhs.typ
c.p.resultSym.typ = rhs.typ c.p.resultSym.typ = rhs.typ
@ -1884,7 +1885,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)
@ -1945,7 +1946,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# type parameters: partial generic specialization # type parameters: partial generic specialization
n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
result = explicitGenericInstantiation(c, n, s) result = explicitGenericInstantiation(c, n, s)
else: elif s != nil and s.kind in {skType}:
result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
else:
result = semArrayAccess(c, n, flags) result = semArrayAccess(c, n, flags)
of nkCurlyExpr: of nkCurlyExpr:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags) result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags)

View file

@ -230,6 +230,7 @@ discard """
""" """
proc evalIs(n, a: PNode): PNode = proc evalIs(n, a: PNode): PNode =
# XXX: This should use the standard isOpImpl
internalAssert a.kind == nkSym and a.sym.kind == skType internalAssert a.kind == nkSym and a.sym.kind == skType
internalAssert n.sonsLen == 3 and internalAssert n.sonsLen == 3 and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType} n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
@ -251,7 +252,7 @@ proc evalIs(n, a: PNode): PNode =
else: else:
# XXX semexprs.isOpImpl is slightly different and requires a context. yay. # XXX semexprs.isOpImpl is slightly different and requires a context. yay.
let t2 = n[2].typ let t2 = n[2].typ
var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1) var match = if t2.kind == tyTypeClass: true
else: sameType(t1, t2) else: sameType(t1, t2)
result = newIntNode(nkIntLit, ord(match)) result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ result.typ = n.typ
@ -612,9 +613,10 @@ 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 if s.typ.n != nil:
result.typ = s.typ.sons[0] result = s.typ.n
result.typ = s.typ.sons[0]
else: else:
result = newSymNodeTypeDesc(s, n.info) result = newSymNodeTypeDesc(s, n.info)
else: discard else: discard

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}
@ -47,7 +47,7 @@ proc sameInstantiation(a, b: TInstantiation): bool =
if a.concreteTypes.len == b.concreteTypes.len: if a.concreteTypes.len == b.concreteTypes.len:
for i in 0..a.concreteTypes.high: for i in 0..a.concreteTypes.high:
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i], if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
flags = {TypeDescExactMatch}): return flags = {ExactTypeDescValues}): return
result = true result = true
proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym = proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
@ -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
@ -165,7 +165,8 @@ proc lateInstantiateGeneric(c: PContext, invocation: PType, info: TLineInfo): PT
result.sons.add instantiated result.sons.add instantiated
cacheTypeInst result cacheTypeInst result
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType = proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
allowMetaTypes = false): PType =
when oUseLateInstantiation: when oUseLateInstantiation:
lateInstantiateGeneric(c, header, info) lateInstantiateGeneric(c, header, info)
else: else:
@ -174,6 +175,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
initIdTable(cl.typeMap) initIdTable(cl.typeMap)
cl.info = info cl.info = info
cl.c = c cl.c = c
cl.allowMetaTypes = allowMetaTypes
result = replaceTypeVarsT(cl, header) result = replaceTypeVarsT(cl, header)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
@ -196,12 +198,31 @@ proc fixupProcType(c: PContext, genericType: PType,
case genericType.kind case genericType.kind
of tyGenericParam, tyTypeClasses: of tyGenericParam, tyTypeClasses:
result = inst.concreteTypes[genericType.sym.position] result = inst.concreteTypes[genericType.sym.position]
of tyTypeDesc: of tyTypeDesc:
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 tyGenericInst:
result = fixupProcType(c, result.lastSon, inst)
of tyObject:
var recList = genericType.n
for i in 0 .. <recList.sonsLen:
let field = recList[i].sym
let changed = fixupProcType(c, field.typ, inst)
if field.typ != changed:
if result == genericType:
result = copyType(genericType, genericType.owner, false)
result.n = copyTree(recList)
result.n.sons[i].sym = copySym(recList[i].sym, true)
result.n.sons[i].typ = changed
result.n.sons[i].sym.typ = changed
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:
if genericType.sons == nil: return if genericType.sons == nil: return
@ -232,7 +253,8 @@ proc fixupProcType(c: PContext, genericType: PType,
continue continue
result.sons[head] = changed result.sons[head] = changed
result.size = 0
if result.n != nil: if result.n != nil:
if result.n.kind == nkRecList: if result.n.kind == nkRecList:
for son in result.n.sons: for son in result.n.sons:
@ -263,7 +285,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym = info: TLineInfo): PSym =
# no need to instantiate generic templates/macros: # no need to instantiate generic templates/macros:
if fn.kind in {skTemplate, skMacro}: return fn if fn.kind in {skTemplate, skMacro}: return fn
# generates an instantiated proc # generates an instantiated proc
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep") if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
inc(c.instCounter) inc(c.instCounter)
@ -288,7 +310,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
var entry = TInstantiation.new var entry = TInstantiation.new
entry.sym = result entry.sym = result
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[]) instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
result.typ = fixupProcType(c, fn.typ, entry[]) # let t1 = fixupProcType(c, fn.typ, entry[])
result.typ = generateTypeInstance(c, pt, info, fn.typ)
n.sons[genericParamsPos] = ast.emptyNode n.sons[genericParamsPos] = ast.emptyNode
var oldPrc = genericCacheGet(fn, entry[]) var oldPrc = genericCacheGet(fn, entry[])
if oldPrc == nil: if oldPrc == nil:

View file

@ -31,7 +31,6 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
line.intVal = toLinenumber(info) line.intVal = toLinenumber(info)
result.add(filename) result.add(filename)
result.add(line) result.add(line)
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode = proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
let typ = operand.skipTypes({tyTypeDesc}) let typ = operand.skipTypes({tyTypeDesc})
@ -40,7 +39,7 @@ proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
result = newStrNode(nkStrLit, typ.typeToString(preferName)) result = newStrNode(nkStrLit, typ.typeToString(preferName))
result.typ = newType(tyString, context) result.typ = newType(tyString, context)
result.info = trait.info result.info = trait.info
of "arity": of "arity":
result = newIntNode(nkIntLit, typ.n.len-1) result = newIntNode(nkIntLit, typ.n.len-1)
result.typ = newType(tyInt, context) result.typ = newType(tyInt, context)
result.info = trait.info result.info = trait.info
@ -50,11 +49,11 @@ proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
proc semTypeTraits(c: PContext, n: PNode): PNode = proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2) checkMinSonsLen(n, 2)
let t = n.sons[1].typ let t = n.sons[1].typ
internalAssert t != nil internalAssert t != nil and t.kind == tyTypeDesc
if t.kind == tyTypeDesc and t.len == 0: if t.sonsLen > 0:
result = n # This is either a type known to sem or a typedesc
elif not containsGenericType(t): # param to a regular proc (again, known at instantiation)
result = evalTypeTrait(n[0], t, getCurrOwner()) result = evalTypeTrait(n[0], t, GetCurrOwner())
else: else:
# a typedesc variable, pass unmodified to evals # a typedesc variable, pass unmodified to evals
result = n result = n
@ -102,7 +101,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

@ -1037,12 +1037,16 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
pushOwner(s) pushOwner(s)
s.options = gOptions s.options = gOptions
if sfDestructor in s.flags: doDestructorStuff(c, s, n) if sfDestructor in s.flags: doDestructorStuff(c, s, n)
if n.sons[bodyPos].kind != nkEmpty: if n.sons[bodyPos].kind != nkEmpty:
# for DLL generation it is annoying to check for sfImportc! # for DLL generation it is annoying to check for sfImportc!
if sfBorrow in s.flags: if sfBorrow in s.flags:
localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
if n.sons[genericParamsPos].kind == nkEmpty: let usePseudoGenerics = kind in {skMacro, skTemplate}
paramsTypeCheck(c, s.typ) # Macros and Templates can have generic parameters, but they are
# only used for overload resolution (there is no instantiation of
# the symbol, so we must process the body now)
if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
if not usePseudoGenerics: paramsTypeCheck(c, s.typ)
pushProcCon(c, s) pushProcCon(c, s)
maybeAddResult(c, s, n) maybeAddResult(c, s, n)
if sfImportc notin s.flags: if sfImportc notin s.flags:
@ -1052,13 +1056,13 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# context as it may even be evaluated in 'system.compiles': # context as it may even be evaluated in 'system.compiles':
n.sons[bodyPos] = transformBody(c.module, semBody, s) n.sons[bodyPos] = transformBody(c.module, semBody, s)
popProcCon(c) popProcCon(c)
else: else:
if s.typ.sons[0] != nil and kind != skIterator: if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
var toBind = initIntSet() var toBind = initIntSet()
n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind) n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind)
fixupInstantiatedSymbols(c, s) fixupInstantiatedSymbols(c, s)
if sfImportc in s.flags: if sfImportc in s.flags:
# so we just ignore the body after semantic checking for importc: # so we just ignore the body after semantic checking for importc:
n.sons[bodyPos] = ast.emptyNode n.sons[bodyPos] = ast.emptyNode
else: else:

View file

@ -18,7 +18,7 @@ proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
if result.kind == tyForward: result.kind = kind if result.kind == tyForward: result.kind = kind
proc newConstraint(c: PContext, k: TTypeKind): PType = proc newConstraint(c: PContext, k: TTypeKind): PType =
result = newTypeS(tyTypeClass, c) result = newTypeS(tyBuiltInTypeClass, c)
result.addSonSkipIntLit(newTypeS(k, c)) result.addSonSkipIntLit(newTypeS(k, c))
proc semEnum(c: PContext, n: PNode, prev: PType): PType = proc semEnum(c: PContext, n: PNode, prev: PType): PType =
@ -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):
@ -579,9 +579,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"
@ -593,18 +593,21 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
let typedescId = getIdent"typedesc" let typedescId = getIdent"typedesc"
template shouldHaveMeta(t) =
InternalAssert tfHasMeta in result.lastSon.flags
# result.lastSon.flags.incl tfHasMeta
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
paramType: PType, paramName: string, paramType: PType, paramName: string,
info: TLineInfo, anon = false): PType = info: TLineInfo, anon = false): PType =
if procKind in {skMacro, skTemplate}:
# generic param types in macros and templates affect overload
# resolution, but don't work as generic params when it comes
# to proc instantiation. We don't need to lift such params here.
return
proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType = proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType =
let finalTypId = if typId != nil: typId let finalTypId = if typId != nil: typId
else: getIdent(paramName & ":type") else: getIdent(paramName & ":type")
if genericParams == nil:
# This happens with anonymous proc types appearing in signatures
# XXX: we need to lift these earlier
return
# is this a bindOnce type class already present in the param list? # is this a bindOnce type class already present in the param list?
for i in countup(0, genericParams.len - 1): for i in countup(0, genericParams.len - 1):
if genericParams.sons[i].sym.name.id == finalTypId.id: if genericParams.sons[i].sym.name.id == finalTypId.id:
@ -618,7 +621,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
s.position = genericParams.len s.position = genericParams.len
genericParams.addSon(newSymNode(s)) genericParams.addSon(newSymNode(s))
result = typeClass result = typeClass
# XXX: There are codegen errors if this is turned into a nested proc # XXX: There are codegen errors if this is turned into a nested proc
template liftingWalk(typ: PType, anonFlag = false): expr = template liftingWalk(typ: PType, anonFlag = false): expr =
liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag) liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
@ -631,25 +634,27 @@ 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)
# no constraints, treat like generic param of tyStatic:
result = addImplicitGeneric(newTypeS(tyGenericParam, c)) # proc(a: expr{string}, b: expr{nkLambda})
else: # overload on compile time values and AST trees
# proc(a: expr{string}, b: expr{nkLambda}) result = addImplicitGeneric(c.newTypeWithSons(tyStatic, paramType.sons))
# overload on compile time values and AST trees result.flags.incl tfHasStatic
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
if paramType.sonsLen == 0 and paramTypId != nil and if paramType.sonsLen == 0 and paramTypId != nil and
paramTypId.id == typedescId.id: paramTypId = nil paramTypId.id == typedescId.id: paramTypId = nil
result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons)) result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons))
of tyDistinct: of tyDistinct:
if paramType.sonsLen == 1: if paramType.sonsLen == 1:
# disable the bindOnce behavior for the type class # disable the bindOnce behavior for the type class
result = liftingWalk(paramType.sons[0], true) result = liftingWalk(paramType.sons[0], true)
of tySequence, tySet, tyArray, tyOpenArray: of tySequence, tySet, tyArray, tyOpenArray:
# XXX: this is a bit strange, but proc(s: seq) # XXX: this is a bit strange, but proc(s: seq)
# produces tySequence(tyGenericParam, null). # produces tySequence(tyGenericParam, null).
@ -658,7 +663,8 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
# Maybe there is another better place to associate # Maybe there is another better place to associate
# the seq type class with the seq identifier. # the seq type class with the seq identifier.
if paramType.lastSon == nil: if paramType.lastSon == nil:
let typ = c.newTypeWithSons(tyTypeClass, @[newTypeS(paramType.kind, c)]) let typ = c.newTypeWithSons(tyBuiltInTypeClass,
@[newTypeS(paramType.kind, c)])
result = addImplicitGeneric(typ) result = addImplicitGeneric(typ)
else: else:
for i in 0 .. <paramType.sons.len: for i in 0 .. <paramType.sons.len:
@ -666,29 +672,45 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
if lifted != nil: if lifted != nil:
paramType.sons[i] = lifted paramType.sons[i] = lifted
result = paramType result = paramType
of tyGenericBody: of tyGenericBody:
# type Foo[T] = object result = newTypeS(tyGenericInvokation, c)
# proc x(a: Foo, b: Foo) result.rawAddSon(paramType)
var typ = newTypeS(tyTypeClass, c) for i in 0 .. paramType.sonsLen - 2:
typ.addSonSkipIntLit(paramType) result.rawAddSon(copyType(paramType.sons[i], getCurrOwner(), true))
result = addImplicitGeneric(typ) result = instGenericContainer(c, paramType.sym.info, result,
allowMetaTypes = true)
result.lastSon.shouldHaveMeta
result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
result = addImplicitGeneric(result)
of tyGenericInst: of tyGenericInst:
for i in 1 .. (paramType.sons.len - 2): for i in 1 .. (paramType.sons.len - 2):
var lifted = liftingWalk(paramType.sons[i]) var lifted = liftingWalk(paramType.sons[i])
if lifted != nil: if lifted != nil:
paramType.sons[i] = lifted paramType.sons[i] = lifted
result = paramType result = paramType
result.lastSon.shouldHaveMeta
if paramType.lastSon.kind == tyTypeClass: let liftBody = liftingWalk(paramType.lastSon)
result = paramType if liftBody != nil:
result.kind = tyParametricTypeClass result = liftBody
result = addImplicitGeneric(copyType(result, result.shouldHaveMeta
getCurrOwner(), false))
elif result != nil: of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
result.kind = tyGenericInvokation result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
result.sons.setLen(result.sons.len - 1)
of tyTypeClass: of tyExpr:
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), false)) if procKind notin {skMacro, skTemplate}:
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
of tyGenericParam:
if tfGenericTypeParam in paramType.flags and false:
if paramType.sonsLen > 0:
result = liftingWalk(paramType.lastSon)
else:
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
else: nil else: nil
# result = liftingWalk(paramType) # result = liftingWalk(paramType)
@ -745,8 +767,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)
@ -842,7 +865,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
else: else:
internalAssert s.typ.kind == tyGenericBody internalAssert s.typ.kind == tyGenericBody
var m = newCandidate(s, n) var m = newCandidate(c, s, n)
matches(c, n, copyTree(n), m) matches(c, n, copyTree(n), m)
if m.state != csMatch: if m.state != csMatch:
@ -867,12 +890,15 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
when oUseLateInstantiation: when oUseLateInstantiation:
result = lateInstantiateGeneric(c, result, n.info) result = lateInstantiateGeneric(c, result, n.info)
else: else:
result = instGenericContainer(c, n, result) result = instGenericContainer(c, n.info, result,
allowMetaTypes = not isConcrete)
if not isConcrete and result.kind == tyGenericInst:
result.lastSon.shouldHaveMeta
proc semTypeExpr(c: PContext, n: PNode): PType = proc semTypeExpr(c: PContext, n: PNode): PType =
var n = semExprWithType(c, n, {efDetermineType}) var n = semExprWithType(c, n, {efDetermineType})
if n.kind == nkSym and n.sym.kind == skType: if n.typ.kind == tyTypeDesc:
result = n.sym.typ result = n.typ.base
else: else:
localError(n.info, errTypeExpected, n.renderTree) localError(n.info, errTypeExpected, n.renderTree)
@ -921,24 +947,27 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
var var
t1 = semTypeNode(c, n.sons[1], nil) t1 = semTypeNode(c, n.sons[1], nil)
t2 = semTypeNode(c, n.sons[2], nil) t2 = semTypeNode(c, n.sons[2], nil)
if t1 == nil: if t1 == nil:
localError(n.sons[1].info, errTypeExpected) localError(n.sons[1].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c) result = newOrPrevType(tyError, prev, c)
elif t2 == nil: elif t2 == nil:
localError(n.sons[2].info, errTypeExpected) localError(n.sons[2].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c) result = newOrPrevType(tyError, prev, c)
else: else:
result = newTypeS(tyTypeClass, c) result = if op.id == ord(wAnd): makeAndType(c, t1, t2)
result.addSonSkipIntLit(t1) else: makeOrType(c, t1, t2)
result.addSonSkipIntLit(t2)
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
result.flags.incl(tfHasMeta)
elif op.id == ord(wNot): elif op.id == ord(wNot):
checkSonsLen(n, 3) case n.len
result = semTypeNode(c, n.sons[1], prev) of 3:
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit: result = semTypeNode(c, n.sons[1], prev)
result = freshType(result, prev) if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
result.flags.incl(tfNotNil) result = freshType(result, prev)
result.flags.incl(tfNotNil)
else:
LocalError(n.info, errGenerated, "invalid type")
of 2:
let negated = semTypeNode(c, n.sons[1], prev)
result = makeNotType(c, negated)
else: else:
localError(n.info, errGenerated, "invalid type") localError(n.info, errGenerated, "invalid type")
else: else:
@ -1004,6 +1033,11 @@ 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)
result.flags.incl tfHasStatic
of nkProcTy, nkIteratorTy: of nkProcTy, nkIteratorTy:
if n.sonsLen == 0: if n.sonsLen == 0:
result = newConstraint(c, tyProc) result = newConstraint(c, tyProc)
@ -1088,11 +1122,7 @@ proc processMagicType(c: PContext, m: PSym) =
else: localError(m.info, errTypeExpected) else: localError(m.info, errTypeExpected)
proc semGenericConstraints(c: PContext, x: PType): PType = proc semGenericConstraints(c: PContext, x: PType): PType =
if x.kind in StructuralEquivTypes and ( result = newTypeWithSons(c, tyGenericParam, @[x])
sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
result = newConstraint(c, x.kind)
else:
result = newTypeWithSons(c, tyGenericParam, @[x])
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
result = copyNode(n) result = copyNode(n)
@ -1109,7 +1139,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)
@ -1120,14 +1150,16 @@ 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)
if typ == nil: if typ == nil:
typ = newTypeS(tyGenericParam, c) typ = newTypeS(tyGenericParam, c)
typ.flags.incl tfGenericTypeParam
for j in countup(0, L-3): for j in countup(0, L-3):
let finalType = if j == 0: typ let finalType = if j == 0: typ
else: copyType(typ, typ.owner, false) else: copyType(typ, typ.owner, false)
@ -1136,7 +1168,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

@ -17,14 +17,14 @@ proc checkPartialConstructedType(info: TLineInfo, t: PType) =
elif t.kind == tyVar and t.sons[0].kind == tyVar: elif t.kind == tyVar and t.sons[0].kind == tyVar:
localError(info, errVarVarTypeNotAllowed) localError(info, errVarVarTypeNotAllowed)
proc checkConstructedType*(info: TLineInfo, typ: PType) = proc checkConstructedType*(info: TLineInfo, typ: PType) =
var t = typ.skipTypes({tyDistinct}) var t = typ.skipTypes({tyDistinct})
if t.kind in {tyTypeClass}: nil if t.kind in tyTypeClasses: nil
elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
localError(info, errInvalidPragmaX, "acyclic") localError(info, errInvalidPragmaX, "acyclic")
elif t.kind == tyVar and t.sons[0].kind == tyVar: elif t.kind == tyVar and t.sons[0].kind == tyVar:
localError(info, errVarVarTypeNotAllowed) localError(info, errVarVarTypeNotAllowed)
elif computeSize(t) < 0: elif computeSize(t) == szIllegalRecursion:
localError(info, errIllegalRecursionInTypeX, typeToString(t)) localError(info, errIllegalRecursionInTypeX, typeToString(t))
when false: when false:
if t.kind == tyObject and t.sons[0] != nil: if t.kind == tyObject and t.sons[0] != nil:
@ -50,9 +50,10 @@ proc searchInstTypes*(key: PType): PType =
block matchType: block matchType:
for j in 1 .. high(key.sons): for j in 1 .. high(key.sons):
# XXX sameType is not really correct for nested generics? # XXX sameType is not really correct for nested generics?
if not sameType(inst.sons[j], key.sons[j]): if not compareTypes(inst.sons[j], key.sons[j],
flags = {ExactGenericParams}):
break matchType break matchType
return inst return inst
proc cacheTypeInst*(inst: PType) = proc cacheTypeInst*(inst: PType) =
@ -67,6 +68,8 @@ type
typeMap*: TIdTable # map PType to PType typeMap*: TIdTable # map PType to PType
symMap*: TIdTable # map PSym to PSym symMap*: TIdTable # map PSym to PSym
info*: TLineInfo info*: TLineInfo
allowMetaTypes*: bool # allow types such as seq[Number]
# i.e. the result contains unresolved generics
proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
@ -132,11 +135,12 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType = proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t)) result = PType(idTableGet(cl.typeMap, t))
if result == nil: if result == nil:
if cl.allowMetaTypes or tfRetType in t.flags: return
localError(t.sym.info, errCannotInstantiateX, typeToString(t)) localError(t.sym.info, errCannotInstantiateX, typeToString(t))
result = errorType(cl.c) result = errorType(cl.c)
elif result.kind == tyGenericParam: elif result.kind == tyGenericParam and not cl.allowMetaTypes:
internalError(cl.info, "substitution with generic parameter") internalError(cl.info, "substitution with generic parameter")
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
# tyGenericInvokation[A, tyGenericInvokation[A, B]] # tyGenericInvokation[A, tyGenericInvokation[A, B]]
# is difficult to handle: # is difficult to handle:
@ -150,11 +154,11 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
var x = t.sons[i] var x = t.sons[i]
if x.kind == tyGenericParam: if x.kind == tyGenericParam:
x = lookupTypeVar(cl, x) x = lookupTypeVar(cl, x)
if header == nil: header = copyType(t, t.owner, false) if x != nil:
header.sons[i] = x if header == nil: header = copyType(t, t.owner, false)
propagateToOwner(header, x) header.sons[i] = x
#idTablePut(cl.typeMap, body.sons[i-1], x) propagateToOwner(header, x)
if header != nil: if header != nil:
# search again after first pass: # search again after first pass:
result = searchInstTypes(header) result = searchInstTypes(header)
@ -166,7 +170,8 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
# recursive instantions: # recursive instantions:
result = newType(tyGenericInst, t.sons[0].owner) result = newType(tyGenericInst, t.sons[0].owner)
result.rawAddSon(header.sons[0]) result.rawAddSon(header.sons[0])
cacheTypeInst(result) if not cl.allowMetaTypes:
cacheTypeInst(result)
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):
var x = replaceTypeVarsT(cl, t.sons[i]) var x = replaceTypeVarsT(cl, t.sons[i])
@ -179,7 +184,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
# if one of the params is not concrete, we cannot do anything # if one of the params is not concrete, we cannot do anything
# but we already raised an error! # but we already raised an error!
rawAddSon(result, header.sons[i]) rawAddSon(result, header.sons[i])
var newbody = replaceTypeVarsT(cl, lastSon(body)) var newbody = replaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + t.flags + body.flags newbody.flags = newbody.flags + t.flags + body.flags
result.flags = result.flags + newbody.flags result.flags = result.flags + newbody.flags
@ -194,28 +199,39 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType = proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result = t result = t
if t == nil: return if t == nil: return
if t.kind == tyStatic and t.sym != nil and t.sym.kind == skGenericParam:
let s = lookupTypeVar(cl, t)
return if s != nil: s else: t
case t.kind case t.kind
of tyTypeClass: discard of tyGenericParam, tyTypeClasses:
of tyGenericParam: let lookup = lookupTypeVar(cl, t)
result = lookupTypeVar(cl, t) if lookup != nil:
if result.kind == tyGenericInvokation: result = lookup
result = handleGenericInvokation(cl, result) if result.kind == tyGenericInvokation:
of tyExpr: result = handleGenericInvokation(cl, result)
if t.sym != nil and t.sym.kind == skGenericParam: of tyGenericInvokation:
result = lookupTypeVar(cl, t)
of tyGenericInvokation:
result = handleGenericInvokation(cl, t) result = handleGenericInvokation(cl, t)
of tyGenericBody: of tyGenericBody:
internalError(cl.info, "ReplaceTypeVarsT: tyGenericBody") internalError(cl.info, "ReplaceTypeVarsT: tyGenericBody" )
result = replaceTypeVarsT(cl, lastSon(t)) result = replaceTypeVarsT(cl, lastSon(t))
of tyInt: of tyInt:
result = skipIntLit(t) result = skipIntLit(t)
# XXX now there are also float literals # XXX now there are also float literals
of tyTypeDesc:
let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
if lookup != nil:
result = lookup
if tfUnresolved in t.flags: result = result.base
of tyGenericInst:
result = copyType(t, t.owner, true)
for i in 1 .. <result.sonsLen:
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
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)
@ -231,14 +247,19 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
if result.kind == tyProc and result.sons[0] != nil: if result.kind == tyProc and result.sons[0] != nil:
if result.sons[0].kind == tyEmpty: if result.sons[0].kind == tyEmpty:
result.sons[0] = nil result.sons[0] = nil
proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode, proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType = t: PType): PType =
var cl: TReplTypeVars var cl: TReplTypeVars
initIdTable(cl.symMap) initIdTable(cl.symMap)
copyIdTable(cl.typeMap, pt) copyIdTable(cl.typeMap, pt)
cl.info = arg.info cl.info = info
cl.c = p cl.c = p
pushInfoContext(arg.info) pushInfoContext(info)
result = replaceTypeVarsT(cl, t) result = replaceTypeVarsT(cl, t)
popInfoContext() popInfoContext()
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): expr =
generateTypeInstance(p, pt, arg.info, t)

View file

@ -21,7 +21,8 @@ type
TCandidateState* = enum TCandidateState* = enum
csEmpty, csMatch, csNoMatch csEmpty, csMatch, csNoMatch
TCandidate* {.final.} = object TCandidate* {.final.} = object
c*: PContext
exactMatches*: int # also misused to prefer iters over procs exactMatches*: int # also misused to prefer iters over procs
genericMatches: int # also misused to prefer constraints genericMatches: int # also misused to prefer constraints
subtypeMatches: int subtypeMatches: int
@ -58,7 +59,9 @@ const
proc markUsed*(n: PNode, s: PSym) proc markUsed*(n: PNode, s: PSym)
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = proc initCandidateAux(ctx: PContext,
c: var TCandidate, callee: PType) {.inline.} =
c.c = ctx
c.exactMatches = 0 c.exactMatches = 0
c.subtypeMatches = 0 c.subtypeMatches = 0
c.convMatches = 0 c.convMatches = 0
@ -71,17 +74,17 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
c.genericConverter = false c.genericConverter = false
c.inheritancePenalty = 0 c.inheritancePenalty = 0
proc initCandidate*(c: var TCandidate, callee: PType) = proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
initCandidateAux(c, callee) initCandidateAux(ctx, c, callee)
c.calleeSym = nil c.calleeSym = nil
initIdTable(c.bindings) initIdTable(c.bindings)
proc put(t: var TIdTable, key, val: PType) {.inline.} = proc put(t: var TIdTable, key, val: PType) {.inline.} =
idTablePut(t, key, val) idTablePut(t, key, val)
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode, proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
calleeScope = -1) = binding: PNode, calleeScope = -1) =
initCandidateAux(c, callee.typ) initCandidateAux(ctx, c, callee.typ)
c.calleeSym = callee c.calleeSym = callee
c.calleeScope = calleeScope c.calleeScope = calleeScope
initIdTable(c.bindings) initIdTable(c.bindings)
@ -90,13 +93,17 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
var typeParams = callee.ast[genericParamsPos] var typeParams = callee.ast[genericParamsPos]
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1): for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
var formalTypeParam = typeParams.sons[i-1].typ var formalTypeParam = typeParams.sons[i-1].typ
#debug(formalTypeParam) var bound = binding[i].typ
put(c.bindings, formalTypeParam, binding[i].typ) if formalTypeParam.kind != tyTypeDesc:
bound = bound.skipTypes({tyTypeDesc})
put(c.bindings, formalTypeParam, bound)
proc newCandidate*(callee: PSym, binding: PNode, calleeScope = -1): TCandidate = proc newCandidate*(ctx: PContext, callee: PSym,
initCandidate(result, callee, binding, calleeScope) binding: PNode, calleeScope = -1): TCandidate =
initCandidate(ctx, result, callee, binding, calleeScope)
proc copyCandidate(a: var TCandidate, b: TCandidate) = proc copyCandidate(a: var TCandidate, b: TCandidate) =
a.c = b.c
a.exactMatches = b.exactMatches a.exactMatches = b.exactMatches
a.subtypeMatches = b.subtypeMatches a.subtypeMatches = b.subtypeMatches
a.convMatches = b.convMatches a.convMatches = b.convMatches
@ -124,7 +131,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 =
@ -203,7 +210,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
add(result, argTypeToString(arg)) add(result, argTypeToString(arg))
if i != sonsLen(n) - 1: add(result, ", ") if i != sonsLen(n) - 1: add(result, ", ")
proc typeRel*(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
proc concreteType(c: TCandidate, t: PType): PType = proc concreteType(c: TCandidate, t: PType): PType =
case t.kind case t.kind
of tyArrayConstr: of tyArrayConstr:
@ -296,24 +303,27 @@ proc minRel(a, b: TTypeRelation): TTypeRelation =
if a <= b: result = a if a <= b: result = a
else: result = b else: result = b
proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation = proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = isNone result = isNone
if sameType(f, a): if sameType(f, a): result = isEqual
result = isEqual
elif sonsLen(a) == sonsLen(f): elif sonsLen(a) == sonsLen(f):
result = isEqual result = isEqual
for i in countup(0, sonsLen(f) - 1): let firstField = if f.kind == tyTuple: 0
else: 1
for i in countup(firstField, sonsLen(f) - 1):
var m = typeRel(c, f.sons[i], a.sons[i]) var m = typeRel(c, f.sons[i], a.sons[i])
if m < isSubtype: return isNone if m < isSubtype: return isNone
result = minRel(result, m) result = minRel(result, m)
if f.n != nil and a.n != nil: if f.n != nil and a.n != nil:
for i in countup(0, sonsLen(f.n) - 1): for i in countup(0, sonsLen(f.n) - 1):
# check field names: # check field names:
if f.n.sons[i].kind != nkSym: internalError(f.n.info, "tupleRel") if f.n.sons[i].kind != nkSym: internalError(f.n.info, "recordRel")
elif a.n.sons[i].kind != nkSym: internalError(a.n.info, "tupleRel") elif a.n.sons[i].kind != nkSym: internalError(a.n.info, "recordRel")
else: else:
var x = f.n.sons[i].sym var x = f.n.sons[i].sym
var y = a.n.sons[i].sym var y = a.n.sons[i].sym
if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype:
return isNone
if x.name.id != y.name.id: return isNone if x.name.id != y.name.id: return isNone
proc allowsNil(f: PType): TTypeRelation {.inline.} = proc allowsNil(f: PType): TTypeRelation {.inline.} =
@ -365,10 +375,6 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
of tyNil: result = f.allowsNil of tyNil: result = f.allowsNil
else: nil else: nil
proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
result = if matchTypeClass(c.bindings, f, a): isGeneric
else: isNone
proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
let let
a0 = firstOrd(a) a0 = firstOrd(a)
@ -385,7 +391,7 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
else: else:
result = isNone result = isNone
proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation = proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# typeRel can be used to establish various relationships between types: # typeRel can be used to establish various relationships between types:
# #
# 1) When used with concrete types, it will check for type equivalence # 1) When used with concrete types, it will check for type equivalence
@ -401,20 +407,22 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
# order to give preferrence to the most specific one: # order to give preferrence to the most specific one:
# #
# seq[seq[any]] is a strict subset of seq[any] and hence more specific. # seq[seq[any]] is a strict subset of seq[any] and hence more specific.
result = isNone result = isNone
assert(f != nil) assert(f != nil)
assert(a != nil) assert(aOrig != nil)
# var and static arguments match regular modifier-free types
let a = aOrig.skipTypes({tyStatic, tyVar})
if a.kind == tyGenericInst and if a.kind == tyGenericInst and
skipTypes(f, {tyVar}).kind notin { skipTypes(f, {tyVar}).kind notin {
tyGenericBody, tyGenericInvokation, tyGenericBody, tyGenericInvokation,
tyGenericParam, tyTypeClass}: tyGenericInst, tyGenericParam} + tyTypeClasses:
return typeRel(c, f, lastSon(a)) return typeRel(c, f, lastSon(a))
if a.kind == tyVar and f.kind != tyVar:
return typeRel(c, f, a.sons[0])
template bindingRet(res) = template bindingRet(res) =
when res == isGeneric: put(c.bindings, f, a) when res == isGeneric: put(c.bindings, f, aOrig)
return res return res
case a.kind case a.kind
@ -457,10 +465,10 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
else: nil else: nil
case f.kind case f.kind
of tyEnum: of tyEnum:
if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual
elif sameEnumTypes(f, skipTypes(a, {tyRange})): result = isSubtype elif sameEnumTypes(f, skipTypes(a, {tyRange})): result = isSubtype
of tyBool, tyChar: of tyBool, tyChar:
if a.kind == f.kind: result = isEqual if a.kind == f.kind: result = isEqual
elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
of tyRange: of tyRange:
@ -488,9 +496,9 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
of tyFloat32: result = handleFloatRange(f, a) of tyFloat32: result = handleFloatRange(f, a)
of tyFloat64: result = handleFloatRange(f, a) of tyFloat64: result = handleFloatRange(f, a)
of tyFloat128: result = handleFloatRange(f, a) of tyFloat128: result = handleFloatRange(f, a)
of tyVar: of tyVar:
if a.kind == f.kind: result = typeRel(c, base(f), base(a)) if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
else: result = typeRel(c, base(f), a) else: result = typeRel(c, f.base, aOrig)
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
# tyArrayConstr cannot happen really, but # tyArrayConstr cannot happen really, but
# we wanna be safe here # we wanna be safe here
@ -544,7 +552,6 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
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
if f.sonsLen == 0: if f.sonsLen == 0:
result = isGeneric result = isGeneric
else: else:
@ -556,10 +563,11 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
of tyNil: of tyNil:
if a.kind == f.kind: result = isEqual if a.kind == f.kind: result = isEqual
of tyTuple: of tyTuple:
if a.kind == tyTuple: result = tupleRel(c, f, a) if a.kind == tyTuple: result = recordRel(c, f, a)
of tyObject: of tyObject:
if a.kind == tyObject: if a.kind == tyObject:
if sameObjectTypes(f, a): result = isEqual if sameObjectTypes(f, a): result = isEqual
elif tfHasMeta in f.flags: result = recordRel(c, f, a)
else: else:
var depth = isObjectSubtype(a, f) var depth = isObjectSubtype(a, f)
if depth > 0: if depth > 0:
@ -641,9 +649,18 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
if a.kind == tyEmpty: result = isEqual if a.kind == tyEmpty: result = isEqual
of tyGenericInst: of tyGenericInst:
result = typeRel(c, lastSon(f), a) if a.kind == tyGenericInst:
if a.base != f.base: return isNone
for i in 1 .. f.sonsLen-2:
result = typeRel(c, f.sons[i], a.sons[i])
if result == isNone: return
result = isGeneric
else:
result = typeRel(c, lastSon(f), a)
of tyGenericBody: of tyGenericBody:
if a.kind == tyGenericInst and a.sons[0] == f:
return isGeneric
let ff = lastSon(f) let ff = lastSon(f)
if ff != nil: result = typeRel(c, ff, a) if ff != nil: result = typeRel(c, ff, a)
@ -673,21 +690,21 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
of tyAnd: of tyAnd:
for branch in f.sons: for branch in f.sons:
if typeRel(c, branch, a) == isNone: if typeRel(c, branch, aOrig) == isNone:
return isNone return isNone
bindingRet isGeneric bindingRet isGeneric
of tyOr: of tyOr:
for branch in f.sons: for branch in f.sons:
if typeRel(c, branch, a) != isNone: if typeRel(c, branch, aOrig) != isNone:
bindingRet isGeneric bindingRet isGeneric
return isNone return isNone
of tyNot: of tyNot:
for branch in f.sons: for branch in f.sons:
if typeRel(c, branch, a) != isNone: if typeRel(c, branch, aOrig) != isNone:
return isNone return isNone
bindingRet isGeneric bindingRet isGeneric
@ -701,7 +718,31 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
return isGeneric return isGeneric
else: else:
return typeRel(c, prev, a) return typeRel(c, prev, a)
of tyBuiltInTypeClass:
var prev = PType(idTableGet(c.bindings, f))
if prev == nil:
let targetKind = f.sons[0].kind
if targetKind == a.skipTypes({tyRange, tyGenericInst}).kind or
(targetKind in {tyProc, tyPointer} and a.kind == tyNil):
put(c.bindings, f, a)
return isGeneric
else:
return isNone
else:
result = typeRel(c, prev, a)
of tyCompositeTypeClass:
var prev = PType(idTableGet(c.bindings, f))
if prev == nil:
if typeRel(c, f.sons[1], a) != isNone:
put(c.bindings, f, a)
return isGeneric
else:
return isNone
else:
result = typeRel(c, prev, a)
of tyGenericParam, tyTypeClass: of tyGenericParam, tyTypeClass:
var x = PType(idTableGet(c.bindings, f)) var x = PType(idTableGet(c.bindings, f))
if x == nil: if x == nil:
@ -722,11 +763,11 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
else: else:
result = isNone result = isNone
else: else:
if a.kind == tyTypeClass: if f.sonsLen > 0:
result = isGeneric result = typeRel(c, f.lastSon, a)
else: else:
result = matchTypeClass(c, f, a) result = isGeneric
if result == isGeneric: if result == isGeneric:
var concrete = concreteType(c, a) var concrete = concreteType(c, a)
if concrete == nil: if concrete == nil:
@ -739,6 +780,14 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
result = isGeneric result = isGeneric
else: else:
result = typeRel(c, x, a) # check if it fits result = typeRel(c, x, a) # check if it fits
of tyStatic:
if aOrig.kind == tyStatic:
result = typeRel(c, f.lastSon, a)
if result != isNone: put(c.bindings, f, aOrig)
else:
result = isNone
of tyTypeDesc: of tyTypeDesc:
var prev = PType(idTableGet(c.bindings, f)) var prev = PType(idTableGet(c.bindings, f))
if prev == nil: if prev == nil:
@ -746,8 +795,8 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
if f.sonsLen == 0: if f.sonsLen == 0:
result = isGeneric result = isGeneric
else: else:
result = matchTypeClass(c, f, a.sons[0]) result = typeRel(c, f.sons[0], a.sons[0])
if result == isGeneric: if result != isNone:
put(c.bindings, f, a) put(c.bindings, f, a)
else: else:
result = isNone result = isNone
@ -756,16 +805,19 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
let toMatch = if tfUnresolved in f.flags: a let toMatch = if tfUnresolved in f.flags: a
else: a.sons[0] else: a.sons[0]
result = typeRel(c, prev.sons[0], toMatch) result = typeRel(c, prev.sons[0], toMatch)
of tyExpr, tyStmt: of tyExpr, tyStmt:
result = isGeneric result = isGeneric
of tyProxy: of tyProxy:
result = isEqual result = isEqual
else: internalError("typeRel: " & $f.kind) else: internalError("typeRel: " & $f.kind)
proc cmpTypes*(f, a: PType): TTypeRelation = proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
var c: TCandidate var m: TCandidate
initCandidate(c, f) initCandidate(c, m, f)
result = typeRel(c, f, a) result = typeRel(m, f, a)
proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
f: PType): PType = f: PType): PType =
@ -887,47 +939,34 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
result = arg result = arg
put(m.bindings, f, a) put(m.bindings, f, a)
proc paramTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType, proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
argSemantized, argOrig: PNode): PNode = argSemantized, argOrig: PNode): PNode =
var var
r: TTypeRelation fMaybeStatic = f.skipTypes({tyDistinct})
arg = argSemantized arg = argSemantized
argType = argType
c = m.c
let if tfHasStatic in fMaybeStatic.flags:
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc}) # XXX: When implicit statics are the default
# this will be done earlier - we just have to
# make sure that static types enter here
var evaluated = c.semTryConstExpr(c, arg)
if evaluated != nil:
arg.typ = newTypeS(tyStatic, c)
arg.typ.sons = @[evaluated.typ]
arg.typ.n = evaluated
argType = arg.typ
var
r: TTypeRelation
a = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc})
else: argType else: argType
fMaybeExpr = f.skipTypes({tyDistinct})
case fMaybeStatic.kind
case fMaybeExpr.kind
of tyExpr:
if fMaybeExpr.sonsLen == 0:
r = isGeneric
else:
if a.kind == tyExpr:
internalAssert a.len > 0
r = typeRel(m, f.lastSon, a.lastSon)
else:
let match = matchTypeClass(m.bindings, fMaybeExpr, a)
if not match: 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.sons = @[evaluated.typ]
arg.typ.n = evaluated
if r == isGeneric:
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,11 +974,14 @@ 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)
case r case r
of isConvertible: of isConvertible:
inc(m.convMatches) inc(m.convMatches)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isIntConv: of isIntConv:
@ -961,6 +1003,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:
@ -1003,19 +1047,20 @@ proc paramTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
else: else:
result = userConvMatch(c, m, base(f), a, arg) result = userConvMatch(c, m, base(f), a, arg)
proc paramTypesMatch*(c: PContext, m: var TCandidate, f, a: PType, proc paramTypesMatch*(m: var TCandidate, f, a: PType,
arg, argOrig: PNode): PNode = arg, argOrig: PNode): PNode =
if arg == nil or arg.kind notin nkSymChoices: if arg == nil or arg.kind notin nkSymChoices:
result = paramTypesMatchAux(c, m, f, a, arg, argOrig) result = paramTypesMatchAux(m, f, a, arg, argOrig)
else: else:
# CAUTION: The order depends on the used hashing scheme. Thus it is # CAUTION: The order depends on the used hashing scheme. Thus it is
# incorrect to simply use the first fitting match. However, to implement # incorrect to simply use the first fitting match. However, to implement
# this correctly is inefficient. We have to copy `m` here to be able to # this correctly is inefficient. We have to copy `m` here to be able to
# roll back the side effects of the unification algorithm. # roll back the side effects of the unification algorithm.
let c = m.c
var x, y, z: TCandidate var x, y, z: TCandidate
initCandidate(x, m.callee) initCandidate(c, x, m.callee)
initCandidate(y, m.callee) initCandidate(c, y, m.callee)
initCandidate(z, m.callee) initCandidate(c, z, m.callee)
x.calleeSym = m.calleeSym x.calleeSym = m.calleeSym
y.calleeSym = m.calleeSym y.calleeSym = m.calleeSym
z.calleeSym = m.calleeSym z.calleeSym = m.calleeSym
@ -1047,7 +1092,7 @@ proc paramTypesMatch*(c: PContext, m: var TCandidate, f, a: PType,
else: else:
# only one valid interpretation found: # only one valid interpretation found:
markUsed(arg, arg.sons[best].sym) markUsed(arg, arg.sons[best].sym)
result = paramTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best], result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
argOrig) argOrig)
proc setSon(father: PNode, at: int, son: PNode) = proc setSon(father: PNode, at: int, son: PNode) =
@ -1138,7 +1183,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1]) n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
n.sons[a].typ = n.sons[a].sons[1].typ n.sons[a].typ = n.sons[a].sons[1].typ
var arg = paramTypesMatch(c, m, formal.typ, n.sons[a].typ, var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a].sons[1], nOrig.sons[a].sons[1]) n.sons[a].sons[1], nOrig.sons[a].sons[1])
if arg == nil: if arg == nil:
m.state = csNoMatch m.state = csNoMatch
@ -1168,7 +1213,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
elif formal != nil: elif formal != nil:
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(c, m, formal.typ, n.sons[a].typ, var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a]) n.sons[a], nOrig.sons[a])
if (arg != nil) and m.baseTypeMatch and (container != nil): if (arg != nil) and m.baseTypeMatch and (container != nil):
addSon(container, arg) addSon(container, arg)
@ -1191,7 +1236,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
return return
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(c, m, formal.typ, n.sons[a].typ, var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a]) n.sons[a], nOrig.sons[a])
if arg == nil: if arg == nil:
m.state = csNoMatch m.state = csNoMatch
@ -1245,8 +1290,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
proc argtypeMatches*(c: PContext, f, a: PType): bool = proc argtypeMatches*(c: PContext, f, a: PType): bool =
var m: TCandidate var m: TCandidate
initCandidate(m, f) initCandidate(c, m, f)
let res = paramTypesMatch(c, m, f, a, ast.emptyNode, nil) let res = paramTypesMatch(m, f, a, ast.emptyNode, nil)
#instantiateGenericConverters(c, res, m) #instantiateGenericConverters(c, res, m)
# XXX this is used by patterns.nim too; I think it's better to not # XXX this is used by patterns.nim too; I think it's better to not
# instantiate generic converters for that # instantiate generic converters for that
@ -1308,7 +1353,7 @@ tests:
setup: setup:
var c: TCandidate var c: TCandidate
InitCandidate(c, nil) InitCandidate(nil, c, nil)
template yes(x, y) = template yes(x, y) =
test astToStr(x) & " is " & astToStr(y): test astToStr(x) & " is " & astToStr(y):

View file

@ -119,7 +119,7 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
case candidate.kind case candidate.kind
of OverloadableSyms: of OverloadableSyms:
var m: TCandidate var m: TCandidate
initCandidate(m, candidate, nil) initCandidate(c, m, candidate, nil)
sigmatch.partialMatch(c, n, nOrig, m) sigmatch.partialMatch(c, n, nOrig, m)
result = m.state != csNoMatch result = m.state != csNoMatch
else: else:

View file

@ -410,18 +410,8 @@ 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", "BuiltInTypeClass", "CompositeTypeClass",
"and", "or", "not", "any", "static"]
proc consToStr(t: PType): string =
if t.len > 0: result = t.typeToString
else: result = typeToStr[t.kind].strip
proc constraintsToStr(t: PType): string =
let sep = if tfAny in t.flags: " or " else: " and "
result = ""
for i in countup(0, t.len - 1):
if i > 0: result.add(sep)
result.add(t.sons[i].consToStr)
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
var t = typ var t = typ
@ -445,16 +435,24 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
add(result, ']') add(result, ']')
of tyTypeDesc: of tyTypeDesc:
if t.len == 0: result = "typedesc" if t.len == 0: result = "typedesc"
else: result = "typedesc[" & constraintsToStr(t) & "]" else: result = "typedesc[" & typeToString(t.sons[0]) & "]"
of tyStatic:
InternalAssert t.len > 0
result = "static[" & typeToString(t.sons[0]) & "]"
of tyTypeClass: of tyTypeClass:
if t.n != nil: return t.sym.owner.name.s InternalAssert t.sym != nil and t.sym.owner != nil
case t.len return t.sym.owner.name.s
of 0: result = "typeclass[]" of tyBuiltInTypeClass:
of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]" return "TypeClass"
else: result = constraintsToStr(t) of tyAnd:
result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
of tyOr:
result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
of tyNot:
result = "not " & typeToString(t.sons[0])
of tyExpr: of tyExpr:
if t.len == 0: result = "expr" InternalAssert t.len == 0
else: result = "expr[" & constraintsToStr(t) & "]" result = "expr"
of tyArray: of tyArray:
if t.sons[0].kind == tyRange: if t.sons[0].kind == tyRange:
result = "array[" & rangeToStr(t.sons[0].n) & ", " & result = "array[" & rangeToStr(t.sons[0].n) & ", " &
@ -607,8 +605,9 @@ type
dcEqOrDistinctOf ## a equals b or a is distinct of b dcEqOrDistinctOf ## a equals b or a is distinct of b
TTypeCmpFlag* = enum TTypeCmpFlag* = enum
IgnoreTupleFields, IgnoreTupleFields
TypeDescExactMatch, ExactTypeDescValues
ExactGenericParams
AllowCommonBase AllowCommonBase
TTypeCmpFlags* = set[TTypeCmpFlag] TTypeCmpFlags* = set[TTypeCmpFlag]
@ -649,7 +648,7 @@ proc sameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
result = sameTypeAux(a, b, c) result = sameTypeAux(a, b, c)
proc equalParam(a, b: PSym): TParamsEquality = proc equalParam(a, b: PSym): TParamsEquality =
if sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}) and if sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}) and
exprStructuralEquivalent(a.constraint, b.constraint): exprStructuralEquivalent(a.constraint, b.constraint):
if a.ast == b.ast: if a.ast == b.ast:
result = paramsEqual result = paramsEqual
@ -685,7 +684,7 @@ proc equalParams(a, b: PNode): TParamsEquality =
return paramsNotEqual # paramsIncompatible; return paramsNotEqual # paramsIncompatible;
# continue traversal! If not equal, we can return immediately; else # continue traversal! If not equal, we can return immediately; else
# it stays incompatible # it stays incompatible
if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {TypeDescExactMatch}): if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}):
if (a.sons[0].typ == nil) or (b.sons[0].typ == nil): if (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
result = paramsNotEqual # one proc has a result, the other not is OK result = paramsNotEqual # one proc has a result, the other not is OK
else: else:
@ -752,9 +751,9 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
proc sameObjectTypes*(a, b: PType): bool = proc sameObjectTypes*(a, b: PType): bool =
# specialized for efficiency (sigmatch uses it) # specialized for efficiency (sigmatch uses it)
ifFastObjectTypeCheckFailed(a, b): ifFastObjectTypeCheckFailed(a, b):
var c = initSameTypeClosure() var c = initSameTypeClosure()
result = sameTypeAux(a, b, c) result = sameTypeAux(a, b, c)
proc sameDistinctTypes*(a, b: PType): bool {.inline.} = proc sameDistinctTypes*(a, b: PType): bool {.inline.} =
result = sameObjectTypes(a, b) result = sameObjectTypes(a, b)
@ -829,9 +828,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):
@ -855,12 +854,15 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
result = sameTypeAux(lastSon(a), lastSon(b), c) result = sameTypeAux(lastSon(a), lastSon(b), c)
of tyTypeDesc: of tyTypeDesc:
if c.cmp == dcEqIgnoreDistinct: result = false if c.cmp == dcEqIgnoreDistinct: result = false
elif TypeDescExactMatch in c.flags: elif ExactTypeDescValues in c.flags:
cycleCheck() cycleCheck()
result = sameChildrenAux(x, y, c) and sameFlags(a, b) result = sameChildrenAux(x, y, c) and sameFlags(a, b)
else: else:
result = sameFlags(a, b) result = sameFlags(a, b)
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, of tyGenericParam:
result = if ExactGenericParams in c.flags: a.id == b.id
else: sameChildrenAux(a, b, c) and sameFlags(a, b)
of tyGenericInvokation, tyGenericBody, tySequence,
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
tyOrdinal, tyTypeClasses: tyOrdinal, tyTypeClasses:
@ -976,42 +978,6 @@ proc isGenericAlias*(t: PType): bool =
proc skipGenericAlias*(t: PType): PType = proc skipGenericAlias*(t: PType): PType =
return if t.isGenericAlias: t.lastSon else: t return if t.isGenericAlias: t.lastSon else: t
proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
for i in countup(0, typeClass.sonsLen - 1):
let req = typeClass.sons[i]
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
if not match:
case req.kind
of tyGenericBody:
if t.kind == tyGenericInst and t.sons[0] == req:
match = true
idTablePut(bindings, typeClass, t)
of tyTypeClass:
match = matchTypeClass(bindings, req, t)
elif t.kind == tyTypeClass:
match = matchTypeClass(bindings, t, req)
elif t.kind in {tyObject} and req.len != 0:
# empty 'object' is fine as constraint in a type class
match = sameType(t, req)
if tfAny in typeClass.flags:
if match: return true
else:
if not match: return false
# if the loop finished without returning, either all constraints matched
# or none of them matched.
result = if tfAny in typeClass.flags: false else: true
if result == true:
idTablePut(bindings, typeClass, t)
proc matchTypeClass*(typeClass, typ: PType): bool =
var bindings: TIdTable
initIdTable(bindings)
result = matchTypeClass(bindings, typeClass, typ)
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
flags: TTypeAllowedFlags = {}): bool = flags: TTypeAllowedFlags = {}): bool =
assert(kind in {skVar, skLet, skConst, skParam, skResult}) assert(kind in {skVar, skLet, skConst, skParam, skResult})
@ -1039,7 +1005,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:
@ -1133,18 +1099,22 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
a = 1 a = 1
result = - 1 result = - 1
proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = const
szIllegalRecursion* = -2
szUnknownSize* = -1
proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
var res, maxAlign, length, currOffset: BiggestInt var res, maxAlign, length, currOffset: BiggestInt
if typ.size == - 2: if typ.size == szIllegalRecursion:
# we are already computing the size of the type # we are already computing the size of the type
# --> illegal recursion in type # --> illegal recursion in type
return - 2 return szIllegalRecursion
if typ.size >= 0: if typ.size >= 0:
# size already computed # size already computed
result = typ.size result = typ.size
a = typ.align a = typ.align
return return
typ.size = - 2 # mark as being computed typ.size = szIllegalRecursion # mark as being computed
case typ.kind case typ.kind
of tyInt, tyUInt: of tyInt, tyUInt:
result = intSize result = intSize
@ -1175,8 +1145,10 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
tyBigNum: tyBigNum:
result = ptrSize result = ptrSize
a = result a = result
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
result = lengthOrd(typ.sons[0]) * computeSizeAux(typ.sons[1], a) let elemSize = computeSizeAux(typ.sons[1], a)
if elemSize < 0: return elemSize
result = lengthOrd(typ.sons[0]) * elemSize
of tyEnum: of tyEnum:
if firstOrd(typ) < 0: if firstOrd(typ) < 0:
result = 4 # use signed int32 result = 4 # use signed int32
@ -1227,11 +1199,12 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter: of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter:
result = computeSizeAux(lastSon(typ), a) result = computeSizeAux(lastSon(typ), a)
of tyTypeDesc: of tyTypeDesc:
result = (if typ.len == 1: computeSizeAux(typ.sons[0], a) else: -1) result = if typ.len == 1: computeSizeAux(typ.sons[0], a)
of tyProxy: result = 1 else: szUnknownSize
of tyForward: return szIllegalRecursion
else: else:
#internalError("computeSizeAux()") #internalError("computeSizeAux()")
result = - 1 result = szUnknownSize
typ.size = result typ.size = result
typ.align = int(a) typ.align = int(a)
@ -1248,9 +1221,9 @@ proc getSize(typ: PType): BiggestInt =
result = computeSize(typ) result = computeSize(typ)
if result < 0: internalError("getSize: " & $typ.kind) if result < 0: internalError("getSize: " & $typ.kind)
proc containsGenericTypeIter(t: PType, closure: PObject): bool =
proc containsGenericTypeIter(t: PType, closure: PObject): bool = result = t.kind in GenericTypes + tyTypeClasses +
result = t.kind in GenericTypes {tyTypeDesc, tyStatic}
proc containsGenericType*(t: PType): bool = proc containsGenericType*(t: PType): bool =
result = iterOverType(t, containsGenericTypeIter, nil) result = iterOverType(t, containsGenericTypeIter, nil)
@ -1315,7 +1288,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

@ -791,7 +791,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
decodeBC(nkIntLit) decodeBC(nkIntLit)
let t1 = regs[rb].typ.skipTypes({tyTypeDesc}) let t1 = regs[rb].typ.skipTypes({tyTypeDesc})
let t2 = c.types[regs[rc].intVal.int] let t2 = c.types[regs[rc].intVal.int]
let match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1) # XXX: This should use the standard isOpImpl
let match = if t2.kind == tyTypeClass: true
else: sameType(t1, t2) else: sameType(t1, t2)
regs[ra].intVal = ord(match) regs[ra].intVal = ord(match)
of opcSetLenSeq: of opcSetLenSeq:

View file

@ -832,7 +832,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,
@ -1039,8 +1039,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, tyRef: tyStmt, tyTypeDesc, tyStatic, tyRef:
result = newNodeIT(nkNilLit, info, t) result = newNodeIT(nkNilLit, info, t)
of tyProc: of tyProc:
if t.callConv != ccClosure: if t.callConv != ccClosure:

View file

@ -3837,6 +3837,60 @@ This is a simple syntactic transformation into:
Special Types Special Types
============= =============
static[T]
---------
As their name suggests, static params must be known at compile-time:
.. code-block:: nimrod
proc precompiledRegex(pattern: static[string]): TRegEx =
var res {.global.} = re(pattern)
return res
precompiledRegex("/d+") # Replaces the call with a precompiled
# regex, stored in a global variable
precompiledRegex(paramStr(1)) # Error, command-line options
# are not known at compile-time
For the purposes of code generation, all static params are treated as
generic params - the proc will be compiled separately for each unique
supplied value (or combination of values).
Furthermore, the system module defines a `semistatic[T]` type than can be
used to declare procs accepting both static and run-time values, which can
optimize their body according to the supplied param using the `isStatic(p)`
predicate:
.. code-block:: nimrod
# The following proc will be compiled once for each unique static
# value and also once for the case handling all run-time values:
proc re(pattern: semistatic[string]): TRegEx =
when isStatic(pattern):
return precompiledRegex(pattern)
else:
return compile(pattern)
Static params can also appear in the signatures of generic types:
.. code-block:: nimrod
type
Matrix[M,N: static[int]; T: Number] = array[0..(M*N - 1), T]
# Please, note how `Number` is just a type constraint here, while
# `static[int]` requires us to supply a compile-time int value
AffineTransform2D[T] = Matrix[3, 3, T]
AffineTransform3D[T] = Matrix[4, 4, T]
AffineTransform3D[float] # OK
AffineTransform2D[string] # Error, `string` is not a `Number`
typedesc typedesc
-------- --------

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,
@ -293,16 +294,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:
## .. code-block:: nimrod ##
## ## 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

@ -2550,7 +2550,7 @@ proc raiseAssert*(msg: string) {.noinline.} =
sysFatal(EAssertionFailed, msg) sysFatal(EAssertionFailed, msg)
when true: when true:
proc hiddenRaiseAssert(msg: string) {.raises: [], tags: [].} = proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
# trick the compiler to not list ``EAssertionFailed`` when called # trick the compiler to not list ``EAssertionFailed`` when called
# by ``assert``. # by ``assert``.
type THide = proc (msg: string) {.noinline, raises: [], noSideEffect, type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
@ -2563,11 +2563,11 @@ 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 instantiationInfo, hiddenRaiseAssert bind instantiationInfo
mixin failedAssertImpl
when compileOption("assertions"): when compileOption("assertions"):
{.line.}: {.line.}:
if not cond: if not cond: failedAssertImpl(astToStr(cond) & ' ' & msg)
hiddenRaiseAssert(astToStr(cond) & ' ' & 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
@ -2580,9 +2580,9 @@ template doAssert*(cond: bool, msg = "") =
when not defined(nimhygiene): when not defined(nimhygiene):
{.pragma: inject.} {.pragma: inject.}
template onFailedAssert*(msg: expr, code: stmt): stmt = template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
## Sets an assertion failure handler that will intercept any assert statements ## Sets an assertion failure handler that will intercept any assert
## following `onFailedAssert` in the current lexical scope. ## statements following `onFailedAssert` in the current lexical scope.
## Can be defined multiple times in a single function. ## Can be defined multiple times in a single function.
## ##
## .. code-block:: nimrod ## .. code-block:: nimrod
@ -2599,8 +2599,8 @@ template onFailedAssert*(msg: expr, code: stmt): stmt =
## ##
## assert(...) ## assert(...)
## ##
template raiseAssert(msgIMPL: string): stmt = template failedAssertImpl(msgIMPL: string): stmt {.dirty, immediate.} =
let msg {.inject.} = msgIMPL let msg = msgIMPL
code code
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
@ -2646,7 +2646,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:
@ -2680,3 +2680,13 @@ proc locals*(): TObject {.magic: "Locals", noSideEffect.} =
## the official signature says, the return type is not ``TObject`` but a ## the official signature says, the return type is not ``TObject`` but a
## tuple of a structure that depends on the current scope. ## tuple of a structure that depends on the current scope.
discard discard
when not defined(booting):
type
semistatic*[T] = static[T] | T
# indicates a param of proc specialized for each static value,
# but also accepting run-time values
template isStatic*(x): expr = compiles(static(x))
# checks whether `x` is a value known at compile-time

View file

@ -16,10 +16,10 @@ type
TBar = tuple TBar = tuple
x, y: int x, y: int
template good(e: expr) = template accept(e: expr) =
static: assert(compiles(e)) static: assert(compiles(e))
template bad(e: expr) = template reject(e: expr) =
static: assert(not compiles(e)) static: assert(not compiles(e))
proc genericParamRepeated[T: typedesc](a: T, b: T) = proc genericParamRepeated[T: typedesc](a: T, b: T) =
@ -27,22 +27,22 @@ proc genericParamRepeated[T: typedesc](a: T, b: T) =
echo a.name echo a.name
echo b.name echo b.name
good(genericParamRepeated(int, int)) accept genericParamRepeated(int, int)
good(genericParamRepeated(float, float)) accept genericParamRepeated(float, float)
bad(genericParamRepeated(string, int)) reject genericParamRepeated(string, int)
bad(genericParamRepeated(int, float)) reject genericParamRepeated(int, float)
proc genericParamOnce[T: typedesc](a, b: T) = proc genericParamOnce[T: typedesc](a, b: T) =
static: static:
echo a.name echo a.name
echo b.name echo b.name
good(genericParamOnce(int, int)) accept genericParamOnce(int, int)
good(genericParamOnce(TFoo, TFoo)) accept genericParamOnce(TFoo, TFoo)
bad(genericParamOnce(string, int)) reject genericParamOnce(string, int)
bad(genericParamOnce(TFoo, float)) reject genericParamOnce(TFoo, float)
type type
type1 = typedesc type1 = typedesc
@ -50,42 +50,42 @@ type
proc typePairs(A, B: type1; C, D: type2) = nil proc typePairs(A, B: type1; C, D: type2) = nil
good(typePairs(int, int, TFoo, TFOO)) accept typePairs(int, int, TFoo, TFOO)
good(typePairs(TBAR, TBar, TBAR, TBAR)) accept typePairs(TBAR, TBar, TBAR, TBAR)
good(typePairs(int, int, string, string)) accept typePairs(int, int, string, string)
bad(typePairs(TBAR, TBar, TBar, TFoo)) reject typePairs(TBAR, TBar, TBar, TFoo)
bad(typePairs(string, int, TBAR, TBAR)) reject typePairs(string, int, TBAR, TBAR)
proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = nil proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = nil
good(typePairs2(int, int, TFoo, TFOO)) accept typePairs2(int, int, TFoo, TFOO)
good(typePairs2(TBAR, TBar, TBAR, TBAR)) accept typePairs2(TBAR, TBar, TBAR, TBAR)
good(typePairs2(int, int, string, string)) accept typePairs2(int, int, string, string)
bad(typePairs2(TBAR, TBar, TBar, TFoo)) reject typePairs2(TBAR, TBar, TBar, TFoo)
bad(typePairs2(string, int, TBAR, TBAR)) reject typePairs2(string, int, TBAR, TBAR)
proc dontBind(a: typedesc, b: typedesc) = proc dontBind(a: typedesc, b: typedesc) =
static: static:
echo a.name echo a.name
echo b.name echo b.name
good(dontBind(int, float)) accept dontBind(int, float)
good(dontBind(TFoo, TFoo)) accept dontBind(TFoo, TFoo)
proc dontBind2(a, b: typedesc) = nil proc dontBind2(a, b: typedesc) = nil
good(dontBind2(int, float)) accept dontBind2(int, float)
good(dontBind2(TBar, int)) accept dontBind2(TBar, int)
proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = nil proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = nil
good(bindArg(int, string, 10, 20, "test", "nest")) accept bindArg(int, string, 10, 20, "test", "nest")
good(bindArg(int, int, 10, 20, 30, 40)) accept bindArg(int, int, 10, 20, 30, 40)
bad(bindArg(int, string, 10, "test", "test", "nest")) reject bindArg(int, string, 10, "test", "test", "nest")
bad(bindArg(int, int, 10, 20, 30, "test")) reject bindArg(int, int, 10, 20, 30, "test")
bad(bindArg(int, string, 10.0, 20, "test", "nest")) reject bindArg(int, string, 10.0, 20, "test", "nest")
bad(bindArg(int, string, "test", "nest", 10, 20)) reject bindArg(int, string, "test", "nest", 10, 20)

View file

@ -0,0 +1,35 @@
template accept(e) =
static: assert(compiles(e))
template reject(e) =
static: assert(not compiles(e))
type
TFoo[T, U] = tuple
x: T
y: U
TBar[K] = TFoo[K, K]
TUserClass = int|string
TBaz = TBar[TUserClass]
var
vfoo: TFoo[int, string]
vbar: TFoo[string, string]
vbaz: TFoo[int, int]
vnotbaz: TFoo[TObject, TObject]
proc foo(x: TFoo) = echo "foo"
proc bar(x: TBar) = echo "bar"
proc baz(x: TBaz) = echo "baz"
accept foo(vfoo)
accept bar(vbar)
accept baz(vbar)
accept baz(vbaz)
reject baz(vnotbaz)
reject bar(vfoo)

View file

@ -1,67 +1,67 @@
# Test nested loops and some other things # Test nested loops and some other things
proc andTest() = proc andTest() =
var a = 0 == 5 and 6 == 6 var a = 0 == 5 and 6 == 6
proc incx(x: var int) = # is built-in proc proc incx(x: var int) = # is built-in proc
x = x + 1 x = x + 1
proc decx(x: var int) = proc decx(x: var int) =
x = x - 1 x = x - 1
proc First(y: var int) = proc First(y: var int) =
var x: int var x: int
i_ncx(x) i_ncx(x)
if x == 10: if x == 10:
y = 0 y = 0
else: else:
if x == 0: if x == 0:
incx(x) incx(x)
else: else:
x=11 x=11
proc TestLoops() = proc TestLoops() =
var i, j: int var i, j: int
while i >= 0: while i >= 0:
if i mod 3 == 0: if i mod 3 == 0:
break break
i = i + 1 i = i + 1
while j == 13: while j == 13:
j = 13 j = 13
break break
break break
while True: while True:
break break
proc Foo(n: int): int = proc Foo(n: int): int =
var var
a, old: int a, old: int
b, c: bool b, c: bool
F_irst(a) F_irst(a)
if a == 10: if a == 10:
a = 30 a = 30
elif a == 11: elif a == 11:
a = 22 a = 22
elif a == 12: elif a == 12:
a = 23 a = 23
elif b: elif b:
old = 12 old = 12
else: else:
a = 40 a = 40
# #
b = false or 2 == 0 and 3 == 9 b = false or 2 == 0 and 3 == 9
a = 0 + 3 * 5 + 6 + 7 + +8 # 36 a = 0 + 3 * 5 + 6 + 7 + +8 # 36
while b: while b:
a = a + 3 a = a + 3
a = a + 5 a = a + 5
write(stdout, "Hello!") write(stdout, "Hello!")
# We should come till here :-) # We should come till here :-)
discard Foo(345) discard Foo(345)
# test the new type symbol lookup feature: # test the new type symbol lookup feature:

View file

@ -3,15 +3,14 @@ discard """
line: 13 line: 13
errormsg: "illegal recursion in type \'TIllegal\'" errormsg: "illegal recursion in type \'TIllegal\'"
""" """
# test illegal recursive types # test illegal recursive types
type
TLegal {.final.} = object
x: int
kids: seq[TLegal]
TIllegal {.final.} = object #ERROR_MSG illegal recursion in type 'TIllegal'
y: Int
x: array[0..3, TIllegal]
type
TLegal {.final.} = object
x: int
kids: seq[TLegal]
TIllegal {.final.} = object #ERROR_MSG illegal recursion in type 'TIllegal'
y: Int
x: array[0..3, TIllegal]

View file

@ -3,8 +3,6 @@ discard """
line: 7 line: 7
errormsg: "illegal recursion in type \'Uint8\'" errormsg: "illegal recursion in type \'Uint8\'"
""" """
type type
Uint8 = Uint8 #ERROR_MSG illegal recursion in type 'Uint8' Uint8 = Uint8 #ERROR_MSG illegal recursion in type 'Uint8'

View file

@ -0,0 +1,51 @@
discard """
output: '''
WARNING: false first asseertion from bar
ERROR: false second assertion from bar
-1
tests/run/tfailedassert.nim:27 false assertion from foo
'''
"""
type
TLineInfo = tuple[filename: string, line: int]
TMyError = object of E_Base
lineinfo: TLineInfo
EMyError = ref TMyError
# module-wide policy to change the failed assert
# exception type in order to include a lineinfo
onFailedAssert(msg):
var e = new(TMyError)
e.msg = msg
e.lineinfo = instantiationInfo(-2)
raise e
proc foo =
assert(false, "assertion from foo")
proc bar: int =
# local overrides that are active only
# in this proc
onFailedAssert(msg): echo "WARNING: " & msg
assert(false, "first asseertion from bar")
onFailedAssert(msg):
echo "ERROR: " & msg
return -1
assert(false, "second assertion from bar")
return 10
echo("")
echo(bar())
try:
foo()
except:
let e = EMyError(getCurrentException())
echo e.lineinfo.filename, ":", e.lineinfo.line, " ", e.msg

View file

@ -1,17 +1,17 @@
discard """ discard """
msg: "test 1\ntest 2" msg: "test 1\ntest 2\ntest 3"
output: "TEST 1\nTEST 2\nTEST 2" output: "TEST 1\nTEST 2\nTEST 3"
""" """
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
return R return R
echo foo("test 1") echo foo("test 1")
echo foo("test 2") echo foo("test 2")
echo foo("test " & $2) echo foo("test " & $3)

24
tests/run/tsemistatic.nim Normal file
View file

@ -0,0 +1,24 @@
discard """
msg: "static 10\ndynamic\nstatic 20\n"
output: "s\nd\nd\ns"
"""
proc foo(x: semistatic[int]) =
when isStatic(x):
static: echo "static ", x
echo "s"
else:
static: echo "dynamic"
echo "d"
foo 10
var
x = 10
y: int
foo x
foo y
foo 20

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"
@ -25,7 +25,7 @@ var y: TBar[float, 4]
echo high(y.data) echo high(y.data)
var var
t1: TA1 t1: TA1[float, 1]
t2: TA2 # t2: TA2[string, 4]
t3: TA3 # t3: TA3[int, 10]

View file

@ -1,6 +1,6 @@
discard """ discard """
msg: "int\nstring\nTBar[int]" msg: "int\nstring\nTBar[int]"
output: "int\nstring\nTBar[int]\nint\nrange 0..2\nstring" output: "int\nstring\nTBar[int]\nint\nrange 0..2(int)\nstring"
""" """
import typetraits import typetraits

View file

@ -8,25 +8,11 @@ import
# This macro mimics the using statement from C# # This macro mimics the using statement from C#
# #
# XXX: # It's kept only as a test for the macro system
# It doen't match the C# version exactly yet. # Nimrod's destructors offer a mechanism for automatic
# In particular, it's not recursive, which prevents it from dealing # disposal of resources.
# with exceptions thrown from the variable initializers when multiple.
# variables are used.
# #
# Also, since nimrod relies less on exceptions in general, a more macro autoClose(e: expr): stmt {.immediate.} =
# idiomatic definition could be:
# var x = init()
# if opened(x):
# try:
# body
# finally:
# close(x)
#
# `opened` here could be an overloaded proc which any type can define.
# A common practice can be returing an Optional[Resource] obj for which
# `opened` is defined to `optional.hasValue`
macro using(e: expr): stmt {.immediate.} =
let e = callsite() let e = callsite()
if e.len != 3: if e.len != 3:
error "Using statement: unexpected number of arguments. Got " & error "Using statement: unexpected number of arguments. Got " &
@ -97,7 +83,7 @@ proc close(r: var TResource) =
proc use(r: var TResource) = proc use(r: var TResource) =
write(stdout, "Using " & r.field & ".") write(stdout, "Using " & r.field & ".")
using(r = openResource("test")): autoClose(r = openResource("test")):
use r use r

View file

@ -41,7 +41,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

View file

@ -33,6 +33,10 @@ Changes affecting backwards compatibility
- The symbol binding rules for clean templates changed: ``bind`` for any - The symbol binding rules for clean templates changed: ``bind`` for any
symbol that's not a parameter is now the default. ``mixin`` can be used symbol that's not a parameter is now the default. ``mixin`` can be used
to require instantiation scope for a symbol. to require instantiation scope for a symbol.
- ``quoteIfContainsWhite`` now escapes argument in such way that it can be safely
passed to shell, instead of just adding double quotes.
- ``macros.dumpTree`` and ``macros.dumpLisp`` have been made ``immediate``,
``dumpTreeImm`` and ``dumpLispImm`` are now deprecated.
Compiler Additions Compiler Additions
@ -56,15 +60,15 @@ Language Additions
- Arrays can now be declared with a single integer literal ``N`` instead of a - Arrays can now be declared with a single integer literal ``N`` instead of a
range; the range is then ``0..N-1``. range; the range is then ``0..N-1``.
- ``macros.dumpTree`` and ``macros.dumpLisp`` have been made ``immediate``,
``dumpTreeImm`` and ``dumpLispImm`` are now deprecated.
- Added ``requiresInit`` pragma to enforce explicit initialization. - Added ``requiresInit`` pragma to enforce explicit initialization.
- Added ``using statement`` for better authoring domain-specific languages and
OOP-like syntactic sugar.
- Added ``delegator pragma`` for handling calls to missing procs and fields at
compile-time.
- Support for user-defined type classes has been added.
- Exported templates are allowed to access hidden fields. - Exported templates are allowed to access hidden fields.
- The ``using statement`` enables you to more easily author domain-specific
languages and libraries providing OOP-like syntactic sugar.
- Added a new ``delegator pragma`` for handling calls to missing procs and
fields at compile-time.
- The overload resolution now supports ``static[T]`` params that must be
evaluatable at compile-time.
- Support for user-defined type classes have been added.
Tools improvements Tools improvements