support for external types with covariant generic params

This commit is contained in:
Zahary Karadjov
2017-05-08 21:45:37 +03:00
parent 2a34552596
commit 5e368f3639
8 changed files with 62 additions and 3 deletions

View File

@@ -212,6 +212,8 @@ 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
@@ -268,6 +270,8 @@ 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
sfContravariant # contravariant generic param
TSymFlags* = set[TSymFlag]

View File

@@ -103,3 +103,4 @@ proc initDefines*() =
defineSymbol("nimNewShiftOps")
defineSymbol("nimDistros")
defineSymbol("nimHasCppDefine")
defineSymbol("nimGenericInOutFlags")

View File

@@ -113,6 +113,7 @@ type
errGenericLambdaNotAllowed,
errProcHasNoConcreteType,
errCompilerDoesntSupportTarget,
errInOutFlagNotExtern,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
@@ -380,6 +381,7 @@ const
"of the generic paramers can be inferred from the expected signature.",
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
errInOutFlagNotExtern: "`in` and `out` flags can be used only with imported types",
errUser: "$1",
warnCannotOpenFile: "cannot open \'$1\'",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",

View File

@@ -1523,6 +1523,13 @@ proc parseGenericParam(p: var TParser): PNode =
# progress guaranteed
while true:
case p.tok.tokType
of tkIn, tkOut:
let kind = if p.tok.tokType == tkIn: nkInTy
else: nkOutTy
a = newNodeP(kind, p)
getTok(p)
expectIdent(p)
a.addSon(parseSymbol(p))
of tkSymbol, tkAccent:
a = parseSymbol(p)
if a.kind == nkEmpty: return
@@ -1551,7 +1558,7 @@ proc parseGenericParamList(p: var TParser): PNode =
getTok(p)
optInd(p, result)
# progress guaranteed
while p.tok.tokType in {tkSymbol, tkAccent}:
while p.tok.tokType in {tkSymbol, tkAccent, tkIn, tkOut}:
var a = parseGenericParam(p)
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break

View File

@@ -1336,6 +1336,11 @@ proc parseGenericParam(p: var TParser): PNode =
result = newNodeP(nkIdentDefs, p)
while true:
case p.tok.tokType
of tkIn, tkOut:
let t = p.tok.tokType
getTok(p)
expectIdent(p)
a = parseSymbol(p)
of tkSymbol, tkAccent:
a = parseSymbol(p)
if a.kind == nkEmpty: return

View File

@@ -1584,10 +1584,22 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
# type for each generic param. the index
# of the parameter will be stored in the
# attached symbol.
var paramName = a.sons[j]
var covarianceFlag = sfPure
if paramName.kind in {nkInTy, nkOutTy}:
if father == nil or sfImportc notin father.sym.flags:
localError(paramName.info, errInOutFlagNotExtern)
paramName = paramName[0]
covarianceFlag = if paramName.kind == nkInTy: sfContravariant
else: sfCovariant
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
newSymG(skGenericParam, paramName, c).linkTo(finalType)
else:
newSymG(skType, a.sons[j], c).linkTo(finalType)
newSymG(skType, paramName, c).linkTo(finalType)
if covarianceFlag != sfPure: s.flags.incl(covarianceFlag)
if def.kind != nkEmpty: s.ast = def
if father != nil: addSonSkipIntLit(father, s.typ)
s.position = result.len

View File

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

View File

@@ -0,0 +1,26 @@
discard """
cmd: "nim check $file"
errormsg: "`in` and `out` flags can be used only with imported types"
nimout: '''
tinvalidinout.nim(14, 7) Error: `in` and `out` flags can be used only with imported types
tinvalidinout.nim(17, 9) Error: `in` and `out` flags can be used only with imported types
tinvalidinout.nim(18, 9) Error: `in` and `out` flags can be used only with imported types
'''
"""
type
Foo {.header: "foo.h", importcpp.} [in T] = object
Bar[out X] = object
x: int
proc f1[in T](x: T) = discard
proc f2[in T](x: T) {.importc: "f", header: "foo.h"}
var
f: Foo[int]
b: Bar[string]
f1 f
f2 b