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:
commit
afddae5aaf
41 changed files with 901 additions and 568 deletions
|
|
@ -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,18 +337,25 @@ 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
|
||||||
|
|
@ -1233,9 +1243,13 @@ 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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -264,7 +265,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||||
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,
|
||||||
|
|
@ -907,9 +908,7 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
|
||||||
#result.typ = newType(tyStmt, c.module)
|
#result.typ = newType(tyStmt, c.module)
|
||||||
|
|
||||||
proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
|
proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
|
||||||
InternalAssert operand.kind == nkSym
|
let typ = operand.typ.skipTypes({tyTypeDesc})
|
||||||
|
|
||||||
let typ = operand.sym.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))
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -965,6 +965,7 @@ 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:
|
||||||
|
when true:
|
||||||
if mode in {pmTypeDesc, pmTypeDef}:
|
if mode in {pmTypeDesc, pmTypeDef}:
|
||||||
result = parseProcExpr(p, false)
|
result = parseProcExpr(p, false)
|
||||||
result.kind = nkIteratorTy
|
result.kind = nkIteratorTy
|
||||||
|
|
@ -973,6 +974,9 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
parMessage(p, errExprExpected, p.tok)
|
parMessage(p, errExprExpected, p.tok)
|
||||||
getTok(p) # we must consume a token here to prevend endless loops!
|
getTok(p) # we must consume a token here to prevend endless loops!
|
||||||
result = ast.emptyNode
|
result = ast.emptyNode
|
||||||
|
else:
|
||||||
|
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
||||||
|
result.kind = nkIteratorTy
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -282,8 +282,11 @@ 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))
|
||||||
|
|
||||||
|
when true:
|
||||||
|
template `~`*(r: string): PRope = r.ropef
|
||||||
|
else:
|
||||||
{.push stack_trace: off, line_trace: off.}
|
{.push stack_trace: off, line_trace: off.}
|
||||||
proc `~`*(r: expr[string]): PRope =
|
proc `~`*(r: static[string]): PRope =
|
||||||
# this is the new optimized "to rope" operator
|
# this is the new optimized "to rope" operator
|
||||||
# the mnemonic is that `~` looks a bit like a rope :)
|
# the mnemonic is that `~` looks a bit like a rope :)
|
||||||
var r {.global.} = r.ropef
|
var r {.global.} = r.ropef
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -171,7 +181,34 @@ when false:
|
||||||
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)
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,6 +214,23 @@ 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 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 =
|
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
||||||
result = newType(kind, getCurrOwner())
|
result = newType(kind, getCurrOwner())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,6 +1946,8 @@ 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)
|
||||||
|
elif s != nil and s.kind in {skType}:
|
||||||
|
result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
|
||||||
else:
|
else:
|
||||||
result = semArrayAccess(c, n, flags)
|
result = semArrayAccess(c, n, flags)
|
||||||
of nkCurlyExpr:
|
of nkCurlyExpr:
|
||||||
|
|
|
||||||
|
|
@ -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,7 +613,8 @@ 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:
|
||||||
|
if s.typ.n != nil:
|
||||||
result = s.typ.n
|
result = s.typ.n
|
||||||
result.typ = s.typ.sons[0]
|
result.typ = s.typ.sons[0]
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -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,6 +253,7 @@ 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:
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
|
||||||
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})
|
||||||
case trait.sym.name.s.normalize
|
case trait.sym.name.s.normalize
|
||||||
|
|
@ -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})
|
||||||
|
|
|
||||||
|
|
@ -1041,8 +1041,12 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
# 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:
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
@ -581,7 +581,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
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:
|
||||||
|
|
@ -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:
|
|
||||||
# proc(a, b: expr)
|
|
||||||
# no constraints, treat like generic param
|
|
||||||
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
|
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
|
||||||
else:
|
|
||||||
|
of tyStatic:
|
||||||
# proc(a: expr{string}, b: expr{nkLambda})
|
# proc(a: expr{string}, b: expr{nkLambda})
|
||||||
# overload on compile time values and AST trees
|
# overload on compile time values and AST trees
|
||||||
result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons))
|
result = addImplicitGeneric(c.newTypeWithSons(tyStatic, paramType.sons))
|
||||||
|
result.flags.incl tfHasStatic
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
let liftBody = liftingWalk(paramType.lastSon)
|
||||||
|
if liftBody != nil:
|
||||||
|
result = liftBody
|
||||||
|
result.shouldHaveMeta
|
||||||
|
|
||||||
|
of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||||
|
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
||||||
|
|
||||||
|
of tyExpr:
|
||||||
|
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))
|
||||||
|
|
||||||
if paramType.lastSon.kind == tyTypeClass:
|
|
||||||
result = paramType
|
|
||||||
result.kind = tyParametricTypeClass
|
|
||||||
result = addImplicitGeneric(copyType(result,
|
|
||||||
getCurrOwner(), false))
|
|
||||||
elif result != nil:
|
|
||||||
result.kind = tyGenericInvokation
|
|
||||||
result.sons.setLen(result.sons.len - 1)
|
|
||||||
of tyTypeClass:
|
|
||||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), false))
|
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
# result = liftingWalk(paramType)
|
# result = liftingWalk(paramType)
|
||||||
|
|
@ -745,7 +767,8 @@ 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):
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
@ -928,17 +954,20 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
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
|
||||||
|
of 3:
|
||||||
result = semTypeNode(c, n.sons[1], prev)
|
result = semTypeNode(c, n.sons[1], prev)
|
||||||
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
|
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
|
||||||
result = freshType(result, prev)
|
result = freshType(result, prev)
|
||||||
result.flags.incl(tfNotNil)
|
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,10 +1122,6 @@ 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 (
|
|
||||||
sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
|
|
||||||
result = newConstraint(c, x.kind)
|
|
||||||
else:
|
|
||||||
result = newTypeWithSons(c, tyGenericParam, @[x])
|
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 =
|
||||||
|
|
@ -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,7 +1150,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
def = semConstExpr(c, def)
|
def = semConstExpr(c, def)
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
if def.typ.kind != tyTypeDesc:
|
if def.typ.kind != tyTypeDesc:
|
||||||
typ = newTypeWithSons(c, tyExpr, @[def.typ])
|
typ = newTypeWithSons(c, tyStatic, @[def.typ])
|
||||||
else:
|
else:
|
||||||
if not containsGenericType(def.typ):
|
if not containsGenericType(def.typ):
|
||||||
def = fitNode(c, typ, def)
|
def = fitNode(c, typ, def)
|
||||||
|
|
@ -1128,6 +1158,8 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,12 @@ proc checkPartialConstructedType(info: TLineInfo, t: PType) =
|
||||||
|
|
||||||
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,7 +50,8 @@ 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
|
||||||
|
|
@ -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,9 +135,10 @@ 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 =
|
||||||
|
|
@ -150,10 +154,10 @@ 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 x != nil:
|
||||||
if header == nil: header = copyType(t, t.owner, false)
|
if header == nil: header = copyType(t, t.owner, false)
|
||||||
header.sons[i] = x
|
header.sons[i] = x
|
||||||
propagateToOwner(header, x)
|
propagateToOwner(header, x)
|
||||||
#idTablePut(cl.typeMap, body.sons[i-1], x)
|
|
||||||
|
|
||||||
if header != nil:
|
if header != nil:
|
||||||
# search again after first pass:
|
# search again after first pass:
|
||||||
|
|
@ -166,6 +170,7 @@ 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])
|
||||||
|
if not cl.allowMetaTypes:
|
||||||
cacheTypeInst(result)
|
cacheTypeInst(result)
|
||||||
|
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
|
|
@ -195,15 +200,17 @@ 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:
|
||||||
|
result = lookup
|
||||||
if result.kind == tyGenericInvokation:
|
if result.kind == tyGenericInvokation:
|
||||||
result = handleGenericInvokation(cl, result)
|
result = handleGenericInvokation(cl, result)
|
||||||
of tyExpr:
|
|
||||||
if t.sym != nil and t.sym.kind == skGenericParam:
|
|
||||||
result = lookupTypeVar(cl, t)
|
|
||||||
of tyGenericInvokation:
|
of tyGenericInvokation:
|
||||||
result = handleGenericInvokation(cl, t)
|
result = handleGenericInvokation(cl, t)
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
|
|
@ -212,10 +219,19 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
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)
|
||||||
|
|
@ -232,13 +248,18 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ type
|
||||||
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
|
||||||
|
|
@ -404,17 +410,19 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -489,8 +497,8 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
|
||||||
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:
|
||||||
|
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)
|
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
|
||||||
|
|
@ -702,6 +719,30 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
|
||||||
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,10 +763,10 @@ 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)
|
||||||
|
|
@ -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
|
||||||
else: argType
|
# this will be done earlier - we just have to
|
||||||
fMaybeExpr = f.skipTypes({tyDistinct})
|
# make sure that static types enter here
|
||||||
|
var evaluated = c.semTryConstExpr(c, arg)
|
||||||
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:
|
if evaluated != nil:
|
||||||
r = isGeneric
|
arg.typ = newTypeS(tyStatic, c)
|
||||||
arg.typ = newTypeS(tyExpr, c)
|
|
||||||
arg.typ.sons = @[evaluated.typ]
|
arg.typ.sons = @[evaluated.typ]
|
||||||
arg.typ.n = evaluated
|
arg.typ.n = evaluated
|
||||||
|
argType = arg.typ
|
||||||
|
|
||||||
if r == isGeneric:
|
var
|
||||||
put(m.bindings, f, arg.typ)
|
r: TTypeRelation
|
||||||
|
a = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc})
|
||||||
|
else: argType
|
||||||
|
|
||||||
|
case fMaybeStatic.kind
|
||||||
of tyTypeClass, tyParametricTypeClass:
|
of tyTypeClass, tyParametricTypeClass:
|
||||||
if fMaybeExpr.n != nil:
|
if fMaybeStatic.n != nil:
|
||||||
let match = matchUserTypeClass(c, m, arg, fMaybeExpr, a)
|
let match = matchUserTypeClass(c, m, arg, fMaybeStatic, a)
|
||||||
if match != nil:
|
if match != nil:
|
||||||
r = isGeneric
|
r = isGeneric
|
||||||
arg = match
|
arg = match
|
||||||
|
|
@ -935,6 +974,9 @@ proc paramTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
|
||||||
r = isNone
|
r = isNone
|
||||||
else:
|
else:
|
||||||
r = typeRel(m, f, a)
|
r = typeRel(m, f, a)
|
||||||
|
of tyExpr:
|
||||||
|
r = isGeneric
|
||||||
|
put(m.bindings, f, arg.typ)
|
||||||
else:
|
else:
|
||||||
r = typeRel(m, f, a)
|
r = typeRel(m, f, a)
|
||||||
|
|
||||||
|
|
@ -961,6 +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):
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
const
|
||||||
|
szIllegalRecursion* = -2
|
||||||
|
szUnknownSize* = -1
|
||||||
|
|
||||||
proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
|
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
|
||||||
|
|
@ -1176,7 +1146,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
|
||||||
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
|
result = t.kind in GenericTypes + tyTypeClasses +
|
||||||
|
{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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -1040,7 +1040,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||||
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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,13 +294,12 @@ 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):
|
||||||
|
template emit*(e: static[string]): stmt =
|
||||||
## accepts a single string argument and treats it as nimrod code
|
## accepts a single string argument and treats it as nimrod code
|
||||||
## that should be inserted verbatim in the program
|
## that should be inserted verbatim in the program
|
||||||
## Example:
|
## Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: nimrod
|
|
||||||
##
|
|
||||||
## emit("echo " & '"' & "hello world".toUpper & '"')
|
## emit("echo " & '"' & "hello world".toUpper & '"')
|
||||||
##
|
##
|
||||||
eval: result = e.parseStmt
|
eval: result = e.parseStmt
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
35
tests/compile/tcompositetypeclasses.nim
Normal file
35
tests/compile/tcompositetypeclasses.nim
Normal 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)
|
||||||
|
|
||||||
|
|
@ -14,4 +14,3 @@ type
|
||||||
y: Int
|
y: Int
|
||||||
x: array[0..3, TIllegal]
|
x: array[0..3, TIllegal]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,3 @@ discard """
|
||||||
type
|
type
|
||||||
Uint8 = Uint8 #ERROR_MSG illegal recursion in type 'Uint8'
|
Uint8 = Uint8 #ERROR_MSG illegal recursion in type 'Uint8'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
51
tests/run/tfailedassert.nim
Normal file
51
tests/run/tfailedassert.nim
Normal 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
|
||||||
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
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
|
||||||
|
|
@ -13,5 +13,5 @@ proc foo(s: expr[string]): string =
|
||||||
|
|
||||||
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
24
tests/run/tsemistatic.nim
Normal 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
|
||||||
|
|
||||||
|
|
@ -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]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -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
|
||||||
|
|
|
||||||
18
web/news.txt
18
web/news.txt
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue