summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/sigmatch.nim5
-rw-r--r--lib/pure/basic3d.nim256
-rw-r--r--tests/overload/tspec.nim10
3 files changed, 140 insertions, 131 deletions
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index aad6b590e..2eda33c14 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -159,7 +159,7 @@ proc sumGeneric(t: PType): int =
       inc result
       inc isvar
     of tyGenericInvocation, tyTuple:
-      result = ord(t.kind == tyGenericInvocation)
+      result += ord(t.kind == tyGenericInvocation)
       for i in 0 .. <t.len: result += t.sons[i].sumGeneric
       break
     of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
@@ -167,7 +167,8 @@ proc sumGeneric(t: PType): int =
         tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
         tyUInt..tyUInt64:
       return isvar
-    else: return 0
+    else:
+      return 0
 
 #var ggDebug: bool
 
diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim
index 18ebed67b..5a943dd05 100644
--- a/lib/pure/basic3d.nim
+++ b/lib/pure/basic3d.nim
@@ -16,33 +16,33 @@ import times
 ## Vectors are implemented as direction vectors, ie. when transformed with a matrix
 ## the translation part of matrix is ignored. The coordinate system used is
 ## right handed, because its compatible with 2d coordinate system (rotation around
-## zaxis equals 2d rotation). 
+## zaxis equals 2d rotation).
 ## Operators `+` , `-` , `*` , `/` , `+=` , `-=` , `*=` and `/=` are implemented
 ## for vectors and scalars.
 ##
 ##
 ## Quick start example:
-##   
+##
 ##   # Create a matrix which first rotates, then scales and at last translates
-##   
+##
 ##   var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
-##   
+##
 ##   # Create a 3d point at (100,150,200) and a vector (5,2,3)
-##   
-##   var pt:TPoint3d=point3d(100.0,150.0,200.0) 
-##   
+##
+##   var pt:TPoint3d=point3d(100.0,150.0,200.0)
+##
 ##   var vec:TVector3d=vector3d(5.0,2.0,3.0)
-##   
-##   
+##
+##
 ##   pt &= m # transforms pt in place
-##   
+##
 ##   var pt2:TPoint3d=pt & m #concatenates pt with m and returns a new point
-##   
+##
 ##   var vec2:TVector3d=vec & m #concatenates vec with m and returns a new vector
 
 
 
-type 
+type
   TMatrix3d* =object
     ## Implements a row major 3d matrix, which means
     ## transformations are applied the order they are concatenated.
@@ -53,12 +53,12 @@ type
     ## [ tx ty tz tw ]
     ax*,ay*,az*,aw*,  bx*,by*,bz*,bw*,  cx*,cy*,cz*,cw*,  tx*,ty*,tz*,tw*:float
   TPoint3d* = object
-    ## Implements a non-homegeneous 2d point stored as 
+    ## Implements a non-homegeneous 2d point stored as
     ## an `x` , `y` and `z` coordinate.
     x*,y*,z*:float
-  TVector3d* = object 
-    ## Implements a 3d **direction vector** stored as 
-    ## an `x` , `y` and `z` coordinate. Direction vector means, 
+  TVector3d* = object
+    ## Implements a 3d **direction vector** stored as
+    ## an `x` , `y` and `z` coordinate. Direction vector means,
     ## that when transforming a vector with a matrix, the translational
     ## part of the matrix is ignored.
     x*,y*,z*:float
@@ -67,7 +67,7 @@ type
 
 # Some forward declarations
 proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d {.noInit.}
-  ## Creates a new 4x4 3d transformation matrix. 
+  ## Creates a new 4x4 3d transformation matrix.
   ## `ax` , `ay` , `az` is the local x axis.
   ## `bx` , `by` , `bz` is the local y axis.
   ## `cx` , `cy` , `cz` is the local z axis.
@@ -76,7 +76,7 @@ proc vector3d*(x,y,z:float):TVector3d {.noInit,inline.}
   ## Returns a new 3d vector (`x`,`y`,`z`)
 proc point3d*(x,y,z:float):TPoint3d {.noInit,inline.}
   ## Returns a new 4d point (`x`,`y`,`z`)
-proc tryNormalize*(v:var TVector3d):bool 
+proc tryNormalize*(v:var TVector3d):bool
   ## Modifies `v` to have a length of 1.0, keeping its angle.
   ## If `v` has zero length (and thus no angle), it is left unmodified and false is
   ## returned, otherwise true is returned.
@@ -85,7 +85,7 @@ proc tryNormalize*(v:var TVector3d):bool
 
 let
   IDMATRIX*:TMatrix3d=matrix3d(
-    1.0,0.0,0.0,0.0, 
+    1.0,0.0,0.0,0.0,
     0.0,1.0,0.0,0.0,
     0.0,0.0,1.0,0.0,
     0.0,0.0,0.0,1.0)
@@ -114,20 +114,20 @@ proc safeArccos(v:float):float=
   ## due to rounding issues
   return arccos(clamp(v,-1.0,1.0))
 
-template makeBinOpVector(s:expr)= 
+template makeBinOpVector(s:expr)=
   ## implements binary operators + , - , * and / for vectors
-  proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} = 
+  proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} =
     vector3d(s(a.x,b.x),s(a.y,b.y),s(a.z,b.z))
-  proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.}  = 
+  proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.}  =
     vector3d(s(a.x,b),s(a.y,b),s(a.z,b))
-  proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.}  = 
+  proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.}  =
     vector3d(s(a,b.x),s(a,b.y),s(a,b.z))
-  
-template makeBinOpAssignVector(s:expr)= 
+
+template makeBinOpAssignVector(s:expr)=
   ## implements inplace binary operators += , -= , /= and *= for vectors
-  proc s*(a:var TVector3d,b:TVector3d) {.inline.} = 
+  proc s*(a:var TVector3d,b:TVector3d) {.inline.} =
     s(a.x,b.x) ; s(a.y,b.y) ; s(a.z,b.z)
-  proc s*(a:var TVector3d,b:float) {.inline.} = 
+  proc s*(a:var TVector3d,b:float) {.inline.} =
     s(a.x,b) ; s(a.y,b) ; s(a.z,b)
 
 
@@ -188,20 +188,20 @@ proc scale*(s:float):TMatrix3d {.noInit.} =
 
 proc scale*(s:float,org:TPoint3d):TMatrix3d {.noInit.} =
   ## Returns a new scaling matrix using, `org` as scale origin.
-  result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0, 
+  result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0,
     org.x-s*org.x,org.y-s*org.y,org.z-s*org.z,1.0)
 
 proc stretch*(sx,sy,sz:float):TMatrix3d {.noInit.} =
   ## Returns new a stretch matrix, which is a
   ## scale matrix with non uniform scale in x,y and z.
   result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, 0,0,0,1)
-    
+
 proc stretch*(sx,sy,sz:float,org:TPoint3d):TMatrix3d {.noInit.} =
   ## Returns a new stretch matrix, which is a
   ## scale matrix with non uniform scale in x,y and z.
   ## `org` is used as stretch origin.
   result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, org.x-sx*org.x,org.y-sy*org.y,org.z-sz*org.z,1)
-    
+
 proc move*(dx,dy,dz:float):TMatrix3d {.noInit.} =
   ## Returns a new translation matrix.
   result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, dx,dy,dz,1)
@@ -235,7 +235,7 @@ proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}=
     uvomc=normax.x*normax.y*omc
     uwomc=normax.x*normax.z*omc
     vwomc=normax.y*normax.z*omc
