summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2017-05-08 21:45:37 +0300
committerZahary Karadjov <zahary@gmail.com>2017-05-08 21:45:37 +0300
commit5e368f36390a8164abbedf2f6c79ead0f510df29 (patch)
treecd4aeececfec7a16722430458e336a4f3523f7c7 /compiler
parent2a3455259618723b9a748b16e2fccf2a06b0c9cb (diff)
downloadNim-5e368f36390a8164abbedf2f6c79ead0f510df29.tar.gz
support for external types with covariant generic params
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim4
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/msgs.nim2
-rw-r--r--compiler/parser.nim9
-rw-r--r--compiler/pbraces.nim5
-rw-r--r--compiler/semtypes.nim16
6 files changed, 34 insertions, 3 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 5b68e9712..d4ffbcfa4 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -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]
 
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 4303fd6c8..a4f47ac72 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -103,3 +103,4 @@ proc initDefines*() =
   defineSymbol("nimNewShiftOps")
   defineSymbol("nimDistros")
   defineSymbol("nimHasCppDefine")
+  defineSymbol("nimGenericInOutFlags")
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 3a97f1ed2..1842ce1de 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -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",
diff --git a/compiler/parser.nim b/compiler/parser.nim
index e4c04c0f7..f4d1aca15 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -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
diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim
index b59fbc6cf..fa4ccc139 100644
--- a/compiler/pbraces.nim
+++ b/compiler/pbraces.nim
@@ -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
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 16066da91..5cc5a1ecf 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -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