Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq
2012-09-26 02:22:39 +02:00
13 changed files with 118 additions and 81 deletions

View File

@@ -344,6 +344,12 @@ type
tfFromGeneric, # type is an instantiation of a generic; this is needed
# because for instantiations of objects, structural
# type equality has to be used
tfInstantiated # XXX: used to mark generic params after instantiation.
# if the concrete type happens to be an implicit generic
# this can lead to invalid proc signatures in the second
# pass of semProcTypeNode performed after instantiation.
# this won't be needed if we don't perform this redundant
# second pass (stay tuned).
tfAll, # type class requires all constraints to be met (default)
tfAny, # type class requires any constraint to be met
tfCapturesEnv, # whether proc really captures some environment

View File

@@ -163,6 +163,7 @@ proc genConstStmt(p: BProc, t: PNode) =
if it.kind == nkCommentStmt: continue
if it.kind != nkConstDef: InternalError(t.info, "genConstStmt")
var c = it.sons[0].sym
if c.typ.containsCompileTimeOnly: continue
if sfFakeConst in c.flags:
genSingleVar(p, it)
elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and

View File

@@ -140,6 +140,14 @@ proc mangleName(s: PSym): PRope =
proc isCompileTimeOnly(t: PType): bool =
result = t.kind in {tyTypedesc, tyExpr}
proc containsCompileTimeOnly(t: PType): bool =
if isCompileTimeOnly(t): return true
if t.sons != nil:
for i in 0 .. <t.sonsLen:
if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
return true
return false
var anonTypeName = toRope"TY"
proc typeName(typ: PType): PRope =
@@ -174,7 +182,7 @@ proc mapType(typ: PType): TCTypeKind =
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray
of tyObject, tyTuple: result = ctStruct
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
tyConst, tyMutable, tyIter, tyTypeDesc:
tyConst, tyMutable, tyIter, tyTypeDesc:
result = mapType(lastSon(typ))
of tyEnum:
if firstOrd(typ) < 0:

View File

@@ -865,11 +865,11 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
# by the type traits procs' signatures, but until the
# code is more mature it doesn't hurt to be extra safe
internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
case n.sons[0].sym.name.s.normalize
of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferExported))
result = newStrNode(nkStrLit, typ.typeToString(preferName))
result.typ = newType(tyString, context)
result.info = n.info
else:
@@ -965,7 +965,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mParseExprToAst: result = evalParseExpr(c, n)
of mParseStmtToAst: result = evalParseStmt(c, n)
of mExpandToAst: result = evalExpandToAst(c, n)
of mTypeTrait: result = evalTypeTrait(n, c.module)
of mTypeTrait:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n, c.module)
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
of mStaticExec:
let cmd = evalAux(c, n.sons[1], {})

View File

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

View File

@@ -19,7 +19,8 @@ proc restoreOldStyleType(n: PNode) =
#
# This is strictly for backward compatibility until
# the transition to types as first-class values is complete.
n.typ = n.typ.skipTypes({tyTypeDesc})
if n.typ.kind == tyTypeDesc and n.typ.sonsLen == 1:
n.typ = n.typ.sons[0]
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
markUsed(n, s)
@@ -376,6 +377,8 @@ proc semArrayConstr(c: PContext, n: PNode): PNode =
addSon(result, semExprWithType(c, x))
var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
# turn any concrete typedesc into the absract typedesc type
if typ.kind == tyTypeDesc: typ.sons = nil
for i in countup(1, sonsLen(n) - 1):
x = n.sons[i]
if x.kind == nkExprColonExpr and sonsLen(x) == 2:

View File

