summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/semgnrc.nim2
-rw-r--r--tests/manyloc/named_argument_bug/gui.nim44
-rw-r--r--tests/manyloc/named_argument_bug/main.nim23
-rw-r--r--tests/manyloc/named_argument_bug/main.nimrod.cfg2
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/config.nim6
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim57
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim61
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim157
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim103
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim31
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/math/circle.nim9
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/math/rect.nim8
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/math/vec.nim55
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim106
14 files changed, 663 insertions, 1 deletions
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index abee5de5a..d626d2eb2 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -312,7 +312,7 @@ proc semGenericStmt(c: PContext, n: PNode,
     n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
     closeScope(c)
   of nkPragma, nkPragmaExpr: nil
-  of nkExprColonExpr:
+  of nkExprColonExpr, nkExprEqExpr:
     checkMinSonsLen(n, 2)
     result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
   else:
diff --git a/tests/manyloc/named_argument_bug/gui.nim b/tests/manyloc/named_argument_bug/gui.nim
new file mode 100644
index 000000000..1e0bc6ffd
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/gui.nim
@@ -0,0 +1,44 @@
+import
+  tri_engine/gfx/gl/primitive,
+  tri_engine/gfx/tex,
+  tri_engine/gfx/color,
+  tri_engine/math/rect,
+  tri_engine/math/vec
+
+type
+  TWidgetLayer* = enum
+    wlBg      = 100,
+    wlOverlap = 200,
+    wlMain    = 300,
+    wlOverlay = 400,
+    wlCursor  = 500
+  TWidgetLayerType = TWidgetLayer|int
+  TWidgetType* = enum
+    wtImg
+  PWidget* = ref object
+    `type`* : TWidgetType
+    layer*  : TWidgetLayer
+    rect*   : TRect
+    prim*   : PPrimitive
+
+const
+  baseZ = 5000
+
+proc newWidget*(`type`: TWidgetType, layer: TWidgetLayerType, rect: TRect): PWidget =
+  new(result)
+  result.`type` = `type`
+  result.layer = layer
+  result.rect = rect
+
+  var verts = newVert(rect)
+
+  # This works because z is accessible at this scope.
+  #var z = baseZ + layer.int
+  #result.prim = newPrimitive(verts, z=z)
+
+  # Doesn't work, because the compiler looks for a symbol called z in this scope,
+  # but it should only check that it is the name of one of the params.
+  #result.prim = newPrimitive(verts, z=baseZ + layer.int)
+
+  # This doesn't work either.
+  result.prim = newPrimitive(verts, z=0)
diff --git a/tests/manyloc/named_argument_bug/main.nim b/tests/manyloc/named_argument_bug/main.nim
new file mode 100644
index 000000000..767674428
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/main.nim
@@ -0,0 +1,23 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec,
+  tri_engine/math/circle,
+  tri_engine/gfx/gl/primitive,
+  tri_engine/gfx/tex,
+  tri_engine/gfx/color,
+  tri_engine/tri_engine,
+  gui
+
+var isRunning = true
+
+block:
+  var renderer = newRenderer(w=10, h=10)
+
+  var primitive = newPrimitiveCircle(0.3.TR, color=white(0.5, 0.8), z=15)
+  renderer.addPrimitive(primitive)
+
+  var verts = newVert((min: newV2xy(-0.4), size: newV2xy(0.3)))
+  var primitive2 = newPrimitive(verts, color=red(0.5, 0.8), z=10)
+  renderer.addPrimitive(primitive2)
+
+  var mainMenuWidget = newWidget(wtImg, wlBg, rect=(newV2xy(-1.0), newV2xy(2.0)))
diff --git a/tests/manyloc/named_argument_bug/main.nimrod.cfg b/tests/manyloc/named_argument_bug/main.nimrod.cfg
new file mode 100644
index 000000000..27cf8e688
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/main.nimrod.cfg
@@ -0,0 +1,2 @@
+# this file only exists to mark 'main.nim' as the main file
+
diff --git a/tests/manyloc/named_argument_bug/tri_engine/config.nim b/tests/manyloc/named_argument_bug/tri_engine/config.nim
new file mode 100644
index 000000000..b90dc0b26
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/config.nim
@@ -0,0 +1,6 @@
+when defined(doublePrecision):
+  type
+    TR* = float64
+else:
+  type
+    TR* = float32
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
new file mode 100644
index 000000000..8e47c1f2f
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
@@ -0,0 +1,57 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec
+
+from strutils import
+  formatFloat,
+  TFloatFormat,
+  `%`
+
+from unsigned import
+  `shr`,
+  `and`
+
+type
+  TColor* = tuple[r, g, b, a: TR]
+
+converter toColor*(o: uint32): TColor =
+  ## Convert an integer to a color. This is mostly useful when the integer is specified as a hex
+  ## literal such as 0xFF00007F, which is 100% red, with 50% alpha.
+  ## TODO: turn this into a template that can take either 4 or 8 characters?
+  ((((o and 0xff000000'u32) shr 24).TR / 255.0).TR,
+   (((o and 0xff0000'u32) shr 16).TR / 255.0).TR,
+   (((o and 0xff00'u32) shr 8).TR / 255.0).TR,
+   (((o and 0xff'u32)).TR / 255.0).TR)
+
+converter toV4*(o: TColor): TV4[TR] =
+  cast[TV4[TR]](o)
+
+proc newColor*(r, g, b: TR=0.0, a: TR=1.0): TColor =
+  (r, g, b, a)
+
+proc white*(rgb, a: TR=1.0): TColor =
+  (rgb, rgb, rgb, a)
+
+proc red*(r, a: TR=1.0): TColor =
+  newColor(r=r, a=a)
+
+proc green*(g, a: TR=1.0): TColor =
+  newColor(g=g, a=a)
+
+proc yellow*(rg, a: TR=1.0): TColor =
+  newColor(r=rg, g=rg, a=a)
+
+proc blue*(b, a: TR=1.0): TColor =
+  newColor(b=b, a=a)
+
+proc cyan*(gb, a: TR=1.0): TColor =
+  newColor(g=gb, b=gb, a=a)
+
+proc purple*(rb, a: TR=1.0): TColor =
+  newColor(r=rb, b=rb, a=a)
+
+proc `$`*(o: TColor): string =
+  proc f(f: float): string =
+    f.formatFloat(precision=2, format=ffDecimal)
+
+  "(r: $#, g: $#, b: $#, s: $#)" % [f(o.r), f(o.g), f(o.b), f(o.a)]
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
new file mode 100644
index 000000000..e731969c1
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
@@ -0,0 +1,61 @@
+import
+  opengl,
+  tri_engine/math/vec
+
+export
+  opengl
+
+type
+  EGL* = object of E_Base
+  EGL_code* = object of EGL
+    code*: EGL_err
+  EGL_err {.pure.} = enum
+    none                 = GL_NO_ERROR
+    invalidEnum          = GL_INVALID_ENUM
+    invalidVal           = GL_INVALID_VALUE
+    invalidOp            = GL_INVALID_OPERATION
+    stackOverflow        = GL_STACK_OVERFLOW
+    stackUnderflow       = GL_STACK_UNDERFLOW
+    outOfMem             = GL_OUT_OF_MEMORY
+    invalidFramebufferOp = GL_INVALID_FRAMEBUFFER_OPERATION
+    unknown
+
+proc newGL_codeException*(msg: string, code: EGL_err): ref EGL_code =
+  result      = newException(EGL_code, $code)
+  result.code = code
+
+proc getErr*(): EGL_err =
+  result = glGetError().EGL_err
+  if result notin {EGL_err.none,
+                   EGL_err.invalidEnum,
+                   EGL_err.invalidVal,
+                   EGL_err.invalidOp,
+                   EGL_err.invalidFramebufferOp,
+                   EGL_err.outOfMem,
+                   EGL_err.stackUnderflow,
+                   EGL_err.stackOverflow}:
+    return EGL_err.unknown
+
+proc errCheck*() =
+  let err = getErr()
+  if err != EGL_err.none:
+    raise newGL_codeException($err, err)
+
+macro `?`*(call: expr{nkCall}): expr =
+  result = call
+  # Can't yet reference foreign symbols in macros.
+  #errCheck()
+
+when defined(doublePrecision):
+  const
+    glRealType* = cGLdouble
+else:
+  const
+    glRealType* = cGLfloat
+
+proc setUniformV4*[T](loc: GLint, vecs: var openarray[TV4[T]]) =
+  glUniform4fv(loc, vecs.len.GLsizei, cast[PGLfloat](vecs[0].addr))
+
+proc setUniformV4*[T](loc: GLint, vec: TV4[T]) =
+  var vecs = [vec]
+  setUniformV4(loc, vecs)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
new file mode 100644
index 000000000..c67748967
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
@@ -0,0 +1,157 @@
+import
+  math,
+  tri_engine/config,
+  tri_engine/gfx/gl/gl,
+  tri_engine/gfx/tex,
+  tri_engine/gfx/color,
+  tri_engine/math/vec,
+  tri_engine/math/rect,
+  tri_engine/math/circle
+
+import strutils
+
+type
+  TVert* = tuple[pos: TV2[TR], texCoord: TV2[TR]]
+  TVertAttrib* = object
+    i*      : GLuint
+    size*   : GLint
+    stride* : GLsizei
+    offset* : PGLvoid
+  TVertMode* = enum
+    vmTriStrip = GLtriangleStrip,
+    vmTriFan   = GLtriangleFan
+  TZ_range* = range[-100_000..100_000]
+  PPrimitive* = ref object
+    verts*        : seq[TVert]
+    indices*      : seq[GLushort]
+    arrBufId*     : GLuint
+    elemArrBufId* : GLuint
+    tex*          : TTex
+    color*        : TColor
+    vertMode*     : TVertMode
+    z*            : int
+
+proc newVert*(pos, texCoord: TV2): TVert =
+  (pos, texCoord)
+
+proc newVertQuad*(min, minRight, maxLeft, max: TV2[TR]): seq[TVert] =
+  @[newVert(min,      newV2()),
+    newVert(minRight, newV2(x=1.0)),
+    newVert(maxLeft,  newV2(y=1.0)),
+    newVert(max,      newV2xy(1.0))
+  ]
+
+proc newVert*(rect: rect.TRect): seq[TVert] =
+  newVertQuad(rect.min, newV2(rect.max.x, rect.min.y), newV2(rect.min.x, rect.max.y), rect.max)
+
+proc newVertAttrib(i: GLuint, size: GLint, stride: GLsizei, offset: PGLvoid): TVertAttrib =
+  TVertAttrib(i: i, size: size, stride: stride, offset: offset)
+
+proc genBuf*[T](vboTarget, objUsage: GLenum, data: var openarray[T]): GLuint =
+  result = 0.GLuint
+  ?glGenBuffers(1, result.addr)
+  ?glBindBuffer(vboTarget, result)
+
+  let size = (data.len * T.sizeof).GLsizeiptr
+  ?glBufferData(vboTarget, size, data[0].addr, objUsage)
+
+proc newPrimitive*(verts: var seq[TVert],
+                   vertMode=vmTriStrip,
+                   tex=whiteTex(),
+                   color=white(),
+                   z: TZ_range=0): PPrimitive =
+  var indices = newSeq[GLushort](verts.len)
+  for i in 0 .. <verts.len:
+    indices[i] = i.GLushort
+
+  new(result)
+  result.verts = verts
+  result.indices = indices
+
+  result.arrBufId     = genBuf(GLarrayBuffer, GL_STATIC_DRAW, verts)
+  result.elemArrBufId = genBuf(GLelementArrayBuffer, GL_STATIC_DRAW, indices)
+  result.tex = tex
+  result.color = color
+  result.vertMode = vertMode
+  result.z = z
+
+proc bindBufs*(o: PPrimitive) =
+  ?glBindBuffer(GLarrayBuffer, o.arrBufId)
+  ?glBindBuffer(GLelementArrayBuffer, o.elemArrBufId)
+
+proc enableVertAttribArrs*() =
+  ?glEnableVertexAttribArray(0)
+  ?glEnableVertexAttribArray(1)
+
+proc disableVertAttribArrs*() =
+  ?glDisableVertexAttribArray(1)
+  ?glDisableVertexAttribArray(0)
+
+proc setVertAttribPointers*() =
+  let vertSize {.global.} = TVert.sizeof.GLint
+  ?glVertexAttribPointer(0, 2, glRealType, false, vertSize, nil)
+  ?glVertexAttribPointer(1, 2, glRealType, false, vertSize, cast[PGLvoid](TR.sizeof * 2))
+
+proc updVerts*(o: PPrimitive, start, `end`: int, f: proc(i: int, vert: var TVert)) =
+  assert start <= `end`
+  assert `end` < o.verts.len
+  for i in start..`end`:
+    f(i, o.verts[i])
+
+  ?glBindBuffer(GLarrayBuffer, o.arrBufId)
+
+  let byteLen = `end` - start + 1 * TVert.sizeof
+  let byteOffset = start * TVert.sizeof
+  ?glBufferSubData(GLarrayBuffer,
+                   byteOffset.GLintptr, # Offset. Is this right?
+                   byteLen.GLsizeiptr, # Size.
+                   cast[PGLvoid](cast[int](o.verts[0].addr) + byteOffset))
+
+proc updAllVerts(o: PPrimitive, f: proc(i: int, vert: var TVert)) =
+  for i in 0 .. <o.verts.len:
+    f(i, o.verts[i])
+
+  ?glBindBuffer(GLarrayBuffer, o.arrBufId)
+
+  # Discard old buffer before creating a new one.
+  let byteLen = (o.verts.len * TVert.sizeof).GLsizeiptr
+  ?glBufferData(GLarrayBuffer, byteLen, nil, GLstaticDraw)
+  ?glBufferData(GLarrayBuffer, byteLen, o.verts[0].addr, GLstaticDraw)
+
+proc newVertCircle*(circle: TCircle, nSegs: Natural=0): seq[TVert] =
+  let nSegs = if nSegs == 0:
+      (circle.r.sqrt() * 400.0).int # TODO: Base this on the window resolution?
+    else:
+      max(nSegs, 3)
+
+  let theta: TR = (PI * 2.0) / (nSegs.TR)
+  let tanFactor = theta.tan()
+  let radialFactor = theta.cos()
+  var x = circle.r
+  var y: TR = 0.0
+
+  result = newSeq[TVert](nSegs)
+  #result[0] = newVert(circle.p, newV2xy(0.5))
+  for i in 1 .. <nSegs:
+    let pos = newV2(x + circle.p.x, y + circle.p.y)
+    let texCoord = pos * newV2xy(1.0 / circle.r)
+
+    result[i] = newVert(pos, texCoord)
+
+    let tx = -y
+    let ty = x
+    x += tx * tanFactor
+    y += ty * tanFactor
+
+    x *= radialFactor
+    y *= radialFactor
+
+  result.add(result[1])
+
+proc newPrimitiveCircle*(circle: TCircle,
+                         nSegs: Natural=0,
+                         tex=whiteTex(),
+                         color=white(),
+                         z: TZ_range=0): PPrimitive =
+  var verts = newVertCircle(circle, nSegs)
+  newPrimitive(verts, vmTriFan, tex, color, z)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
new file mode 100644
index 000000000..5972aa4fb
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
@@ -0,0 +1,103 @@
+import
+  pure/os,
+  tri_engine/gfx/gl/gl
+
+type
+  TShader* = object
+    id*: GL_handle
+  TShaderType* {.pure.} = enum
+    frag = GL_FRAGMENT_SHADER,
+    vert   = GL_VERTEX_SHADER
+  E_Shader* = object of E_Base
+  E_UnknownShaderType* = object of E_Shader
+
+converter pathToShaderType*(s: string): TShaderType =
+  case s.splitFile().ext:
+  of ".vs":
+    return TShaderType.vert
+  of ".fs":
+    return TShaderType.frag
+  else:
+    raise newException(E_UnknownShaderType, "Can't determine shader type from file extension: " & s)
+
+proc setSrc*(shader: TShader, src: string) =
+  var s = src.cstring
+  ?glShaderSource(shader.id, 1, cast[cstringarray](s.addr), nil)
+
+proc newShader*(id: GL_handle): TShader =
+  if id != 0 and not (?glIsShader(id)).bool:
+    raise newException(E_GL, "Invalid shader ID: " & $id)
+
+  result.id = id
+
+proc shaderInfoLog*(o: TShader): string =
+  var log {.global.}: array[0..1024, char]
+  var logLen: GLsizei
+  ?glGetShaderInfoLog(o.id, log.len.GLsizei, logLen, cast[PGLchar](log.addr))
+  cast[string](log.addr).substr(0, logLen)
+
+proc compile*(shader: TShader, path="") =
+  ?glCompileShader(shader.id)
+  var compileStatus = 0.GLint
+  ?glGetShaderIv(shader.id, GL_COMPILE_STATUS, compileStatus.addr)
+
+  if compileStatus == 0:
+    raise newException(E_GL, if path.len == 0:
+        shaderInfoLog(shader)
+      else:
+        path & ":\n" & shaderInfoLog(shader)
+    )
+
+proc newShaderFromSrc*(src: string, `type`: TShaderType): TShader =
+  result.id = ?glCreateShader(`type`.GLenum)
+  result.setSrc(src)
+  result.compile()
+
+proc newShaderFromFile*(path: string): TShader =
+  newShaderFromSrc(readFile(path), path)
+
+type
+  TProgram* = object
+    id*: GL_handle
+    shaders: seq[TShader]
+
+proc attach*(o: TProgram, shader: TShader) =
+  ?glAttachShader(o.id, shader.id)
+
+proc infoLog*(o: TProgram): string =
+  var log {.global.}: array[0..1024, char]
+  var logLen: GLsizei
+  ?glGetProgramInfoLog(o.id, log.len.GLsizei, logLen, cast[PGLchar](log.addr))
+  cast[string](log.addr).substr(0, logLen)
+
+proc link*(o: TProgram) =
+  ?glLinkProgram(o.id)
+  var linkStatus = 0.GLint
+  ?glGetProgramIv(o.id, GL_LINK_STATUS, linkStatus.addr)
+  if linkStatus == 0:
+    raise newException(E_GL, o.infoLog())
+
+proc validate*(o: TProgram) =
+  ?glValidateProgram(o.id)
+  var validateStatus = 0.GLint
+  ?glGetProgramIv(o.id, GL_VALIDATE_STATUS, validateStatus.addr)
+  if validateStatus == 0:
+    raise newException(E_GL, o.infoLog())
+
+proc newProgram*(shaders: seq[TShader]): TProgram =
+  result.id = ?glCreateProgram()
+  if result.id == 0:
+    return
+
+  for shader in shaders:
+    if shader.id == 0:
+      return
+
+    ?result.attach(shader)
+
+  result.shaders = shaders
+  result.link()
+  result.validate()
+
+proc use*(o: TProgram) =
+  ?glUseProgram(o.id)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim
new file mode 100644
index 000000000..e5043ae34
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim
@@ -0,0 +1,31 @@
+import
+  tri_engine/gfx/gl/gl
+
+type
+  TTex* = object
+    id*: GLuint
+
+var gWhiteTex = TTex(id: 0)
+
+proc setTexParams() =
+  ?glTexParameteri(GLtexture2D, GLtextureMinFilter, GLlinear)
+
+  #glTexParameteri(GLtexture2D, GLtextureMagFilter, GLlinear)
+  ?glTexParameteri(GLtexture2D, GLTextureMagFilter, GLnearest)
+
+  ?glTexParameteri(GLtexture2D, GLTextureWrapS, GLClampToEdge)
+  ?glTexParameteri(GLtexture2D, GLTextureWrapT, GLClampToEdge)
+
+proc whiteTex*(): TTex =
+  if gWhiteTex.id.int != 0:
+    return gWhiteTex
+
+  ?glGenTextures(1, gWhiteTex.id.addr)
+  ?glBindTexture(GLtexture2D, gWhiteTex.id)
+  setTexParams()
+
+  var pixel = [255'u8, 255'u8, 255'u8, 255'u8]
+  ?glTexImage2D(GLtexture2D, 0, GL_RGBA, 1, 1, 0, GL_BGRA, cGLUnsignedByte, pixel[0].addr)
+  ?glBindTexture(GLtexture2D, 0)
+
+  result = gWhiteTex
diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim b/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim
new file mode 100644
index 000000000..7e7517998
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim
@@ -0,0 +1,9 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec
+
+type
+  TCircle* = tuple[p: TV2[TR], r: TR]
+
+converter toCircle*(o: TR): TCircle =
+  (newV2(), o)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/rect.nim b/tests/manyloc/named_argument_bug/tri_engine/math/rect.nim
new file mode 100644
index 000000000..b6fd9ce84
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/math/rect.nim
@@ -0,0 +1,8 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec
+
+type
+  TRect* = tuple[min, size: TV2[TR]]
+
+proc max*(o: TRect): TV2[TR] = o.min + o.size
diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim
new file mode 100644
index 000000000..a6b7bac63
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim
@@ -0,0 +1,55 @@
+import
+  macros,
+  tri_engine/config
+
+type
+  TV2*[T:TNumber=TR] = array[0..1, T]
+  TV3*[T:TNumber=TR] = array[0..2, T]
+  TV4*[T:TNumber=TR] = array[0..3, T]
+  TVT*[T:TNumber=TR] = TV2|TV3|TV4
+  #TV2* = array[0..1, TR]
+  #TV3* = array[0..2, TR]
+  #TV4* = array[0..3, TR]
+
+# TODO: Change to TVT when compiler issue is resolved.
+proc `$`*[T](o: TV2[T]): string =
+  result = "("
+  for i in 0 .. <o.len:
+    result &= $o[0]
+    if i != o.len - 1:
+      result &= ", "
+
+  result & ")"
+
+proc newV2T*[T](x, y: T=0): TV2[T] =
+  [x, y]
+
+proc newV2*(x, y: TR=0.0): TV2[TR] =
+  [x, y]
+
+proc newV2xy*(xy: TR): TV2[TR] =
+  [xy, xy]
+
+proc x*[T](o: TV2[T]): T =
+  o[0]
+
+proc y*[T](o: TV2[T]): T =
+  o[1]
+
+proc `*`*(lhs: TV2[TR], rhs: TV2[TR]): TV2[TR] =
+  [(lhs.x * rhs.x).TR, (lhs.y * rhs.y).TR]
+
+proc `+`*(lhs: TV2[TR], rhs: TV2[TR]): TV2[TR] =
+  [(lhs.x + rhs.x).TR, (lhs.y + rhs.y).TR]
+
+#proc dotProduct[T](a: TVT[T], b: TVT[T]): T =
+#  for i in 0 .. a.len - 1:
+#    result += a[i] * b[i]
+
+proc dot[T](a, b: TV2[T]): T =
+  for i in 0 .. <a.len:
+    result += a[i] * b[i]
+
+assert dot(newV2(), newV2()) == 0.0
+assert dot(newV2(2, 3), newV2(6, 7)) == 33.0
+assert dot([2.0, 3.0], [6.0, 7.0]) == 33.0
diff --git a/tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim b/tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim
new file mode 100644
index 000000000..ba9989bbb
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim
@@ -0,0 +1,106 @@
+import
+  algorithm,
+  tri_engine/config,
+  tri_engine/gfx/gl/gl,
+  tri_engine/gfx/gl/primitive,
+  tri_engine/gfx/gl/shader,
+  tri_engine/gfx/color
+
+const primitiveVs = """
+#version 330 core
+
+layout(location = 0) in vec2 pos;
+layout(location = 1) in vec2 texCoord;
+
+out vec2 uv;
+
+void main()
+{
+    gl_Position = vec4(pos, 0, 1);
+    uv = texCoord;
+}
+
+"""
+const primitiveFs = """
+#version 330 core
+
+in vec2 uv;
+out vec4 color;
+uniform sampler2D tex;
+uniform vec4 inColor;
+
+void main()
+{
+    color = texture(tex, uv) * inColor;
+}
+
+"""
+
+var gW, gH: Natural = 0
+
+proc w*(): int =
+  gW
+
+proc h*(): int =
+  gH
+
+type
+  PRenderer = ref object
+    primitiveProgram: TProgram
+    primitives: seq[PPrimitive]
+
+proc setupGL() =
+  ?glEnable(GLblend)
+  ?glBlendFunc(GLsrcAlpha, GLoneMinusSrcAlpha)
+  ?glClearColor(0.0, 0.0, 0.0, 1.0)
+  ?glPolygonMode(GLfrontAndBack, GLfill)
+
+proc newRenderer*(w, h: Positive): PRenderer =
+  gW = w
+  gH = h
+
+  new(result)
+  newSeq(result.primitives, 0)
+  loadExtensions()
+  setupGL()
+  result.primitiveProgram = newProgram(@[
+    newShaderFromSrc(primitiveVs, TShaderType.vert),
+    newShaderFromSrc(primitiveFs, TShaderType.frag)])
+
+proc draw(o: PRenderer, p: PPrimitive) =
+  let loc = proc(x: string): Glint =
+    result = glGetUniformLocation(o.primitiveProgram.id, x)
+    if result == -1:
+      raise newException(E_GL, "Shader error: " & x & " does not correspond to a uniform variable")
+
+  setUniformV4(loc("inColor"), p.color)
+  ?glActiveTexture(GLtexture0)
+  ?glBindTexture(GLtexture2D, p.tex.id.GLuint)
+  ?glUniform1i(loc("tex"), 0)
+
+  p.bindBufs()
+  setVertAttribPointers()
+
+  ?glDrawElements(p.vertMode.GLenum, p.indices.len.GLsizei, cGLunsignedShort, nil)
+
+proc draw*(o: PRenderer) =
+  ?glClear(GLcolorBufferBit)
+  o.primitiveProgram.use()
+
+  enableVertAttribArrs()
+  var zSortedPrimitives = o.primitives
+  zSortedPrimitives.sort(proc(x, y: PPrimitive): int =
+    if x.z < y.z:
+      -1
+    elif x.z > y.z:
+      1
+    else:
+      0)
+
+  for x in zSortedPrimitives:
+    o.draw(x)
+
+  disableVertAttribArrs()
+
+proc addPrimitive*(o: PRenderer, p: PPrimitive) =
+  o.primitives.add(p)