mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-08 14:03:23 +00:00
support for external types with covariant generic params
This commit is contained in:
@@ -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]
|
||||
|
||||
|
||||
@@ -103,3 +103,4 @@ proc initDefines*() =
|
||||
defineSymbol("nimNewShiftOps")
|
||||
defineSymbol("nimDistros")
|
||||
defineSymbol("nimHasCppDefine")
|
||||
defineSymbol("nimGenericInOutFlags")
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -68,6 +68,8 @@ type
|
||||
nnkProcTy,
|
||||
nnkIteratorTy, # iterator type
|
||||
nnkSharedTy, # 'shared T'
|
||||
nnkInTy,
|
||||
nnkOutTy,
|
||||
nnkEnumTy,
|
||||
nnkEnumFieldDef,
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user