@@ -33,6 +33,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
#t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t)
#t = ReplaceTypeVarsT(cl, t)
t.flags.incl tfInstantiated
s.typ = t
addDecl(c, s)
entry.concreteTypes[i] = t
@@ -41,7 +42,8 @@ proc sameInstantiation(a, b: TInstantiatedSymbol): bool =
if a.genericSym.id == b.genericSym.id and
a.concreteTypes.len == b.concreteTypes.len:
for i in 0 .. < a.concreteTypes.len:
if not sameType(a.concreteTypes[i], b.concreteTypes[i]): return
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
flags = {TypeDescExactMatch}): return
result = true
proc GenericCacheGet(c: PContext, entry: var TInstantiatedSymbol): PSym =
@@ -122,33 +124,6 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
s.ast.sons[genericParamsPos].kind == nkEmpty:
c.threadEntries.add(s)
proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType =
# XXX: This is intended to replace the use of semParamList in generateInstance.
# The results of semParamList's analysis are already encoded in the original
# proc type and any concrete types may be aplied directly over it.
# Besides being more efficient, it will remove the awkward case of
# genericParams == nil in semParamList.
# Currenly, it fails in some cases such as:
# proc inc2*[T](x: var ordinal[T], y = 1) {.magic: "Inc", noSideEffect.}
let sig = genericProc.typ
result = copyType(sig, getCurrOwner(), false)
result.n = sig.n.shallowCopy
for i in countup(0, sig.len - 1):
let tOrig = sig.sons[i]
if tOrig == nil: continue
let oGenParams = genericProc.ast.sons[genericParamsPos]
if skipTypes(tOrig, skipPtrs).kind in {tyGenericParam}:
var tConcrete = concTypes[tOrig.sym.position]
if i > 0:
let param = sig.n.sons[i].sym.copySym
param.typ = tConcrete
result.n.sons[i] = newSymNode(param)
result.sons[i] = tConcrete
else:
result.sons[i] = tOrig
if i > 0: result.n.sons[i] = sig.n.sons[i]
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
# no need to instantiate generic templates/macros:
@@ -182,12 +157,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
n.sons[genericParamsPos] = ast.emptyNode
# semantic checking for the parameters:
if n.sons[paramsPos].kind != nkEmpty:
if false and nimdbg:
result.typ = applyConcreteTypesToSig(fn, entry.concreteTypes)
addParams(c, result.typ.n, fn.kind)
else:
removeDefaultParamValues(n.sons[ParamsPos])
semParamList(c, n.sons[ParamsPos], nil, result)
removeDefaultParamValues(n.sons[ParamsPos])
semParamList(c, n.sons[ParamsPos], nil, result)
else:
result.typ = newTypeS(tyProc, c)
rawAddSon(result.typ, nil)

View File

@@ -34,10 +34,14 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2)
internalAssert n.sons[1].kind == nkSym
if n.sons[1].sym.kind == skType:
let typArg = n.sons[1].sym
if typArg.kind == skType or
(typArg.kind == skParam and typArg.typ.sonsLen > 0):
# This is either a type known to sem or a typedesc
# param to a regular proc (again, known at instantiation)
result = evalTypeTrait(n, GetCurrOwner())
else:
# pass unmodified to evals
# a typedesc variable, pass unmodified to evals
result = n
proc semOrd(c: PContext, n: PNode): PNode =

View File

