cleanup of in/out covariance handling

This commit is contained in:
Andreas Rumpf
2017-05-17 20:54:53 +02:00
parent 61a0eba14f
commit 7a95c961a7
6 changed files with 32 additions and 37 deletions

View File

@@ -212,8 +212,6 @@ type
nkIteratorTy, # iterator type
nkSharedTy, # 'shared T'
# 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
nkEnumFieldDef, # `ident = expr` in an enumeration
nkArgList, # argument list
@@ -226,7 +224,7 @@ type
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # already 32 flags!
TSymFlag* = enum # already 33 flags!
sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed
@@ -270,9 +268,6 @@ type
sfDiscardable, # returned value may be discarded implicitly
sfOverriden, # proc is overriden
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]
@@ -460,7 +455,7 @@ type
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
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
# tyArray type represeting a varargs list
tfNoSideEffect, # procedure type does not allow side effects
@@ -513,6 +508,9 @@ type
tfTriggersCompileTime # uses the NimNode type which make the proc
# implicitly '.compiletime'
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]

View File

@@ -1521,9 +1521,9 @@ proc parseGenericParam(p: var TParser): PNode =
while true:
case p.tok.tokType
of tkIn, tkOut:
let kind = if p.tok.tokType == tkIn: nkInTy
else: nkOutTy
a = newNodeP(kind, p)
let x = p.lex.cache.getIdent(if p.tok.tokType == tkIn: "in" else: "out")
a = newNodeP(nkPrefix, p)
a.addSon newIdentNodeP(x, p)
getTok(p)
expectIdent(p)
a.addSon(parseSymbol(p))

View File

@@ -758,7 +758,7 @@ proc checkCovariantParamsUsages(genericType: PType) =
case t.kind
of tyGenericParam:
t.sym.flags.incl sfWeakCovariant
t.flags.incl tfWeakCovariant
return true
of tyObject:
@@ -783,17 +783,17 @@ proc checkCovariantParamsUsages(genericType: PType) =
for i in 1 .. <t.len:
let param = t[i]
if param.kind == tyGenericParam:
if sfCovariant in param.sym.flags:
let formalFlags = targetBody[i-1].sym.flags
if sfCovariant notin formalFlags:
if tfCovariant in param.flags:
let formalFlags = targetBody[i-1].flags
if tfCovariant notin formalFlags:
error("covariant param '" & param.sym.name.s &
"' used in a non-covariant position")
elif sfWeakCovariant in formalFlags:
param.sym.flags.incl sfWeakCovariant
elif tfWeakCovariant in formalFlags:
param.flags.incl tfWeakCovariant
result = true
elif sfContravariant in param.sym.flags:
elif tfContravariant in param.flags:
let formalParam = targetBody[i-1].sym
if sfContravariant notin formalParam.flags:
if tfContravariant notin formalParam.typ.flags:
error("contravariant param '" & param.sym.name.s &
"' used in a non-contravariant position")
result = true
@@ -865,7 +865,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
body.sym = s
body.size = -1 # could not be computed properly
s.typ.sons[sonsLen(s.typ) - 1] = body
if sfCovariant in s.flags:
if tfCovariant in s.typ.flags:
checkCovariantParamsUsages(s.typ)
# XXX: This is a temporary limitation:
# The codegen currently produces various failures with

View File

@@ -1585,24 +1585,23 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
# of the parameter will be stored in the
# attached symbol.
var paramName = a.sons[j]
var covarianceFlag = sfPure
var covarianceFlag = tfUnresolved
if paramName.kind in {nkInTy, nkOutTy}:
if not nimEnableCovariance or paramName.kind == nkInTy:
if paramName.safeLen == 2:
if not nimEnableCovariance or paramName[0].ident.s == "in":
if father == nil or sfImportc notin father.sym.flags:
localError(paramName.info, errInOutFlagNotExtern,
if paramName.kind == nkInTy: "in" else: "out")
covarianceFlag = if paramName.kind == nkInTy: sfContravariant
else: sfCovariant
if father != nil: father.sym.flags.incl sfCovariant
paramName = paramName[0]
localError(paramName.info, errInOutFlagNotExtern, paramName[0].ident.s)
covarianceFlag = if paramName[0].ident.s == "in": tfContravariant
else: tfCovariant
if father != nil: father.flags.incl tfCovariant
paramName = paramName[1]
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
newSymG(skGenericParam, paramName, c).linkTo(finalType)
else:
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 father != nil: addSonSkipIntLit(father, s.typ)
s.position = result.len

View File

@@ -883,7 +883,7 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
let body = f.base
return body == a.base 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])
else:
return false
@@ -1302,22 +1302,22 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
result = typeRel(c, ff, aa, nextFlags)
if result notin {isEqual, isGeneric}:
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 =
if sfCovariant in paramFlags:
if sfWeakCovariant in paramFlags:
if tfCovariant in paramFlags:
if tfWeakCovariant in paramFlags:
isCovariantPtr(c, ff, aa)
else:
ff.kind notin {tyRef, tyPtr} and result == isSubtype
else:
sfContravariant in paramFlags and
tfContravariant in paramFlags and
typeRel(c, aa, ff) == isSubtype
if hasCovariance:
continue
return isNone
if prev == nil: put(c, f, a)
result = if hasCovariance: isGeneric else: isGeneric
result = isGeneric
else:
let fKind = rootf.lastSon.kind
if fKind in {tyAnd, tyOr}:

View File

@@ -68,8 +68,6 @@ type
nnkProcTy,
nnkIteratorTy, # iterator type
nnkSharedTy, # 'shared T'
nnkInTy,
nnkOutTy,
nnkEnumTy,
nnkEnumFieldDef,
nnkArglist, nnkPattern