support for external types with covariant generic params
This commit is contained in:
parent
2a34552596
commit
5e368f3639
8 changed files with 62 additions and 3 deletions
|
|
@ -212,6 +212,8 @@ 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
|
||||||
|
|
@ -268,6 +270,8 @@ 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
|
||||||
|
sfContravariant # contravariant generic param
|
||||||
|
|
||||||
TSymFlags* = set[TSymFlag]
|
TSymFlags* = set[TSymFlag]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,3 +103,4 @@ proc initDefines*() =
|
||||||
defineSymbol("nimNewShiftOps")
|
defineSymbol("nimNewShiftOps")
|
||||||
defineSymbol("nimDistros")
|
defineSymbol("nimDistros")
|
||||||
defineSymbol("nimHasCppDefine")
|
defineSymbol("nimHasCppDefine")
|
||||||
|
defineSymbol("nimGenericInOutFlags")
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ type
|
||||||
errGenericLambdaNotAllowed,
|
errGenericLambdaNotAllowed,
|
||||||
errProcHasNoConcreteType,
|
errProcHasNoConcreteType,
|
||||||
errCompilerDoesntSupportTarget,
|
errCompilerDoesntSupportTarget,
|
||||||
|
errInOutFlagNotExtern,
|
||||||
errUser,
|
errUser,
|
||||||
warnCannotOpenFile,
|
warnCannotOpenFile,
|
||||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||||
|
|
@ -380,6 +381,7 @@ const
|
||||||
"of the generic paramers can be inferred from the expected signature.",
|
"of the generic paramers can be inferred from the expected signature.",
|
||||||
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
|
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",
|
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",
|
errUser: "$1",
|
||||||
warnCannotOpenFile: "cannot open \'$1\'",
|
warnCannotOpenFile: "cannot open \'$1\'",
|
||||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||||
|
|
|
||||||
|
|
@ -1523,6 +1523,13 @@ proc parseGenericParam(p: var TParser): PNode =
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
while true:
|
while true:
|
||||||
case p.tok.tokType
|
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:
|
of tkSymbol, tkAccent:
|
||||||
a = parseSymbol(p)
|
a = parseSymbol(p)
|
||||||
if a.kind == nkEmpty: return
|
if a.kind == nkEmpty: return
|
||||||
|
|
@ -1551,7 +1558,7 @@ proc parseGenericParamList(p: var TParser): PNode =
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
while p.tok.tokType in {tkSymbol, tkAccent, tkIn, tkOut}:
|
||||||
var a = parseGenericParam(p)
|
var a = parseGenericParam(p)
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
||||||
|
|
|
||||||
|
|
@ -1336,6 +1336,11 @@ proc parseGenericParam(p: var TParser): PNode =
|
||||||
result = newNodeP(nkIdentDefs, p)
|
result = newNodeP(nkIdentDefs, p)
|
||||||
while true:
|
while true:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
of tkIn, tkOut:
|
||||||
|
let t = p.tok.tokType
|
||||||
|
getTok(p)
|
||||||
|
expectIdent(p)
|
||||||
|
a = parseSymbol(p)
|
||||||
of tkSymbol, tkAccent:
|
of tkSymbol, tkAccent:
|
||||||
a = parseSymbol(p)
|
a = parseSymbol(p)
|
||||||
if a.kind == nkEmpty: return
|
if a.kind == nkEmpty: return
|
||||||
|
|
|
||||||
|
|
@ -1584,10 +1584,22 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
# type for each generic param. the index
|
# type for each generic param. the index
|
||||||
# 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 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:
|
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:
|
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 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
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ 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
|
||||||
|
|
|
||||||
26
tests/errmsgs/tinvalidinout.nim
Normal file
26
tests/errmsgs/tinvalidinout.nim
Normal 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
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue