summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-11-03 15:57:12 +0100
committerAraq <rumpf_a@web.de>2012-11-03 15:57:12 +0100
commit9f38ff0c6578a7030b85acf66363d8f4e51dbe33 (patch)
treeb2e353df34715c8eae026341c8ea0368db4cebbd
parent224f42bbd70c9c39e6c93bc7c0cf9568e79e115b (diff)
downloadNim-9f38ff0c6578a7030b85acf66363d8f4e51dbe33.tar.gz
next steps for exception tracking
-rwxr-xr-xcompiler/cgmeth.nim11
-rwxr-xr-xcompiler/options.nim2
-rwxr-xr-xcompiler/sem.nim2
-rw-r--r--compiler/sempass2.nim64
-rwxr-xr-xcompiler/semtypes.nim3
-rwxr-xr-xcompiler/sigmatch.nim2
-rwxr-xr-xcompiler/types.nim23
7 files changed, 73 insertions, 34 deletions
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index 76f5414ec..687653aaf 100755
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -10,7 +10,8 @@
 ## This module implements code generation for multi methods.
 
 import 
-  intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys
+  intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
+  sempass2
 
 proc genConv(n: PNode, d: PType, downcast: bool): PNode = 
   var dest = skipTypes(d, abstractPtrs)
@@ -81,10 +82,12 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) =
 
 proc methodDef*(s: PSym, fromCache: bool) =
   var L = len(gMethods)
-  for i in countup(0, L - 1): 
-    if sameMethodBucket(gMethods[i][0], s): 
+  for i in countup(0, L - 1):
+    let disp = gMethods[i][0]
+    if sameMethodBucket(disp, s):
       add(gMethods[i], s)
-      attachDispatcher(s, lastSon(gMethods[i][0].ast))
+      attachDispatcher(s, lastSon(disp.ast))
+      when useEffectSystem: checkMethodEffects(disp, s)
       return 
   add(gMethods, @[s])
   # create a new dispatcher:
diff --git a/compiler/options.nim b/compiler/options.nim
index f5e54a613..2051953ce 100755
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -12,7 +12,7 @@ import
   
 const
   hasTinyCBackend* = defined(tinyc)
-  useEffectSystem* = false
+  useEffectSystem* = true
 
 type                          # please make sure we have under 32 options
                               # (improves code efficiency a lot!)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 93d023806..bd1ad1468 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -15,7 +15,7 @@ import
   magicsys, parser, nversion, nimsets, semfold, importer,
   procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
   semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting,
-  evaltempl, patterns, parampatterns
+  evaltempl, patterns, parampatterns, sempass2
 
 proc semPass*(): TPass
 # implementation
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 936fe1822..4199aa5f7 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -25,7 +25,7 @@ import
 #   io, time (time dependent), gc (performs GC'ed allocation), exceptions,
 #   side effect (accesses global), store (stores into *type*),
 #   store_unkown (performs some store) --> store(any)|store(x) 
-#   load (loads from *type*), recursive (recursive call),
+#   load (loads from *type*), recursive (recursive call), unsafe,
 #   endless (has endless loops), --> user effects are defined over *patterns*
 #   --> a TR macro can annotate the proc with user defined annotations
 #   --> the effect system can access these
@@ -84,20 +84,16 @@ type
   PEffects = var TEffects
 
 proc throws(tracked: PEffects, n: PNode) =
-  # since a 'raise' statement occurs rarely and we need distinct reasons;
-  # we simply do not merge anything here, this would be problematic for the
-  # stack of exceptions anyway:
   tracked.exc.add n
   
 proc excType(n: PNode): PType =
-  assert n.kind == nkRaiseStmt
+  assert n.kind != nkRaiseStmt
   # reraise is like raising E_Base:
-  let t = if n.sons[0].kind == nkEmpty: sysTypeFromName"E_Base"
-          else: n.sons[0].typ
+  let t = if n.kind == nkEmpty: sysTypeFromName"E_Base" else: n.typ
   result = skipTypes(t, skipPtrs)
 
 proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
-  assert e.kind == nkRaiseStmt
+  assert e.kind != nkRaiseStmt
   var aa = a.exc
   for i in a.bottom .. <aa.len:
     if sameType(aa[i].excType, e.excType):
@@ -111,7 +107,7 @@ proc mergeEffects(a: PEffects, b: PNode, useLineInfo) =
 proc listEffects(a: PEffects) =
   var aa = a.exc
   for e in items(aa):
-    Message(e.info, hintUser, renderTree(e))
+    Message(e.info, hintUser, typeToString(e.typ))
 
 proc catches(tracked: PEffects, e: PType) =
   let e = skipTypes(e, skipPtrs)
@@ -172,13 +168,12 @@ proc raisesSpec(n: PNode): PNode =
         result.add(it.sons[1])
       return
 
-proc createRaise(n: PNode, t: PType): PNode =
-  result = newNodeI(nkRaiseStmt, n.info)
-  result.add(newNodeIT(nkType, n.info, t))
+proc createRaise(n: PNode): PNode =
+  result = newNodeIT(nkType, n.info, sysTypeFromName"E_Base")
 
 proc track(tracked: PEffects, n: PNode) =
   case n.kind