-    
+
   result.setElements(
     u2+(1.0-u2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
     uvomc-wsi, v2+(1.0-v2)*cs, vwomc+usi, 0.0,
@@ -248,11 +248,11 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
 
   # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
   # for how this is computed
-  
+
   var normax=axis
   if not normax.tryNormalize: #simplifies matrix computation below a lot
     raise newException(DivByZeroError,"Cannot rotate around zero length axis")
-  
+
   let
     u=normax.x
     v=normax.y
@@ -272,7 +272,7 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
     uvomc=normax.x*normax.y*omc
     uwomc=normax.x*normax.z*omc
     vwomc=normax.y*normax.z*omc
-    
+
   result.setElements(
     u2+(v2+w2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
     uvomc-wsi, v2+(u2+w2)*cs, vwomc+usi, 0.0,
@@ -305,7 +305,7 @@ proc rotateY*(angle:float):TMatrix3d {.noInit.}=
     0,1,0,0,
     s,0,c,0,
     0,0,0,1)
-    
+
 proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
   ## Creates a matrix that rotates around the z-axis with `angle` radians,
   ## which is also called a 'yaw' matrix.
@@ -317,19 +317,19 @@ proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
     -s,c,0,0,
     0,0,1,0,
     0,0,0,1)
-    
+
 proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
-  ## Checks if the transform is uniform, that is 
+  ## Checks if the transform is uniform, that is
   ## perpendicular axes of equal length, which means (for example)
   ## it cannot transform a sphere into an ellipsoid.
-  ## `tol` is used as tolerance for both equal length comparison 
+  ## `tol` is used as tolerance for both equal length comparison
   ## and perpendicular comparison.
-  
+
   #dot product=0 means perpendicular coord. system, check xaxis vs yaxis and  xaxis vs zaxis
   if abs(m.ax*m.bx+m.ay*m.by+m.az*m.bz)<=tol and # x vs y
     abs(m.ax*m.cx+m.ay*m.cy+m.az*m.cz)<=tol and #x vs z
     abs(m.bx*m.cx+m.by*m.cy+m.bz*m.cz)<=tol: #y vs z
-    
+
     #subtract squared lengths of axes to check if uniform scaling:
     let
       sqxlen=(m.ax*m.ax+m.ay*m.ay+m.az*m.az)
@@ -340,16 +340,16 @@ proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
   return false
 
 
-    
+
 proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
   ## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
   ## and passes through origo. `planeperp` does not need to be normalized.
-  
+
   # https://en.wikipedia.org/wiki/Transformation_matrix
   var n=planeperp
   if not n.tryNormalize:
     raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
-  
+
   let
     a=n.x
     b=n.y
@@ -357,7 +357,7 @@ proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
     ab=a*b
     ac=a*c
     bc=b*c
-  
+
   result.setElements(
     1-2*a*a , -2*ab,-2*ac,0,
     -2*ab , 1-2*b*b, -2*bc, 0,
@@ -376,7 +376,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
   var n=planeperp
   if not n.tryNormalize:
     raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
-  
+
   let
     a=n.x
     b=n.y
@@ -390,7 +390,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
     tx=org.x
     ty=org.y
     tz=org.z
-  
+
   result.setElements(
     1-2*aa , -2*ab,-2*ac,0,
     -2*ab , 1-2*bb, -2*bc, 0,
@@ -402,8 +402,8 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
 
 proc determinant*(m:TMatrix3d):float=
   ## Computes the determinant of matrix `m`.
-  
-  # This computation is gotten from ratsimp(optimize(determinant(m))) 
+
+  # This computation is gotten from ratsimp(optimize(determinant(m)))
   # in maxima CAS
   let
     O1=m.cx*m.tw-m.cw*m.tx
@@ -423,10 +423,10 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
   ## Computes the inverse of matrix `m`. If the matrix
   ## determinant is zero, thus not invertible, a EDivByZero
   ## will be raised.
-  
+
   # this computation comes from optimize(invert(m)) in maxima CAS
-  
-  let 
+
+  let
     det=m.determinant
     O2=m.cy*m.tw-m.cw*m.ty
     O3=m.cz*m.tw-m.cw*m.tz
@@ -464,7 +464,7 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
 proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
   ## Checks if all elements of `m1`and `m2` is equal within
   ## a given tolerance `tol`.
-  return 
+  return
     abs(m1.ax-m2.ax)<=tol and
     abs(m1.ay-m2.ay)<=tol and
     abs(m1.az-m2.az)<=tol and
@@ -486,11 +486,11 @@ proc `=~`*(m1,m2:TMatrix3d):bool=
   ## Checks if `m1` and `m2` is approximately equal, using a
   ## tolerance of 1e-6.
   equals(m1,m2)
-  
+
 proc transpose*(m:TMatrix3d):TMatrix3d {.noInit.}=
   ## Returns the transpose of `m`
   result.setElements(m.ax,m.bx,m.cx,m.tx,m.ay,m.by,m.cy,m.ty,m.az,m.bz,m.cz,m.tz,m.aw,m.bw,m.cw,m.tw)
-  
+
 proc getXAxis*(m:TMatrix3d):TVector3d {.noInit.}=
   ## Gets the local x axis of `m`
   result.x=m.ax
@@ -509,26 +509,26 @@ proc getZAxis*(m:TMatrix3d):TVector3d {.noInit.}=
   result.y=m.cy
   result.z=m.cz
 
-    
+
 proc `$`*(m:TMatrix3d):string=
   ## String representation of `m`
-  return rtos(m.ax) & "," & rtos(m.ay) & "," &rtos(m.az) & "," & rtos(m.aw) &
-    "\n" & rtos(m.bx) & "," & rtos(m.by) & "," &rtos(m.bz) & "," & rtos(m.bw) &
-    "\n" & rtos(m.cx) & "," & rtos(m.cy) & "," &rtos(m.cz) & "," & rtos(m.cw) &
-    "\n" & rtos(m.tx) & "," & rtos(m.ty) & "," &rtos(m.tz) & "," & rtos(m.tw)
-    
+  return rtos(m.ax) & "," & rtos(m.ay) & "," & rtos(m.az) & "," & rtos(m.aw) &
+    "\n" & rtos(m.bx) & "," & rtos(m.by) & "," & rtos(m.bz) & "," & rtos(m.bw) &
+    "\n" & rtos(m.cx) & "," & rtos(m.cy) & "," & rtos(m.cz) & "," & rtos(m.cw) &
+    "\n" & rtos(m.tx) & "," & rtos(m.ty) & "," & rtos(m.tz) & "," & rtos(m.tw)
+
 proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)=
   ## Applies transformation `m` onto `x` , `y` , `z` , optionally
   ## using the translation part of the matrix.
-  let 
+  let
     oldx=x
     oldy=y
     oldz=z
-    
+
   x=m.cx*oldz+m.bx*oldy+m.ax*oldx
   y=m.cy*oldz+m.by*oldy+m.ay*oldx
   z=m.cz*oldz+m.bz*oldy+m.az*oldx
-    
+
   if translate:
     x+=m.tx
     y+=m.ty
@@ -552,13 +552,13 @@ proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} =
   ## an arbitrary vector of the requested length is returned.
 
   let fac=newlen/v.len
-  
+
   if newlen==0.0:
     v.x=0.0
     v.y=0.0
     v.z=0.0
     return
-  
+
   if fac==Inf or fac==NegInf:
     #to short for float accuracy
     #do as good as possible:
@@ -588,7 +588,7 @@ proc `&` *(v:TVector3d,m:TMatrix3d):TVector3d {.noInit.} =
   ## Concatenate vector `v` with a transformation matrix.
   ## Transforming a vector ignores the translational part
   ## of the matrix.
-  
+
   #               | AX AY AZ AW |
   # | X Y Z 1 | * | BX BY BZ BW |
   #               | CX CY CZ CW |
@@ -605,12 +605,12 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
   ## Applies transformation `m` onto `v` in place.
   ## Transforming a vector ignores the translational part
   ## of the matrix.
-  
+
   #               | AX AY AZ AW |
   # | X Y Z 1 | * | BX BY BZ BW |
   #               | CX CY CZ CW |
   #               | 0  0  0  1  |
-  
+
   let
     newx=m.cx*v.z+m.bx*v.y+m.ax*v.x
     newy=m.cy*v.z+m.by*v.y+m.ay*v.x
@@ -620,38 +620,38 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
 
 proc transformNorm*(v:var TVector3d,m:TMatrix3d)=
   ## Applies a normal direction transformation `m` onto `v` in place.
-  ## The resulting vector is *not* normalized.  Transforming a vector ignores the 
-  ## translational part of the matrix. If the matrix is not invertible 
+  ## The resulting vector is *not* normalized.  Transforming a vector ignores the
+  ## translational part of the matrix. If the matrix is not invertible
   ## (determinant=0), an EDivByZero will be raised.
 
   # transforming a normal is done by transforming
   # by the transpose of the inverse of the original matrix
-  
+
   # Major reason this simple function is here is that this function can be optimized in the future,
   # (possibly by hardware) as well as having a consistent API with the 2d version.
   v&=transpose(inverse(m))
-  
+
 proc transformInv*(v:var TVector3d,m:TMatrix3d)=
-  ## Applies the inverse of `m` on vector `v`. Transforming a vector ignores 
-  ## the translational part of the matrix.  Transforming a vector ignores the 
+  ## Applies the inverse of `m` on vector `v`. Transforming a vector ignores
+  ## the translational part of the matrix.  Transforming a vector ignores the
   ## translational part of the matrix.
   ## If the matrix is not invertible (determinant=0), an EDivByZero
   ## will be raised.
-  
+
   # Major reason this simple function is here is that this function can be optimized in the future,
   # (possibly by hardware) as well as having a consistent API with the 2d version.
   v&=m.inverse
- 
+
 proc transformNormInv*(vec:var TVector3d,m:TMatrix3d)=
   ## Applies an inverse normal direction transformation `m` onto `v` in place.
-  ## This is faster than creating an inverse 
-  ## matrix and transformNorm(...) it. Transforming a vector ignores the 
+  ## This is faster than creating an inverse
+  ## matrix and transformNorm(...) it. Transforming a vector ignores the
   ## translational part of the matrix.
-  
+
   # see vector2d:s equivalent for a deeper look how/why this works
   vec&=m.transpose
 
-proc tryNormalize*(v:var TVector3d):bool= 
+proc tryNormalize*(v:var TVector3d):bool=
   ## Modifies `v` to have a length of 1.0, keeping its angle.
   ## If `v` has zero length (and thus no angle), it is left unmodified and false is
   ## returned, otherwise true is returned.
@@ -663,26 +663,26 @@ proc tryNormalize*(v:var TVector3d):bool=
   v.x/=mag
   v.y/=mag
   v.z/=mag
-  
+
   return true
 
-proc normalize*(v:var TVector3d) {.inline.}= 
+proc normalize*(v:var TVector3d) {.inline.}=
   ## Modifies `v` to have a length of 1.0, keeping its angle.
   ## If  `v` has zero length, an EDivByZero will be raised.
   if not tryNormalize(v):
     raise newException(DivByZeroError,"Cannot normalize zero length vector")
 
 proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
-  ## Rotates `vec` in place, with `angle` radians over `axis`, which passes 
+  ## Rotates `vec` in place, with `angle` radians over `axis`, which passes
   ## through origo.
 
   # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
   # for how this is computed
-  
+
   var normax=axis
   if not normax.tryNormalize:
     raise newException(DivByZeroError,"Cannot rotate around zero length axis")
-  
+
   let
     cs=cos(angle)
     si=sin(angle)
@@ -694,11 +694,11 @@ proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
     y=vec.y
     z=vec.z
     uxyzomc=(u*x+v*y+w*z)*omc
-  
+
   vec.x=u*uxyzomc+x*cs+(v*z-w*y)*si
   vec.y=v*uxyzomc+y*cs+(w*x-u*z)*si
   vec.z=w*uxyzomc+z*cs+(u*y-v*x)*si
-  
+
 proc scale*(v:var TVector3d,s:float)=
   ## Scales the vector in place with factor `s`
   v.x*=s
@@ -713,12 +713,12 @@ proc stretch*(v:var TVector3d,sx,sy,sz:float)=
 
 proc mirror*(v:var TVector3d,planeperp:TVector3d)=
   ## Computes the mirrored vector of `v` over the plane
-  ## that has `planeperp` as normal direction. 
+  ## that has `planeperp` as normal direction.
   ## `planeperp` does not need to be normalized.
-  
+
   var n=planeperp
   n.normalize
-  
+
   let
     x=v.x
     y=v.y
@@ -729,7 +729,7 @@ proc mirror*(v:var TVector3d,planeperp:TVector3d)=
     ac=a*c
     ab=a*b
     bc=b*c
-  
+
   v.x= -2*(ac*z+ab*y+a*a*x)+x
   v.y= -2*(bc*z+b*b*y+ab*x)+y
   v.z= -2*(c*c*z+bc*y+ac*x)+z
@@ -740,7 +740,7 @@ proc `-` *(v:TVector3d):TVector3d=
   result.x= -v.x
   result.y= -v.y
   result.z= -v.z
-    
+
 # declare templated binary operators
 makeBinOpVector(`+`)
 makeBinOpVector(`-`)
@@ -752,7 +752,7 @@ makeBinOpAssignVector(`*=`)
 makeBinOpAssignVector(`/=`)
 
 proc dot*(v1,v2:TVector3d):float {.inline.}=
-  ## Computes the dot product of two vectors. 
+  ## Computes the dot product of two vectors.
   ## Returns 0.0 if the vectors are perpendicular.
   return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
 
@@ -769,12 +769,12 @@ proc cross*(v1,v2:TVector3d):TVector3d {.inline.}=
 proc equals*(v1,v2:TVector3d,tol=1.0e-6):bool=
   ## Checks if two vectors approximately equals with a tolerance.
   return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol and abs(v2.z-v1.z)<=tol
-  
+
 proc `=~` *(v1,v2:TVector3d):bool=
-  ## Checks if two vectors approximately equals with a 
+  ## Checks if two vectors approximately equals with a
   ## hardcoded tolerance 1e-6
   equals(v1,v2)
-  
+
 proc angleTo*(v1,v2:TVector3d):float=
   ## Returns the smallest angle between v1 and v2,
   ## which is in range 0-PI
@@ -801,7 +801,7 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
   ay=cross(norm,ax)
   ay.normalize()
   az=cross(ax,ay)
-  
+
   result.setElements(
     ax.x,ax.y,ax.z,0.0,
     ay.x,ay.y,ay.z,0.0,
@@ -811,20 +811,20 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
 proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
   ## Computes the bisector between v1 and v2 as a normalized vector.
   ## If one of the input vectors has zero length, a normalized version
-  ## of the other is returned. If both input vectors has zero length, 
+  ## of the other is returned. If both input vectors has zero length,
   ## an arbitrary normalized vector `v1` is returned.
   var
     vmag1=v1.len
     vmag2=v2.len
-    
-  # zero length vector equals arbitrary vector, just change 
+
+  # zero length vector equals arbitrary vector, just change
   # magnitude to one to avoid zero division
-  if vmag1==0.0: 
+  if vmag1==0.0:
     if vmag2==0: #both are zero length return any normalized vector
       return XAXIS
     vmag1=1.0
-  if vmag2==0.0: vmag2=1.0    
-    
+  if vmag2==0.0: vmag2=1.0
+
   let
     x1=v1.x/vmag1
     y1=v1.y/vmag1
@@ -832,14 +832,14 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
     x2=v2.x/vmag2
     y2=v2.y/vmag2
     z2=v2.z/vmag2
-    
+
   result.x=(x1 + x2) * 0.5
   result.y=(y1 + y2) * 0.5
   result.z=(z1 + z2) * 0.5
-  
+
   if not result.tryNormalize():
     # This can happen if vectors are colinear. In this special case
-    # there are actually inifinitely many bisectors, we select just 
+    # there are actually inifinitely many bisectors, we select just
     # one of them.
     result=v1.cross(XAXIS)
     if result.sqrLen<1.0e-9:
@@ -857,14 +857,14 @@ proc point3d*(x,y,z:float):TPoint3d=
   result.x=x
   result.y=y
   result.z=z
- 
+
 proc sqrDist*(a,b:TPoint3d):float=
   ## Computes the squared distance between `a`and `b`
   let dx=b.x-a.x
   let dy=b.y-a.y
   let dz=b.z-a.z
   result=dx*dx+dy*dy+dz*dz
-  
+
 proc dist*(a,b:TPoint3d):float {.inline.}=
   ## Computes the absolute distance between `a`and `b`
   result=sqrt(sqrDist(a,b))
@@ -876,7 +876,7 @@ proc `$` *(p:TPoint3d):string=
   result.add(rtos(p.y))
   result.add(",")
   result.add(rtos(p.z))
-  
+
 proc `&`*(p:TPoint3d,m:TMatrix3d):TPoint3d=
   ## Concatenates a point `p` with a transform `m`,
   ## resulting in a new, transformed point.
@@ -893,18 +893,18 @@ proc `&=` *(p:var TPoint3d,m:TMatrix3d)=
   p.x=m.cx*z+m.bx*y+m.ax*x+m.tx
   p.y=m.cy*z+m.by*y+m.ay*x+m.ty
   p.z=m.cz*z+m.bz*y+m.az*x+m.tz
-    
+
 proc transformInv*(p:var TPoint3d,m:TMatrix3d)=
   ## Applies the inverse of transformation `m` onto `p` in place.
   ## If the matrix is not invertable (determinant=0) , EDivByZero will
   ## be raised.
-  
+
   # can possibly be more optimized in the future so use this function when possible
   p&=inverse(m)
 
 
 proc `+`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
-  ## Adds a vector `v` to a point `p`, resulting 
+  ## Adds a vector `v` to a point `p`, resulting
   ## in a new point.
   result.x=p.x+v.x
   result.y=p.y+v.y
@@ -917,7 +917,7 @@ proc `+=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
   p.z+=v.z
 
 proc `-`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
-  ## Subtracts a vector `v` from a point `p`, resulting 
+  ## Subtracts a vector `v` from a point `p`, resulting
   ## in a new point.
   result.x=p.x-v.x
   result.y=p.y-v.y
@@ -933,37 +933,37 @@ proc `-=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
   ## Subtracts a vector `v` from a point `p` in place.
   p.x-=v.x
   p.y-=v.y
-  p.z-=v.z  
+  p.z-=v.z
 
 proc equals(p1,p2:TPoint3d,tol=1.0e-6):bool {.inline.}=
   ## Checks if two points approximately equals with a tolerance.
   return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol and abs(p2.z-p1.z)<=tol
 
 proc `=~`*(p1,p2:TPoint3d):bool {.inline.}=
-  ## Checks if two vectors approximately equals with a 
+  ## Checks if two vectors approximately equals with a
   ## hardcoded tolerance 1e-6
   equals(p1,p2)
 
 proc rotate*(p:var TPoint3d,rad:float,axis:TVector3d)=
-  ## Rotates point `p` in place `rad` radians about an axis 
+  ## Rotates point `p` in place `rad` radians about an axis
   ## passing through origo.
-  
+
   var v=vector3d(p.x,p.y,p.z)
   v.rotate(rad,axis) # reuse this code here since doing the same thing and quite complicated
   p.x=v.x
   p.y=v.y
   p.z=v.z
-    
+
 proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
-  ## Rotates point `p` in place `rad` radians about an axis 
+  ## Rotates point `p` in place `rad` radians about an axis
   ## passing through `org`
-  
+
   # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
   # for how this is computed
-  
+
   var normax=axis
   normax.normalize
-  
+
   let
     cs=cos(angle)
     omc=1.0-cs
@@ -987,17 +987,17 @@ proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
     bv=b*v
     cw=c*w
     uxmvymwz=ux-vy-wz
-    
+
   p.x=(a*(vv+ww)-u*(bv+cw-uxmvymwz))*omc + x*cs + (b*w+v*z-c*v-w*y)*si
   p.y=(b*(uu+ww)-v*(au+cw-uxmvymwz))*omc + y*cs + (c*u-a*w+w*x-u*z)*si
   p.z=(c*(uu+vv)-w*(au+bv-uxmvymwz))*omc + z*cs + (a*v+u*y-b*u-v*x)*si
-  
+
 proc scale*(p:var TPoint3d,fac:float) {.inline.}=
   ## Scales a point in place `fac` times with world origo as origin.
   p.x*=fac
   p.y*=fac
   p.z*=fac
-  
+
 proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
   ## Scales the point in place `fac` times with `org` as origin.
   p.x=(p.x - org.x) * fac + org.x
@@ -1005,7 +1005,7 @@ proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
   p.z=(p.z - org.z) * fac + org.z
 
 proc stretch*(p:var TPoint3d,facx,facy,facz:float){.inline.}=
-  ## Scales a point in place non uniformly `facx` , `facy` , `facz` times 
+  ## Scales a point in place non uniformly `facx` , `facy` , `facz` times
   ## with world origo as origin.
   p.x*=facx
   p.y*=facy
@@ -1017,7 +1017,7 @@ proc stretch*(p:var TPoint3d,facx,facy,facz:float,org:TPoint3d){.inline.}=
   p.x=(p.x - org.x) * facx + org.x
   p.y=(p.y - org.y) * facy + org.y
   p.z=(p.z - org.z) * facz + org.z
-  
+
 
 proc move*(p:var TPoint3d,dx,dy,dz:float){.inline.}=
   ## Translates a point `dx` , `dy` , `dz` in place.
@@ -1033,7 +1033,7 @@ proc move*(p:var TPoint3d,v:TVector3d){.inline.}=
 
 proc area*(a,b,c:TPoint3d):float {.inline.}=
   ## Computes the area of the triangle thru points `a` , `b` and `c`
-  
+
   # The area of a planar 3d quadliteral is the magnitude of the cross
   # product of two edge vectors. Taking this time 0.5 gives the triangle area.
   return cross(b-a,c-a).len*0.5
diff --git a/tests/overload/tspec.nim b/tests/overload/tspec.nim
index 99966e93e..f2002a390 100644
--- a/tests/overload/tspec.nim
+++ b/tests/overload/tspec.nim
@@ -12,7 +12,9 @@ ref T
 2
 1
 @[123, 2, 1]
-Called!'''
+Called!
+merge with var
+merge no var'''
 """
 
 # Things that's even in the spec now!
@@ -103,8 +105,14 @@ proc mget*[T](future: FutureVar[T]): var T =
 proc reset*[T](future: FutureVar[T]) =
   echo "Called!"
 
+proc merge[T](x: Future[T]) = echo "merge no var"
+proc merge[T](x: var Future[T]) = echo "merge with var"
+
 when true:
   var foo = newFutureVar[string]()
   foo.mget() = ""
   foo.mget.add("Foobar")
   foo.reset()
+  var bar = newFuture[int]()
+  bar.merge # merge with var
+  merge(newFuture[int]()) # merge no var