mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
more robust handling of proc signatures containing inter-param type references
This commit is contained in:
@@ -899,10 +899,13 @@ proc makeDeref(n: PNode): PNode =
|
||||
addSon(result, a)
|
||||
t = skipTypes(t.sons[0], {tyGenericInst})
|
||||
|
||||
proc readTypeParameter(c: PContext, ty: PType,
|
||||
const tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
|
||||
|
||||
proc readTypeParameter(c: PContext, typ: PType,
|
||||
paramName: PIdent, info: TLineInfo): PNode =
|
||||
internalAssert ty.kind == tyGenericInst
|
||||
let ty = ty.skipGenericAlias
|
||||
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
|
||||
else: (internalAssert typ.kind == tyCompositeTypeClass; typ.sons[1])
|
||||
|
||||
let tbody = ty.sons[0]
|
||||
for s in countup(0, tbody.len-2):
|
||||
let tParam = tbody.sons[s]
|
||||
@@ -946,7 +949,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result.typ = ty
|
||||
markUsed(n, f)
|
||||
return
|
||||
of tyGenericInst:
|
||||
of tyTypeParamsHolders:
|
||||
return readTypeParameter(c, ty, i, n.info)
|
||||
of tyObject, tyTuple:
|
||||
if ty.n.kind == nkRecList:
|
||||
@@ -996,7 +999,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = n
|
||||
|
||||
# we didn't find any field, let's look for a generic param
|
||||
if result == nil and n.sons[0].typ.kind == tyGenericInst:
|
||||
if result == nil and n.sons[0].typ.kind in tyTypeParamsHolders:
|
||||
result = readTypeParameter(c, n.sons[0].typ, i, n.info)
|
||||
|
||||
proc dotTransformation(c: PContext, n: PNode): PNode =
|
||||
|
||||
@@ -85,19 +85,21 @@ proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
|
||||
|
||||
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
|
||||
|
||||
proc addProcDecls(c: PContext, fn: PSym) =
|
||||
# get the proc itself in scope (e.g. for recursion)
|
||||
addDecl(c, fn)
|
||||
|
||||
for i in 1 .. <fn.typ.n.len:
|
||||
var param = fn.typ.n.sons[i].sym
|
||||
param.owner = fn
|
||||
addParamOrResult(c, param, fn.kind)
|
||||
|
||||
maybeAddResult(c, fn, fn.ast)
|
||||
|
||||
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
inc c.inGenericInst
|
||||
# add it here, so that recursive generic procs are possible:
|
||||
addDecl(c, result)
|
||||
pushProcCon(c, result)
|
||||
# add params to scope
|
||||
for i in 1 .. <result.typ.n.len:
|
||||
var param = result.typ.n.sons[i].sym
|
||||
param.owner = result
|
||||
addParamOrResult(c, param, result.kind)
|
||||
# debug result.typ.n
|
||||
maybeAddResult(c, result, n)
|
||||
var b = n.sons[bodyPos]
|
||||
var symMap: TIdTable
|
||||
initIdTable symMap
|
||||
@@ -107,7 +109,6 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||
n.sons[bodyPos] = transformBody(c.module, b, result)
|
||||
#echo "code instantiated ", result.name.s
|
||||
excl(result.flags, sfForward)
|
||||
popProcCon(c)
|
||||
dec c.inGenericInst
|
||||
|
||||
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||
@@ -116,9 +117,12 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||
var oldPrc = c.generics[i].inst.sym
|
||||
pushInfoContext(oldPrc.info)
|
||||
openScope(c)
|
||||
pushProcCon(c, oldPrc)
|
||||
addProcDecls(c, oldPrc)
|
||||
var n = oldPrc.ast
|
||||
n.sons[bodyPos] = copyTree(s.getBody)
|
||||
instantiateBody(c, n, oldPrc)
|
||||
popProcCon(c)
|
||||
closeScope(c)
|
||||
popInfoContext()
|
||||
|
||||
@@ -144,6 +148,47 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||
result = instGenericContainer(c, n.info, header)
|
||||
|
||||
proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
prc: PSym, info: TLineInfo) =
|
||||
# XXX: Instantiates a generic proc signature, while at the same
|
||||
# time adding the instantiated proc params into the current scope.
|
||||
# This is necessary, because the instantiation process may refer to
|
||||
# these params in situations like this:
|
||||
# proc foo[Container](a: Container, b: a.type.Item): type(b.x)
|
||||
#
|
||||
# Alas, doing this here is probably not enough, because another
|
||||
# proc signature could appear in the params:
|
||||
# proc foo[T](a: proc (x: T, b: type(x.y))
|
||||
#
|
||||
# The solution would be to move this logic into semtypinst, but
|
||||
# at this point semtypinst have to become part of sem, because it
|
||||
# will need to use openScope, addDecl, etc
|
||||
#
|
||||
pushInfoContext(info)
|
||||
var cl = initTypeVars(c, pt, info)
|
||||
var result = instCopyType(cl, prc.typ)
|
||||
addDecl(c, prc)
|
||||
let originalParams = result.n
|
||||
result.n = originalParams.shallowCopy
|
||||
|
||||
for i in 1 .. <result.len:
|
||||
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
||||
propagateToOwner(result, result.sons[i])
|
||||
let param = replaceTypeVarsN(cl, originalParams[i])
|
||||
internalAssert param.kind == nkSym
|
||||
result.n.sons[i] = param
|
||||
addDecl(c, param.sym)
|
||||
|
||||
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
|
||||
result.n.sons[0] = originalParams[0].copyTree
|
||||
|
||||
eraseVoidParams(result)
|
||||
skipIntLiteralParams(result)
|
||||
|
||||
prc.typ = result
|
||||
maybeAddResult(c, prc, prc.ast)
|
||||
popInfoContext()
|
||||
|
||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
info: TLineInfo): PSym =
|
||||
# no need to instantiate generic templates/macros:
|
||||
@@ -171,7 +216,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
var entry = TInstantiation.new
|
||||
entry.sym = result
|
||||
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
|
||||
result.typ = generateTypeInstance(c, pt, info, fn.typ)
|
||||
pushProcCon(c, result)
|
||||
instantiateProcType(c, pt, result, info)
|
||||
n.sons[genericParamsPos] = ast.emptyNode
|
||||
var oldPrc = genericCacheGet(fn, entry[])
|
||||
if oldPrc == nil:
|
||||
@@ -186,6 +232,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
paramsTypeCheck(c, result.typ)
|
||||
else:
|
||||
result = oldPrc
|
||||
popProcCon(c)
|
||||
popInfoContext()
|
||||
closeScope(c) # close scope for parameters
|
||||
popOwner()
|
||||
|
||||
@@ -680,6 +680,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
s.position = genericParams.len
|
||||
genericParams.addSon(newSymNode(s))
|
||||
result = typeClass
|
||||
addDecl(c, s)
|
||||
|
||||
# XXX: There are codegen errors if this is turned into a nested proc
|
||||
template liftingWalk(typ: PType, anonFlag = false): expr =
|
||||
@@ -802,10 +803,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
result = addImplicitGeneric(newTypeS(tyAnything, c))
|
||||
|
||||
of tyGenericParam:
|
||||
markUsed(genericParams, paramType.sym)
|
||||
if tfWildcard in paramType.flags:
|
||||
paramType.flags.excl tfWildcard
|
||||
paramType.sym.kind = skType
|
||||
|
||||
|
||||
else: discard
|
||||
|
||||
# result = liftingWalk(paramType)
|
||||
@@ -1108,13 +1110,17 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
for i in countup(1, n.len - 1):
|
||||
result.rawAddSon(semTypeNode(c, n.sons[i], nil))
|
||||
else: result = semGeneric(c, n, s, prev)
|
||||
of nkIdent, nkDotExpr, nkAccQuoted:
|
||||
if n.kind == nkDotExpr:
|
||||
let head = qualifiedLookUp(c, n[0], {checkAmbiguity, checkUndeclared})
|
||||
if head.kind in {skType}:
|
||||
var toBind = initIntSet()
|
||||
var preprocessed = semGenericStmt(c, n, {}, toBind)
|
||||
return makeTypeFromExpr(c, preprocessed)
|
||||
of nkDotExpr:
|
||||
var typeExpr = semExpr(c, n)
|
||||
if typeExpr.typ.kind != tyTypeDesc:
|
||||
localError(n.info, errTypeExpected)
|
||||
return errorType(c)
|
||||
result = typeExpr.typ.base
|
||||
if result.isMetaType:
|
||||
var toBind = initIntSet()
|
||||
var preprocessed = semGenericStmt(c, n, {}, toBind)
|
||||
return makeTypeFromExpr(c, preprocessed)
|
||||
of nkIdent, nkAccQuoted:
|
||||
var s = semTypeIdent(c, n)
|
||||
if s.typ == nil:
|
||||
if s.kind != skError: localError(n.info, errTypeExpected)
|
||||
|
||||
@@ -80,7 +80,7 @@ type
|
||||
|
||||
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
|
||||
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
||||
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
|
||||
proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode): PNode
|
||||
|
||||
template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
|
||||
when false:
|
||||
@@ -210,7 +210,7 @@ proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
|
||||
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
||||
internalError(cl.info, "substitution with generic parameter")
|
||||
|
||||
proc instCopyType(cl: var TReplTypeVars, t: PType): PType =
|
||||
proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
||||
# XXX: relying on allowMetaTypes is a kludge
|
||||
result = copyType(t, t.owner, cl.allowMetaTypes)
|
||||
result.flags.incl tfFromGeneric
|
||||
@@ -281,7 +281,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||
rawAddSon(result, newbody)
|
||||
checkPartialConstructedType(cl.info, newbody)
|
||||
|
||||
proc eraseVoidParams(t: PType) =
|
||||
proc eraseVoidParams*(t: PType) =
|
||||
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
|
||||
t.sons[0] = nil
|
||||
|
||||
@@ -298,7 +298,7 @@ proc eraseVoidParams(t: PType) =
|
||||
setLen t.n.sons, pos
|
||||
return
|
||||
|
||||
proc skipIntLiteralParams(t: PType) =
|
||||
proc skipIntLiteralParams*(t: PType) =
|
||||
for i in 0 .. <t.sonsLen:
|
||||
let p = t.sons[i]
|
||||
if p == nil: continue
|
||||
@@ -409,7 +409,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
|
||||
else: discard
|
||||
|
||||
proc initTypeVars(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars =
|
||||
proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars =
|
||||
initIdTable(result.symMap)
|
||||
copyIdTable(result.typeMap, pt)
|
||||
initIdTable(result.localCache)
|
||||
|
||||
@@ -944,8 +944,19 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
|
||||
of tyProxy:
|
||||
result = isEqual
|
||||
|
||||
of tyFromExpr:
|
||||
# fix the expression, so it contains the already instantiated types
|
||||
let instantiated = replaceTypesInBody(c.c, c.bindings, f.n)
|
||||
let reevaluted = c.c.semExpr(c.c, instantiated)
|
||||
if reevaluted.typ.kind != tyTypeDesc:
|
||||
localError(f.n.info, errTypeExpected)
|
||||
result = isNone
|
||||
else:
|
||||
result = typeRel(c, a, reevaluted.typ.base)
|
||||
|
||||
else: internalAssert false
|
||||
else:
|
||||
internalAssert false
|
||||
|
||||
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
|
||||
var m: TCandidate
|
||||
|
||||
9
tests/generics/tsigtypeop.nim
Normal file
9
tests/generics/tsigtypeop.nim
Normal file
@@ -0,0 +1,9 @@
|
||||
type
|
||||
Vec3[T] = array[3, T]
|
||||
|
||||
proc foo(x: Vec3, y: Vec3.T, z: x.T): x.type.T =
|
||||
return 10
|
||||
|
||||
var y: Vec3[int] = [1, 2, 3]
|
||||
var z: int = foo(y, 3, 4)
|
||||
|
||||
Reference in New Issue
Block a user