summary refs log tree commit diff stats
path: root/compiler/sinkparameter_inference.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/sinkparameter_inference.nim')
-rw-r--r--compiler/sinkparameter_inference.nim70
1 files changed, 70 insertions, 0 deletions
diff --git a/compiler/sinkparameter_inference.nim b/compiler/sinkparameter_inference.nim
new file mode 100644
index 000000000..1becc250e
--- /dev/null
+++ b/compiler/sinkparameter_inference.nim
@@ -0,0 +1,70 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2020 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+proc checkForSink*(config: ConfigRef; owner: PSym; arg: PNode) =
+  #[ Patterns we seek to detect:
+
+    someLocation = p # ---> p: sink T
+    passToSink(p)    # p: sink
+    ObjConstr(fieldName: p)
+    [p, q] # array construction
+
+    # Open question:
+    var local = p # sink parameter?
+    passToSink(local)
+  ]#
+  if optSinkInference notin config.options: return
+  case arg.kind
+  of nkSym:
+    if arg.sym.kind == skParam and
+        arg.sym.owner == owner and
+        owner.typ != nil and owner.typ.kind == tyProc and
+        arg.sym.typ.hasDestructor and
+        arg.sym.typ.kind notin {tyVar, tySink, tyOwned}:
+      # Watch out: cannot do this inference for procs with forward
+      # declarations.
+      if sfWasForwarded notin owner.flags:
+        let argType = arg.sym.typ
+
+        let sinkType = newType(tySink, owner)
+        sinkType.size = argType.size
+        sinkType.align = argType.align
+        sinkType.paddingAtEnd = argType.paddingAtEnd
+        sinkType.add argType
+
+        arg.sym.typ = sinkType
+        owner.typ[arg.sym.position+1] = sinkType
+
+        #message(config, arg.info, warnUser,
+        #  ("turned '$1' to a sink parameter") % [$arg])
+        #echo config $ arg.info, " turned into a sink parameter ", arg.sym.name.s
+      elif sfWasForwarded notin arg.sym.flags:
+        # we only report every potential 'sink' parameter only once:
+        incl arg.sym.flags, sfWasForwarded
+        message(config, arg.info, hintPerformance,
+          ("could not turn '$1' to a sink parameter " &
+          "because '$2' was forward declared") % [arg.sym.name.s, owner.name.s])
+      #echo config $ arg.info, " candidate for a sink parameter here"
+  of nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr:
+    if not isEmptyType(arg.typ):
+      checkForSink(config, owner, arg.lastSon)
+  of nkIfStmt, nkIfExpr, nkWhen:
+    for branch in arg:
+      let value = branch.lastSon
+      if not isEmptyType(value.typ):
+        checkForSink(config, owner, value)
+  of nkCaseStmt:
+    for i in 1..<arg.len:
+      let value = arg[i].lastSon
+      if not isEmptyType(value.typ):
+        checkForSink(config, owner, value)
+  of nkTryStmt:
+    checkForSink(config, owner, arg[0])
+  else:
+    discard "nothing to do"