cleanup of in/out covariance handling
This commit is contained in:
parent
61a0eba14f
commit
7a95c961a7
6 changed files with 32 additions and 37 deletions
|
|
@ -212,8 +212,6 @@ type
|
||||||
nkIteratorTy, # iterator type
|
nkIteratorTy, # iterator type
|
||||||
nkSharedTy, # 'shared T'
|
nkSharedTy, # 'shared T'
|
||||||
# we use 'nkPostFix' for the 'not nil' addition
|
# we use 'nkPostFix' for the 'not nil' addition
|
||||||
nkInTy, # prefix `in` used to mark contravariant types
|
|
||||||
nkOutTy, # prefix `out` used to mark covariant types
|
|
||||||
nkEnumTy, # enum body
|
nkEnumTy, # enum body
|
||||||
nkEnumFieldDef, # `ident = expr` in an enumeration
|
nkEnumFieldDef, # `ident = expr` in an enumeration
|
||||||
nkArgList, # argument list
|
nkArgList, # argument list
|
||||||
|
|
@ -226,7 +224,7 @@ type
|
||||||
TNodeKinds* = set[TNodeKind]
|
TNodeKinds* = set[TNodeKind]
|
||||||
|
|
||||||
type
|
type
|
||||||
TSymFlag* = enum # already 32 flags!
|
TSymFlag* = enum # already 33 flags!
|
||||||
sfUsed, # read access of sym (for warnings) or simply used
|
sfUsed, # read access of sym (for warnings) or simply used
|
||||||
sfExported, # symbol is exported from module
|
sfExported, # symbol is exported from module
|
||||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||||
|
|
@ -270,9 +268,6 @@ type
|
||||||
sfDiscardable, # returned value may be discarded implicitly
|
sfDiscardable, # returned value may be discarded implicitly
|
||||||
sfOverriden, # proc is overriden
|
sfOverriden, # proc is overriden
|
||||||
sfGenSym # symbol is 'gensym'ed; do not add to symbol table
|
sfGenSym # symbol is 'gensym'ed; do not add to symbol table
|
||||||
sfCovariant # covariant generic param mimicing a ptr type
|
|
||||||
sfWeakCovariant # covariant generic param mimicing a seq/array type
|
|
||||||
sfContravariant # contravariant generic param
|
|
||||||
|
|
||||||
TSymFlags* = set[TSymFlag]
|
TSymFlags* = set[TSymFlag]
|
||||||
|
|
||||||
|
|
@ -460,7 +455,7 @@ type
|
||||||
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 30)
|
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that)
|
||||||
tfVarargs, # procedure has C styled varargs
|
tfVarargs, # procedure has C styled varargs
|
||||||
# tyArray type represeting a varargs list
|
# tyArray type represeting a varargs list
|
||||||
tfNoSideEffect, # procedure type does not allow side effects
|
tfNoSideEffect, # procedure type does not allow side effects
|
||||||
|
|
@ -513,6 +508,9 @@ type
|
||||||
tfTriggersCompileTime # uses the NimNode type which make the proc
|
tfTriggersCompileTime # uses the NimNode type which make the proc
|
||||||
# implicitly '.compiletime'
|
# implicitly '.compiletime'
|
||||||
tfRefsAnonObj # used for 'ref object' and 'ptr object'
|
tfRefsAnonObj # used for 'ref object' and 'ptr object'
|
||||||
|
tfCovariant # covariant generic param mimicing a ptr type
|
||||||
|
tfWeakCovariant # covariant generic param mimicing a seq/array type
|
||||||
|
tfContravariant # contravariant generic param
|
||||||
|
|
||||||
TTypeFlags* = set[TTypeFlag]
|
TTypeFlags* = set[TTypeFlag]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1521,9 +1521,9 @@ proc parseGenericParam(p: var TParser): PNode =
|
||||||
while true:
|
while true:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
of tkIn, tkOut:
|
of tkIn, tkOut:
|
||||||
let kind = if p.tok.tokType == tkIn: nkInTy
|
let x = p.lex.cache.getIdent(if p.tok.tokType == tkIn: "in" else: "out")
|
||||||
else: nkOutTy
|
a = newNodeP(nkPrefix, p)
|
||||||
a = newNodeP(kind, p)
|
a.addSon newIdentNodeP(x, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
expectIdent(p)
|
expectIdent(p)
|
||||||
a.addSon(parseSymbol(p))
|
a.addSon(parseSymbol(p))
|
||||||
|
|
|
||||||
|
|
@ -758,7 +758,7 @@ proc checkCovariantParamsUsages(genericType: PType) =
|
||||||
|
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
t.sym.flags.incl sfWeakCovariant
|
t.flags.incl tfWeakCovariant
|
||||||
return true
|
return true
|
||||||
|
|
||||||
of tyObject:
|
of tyObject:
|
||||||
|
|
@ -783,17 +783,17 @@ proc checkCovariantParamsUsages(genericType: PType) =
|
||||||
for i in 1 .. <t.len:
|
for i in 1 .. <t.len:
|
||||||
let param = t[i]
|
let param = t[i]
|
||||||
if param.kind == tyGenericParam:
|
if param.kind == tyGenericParam:
|
||||||
if sfCovariant in param.sym.flags:
|
if tfCovariant in param.flags:
|
||||||
let formalFlags = targetBody[i-1].sym.flags
|
let formalFlags = targetBody[i-1].flags
|
||||||
if sfCovariant notin formalFlags:
|
if tfCovariant notin formalFlags:
|
||||||
error("covariant param '" & param.sym.name.s &
|
error("covariant param '" & param.sym.name.s &
|
||||||
"' used in a non-covariant position")
|
"' used in a non-covariant position")
|
||||||
elif sfWeakCovariant in formalFlags:
|
elif tfWeakCovariant in formalFlags:
|
||||||
param.sym.flags.incl sfWeakCovariant
|
param.flags.incl tfWeakCovariant
|
||||||
result = true
|
result = true
|
||||||
elif sfContravariant in param.sym.flags:
|
elif tfContravariant in param.flags:
|
||||||
let formalParam = targetBody[i-1].sym
|
let formalParam = targetBody[i-1].sym
|
||||||
if sfContravariant notin formalParam.flags:
|
if tfContravariant notin formalParam.typ.flags:
|
||||||
error("contravariant param '" & param.sym.name.s &
|
error("contravariant param '" & param.sym.name.s &
|
||||||
"' used in a non-contravariant position")
|
"' used in a non-contravariant position")
|
||||||
result = true
|
result = true
|
||||||
|
|
@ -865,7 +865,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
body.sym = s
|
body.sym = s
|
||||||
body.size = -1 # could not be computed properly
|
body.size = -1 # could not be computed properly
|
||||||
s.typ.sons[sonsLen(s.typ) - 1] = body
|
s.typ.sons[sonsLen(s.typ) - 1] = body
|
||||||
if sfCovariant in s.flags:
|
if tfCovariant in s.typ.flags:
|
||||||
checkCovariantParamsUsages(s.typ)
|
checkCovariantParamsUsages(s.typ)
|
||||||
# XXX: This is a temporary limitation:
|
# XXX: This is a temporary limitation:
|
||||||
# The codegen currently produces various failures with
|
# The codegen currently produces various failures with
|
||||||
|
|
|
||||||
|
|
@ -1585,24 +1585,23 @@ 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 paramName = a.sons[j]
|
var paramName = a.sons[j]
|
||||||
var covarianceFlag = sfPure
|
var covarianceFlag = tfUnresolved
|
||||||
|
|
||||||
if paramName.kind in {nkInTy, nkOutTy}:
|
if paramName.safeLen == 2:
|
||||||
if not nimEnableCovariance or paramName.kind == nkInTy:
|
if not nimEnableCovariance or paramName[0].ident.s == "in":
|
||||||
if father == nil or sfImportc notin father.sym.flags:
|
if father == nil or sfImportc notin father.sym.flags:
|
||||||
localError(paramName.info, errInOutFlagNotExtern,
|
localError(paramName.info, errInOutFlagNotExtern, paramName[0].ident.s)
|
||||||
if paramName.kind == nkInTy: "in" else: "out")
|
covarianceFlag = if paramName[0].ident.s == "in": tfContravariant
|
||||||
covarianceFlag = if paramName.kind == nkInTy: sfContravariant
|
else: tfCovariant
|
||||||
else: sfCovariant
|
if father != nil: father.flags.incl tfCovariant
|
||||||
if father != nil: father.sym.flags.incl sfCovariant
|
paramName = paramName[1]
|
||||||
paramName = paramName[0]
|
|
||||||
|
|
||||||
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
|
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
|
||||||
newSymG(skGenericParam, paramName, c).linkTo(finalType)
|
newSymG(skGenericParam, paramName, c).linkTo(finalType)
|
||||||
else:
|
else:
|
||||||
newSymG(skType, paramName, c).linkTo(finalType)
|
newSymG(skType, paramName, c).linkTo(finalType)
|
||||||
|
|
||||||
if covarianceFlag != sfPure: s.flags.incl(covarianceFlag)
|
if covarianceFlag != tfUnresolved: s.typ.flags.incl(covarianceFlag)
|
||||||
if def.kind != nkEmpty: s.ast = def
|
if def.kind != nkEmpty: s.ast = def
|
||||||
if father != nil: addSonSkipIntLit(father, s.typ)
|
if father != nil: addSonSkipIntLit(father, s.typ)
|
||||||
s.position = result.len
|
s.position = result.len
|
||||||
|
|
|
||||||
|
|
@ -883,7 +883,7 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
|
||||||
let body = f.base
|
let body = f.base
|
||||||
return body == a.base and
|
return body == a.base and
|
||||||
a.sonsLen == 3 and
|
a.sonsLen == 3 and
|
||||||
sfWeakCovariant notin body.sons[0].sym.flags and
|
tfWeakCovariant notin body.sons[0].flags and
|
||||||
baseTypesCheck(f.sons[1], a.sons[1])
|
baseTypesCheck(f.sons[1], a.sons[1])
|
||||||
else:
|
else:
|
||||||
return false
|
return false
|
||||||
|
|
@ -1302,22 +1302,22 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
result = typeRel(c, ff, aa, nextFlags)
|
result = typeRel(c, ff, aa, nextFlags)
|
||||||
if result notin {isEqual, isGeneric}:
|
if result notin {isEqual, isGeneric}:
|
||||||
if trNoCovariance notin flags and ff.kind == aa.kind:
|
if trNoCovariance notin flags and ff.kind == aa.kind:
|
||||||
let paramFlags = rootf.base.sons[i-1].sym.flags
|
let paramFlags = rootf.base.sons[i-1].flags
|
||||||
hasCovariance =
|
hasCovariance =
|
||||||
if sfCovariant in paramFlags:
|
if tfCovariant in paramFlags:
|
||||||
if sfWeakCovariant in paramFlags:
|
if tfWeakCovariant in paramFlags:
|
||||||
isCovariantPtr(c, ff, aa)
|
isCovariantPtr(c, ff, aa)
|
||||||
else:
|
else:
|
||||||
ff.kind notin {tyRef, tyPtr} and result == isSubtype
|
ff.kind notin {tyRef, tyPtr} and result == isSubtype
|
||||||
else:
|
else:
|
||||||
sfContravariant in paramFlags and
|
tfContravariant in paramFlags and
|
||||||
typeRel(c, aa, ff) == isSubtype
|
typeRel(c, aa, ff) == isSubtype
|
||||||
if hasCovariance:
|
if hasCovariance:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return isNone
|
return isNone
|
||||||
if prev == nil: put(c, f, a)
|
if prev == nil: put(c, f, a)
|
||||||
result = if hasCovariance: isGeneric else: isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
let fKind = rootf.lastSon.kind
|
let fKind = rootf.lastSon.kind
|
||||||
if fKind in {tyAnd, tyOr}:
|
if fKind in {tyAnd, tyOr}:
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,6 @@ type
|
||||||
nnkProcTy,
|
nnkProcTy,
|
||||||
nnkIteratorTy, # iterator type
|
nnkIteratorTy, # iterator type
|
||||||
nnkSharedTy, # 'shared T'
|
nnkSharedTy, # 'shared T'
|
||||||
nnkInTy,
|
|
||||||
nnkOutTy,
|
|
||||||
nnkEnumTy,
|
nnkEnumTy,
|
||||||
nnkEnumFieldDef,
|
nnkEnumFieldDef,
|
||||||
nnkArglist, nnkPattern
|
nnkArglist, nnkPattern
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue