improved support for typedesc values
* can be stored in constants and variables (including in containers like sequences) * can be passed to and returned from macros
This commit is contained in:
parent
92b0d64018
commit
badb6c0f66
11 changed files with 90 additions and 79 deletions
|
|
@ -344,6 +344,12 @@ type
|
||||||
tfFromGeneric, # type is an instantiation of a generic; this is needed
|
tfFromGeneric, # type is an instantiation of a generic; this is needed
|
||||||
# because for instantiations of objects, structural
|
# because for instantiations of objects, structural
|
||||||
# type equality has to be used
|
# 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)
|
tfAll, # type class requires all constraints to be met (default)
|
||||||
tfAny, # type class requires any constraint to be met
|
tfAny, # type class requires any constraint to be met
|
||||||
tfCapturesEnv, # whether proc really captures some environment
|
tfCapturesEnv, # whether proc really captures some environment
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,7 @@ proc genConstStmt(p: BProc, t: PNode) =
|
||||||
if it.kind == nkCommentStmt: continue
|
if it.kind == nkCommentStmt: continue
|
||||||
if it.kind != nkConstDef: InternalError(t.info, "genConstStmt")
|
if it.kind != nkConstDef: InternalError(t.info, "genConstStmt")
|
||||||
var c = it.sons[0].sym
|
var c = it.sons[0].sym
|
||||||
|
if c.typ.containsCompileTimeOnly: continue
|
||||||
if sfFakeConst in c.flags:
|
if sfFakeConst in c.flags:
|
||||||
genSingleVar(p, it)
|
genSingleVar(p, it)
|
||||||
elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
|
elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,14 @@ proc mangleName(s: PSym): PRope =
|
||||||
proc isCompileTimeOnly(t: PType): bool =
|
proc isCompileTimeOnly(t: PType): bool =
|
||||||
result = t.kind in {tyTypedesc, tyExpr}
|
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"
|
var anonTypeName = toRope"TY"
|
||||||
|
|
||||||
proc typeName(typ: PType): PRope =
|
proc typeName(typ: PType): PRope =
|
||||||
|
|
|
||||||
|
|
@ -869,7 +869,7 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
|
||||||
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
|
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
|
||||||
case n.sons[0].sym.name.s.normalize
|
case n.sons[0].sym.name.s.normalize
|
||||||
of "name":
|
of "name":
|
||||||
result = newStrNode(nkStrLit, typ.typeToString(preferExported))
|
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
||||||
result.typ = newType(tyString, context)
|
result.typ = newType(tyString, context)
|
||||||
result.info = n.info
|
result.info = n.info
|
||||||
else:
|
else:
|
||||||
|
|
@ -965,7 +965,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
of mParseExprToAst: result = evalParseExpr(c, n)
|
of mParseExprToAst: result = evalParseExpr(c, n)
|
||||||
of mParseStmtToAst: result = evalParseStmt(c, n)
|
of mParseStmtToAst: result = evalParseStmt(c, n)
|
||||||
of mExpandToAst: result = evalExpandToAst(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 mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
|
||||||
of mStaticExec:
|
of mStaticExec:
|
||||||
let cmd = evalAux(c, n.sons[1], {})
|
let cmd = evalAux(c, n.sons[1], {})
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ proc equalGenericParams(procA, procB: PNode): bool =
|
||||||
return
|
return
|
||||||
a = procA.sons[i].sym
|
a = procA.sons[i].sym
|
||||||
b = procB.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 (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
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ proc restoreOldStyleType(n: PNode) =
|
||||||
#
|
#
|
||||||
# This is strictly for backward compatibility until
|
# This is strictly for backward compatibility until
|
||||||
# the transition to types as first-class values is complete.
|
# 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 =
|
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
|
|
@ -376,6 +377,8 @@ proc semArrayConstr(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
addSon(result, semExprWithType(c, x))
|
addSon(result, semExprWithType(c, x))
|
||||||
var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
|
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):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
x = n.sons[i]
|
x = n.sons[i]
|
||||||
if x.kind == nkExprColonExpr and sonsLen(x) == 2:
|
if x.kind == nkExprColonExpr and sonsLen(x) == 2:
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
#t = instGenericContainer(c, a, t)
|
#t = instGenericContainer(c, a, t)
|
||||||
t = generateTypeInstance(c, pt, a, t)
|
t = generateTypeInstance(c, pt, a, t)
|
||||||
#t = ReplaceTypeVarsT(cl, t)
|
#t = ReplaceTypeVarsT(cl, t)
|
||||||
|
t.flags.incl tfInstantiated
|
||||||
s.typ = t
|
s.typ = t
|
||||||
addDecl(c, s)
|
addDecl(c, s)
|
||||||
entry.concreteTypes[i] = t
|
entry.concreteTypes[i] = t
|
||||||
|
|
@ -41,7 +42,8 @@ proc sameInstantiation(a, b: TInstantiatedSymbol): bool =
|
||||||
if a.genericSym.id == b.genericSym.id and
|
if a.genericSym.id == b.genericSym.id and
|
||||||
a.concreteTypes.len == b.concreteTypes.len:
|
a.concreteTypes.len == b.concreteTypes.len:
|
||||||
for i in 0 .. < a.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
|
result = true
|
||||||
|
|
||||||
proc GenericCacheGet(c: PContext, entry: var TInstantiatedSymbol): PSym =
|
proc GenericCacheGet(c: PContext, entry: var TInstantiatedSymbol): PSym =
|
||||||
|
|
@ -122,33 +124,6 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||||
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
||||||
c.threadEntries.add(s)
|
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,
|
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
info: TLineInfo): PSym =
|
info: TLineInfo): PSym =
|
||||||
# no need to instantiate generic templates/macros:
|
# no need to instantiate generic templates/macros:
|
||||||
|
|
@ -182,10 +157,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
n.sons[genericParamsPos] = ast.emptyNode
|
n.sons[genericParamsPos] = ast.emptyNode
|
||||||
# semantic checking for the parameters:
|
# semantic checking for the parameters:
|
||||||
if n.sons[paramsPos].kind != nkEmpty:
|
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])
|
removeDefaultParamValues(n.sons[ParamsPos])
|
||||||
semParamList(c, n.sons[ParamsPos], nil, result)
|
semParamList(c, n.sons[ParamsPos], nil, result)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,14 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
|
||||||
proc semTypeTraits(c: PContext, n: PNode): PNode =
|
proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
internalAssert n.sons[1].kind == nkSym
|
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())
|
result = evalTypeTrait(n, GetCurrOwner())
|
||||||
else:
|
else:
|
||||||
# pass unmodified to evals
|
# a typedesc variable, pass unmodified to evals
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
proc semOrd(c: PContext, n: PNode): PNode =
|
proc semOrd(c: PContext, n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -552,7 +552,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:
|
if kind == skMacro and param.typ.kind != tyTypeDesc:
|
||||||
# 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"
|
||||||
|
|
@ -579,7 +579,8 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
||||||
result.typ = newTypeS(tyExpr, c)
|
result.typ = newTypeS(tyExpr, c)
|
||||||
result.typ.sons = paramType.sons
|
result.typ.sons = paramType.sons
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
if procKind notin {skTemplate, skMacro}:
|
if procKind notin {skTemplate, skMacro} and
|
||||||
|
tfInstantiated notin paramType.flags:
|
||||||
result.typ = newTypeS(tyTypeDesc, c)
|
result.typ = newTypeS(tyTypeDesc, c)
|
||||||
result.typ.sons = paramType.sons
|
result.typ.sons = paramType.sons
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
|
|
@ -777,19 +778,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
else:
|
else:
|
||||||
result = instGenericContainer(c, n, result)
|
result = instGenericContainer(c, n, result)
|
||||||
|
|
||||||
proc semTypeFromMacro(c: PContext, n: PNode): PType =
|
proc semTypeExpr(c: PContext, n: PNode): PType =
|
||||||
# Expands a macro or template until a type is returned
|
var n = semExprWithType(c, n)
|
||||||
# results in an error type if the macro expands to something different
|
if n.kind == nkSym and n.sym.kind == skType:
|
||||||
var sym = expectMacroOrTemplateCall(c, n)
|
result = n.sym.typ
|
||||||
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)
|
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
|
LocalError(n.info, errTypeExpected, n.renderTree)
|
||||||
result = errorType(c)
|
|
||||||
|
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = nil
|
result = nil
|
||||||
|
|
@ -823,7 +817,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result.addSonSkipIntLit(t2)
|
result.addSonSkipIntLit(t2)
|
||||||
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
|
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
|
||||||
else:
|
else:
|
||||||
result = semTypeFromMacro(c, n)
|
result = semTypeExpr(c, n)
|
||||||
of nkCurlyExpr:
|
of nkCurlyExpr:
|
||||||
result = semTypeNode(c, n.sons[0], nil)
|
result = semTypeNode(c, n.sons[0], nil)
|
||||||
if result != nil:
|
if result != nil:
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
|
||||||
of tyTypeClass:
|
of tyTypeClass:
|
||||||
match = matchTypeClass(c, req, t) == isGeneric
|
match = matchTypeClass(c, req, t) == isGeneric
|
||||||
else: nil
|
else: nil
|
||||||
elif t.kind in {tyTypeDesc, tyObject}:
|
elif t.kind in {tyObject}:
|
||||||
match = sameType(t, req)
|
match = sameType(t, req)
|
||||||
|
|
||||||
if tfAny in typeClass.flags:
|
if tfAny in typeClass.flags:
|
||||||
|
|
@ -659,7 +659,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
|
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
|
||||||
result = argOrig
|
if f.kind == tyTypeDesc: result = arg
|
||||||
|
else: result = argOrig
|
||||||
else:
|
else:
|
||||||
result = copyTree(arg)
|
result = copyTree(arg)
|
||||||
result.typ = getInstantiatedType(c, arg, m, f)
|
result.typ = getInstantiatedType(c, arg, m, f)
|
||||||
|
|
|
||||||
|
|
@ -585,10 +585,17 @@ type
|
||||||
## or a == (distinct b)
|
## or a == (distinct b)
|
||||||
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
||||||
|
|
||||||
|
TTypeCmpFlag* = enum
|
||||||
|
IgnoreTupleFields,
|
||||||
|
TypeDescExactMatch,
|
||||||
|
AllowCommonBase
|
||||||
|
|
||||||
|
TTypeCmpFlags* = set[TTypeCmpFlag]
|
||||||
|
|
||||||
TSameTypeClosure = object {.pure.}
|
TSameTypeClosure = object {.pure.}
|
||||||
cmp: TDistinctCompare
|
cmp: TDistinctCompare
|
||||||
ignoreTupleFields: bool
|
|
||||||
recCheck: int
|
recCheck: int
|
||||||
|
flags: TTypeCmpFlags
|
||||||
s: seq[tuple[a,b: int]] # seq for a set as it's hopefully faster
|
s: seq[tuple[a,b: int]] # seq for a set as it's hopefully faster
|
||||||
# (few elements expected)
|
# (few elements expected)
|
||||||
|
|
||||||
|
|
@ -610,13 +617,14 @@ proc SameTypeOrNilAux(a, b: PType, c: var TSameTypeClosure): bool =
|
||||||
if a == nil or b == nil: result = false
|
if a == nil or b == nil: result = false
|
||||||
else: result = SameTypeAux(a, b, c)
|
else: result = SameTypeAux(a, b, c)
|
||||||
|
|
||||||
proc SameTypeOrNil*(a, b: PType): bool =
|
proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
|
||||||
if a == b:
|
if a == b:
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
if a == nil or b == nil: result = false
|
if a == nil or b == nil: result = false
|
||||||
else:
|
else:
|
||||||
var c = initSameTypeClosure()
|
var c = initSameTypeClosure()
|
||||||
|
c.flags = flags
|
||||||
result = SameTypeAux(a, b, c)
|
result = SameTypeAux(a, b, c)
|
||||||
|
|
||||||
proc equalParam(a, b: PSym): TParamsEquality =
|
proc equalParam(a, b: PSym): TParamsEquality =
|
||||||
|
|
@ -655,7 +663,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):
|
if not SameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {TypeDescExactMatch}):
|
||||||
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:
|
||||||
|
|
@ -683,13 +691,13 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
|
||||||
for i in countup(0, sonsLen(a) - 1):
|
for i in countup(0, sonsLen(a) - 1):
|
||||||
var x = a.sons[i]
|
var x = a.sons[i]
|
||||||
var y = b.sons[i]
|
var y = b.sons[i]
|
||||||
if c.ignoreTupleFields:
|
if IgnoreTupleFields in c.flags:
|
||||||
x = skipTypes(x, {tyRange})
|
x = skipTypes(x, {tyRange})
|
||||||
y = skipTypes(y, {tyRange})
|
y = skipTypes(y, {tyRange})
|
||||||
|
|
||||||
result = SameTypeAux(x, y, c)
|
result = SameTypeAux(x, y, c)
|
||||||
if not result: return
|
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):
|
for i in countup(0, sonsLen(a.n) - 1):
|
||||||
# check field names:
|
# check field names:
|
||||||
if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym:
|
if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym:
|
||||||
|
|
@ -760,6 +768,13 @@ proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool =
|
||||||
if not SameObjectTree(a.n, b.n, c): return
|
if not SameObjectTree(a.n, b.n, c): return
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
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 =
|
proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
template CycleCheck() =
|
template CycleCheck() =
|
||||||
# believe it or not, the direct check for ``containsOrIncl(c, a, b)``
|
# believe it or not, the direct check for ``containsOrIncl(c, a, b)``
|
||||||
|
|
@ -808,16 +823,18 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
result = sameTuple(a, b, c)
|
result = sameTuple(a, b, c)
|
||||||
of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(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,
|
of tyGenericParam, 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, tyTypeDesc, tyTypeClass:
|
tyOrdinal, tyTypeClass:
|
||||||
if sonsLen(a) == sonsLen(b):
|
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
result = true
|
result = sameChildrenAux(a, b, c)
|
||||||
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):
|
if result and (a.kind == tyProc):
|
||||||
result = a.callConv == b.callConv
|
result = a.callConv == b.callConv
|
||||||
of tyRange:
|
of tyRange:
|
||||||
|
|
@ -827,19 +844,22 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
SameValue(a.n.sons[1], b.n.sons[1])
|
SameValue(a.n.sons[1], b.n.sons[1])
|
||||||
of tyNone: result = false
|
of tyNone: result = false
|
||||||
|
|
||||||
proc SameType*(x, y: PType): bool =
|
proc sameType*(x, y: PType): bool =
|
||||||
var c = initSameTypeClosure()
|
var c = initSameTypeClosure()
|
||||||
result = sameTypeAux(x, y, c)
|
result = sameTypeAux(x, y, c)
|
||||||
|
|
||||||
proc sameBackendType*(x, y: PType): bool =
|
proc sameBackendType*(x, y: PType): bool =
|
||||||
var c = initSameTypeClosure()
|
var c = initSameTypeClosure()
|
||||||
c.ignoreTupleFields = true
|
c.flags.incl IgnoreTupleFields
|
||||||
result = sameTypeAux(x, y, c)
|
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)
|
## compares two type for equality (modulo type distinction)
|
||||||
var c = initSameTypeClosure()
|
var c = initSameTypeClosure()
|
||||||
c.cmp = cmp
|
c.cmp = cmp
|
||||||
|
c.flags = flags
|
||||||
result = sameTypeAux(x, y, c)
|
result = sameTypeAux(x, y, c)
|
||||||
|
|
||||||
proc inheritanceDiff*(a, b: PType): int =
|
proc inheritanceDiff*(a, b: PType): int =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue