summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim2
-rwxr-xr-xcompiler/parser.nim75
-rwxr-xr-xcompiler/semtypes.nim47
-rwxr-xr-xcompiler/sigmatch.nim37
-rwxr-xr-xcompiler/types.nim26
5 files changed, 120 insertions, 67 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index edf93f4c9..027f4d003 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -715,6 +715,8 @@ const
     tyFloat..tyFloat128, tyUInt..tyUInt64}
   ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, 
                                     tyTuple, tySequence}
+  NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
+    tyProc, tyString, tyError}
   ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, 
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
   PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 59f7934e0..c0a7bc7fe 100755
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -183,14 +183,15 @@ proc getPrecedence(tok: TToken): int =
     of '?': result = 2
     else: considerAsgn(2)
   of tkDiv, tkMod, tkShl, tkShr: result = 9
-  of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf, tkAs: result = 5
+  of tkIn, tkNotIn, tkIs, tkIsNot, tkOf, tkAs: result = 5
   of tkDotDot: result = 6
   of tkAnd: result = 4
   of tkOr, tkXor: result = 3
+  of tkNot: result = -2
   else: result = - 10
   
 proc isOperator(tok: TToken): bool = 
-  result = getPrecedence(tok) >= 0
+  result = getPrecedence(tok) >= -2
 
 proc parseSymbol(p: var TParser): PNode = 
   case p.tok.tokType
@@ -509,10 +510,13 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
       result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
     else: break
 
-proc primary(p: var TParser, skipSuffix = false): PNode
+type
+  TPrimaryMode = enum pmNormal, pmIsType, pmSkipSuffix
+
+proc primary(p: var TParser, mode: TPrimaryMode): PNode
 
-proc lowestExprAux(p: var TParser, limit: int): PNode = 
-  result = primary(p) 
+proc lowestExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
+  result = primary(p, mode)
   # expand while operators have priorities higher than 'limit'
   var opPrec = getPrecedence(p.tok)
   while opPrec >= limit: 
@@ -522,15 +526,15 @@ proc lowestExprAux(p: var TParser, limit: int): PNode =
     getTok(p)
     optInd(p, opNode)         
     # read sub-expression with higher priority:
-    var b = lowestExprAux(p, opPrec + leftAssoc)
+    var b = lowestExprAux(p, opPrec + leftAssoc, mode)
     addSon(a, opNode)
     addSon(a, result)
     addSon(a, b)
     result = a
     opPrec = getPrecedence(p.tok)
   
-proc lowestExpr(p: var TParser): PNode = 
-  result = lowestExprAux(p, -1)
+proc lowestExpr(p: var TParser, mode = pmNormal): PNode = 
+  result = lowestExprAux(p, -1, mode)
 
 proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = 
   result = newNodeP(kind, p)
@@ -738,12 +742,20 @@ proc isExprStart(p: TParser): bool =
     result = true
   else: result = false
   
+when false:
+  proc parseTypeDescNoSuffix(p: var TParser): PNode = 
+    if p.tok.toktype == tkProc: result = parseProcExpr(p, false)
+    elif p.tok.toktype == tkIterator: 
+      result = parseProcExpr(p, false)
+      result.kind = nkIteratorTy
+    else: result = primary(p)
+  
 proc parseTypeDescKAux(p: var TParser, kind: TNodeKind): PNode = 
   result = newNodeP(kind, p)
   getTok(p)
   optInd(p, result)
   if not isOperator(p.tok) and isExprStart(p):
-    addSon(result, parseTypeDesc(p))
+    addSon(result, primary(p, pmIsType))
 
 proc parseExpr(p: var TParser): PNode = 
   #
@@ -759,7 +771,7 @@ proc parseExpr(p: var TParser): PNode =
   # XXX needs proper support:
   #of tkTry: result = parseTry(p)
 
-proc primary(p: var TParser, skipSuffix = false): PNode = 
+proc primary(p: var TParser, mode: TPrimaryMode): PNode = 
   # prefix operator?
   if isOperator(p.tok):
     let isSigil = IsSigilLike(p.tok)
@@ -770,10 +782,10 @@ proc primary(p: var TParser, skipSuffix = false): PNode =
     optInd(p, a)
     if isSigil: 
       #XXX prefix operators
-      addSon(result, primary(p, true))
+      addSon(result, primary(p, pmSkipSuffix))
       result = primarySuffix(p, result)
     else:
-      addSon(result, primary(p))
+      addSon(result, primary(p, pmNormal))
     return
   
   case p.tok.tokType:
@@ -782,7 +794,16 @@ proc primary(p: var TParser, skipSuffix = false): PNode =
   of tkPtr: result = parseTypeDescKAux(p, nkPtrTy)
   of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr)
   of tkTuple: result = parseTuple(p)
-  of tkProc: result = parseProcExpr(p, true)
+  of tkProc: result = parseProcExpr(p, mode != pmIsType)
+  of tkIterator:
+    if mode == pmIsType:
+      result = parseProcExpr(p, false)
+      result.kind = nkIteratorTy
+    else:
+      # no anon iterators for now:
+      parMessage(p, errExprExpected, p.tok)
+      getTok(p)  # we must consume a token here to prevend endless loops!
+      result = ast.emptyNode
   of tkEnum:
     result = newNodeP(nkEnumTy, p)
     getTok(p)
@@ -795,27 +816,35 @@ proc primary(p: var TParser, skipSuffix = false): PNode =
   of tkAddr:
     result = newNodeP(nkAddr, p)
     getTok(p)
-    addSon(result, primary(p))
+    addSon(result, primary(p, pmNormal))
   of tkStatic:
     result = newNodeP(nkStaticExpr, p)
     getTok(p)
-    addSon(result, primary(p))
+    addSon(result, primary(p, pmNormal))
   of tkBind: 
     result = newNodeP(nkBind, p)
     getTok(p)
     optInd(p, result)
-    addSon(result, primary(p))
+    addSon(result, primary(p, pmNormal))
   else:
     result = identOrLiteral(p)
-    if not skipSuffix:
+    if mode != pmSkipSuffix:
       result = primarySuffix(p, result)
-  
+
 proc parseTypeDesc(p: var TParser): PNode = 
-  if p.tok.toktype == tkProc: result = parseProcExpr(p, false)
-  elif p.tok.toktype == tkIterator: 
-    result = parseProcExpr(p, false)
-    result.kind = nkIteratorTy
-  else: result = parseExpr(p)
+  result = lowestExpr(p, pmIsType)
+  when false:
+    result = parseTypeDescNoSuffix(p)
+    # optional 'not nil' suffix?
+    if p.tok.tokType == tkNot:
+      # we don't call 'getTok' here, so 'parseExpr' includes the 'not' in the
+      # expression; this will yield an nkPrefix AST ;-)
+      let ex = parseExpr(p)
+      let a = newNodeI(nkInfix, result.info, 3)
+      a.sons[0] = ex.sons[0]
+      a.sons[1] = result
+      a.sons[2] = ex.sons[1]
+      result = a
 
 proc parseExprStmt(p: var TParser): PNode = 
   var a = lowestExpr(p)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index ab80298de..530e803a3 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -799,16 +799,18 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkPar: 
     if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
     else:
+      # XXX support anon tuple here
       LocalError(n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
   of nkCallKinds:
     if n[0].kind == nkIdent:
       let op = n.sons[0].ident
       if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
+        checkSonsLen(n, 3)
         var
           t1 = semTypeNode(c, n.sons[1], nil)
           t2 = semTypeNode(c, n.sons[2], nil)
-        if   t1 == nil: 
+        if t1 == nil: 
           LocalError(n.sons[1].info, errTypeExpected)
           result = newOrPrevType(tyError, prev, c)
         elif t2 == nil: 
@@ -819,6 +821,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
           result.addSonSkipIntLit(t1)
           result.addSonSkipIntLit(t2)
           result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
+      elif op.id == ord(wNot):
+        checkSonsLen(n, 3)
+        result = semTypeNode(c, n.sons[1], prev)
+        if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
+          result.flags.incl(tfNotNil)
+        else:
+          LocalError(n.info, errGenerated, "invalid type")
       else:
         result = semTypeExpr(c, n)
     else:
@@ -883,25 +892,33 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkVarTy: result = semVarType(c, n, prev)
   of nkDistinctTy: result = semDistinct(c, n, prev)
   of nkProcTy, nkIteratorTy:
-    if n.sonsLen == 0: return newConstraint(c, tyProc)
-    checkSonsLen(n, 2)
-    openScope(c.tab)
-    result = semProcTypeNode(c, n.sons[0], nil, prev, skProc)
-    # dummy symbol for `pragma`:
-    var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
-    s.typ = result
-    if n.sons[1].kind == nkEmpty or n.sons[1].len == 0:
-      if result.callConv == ccDefault:
-        result.callConv = ccClosure
-        #Message(n.info, warnImplicitClosure, renderTree(n))
+    if n.sonsLen == 0:
+      result = newConstraint(c, tyProc)
     else:
-      pragma(c, s, n.sons[1], procTypePragmas)
-      when useEffectSystem: SetEffectsForProcType(result, n.sons[1])
-    closeScope(c.tab)
+      checkSonsLen(n, 2)
+      openScope(c.tab)
+      result = semProcTypeNode(c, n.sons[0], nil, prev, skProc)
+      # dummy symbol for `pragma`:
+      var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
+      s.typ = result
+      if n.sons[1].kind == nkEmpty or n.sons[1].len == 0:
+        if result.callConv == ccDefault:
+          result.callConv = ccClosure
+          #Message(n.info, warnImplicitClosure, renderTree(n))
+      else:
+        pragma(c, s, n.sons[1], procTypePragmas)
+        when useEffectSystem: SetEffectsForProcType(result, n.sons[1])
+      closeScope(c.tab)
+    if n.kind == nkIteratorTy:
+      result.flags.incl(tfIterator)
   of nkEnumTy: result = semEnum(c, n, prev)
   of nkType: result = n.typ
   of nkStmtListType: result = semStmtListType(c, n, prev)
   of nkBlockType: result = semBlockType(c, n, prev)
+  of nkSharedTy:
+    checkSonsLen(n, 1)
+    result = semTypeNode(c, n.sons[0], prev)
+    result.flags.incl(tfShared)
   else:
     LocalError(n.info, errTypeExpected)
     result = newOrPrevType(tyError, prev, c)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 0b9244c2a..03fb9a075 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -257,12 +257,14 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation =
           var y = a.n.sons[i].sym
           if x.name.id != y.name.id: return isNone
 
+proc allowsNil(f: PType): TTypeRelation {.inline.} =
+  result = if tfNotNil notin f.flags: isSubtype else: isNone
+
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
     result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
 
   case a.kind
-  of tyNil: result = isSubtype
   of tyProc:
     if sonsLen(f) != sonsLen(a): return
     # Note: We have to do unification for the parameters before the
@@ -299,6 +301,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
         return isNone
     when useEffectSystem:
       if not compatibleEffects(f, a): return isNone
+  of tyNil: result = f.allowsNil
   else: nil
 
 proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
@@ -388,16 +391,15 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
       elif typeRel(c, base(f), a.sons[0]) >= isGeneric: 
         result = isConvertible
     else: nil
-  of tySequence: 
+  of tySequence:
     case a.Kind
-    of tyNil: 
-      result = isSubtype
-    of tySequence: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
+    of tySequence:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
         result = isSubtype
-      else: 
+      else:
         result = typeRel(c, f.sons[0], a.sons[0])
         if result < isGeneric: result = isNone
+    of tyNil: result = f.allowsNil
     else: nil
   of tyOrdinal:
     if isOrdinalType(a):
@@ -432,21 +434,21 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
     of tyPtr: 
       result = typeRel(c, base(f), base(a))
       if result <= isConvertible: result = isNone
-    of tyNil: result = isSubtype
+    of tyNil: result = f.allowsNil
     else: nil
   of tyRef: 
     case a.kind
-    of tyRef: 
+    of tyRef:
       result = typeRel(c, base(f), base(a))
       if result <= isConvertible: result = isNone
-    of tyNil: result = isSubtype
+    of tyNil: result = f.allowsNil
     else: nil
-  of tyProc: 
+  of tyProc:
     result = procTypeRel(c, f, a)
   of tyPointer: 
     case a.kind
     of tyPointer: result = isEqual
-    of tyNil: result = isSubtype
+    of tyNil: result = f.allowsNil
     of tyProc:
       if a.callConv != ccClosure: result = isConvertible
     of tyPtr, tyCString: result = isConvertible
@@ -454,15 +456,15 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   of tyString: 
     case a.kind
     of tyString: result = isEqual
-    of tyNil: result = isSubtype
+    of tyNil: result = f.allowsNil
     else: nil
-  of tyCString: 
+  of tyCString:
     # conversion from string to cstring is automatic:
     case a.Kind
     of tyCString: result = isEqual
-    of tyNil: result = isSubtype
+    of tyNil: result = f.allowsNil
     of tyString: result = isConvertible
-    of tyPtr: 
+    of tyPtr:
       if a.sons[0].kind == tyChar: result = isConvertible
     of tyArray: 
       if (firstOrd(a.sons[0]) == 0) and
@@ -706,8 +708,7 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
     z.calleeSym = m.calleeSym
     var best = -1
     for i in countup(0, sonsLen(arg) - 1): 
-      # iterators are not first class yet, so ignore them
-      if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}: 
+      if arg.sons[i].sym.kind in {skProc, skIterator, skMethod, skConverter}: 
         copyCandidate(z, m)
         var r = typeRel(z, f, arg.sons[i].typ)
         if r != isNone: 
