summary refs log tree commit diff stats
path: root/compiler/sinkparameter_inference.nim
blob: 09d54ec7906c872ce675b13fce1ee5598c0d7164 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#
#
#           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; idgen: IdGenerator; 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)
  ]#
  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, idgen, 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" % [arg.sym.name.s])
      #echo config $ arg.info, " candidate for a sink parameter here"
  of nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr:
    if not isEmptyType(arg.typ):
      checkForSink(config, idgen, owner, arg.lastSon)
  of nkIfStmt, nkIfExpr, nkWhen:
    for branch in arg:
      let value = branch.lastSon
      if not isEmptyType(value.typ):
        checkForSink(config, idgen, owner, value)
  of nkCaseStmt:
    for i in 1..<arg.len:
      let value = arg[i].lastSon
      if not isEmptyType(value.typ):
        checkForSink(config, idgen, owner, value)
  of nkTryStmt:
    checkForSink(config, idgen, owner, arg[0])
  else:
    discard "nothing to do"
bookmarks.remember(pwd) except NonexistantBookmark: pass def set_bookmark(self, key): """Set the bookmark with the name <key> to the current directory""" self.bookmarks[key] = self.env.pwd def unset_bookmark(self, key): """Delete the bookmark with the name <key>""" self.bookmarks.delete(key) def move_left(self, n=1): """Enter the parent directory""" try: directory = os.path.join(*(['..'] * n)) except: return self.env.enter_dir(directory) def move_right(self, mode=0): """Enter the current directory or execute the current file""" cf = self.env.cf marked_items = self.env.pwd.marked_items sel = self.env.get_selection() if not self.env.enter_dir(cf): if sel: if not self.execute_file(sel, mode=mode): self.open_console('@') def history_go(self, relative): """Move back and forth in the history""" self.env.history_go(relative) def handle_mouse(self): """Handle mouse-buttons if one was pressed""" self.ui.handle_mouse() def execute_file(self, files, app='', flags='', mode=0): """Execute a file. app is the name of a method in Applications, without the "app_" flags is a string consisting of applications.ALLOWED_FLAGS mode is a positive integer. Both flags and mode specify how the program is run.""" if isinstance(files, set): files = list(files) elif type(files) not in (list, tuple): files = [files] return self.apps.get(app)( mainfile = files[0], files = list(files), flags = flags, mode = mode, fm = self, stdin = None, apps = self.apps) def edit_file(self): """Calls execute_file with the current file and app='editor'""" if self.env.cf is None: return self.execute_file(self.env.cf, app = 'editor') def open_console(self, mode=':', string=''): """Open the console if the current UI supports that""" if hasattr(self.ui, 'open_console'): self.ui.open_console(mode, string) def move_pointer(self, relative = 0, absolute = None): """Move the pointer down by <relative> or to <absolute>""" self.env.cf = self.env.pwd.move_pointer(relative, absolute) def move_pointer_by_pages(self, relative): """Move the pointer down by <relative> pages""" self.env.cf = self.env.pwd.move_pointer( relative = int(relative * self.env.termsize[0])) def move_pointer_by_percentage(self, relative=0, absolute=None): """Move the pointer down by <relative>% or to <absolute>%""" try: factor = len(self.env.pwd) / 100.0 except: return self.env.cf = self.env.pwd.move_pointer( \ relative=int(relative * factor), \ absolute=int(absolute * factor) ) def scroll(self, relative): """Scroll down by <relative> lines""" if hasattr(self.ui, 'scroll'): self.ui.scroll(relative) self.env.cf = self.env.pwd.pointed_file def redraw_window(self): """Redraw the window""" self.ui.redraw_window() def reset(self): """Reset the filemanager, clearing the directory buffer""" old_path = self.env.pwd.path self.env.directories = {} self.enter_dir(old_path) def toggle_boolean_option(self, string): """Toggle a boolean option named <string>""" if isinstance(self.env.settings[string], bool): self.env.settings[string] ^= True def sort(self, func=None, reverse=None): if reverse is not None: self.env.settings['reverse'] = bool(reverse) if func is not None: self.env.settings['sort'] = str(func) def force_load_preview(self): cf = self.env.cf if cf is not None: cf.force_load = True # ------------------------------------ filesystem operations def copy(self): """Copy the selected items""" selected = self.env.get_selection() self.env.copy = set(f for f in selected if f in self.env.pwd.files) self.env.cut = False def cut(self): self.copy() self.env.cut = True def paste(self): """Paste the selected items into the current directory""" from os.path import join, isdir from ranger.ext import shutil_generatorized as shutil_g from ranger.fsobject.loader import LoadableObject copied_files = self.env.copy if not copied_files: return if self.env.cut: for f in self.env.copy: self.loader.add(LoadableObject(\ shutil_g.move(f.path, self.env.pwd.path),\ "moving: " + f.path)) self.env.copy.clear() self.env.cut = False else: for f in self.env.copy: if isdir(f.path): self.loader.add(LoadableObject( shutil_g.copytree(f.path, join(self.env.pwd.path, f.basename)), "copying tree: " + str(f.path))) else: self.loader.add(LoadableObject( shutil_g.copy2(f.path, self.env.pwd.path), "copying: " + str(f.path))) self.env.pwd.load_content() def delete(self): msg = self.notify("Deleting ...", duration=0) selected = self.env.get_selection() self.env.copy -= selected if selected: for f in selected: if os.path.isdir(f.path): try: shutil.rmtree(f.path) except OSError as err: self.notify(str(err), bad=True) else: try: os.remove(f.path) except OSError as err: self.notify(str(err), bad=True) msg.delete() def mkdir(self, name): try: os.mkdir(os.path.join(self.env.pwd.path, name)) except OSError as err: self.notify(str(err), bad=True) def notify(self, text, duration=4, bad=False): try: method = self.ui.display except AttributeError: pass else: return method(text, duration=duration, bad=bad) def mark(self, all=False, toggle=False, val=None, movedown=None): """ A wrapper for the directory.mark_xyz functions. Arguments: all - change all files of the current directory at once? toggle - toggle the marked-status? val - mark or unmark? """ if self.env.pwd is None: return pwd = self.env.pwd if movedown is None: movedown = not all if val is None and toggle is False: return if all: if toggle: pwd.toggle_all_marks() else: pwd.mark_all(val) else: item = self.env.cf if item is not None: if toggle: pwd.toggle_mark(item) else: pwd.mark_item(item, val) if movedown: self.move_pointer(relative=1) # aliases: cd = enter_dir