@@ -552,7 +552,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
incl(result.flags, tfFinal)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
if kind == skMacro:
if kind == skMacro and param.typ.kind != tyTypeDesc:
# within a macro, every param has the type PNimrodNode!
# and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
let nn = getSysSym"PNimrodNode"
@@ -579,7 +579,8 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
result.typ = newTypeS(tyExpr, c)
result.typ.sons = paramType.sons
of tyTypeDesc:
if procKind notin {skTemplate, skMacro}:
if procKind notin {skTemplate, skMacro} and
tfInstantiated notin paramType.flags:
result.typ = newTypeS(tyTypeDesc, c)
result.typ.sons = paramType.sons
of tyDistinct:
@@ -777,19 +778,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
else:
result = instGenericContainer(c, n, result)
proc semTypeFromMacro(c: PContext, n: PNode): PType =
# Expands a macro or template until a type is returned
# results in an error type if the macro expands to something different
var sym = expectMacroOrTemplateCall(c, n)
markUsed(n, sym)
case sym.kind
of skMacro:
result = semTypeNode(c, semMacroExpr(c, n, n, sym), nil)
of skTemplate:
result = semTypeNode(c, semTemplateExpr(c, n, sym), nil)
proc semTypeExpr(c: PContext, n: PNode): PType =
var n = semExprWithType(c, n)
if n.kind == nkSym and n.sym.kind == skType:
result = n.sym.typ
else:
LocalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
result = errorType(c)
LocalError(n.info, errTypeExpected, n.renderTree)
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
@@ -823,7 +817,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result.addSonSkipIntLit(t2)
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
else:
result = semTypeFromMacro(c, n)
result = semTypeExpr(c, n)
of nkCurlyExpr:
result = semTypeNode(c, n.sons[0], nil)
if result != nil:

View File

@@ -271,7 +271,7 @@ proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
of tyTypeClass:
match = matchTypeClass(c, req, t) == isGeneric
else: nil
elif t.kind in {tyTypeDesc, tyObject}:
elif t.kind in {tyObject}:
match = sameType(t, req)
if tfAny in typeClass.flags:
@@ -659,7 +659,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
of isGeneric:
inc(m.genericMatches)
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
result = argOrig
if f.kind == tyTypeDesc: result = arg
else: result = argOrig
else:
result = copyTree(arg)
result.typ = getInstantiatedType(c, arg, m, f)

View File

@@ -585,10 +585,17 @@ type
## or a == (distinct b)
dcEqOrDistinctOf ## a equals b or a is distinct of b
TTypeCmpFlag* = enum
IgnoreTupleFields,
TypeDescExactMatch,
AllowCommonBase
TTypeCmpFlags* = set[TTypeCmpFlag]
TSameTypeClosure = object {.pure.}
cmp: TDistinctCompare
ignoreTupleFields: bool
recCheck: int
flags: TTypeCmpFlags
s: seq[tuple[a,b: int]] # seq for a set as it's hopefully faster
# (few elements expected)
@@ -610,13 +617,14 @@ proc SameTypeOrNilAux(a, b: PType, c: var TSameTypeClosure): bool =
if a == nil or b == nil: result = false
else: result = SameTypeAux(a, b, c)
proc SameTypeOrNil*(a, b: PType): bool =
proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
if a == b:
result = true
else:
if a == nil or b == nil: result = false
else:
var c = initSameTypeClosure()
c.flags = flags
result = SameTypeAux(a, b, c)
proc equalParam(a, b: PSym): TParamsEquality =
@@ -655,7 +663,7 @@ proc equalParams(a, b: PNode): TParamsEquality =
return paramsNotEqual # paramsIncompatible;
# continue traversal! If not equal, we can return immediately; else
# it stays incompatible
if not SameTypeOrNil(a.sons[0].typ, b.sons[0].typ):
if not SameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {TypeDescExactMatch}):
if (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
result = paramsNotEqual # one proc has a result, the other not is OK
else:
@@ -683,13 +691,13 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
for i in countup(0, sonsLen(a) - 1):
var x = a.sons[i]
var y = b.sons[i]
if c.ignoreTupleFields:
if IgnoreTupleFields in c.flags:
x = skipTypes(x, {tyRange})
y = skipTypes(y, {tyRange})
result = SameTypeAux(x, y, c)
if not result: return
if a.n != nil and b.n != nil and not c.ignoreTupleFields:
if a.n != nil and b.n != nil and IgnoreTupleFields notin c.flags:
for i in countup(0, sonsLen(a.n) - 1):
# check field names:
if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym:
@@ -760,7 +768,14 @@ proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool =
if not SameObjectTree(a.n, b.n, c): return
result = true
proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool =
if sonsLen(a) != sonsLen(b): return false
result = true
for i in countup(0, sonsLen(a) - 1):
result = SameTypeOrNilAux(a.sons[i], b.sons[i], c)
if not result: return
proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
template CycleCheck() =
# believe it or not, the direct check for ``containsOrIncl(c, a, b)``
# increases bootstrapping time from 2.4s to 3.3s on my laptop! So we cheat
@@ -808,38 +823,43 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
CycleCheck()
result = sameTuple(a, b, c)
of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c)
of tyTypeDesc:
if TypeDescExactMatch in c.flags:
CycleCheck()
result = sameChildrenAux(x, y, c)
else:
result = true
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
tyOrdinal, tyTypeDesc, tyTypeClass:
if sonsLen(a) == sonsLen(b):
CycleCheck()
result = true
for i in countup(0, sonsLen(a) - 1):
result = SameTypeOrNilAux(a.sons[i], b.sons[i], c)
if not result: return
if result and (a.kind == tyProc):
result = a.callConv == b.callConv
tyOrdinal, tyTypeClass:
CycleCheck()
result = sameChildrenAux(a, b, c)
if result and (a.kind == tyProc):
result = a.callConv == b.callConv
of tyRange:
CycleCheck()
CycleCheck()
result = SameTypeOrNilAux(a.sons[0], b.sons[0], c) and
SameValue(a.n.sons[0], b.n.sons[0]) and
SameValue(a.n.sons[1], b.n.sons[1])
of tyNone: result = false
proc SameType*(x, y: PType): bool =
proc sameType*(x, y: PType): bool =
var c = initSameTypeClosure()
result = sameTypeAux(x, y, c)
proc sameBackendType*(x, y: PType): bool =
var c = initSameTypeClosure()
c.ignoreTupleFields = true
c.flags.incl IgnoreTupleFields
result = sameTypeAux(x, y, c)
proc compareTypes*(x, y: PType, cmp: TDistinctCompare): bool =
proc compareTypes*(x, y: PType,
cmp: TDistinctCompare = dcEq,
flags: TTypeCmpFlags = {}): bool =
## compares two type for equality (modulo type distinction)
var c = initSameTypeClosure()
c.cmp = cmp
c.flags = flags
result = sameTypeAux(x, y, c)
proc inheritanceDiff*(a, b: PType): int =

