cleanup of in/out covariance handling

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

View file

@ -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]

View file

@ -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))

View file

@ -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

View file

@ -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

View file

@ -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}:

View file

@ -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