summary refs log tree commit diff stats
path: root/tests/generics/tuninstantiated_failure.nim
blob: f3d5b34b8979e841c3dce9cefa652fb5e856e5c5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
discard """
cmd: "nim check $file"
"""

type
  Test[T, K] = object
    name: string
  Something = Test[int]

func `[]`[T, K](x: var Test[T, K], idx: int): var Test[T, K] =
  x

var b: Something
# Should give an error since Something isn't a valid Test
b[0].name = "Test" #[tt.Error
 ^  expression '' has no type (or is ambiguous)]#
t .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
#
#
#            Nim's Runtime Library
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Implements Nim's 'spawn'.

when not declared(NimString):
  {.error: "You must not import this module explicitly".}

{.push stackTrace:off.}

# We declare our own condition variables here to get rid of the dummy lock
# on Windows:

type
  CondVar = object
    c: SysCond
    when defined(posix):
      stupidLock: SysLock
      counter: int

proc createCondVar(): CondVar =
  initSysCond(result.c)
  when defined(posix):
    initSysLock(result.stupidLock)
    #acquireSys(result.stupidLock)

proc destroyCondVar(c: var CondVar) {.inline.} =
  deinitSysCond(c.c)

proc await(cv: var CondVar) =
  when defined(posix):
    acquireSys(cv.stupidLock)
    while cv.counter <= 0:
      waitSysCond(cv.c, cv.stupidLock)
    dec cv.counter
    releaseSys(cv.stupidLock)
  else:
    waitSysCondWindows(cv.c)

proc signal(cv: var CondVar) =
  when defined(posix):
    acquireSys(cv.stupidLock)
    inc cv.counter
    releaseSys(cv.stupidLock)
  signalSysCond(cv.c)

type
  FastCondVar = object
    event, slowPath: bool
    slow: CondVar

proc createFastCondVar(): FastCondVar =
  initSysCond(result.slow.c)
  when defined(posix):
    initSysLock(result.slow.stupidLock)
    #acquireSys(result.slow.stupidLock)
  result.event = false
  result.slowPath = false

proc await(cv: var FastCondVar) =
  #for i in 0 .. 50:
  #  if cas(addr cv.event, true, false):
  #    # this is a HIT: Triggers > 95% in my tests.
  #    return
  #  cpuRelax()
  #cv.slowPath = true
  # XXX For some reason this crashes some test programs
  await(cv.slow)
  cv.event = false

proc signal(cv: var FastCondVar) =
  cv.event = true
  #if cas(addr cv.slowPath, true, false):
  signal(cv.slow)

type
  Barrier* {.compilerProc.} = object
    counter: int
    cv: CondVar

proc barrierEnter*(b: ptr Barrier) {.compilerProc.} =
  atomicInc b.counter

proc barrierLeave*(b: ptr Barrier) {.compilerProc.} =
  atomicDec b.counter
  if b.counter <= 0: signal(b.cv)

proc openBarrier*(b: ptr Barrier) {.compilerProc.} =
  b.counter = 0
  b.cv = createCondVar()

proc closeBarrier*(b: ptr Barrier) {.compilerProc.} =
  await(b.cv)
  destroyCondVar(b.cv)

{.pop.}

# ----------------------------------------------------------------------------

type
  WorkerProc = proc (thread, args: pointer) {.nimcall, gcsafe.}
  Worker = object
    taskArrived: CondVar
    taskStarted: FastCondVar #\
    # task data:
    f: WorkerProc
    data: pointer
    ready: bool # put it here for correct alignment!

proc nimArgsPassingDone(p: pointer) {.compilerProc.} =
  let w = cast[ptr Worker](p)
  signal(w.taskStarted)

var gSomeReady = createFastCondVar()

proc slave(w: ptr Worker) {.thread.} =
  while true:
    w.ready = true # If we instead signal "workerReady" we need the scheduler
                   # to notice this. The scheduler could then optimize the
                   # layout of the worker threads (e.g. keep the list sorted)
                   # so that no search for a "ready" thread is necessary.
                   # This might be implemented later, but is more tricky than
                   # it looks because 'spawn' itself can run concurrently.
    signal(gSomeReady)
    await(w.taskArrived)
    assert(not w.ready)
    # shield against spurious wakeups:
    if w.data != nil:
      w.f(w, w.data)
      w.data = nil

const NumThreads = 4

var
  workers: array[NumThreads, Thread[ptr Worker]]
  workersData: array[NumThreads, Worker]

proc setup() =
  for i in 0 ..< NumThreads:
    workersData[i].taskArrived = createCondVar()
    workersData[i].taskStarted = createFastCondVar()
    createThread(workers[i], slave, addr(workersData[i]))

proc preferSpawn*(): bool =
  ## Use this proc to determine quickly if a 'spawn' or a direct call is
  ## preferable. If it returns 'true' a 'spawn' may make sense. In general
  ## it is not necessary to call this directly; use 'spawnX' instead.
  result = gSomeReady.event

proc spawn*(call: typed) {.magic: "Spawn".}
  ## always spawns a new task, so that the 'call' is never executed on
  ## the calling thread. 'call' has to be proc call 'p(...)' where 'p'
  ## is gcsafe and has 'void' as the return type.

template spawnX*(call: typed) =
  ## spawns a new task if a CPU core is ready, otherwise executes the
  ## call in the calling thread. Usually it is advised to
  ## use 'spawn' in order to not block the producer for an unknown
  ## amount of time. 'call' has to be proc call 'p(...)' where 'p'
  ## is gcsafe and has 'void' as the return type.
  if preferSpawn(): spawn call
  else: call

proc nimSpawn(fn: WorkerProc; data: pointer) {.compilerProc.} =
  # implementation of 'spawn' that is used by the code generator.
  while true:
    for i in 0.. high(workers):
      let w = addr(workersData[i])
      if cas(addr w.ready, true, false):
        w.data = data
        w.f = fn
        signal(w.taskArrived)
        await(w.taskStarted)
        return
    await(gSomeReady)

proc sync*() =
  ## a simple barrier to wait for all spawn'ed tasks. If you need more elaborate
  ## waiting, you have to use an explicit barrier.
  while true:
    var allReady = true
    for i in 0 .. high(workers):
      if not allReady: break
      allReady = allReady and workersData[i].ready
    if allReady: break
    await(gSomeReady)

setup()