-  of nkRaiseStmt: throws(tracked, n)
+  of nkRaiseStmt: throws(tracked, n.sons[0])
   of nkCallKinds:
     # p's effects are ours too:
     let op = n.sons[0].typ
@@ -191,9 +186,9 @@ proc track(tracked: PEffects, n: PNode) =
           if not isNil(spec):
             mergeEffects(tracked, spec, useLineInfo=false)
           else:
-            addEffect(tracked, createRaise(n, sysTypeFromName"E_Base"))
+            addEffect(tracked, createRaise(n))
         elif isIndirectCall(n.sons[0]):
-          addEffect(tracked, createRaise(n, sysTypeFromName"E_Base"))
+          addEffect(tracked, createRaise(n))
       else:
         effectList = effectList.sons[exceptionEffects]
         mergeEffects(tracked, effectList, useLineInfo=true)
@@ -209,7 +204,7 @@ proc track(tracked: PEffects, n: PNode) =
     track(tracked, n.sons[i])
 
 # XXX
-# - make use of 'raises' in proc types compatibility
+# - doc2 should report effects
 # - check for 'raises' consistency for multi-methods
 
 proc checkRaisesSpec(spec, real: PNode) =
@@ -224,22 +219,37 @@ proc checkRaisesSpec(spec, real: PNode) =
           break search
       # XXX call graph analysis would be nice here!
       localError(r.info, errGenerated, "can raise an unlisted exception: " &
-        typeToString(r.sons[0].typ))
+        typeToString(r.typ))
   # hint about unnecessarily listed exception types:
   for s in 0 .. <spec.len:
     if not used.contains(s):
       Message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
 
-proc compatibleEffects*(formal, actual: PType): bool =
-  # for proc type compatibility checking:
-  assert formal.kind == tyProc and actual.kind == tyProc
-  InternalAssert formal.n.sons[0].kind == nkEffectList
-  InternalAssert actual.n.sons[0].kind == nkEffectList
-  
-  var effectList = formal.n.sons[0]
-  if effectList.len == 0:
-    # 'formal' has no restrictions :-)
-    result = true
+proc checkMethodEffects*(disp, branch: PSym) =
+  ## checks for consistent effects for multi methods.
+  let spec = raisesSpec(disp.ast.sons[pragmasPos])
+  if not isNil(spec):
+    let actual = branch.typ.n.sons[0]
+    if actual.len != effectListLen: return
+    let real = actual.sons[exceptionEffects]
+    
+    for r in items(real):
+      block search:
+        for s in 0 .. <spec.len:
+          if inheritanceDiff(r.excType, spec[s].typ) <= 0:
+            break search
+        localError(r.info, errGenerated, "can raise an unlisted exception: " &
+          typeToString(r.typ))
+
+proc setEffectsForProcType*(t: PType, n: PNode) =
+  var effects = t.n.sons[0]
+  InternalAssert t.kind == tyProc and effects.kind == nkEffectList
+
+  let spec = raisesSpec(n)
+  if not isNil(spec):
+    InternalAssert effects.len == 0
+    newSeq(effects.sons, effectListLen)
+    effects.sons[exceptionEffects] = spec
 
 proc trackProc*(s: PSym, body: PNode) =
   var effects = s.typ.n.sons[0]
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 00be65203..6716693ca 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -893,9 +893,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     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))
+        #Message(n.info, warnImplicitClosure, renderTree(n))
     else:
       pragma(c, s, n.sons[1], procTypePragmas)
+      when useEffectSystem: SetEffectsForProcType(result, n.sons[1])
     closeScope(c.tab)
   of nkEnumTy: result = semEnum(c, n, prev)
   of nkType: result = n.typ
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 3205866d1..0b9244c2a 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -297,6 +297,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
         result = isConvertible
       else:
         return isNone
+    when useEffectSystem:
+      if not compatibleEffects(f, a): return isNone
   else: nil
 
 proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
diff --git a/compiler/types.nim b/compiler/types.nim
index 7b7078e20..7ee69a59a 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1189,3 +1189,26 @@ proc baseOfDistinct*(t: PType): PType =
     if it.kind == tyDistinct:
       internalAssert parent != nil
       parent.sons[0] = it.sons[0]
+
+proc compatibleEffects*(formal, actual: PType): bool =
+  # for proc type compatibility checking:
+  assert formal.kind == tyProc and actual.kind == tyProc
+  InternalAssert formal.n.sons[0].kind == nkEffectList
+  InternalAssert actual.n.sons[0].kind == nkEffectList
+  
+  var spec = formal.n.sons[0]
+  # if 'spec.sons[0].kind == nkArgList' it is no formal type really, but a
+  # computed effect and as such no spec:
+  # 'r.msgHandler = if isNil(msgHandler): defaultMsgHandler else: msgHandler'
+  if spec.len != 0 and spec.sons[0].kind != nkArgList:
+    var real = actual.n.sons[0]
+    if real.len == 0: 
+      # we don't know anything about 'real' ...
+      return false
+    for r in items(real):
+      block search:
+        for s in items(spec):
+          if inheritanceDiff(r.typ, s.typ) <= 0:
+            break search
+        return false
+  result = true