View File

@@ -1,10 +1,12 @@
import unittest
import unittest, typetraits
type
TFoo[T, U] = object
x: T
y: U
proc getTypeName(t: typedesc): string = t.name
proc foo(T: typedesc[float], a: expr): string =
result = "float " & $(a.len > 5)
@@ -21,6 +23,9 @@ template foo(T: typedesc[seq]): expr = "seq"
test "types can be used as proc params":
# XXX: `check` needs to know that TFoo[int, float] is a type and
# cannot be assigned for a local variable for later inspection
check ((string.getTypeName == "string"))
check ((getTypeName(int) == "int"))
check ((foo(TFoo[int, float], 1000) == "TFoo 1000"))
var f = 10.0

View File

@@ -1,6 +1,6 @@
discard """
msg: "int\nstring\nTBar[int]"
output: "int\nstring\nTBar[int]\nint\nrange 0..2"
output: "int\nstring\nTBar[int]\nint\nrange 0..2\nstring"
"""
import typetraits
@@ -36,3 +36,24 @@ proc foo3[R, T](x: array[R, T]) =
echo name(R)
foo3 arr
const TypeList = [int, string, seq[int]]
macro selectType(inType: typedesc): typedesc =
var typeSeq = @[float, TBar[int]]
for t in TypeList:
typeSeq.add(t)
typeSeq.add(inType)
typeSeq.add(type(10))
var typeSeq2: seq[typedesc] = @[]
typeSeq2 = typeSeq
result = typeSeq2[5]
var xvar: selectType(string)
xvar = "proba"
echo xvar.type.name