diff --git a/compiler/types.nim b/compiler/types.nim
index dbd03620c..825b1027a 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -791,6 +791,9 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     else:
       if containsOrIncl(c, a, b): return true
 
+  proc sameFlags(a, b: PType): bool {.inline.} =
+    result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
+    
   if x == y: return true
   var a = skipTypes(x, {tyGenericInst})
   var b = skipTypes(y, {tyGenericInst})
@@ -809,36 +812,37 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
   case a.Kind
   of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
      tyInt..tyBigNum, tyStmt:
-    result = true
+    result = sameFlags(a, b)
   of tyExpr:
-    result = ExprStructuralEquivalent(a.n, b.n)
+    result = ExprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
   of tyObject:
     IfFastObjectTypeCheckFailed(a, b):
       CycleCheck()
-      result = sameObjectStructures(a, b, c)
+      result = sameObjectStructures(a, b, c) and sameFlags(a, b)
   of tyDistinct:
     CycleCheck()
-    if c.cmp == dcEq: result = sameDistinctTypes(a, b)
-    else: result = sameTypeAux(a.sons[0], b.sons[0], c)
+    if c.cmp == dcEq: result = sameDistinctTypes(a, b) and sameFlags(a, b)
+    else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
   of tyEnum, tyForward, tyProxy:
     # XXX generic enums do not make much sense, but require structural checking
-    result = a.id == b.id
+    result = a.id == b.id and sameFlags(a, b)
   of tyTuple:
     CycleCheck()
-    result = sameTuple(a, b, c)
-  of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c)
+    result = sameTuple(a, b, c) and sameFlags(a, b)
+  of tyGenericInst:
+    result = sameTypeAux(lastSon(a), lastSon(b), c)
   of tyTypeDesc:
     if TypeDescExactMatch in c.flags:
       CycleCheck()
-      result = sameChildrenAux(x, y, c)
+      result = sameChildrenAux(x, y, c) and sameFlags(a, b)
     else:
-      result = true
+      result = sameFlags(a, b)
   of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
      tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
      tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
      tyOrdinal, tyTypeClass:
     CycleCheck()
-    result = sameChildrenAux(a, b, c)
+    result = sameChildrenAux(a, b, c) and sameFlags(a, b)
     if result and (a.kind == tyProc):
       result = a.callConv == b.callConv
   of tyRange: