summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/cgmeth.nim4
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/semdata.nim2
-rw-r--r--compiler/semexprs.nim10
-rw-r--r--compiler/semstmts.nim16
-rw-r--r--compiler/semtypinst.nim13
-rw-r--r--compiler/sigmatch.nim9
-rw-r--r--compiler/suggest.nim2
-rw-r--r--compiler/types.nim2
-rw-r--r--lib/pure/htmlparser.nim10
-rw-r--r--lib/pure/httpclient.nim2
-rw-r--r--tests/converter/texplicit_conversion.nim13
-rw-r--r--tests/method/tgeneric_methods.nim24
-rw-r--r--tests/method/tmultim6.nim20
-rw-r--r--tests/stdlib/thtmlparser2814.nim44
-rw-r--r--tests/tuples/twrong_generic_caching.nim4
-rw-r--r--todo.txt1
18 files changed, 148 insertions, 31 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 9ec88ba8e..4c98219f9 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -850,6 +850,7 @@ type
                               # see instantiateDestructor in semdestruct.nim
     deepCopy*: PSym           # overriden 'deepCopy' operation
     assignment*: PSym         # overriden '=' operator
+    methods*: seq[(int,PSym)] # attached methods
     size*: BiggestInt         # the size of the type in bytes
                               # -1 means that the size is unkwown
     align*: int16             # the type's alignment requirements
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index 3dbd4f815..624c5b183 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -63,7 +63,7 @@ proc sameMethodBucket(a, b: PSym): MethodResult =
     while true:
       aa = skipTypes(aa, {tyGenericInst})
       bb = skipTypes(bb, {tyGenericInst})
-      if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}):
+      if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef}:
         aa = aa.lastSon
         bb = bb.lastSon
       else:
@@ -187,7 +187,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
       var aa = skipTypes(a.typ.sons[col], skipPtrs)
       var bb = skipTypes(b.typ.sons[col], skipPtrs)
       var d = inheritanceDiff(aa, bb)
-      if (d != high(int)):
+      if (d != high(int)) and d != 0:
         return d
 
 proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index c15794b99..d7d1ed838 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -68,7 +68,7 @@ const
   letPragmas* = varPragmas
   procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
                       wThread, wRaises, wLocks, wTags, wGcSafe}
-  allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
+  allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas
 
 proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
 # implementation
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 52b5dc274..30b6e261d 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -104,7 +104,7 @@ type
     hloLoopDetector*: int     # used to prevent endless loops in the HLO
     inParallelStmt*: int
     instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
-                            op: TTypeAttachedOp): PSym {.nimcall.}
+                            op: TTypeAttachedOp; col: int): PSym {.nimcall.}
     selfName*: PIdent
     signatures*: TStrTable
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 9f0696252..d76bd791e 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -191,10 +191,6 @@ proc semConv(c: PContext, n: PNode): PNode =
     case status
     of convOK:
       # handle SomeProcType(SomeGenericProc)
-      # XXX: This needs fixing. checkConvertible uses typeRel internally, but
-      # doesn't bother to perform the work done in paramTypeMatchAux/fitNode
-      # so we are redoing the typeRel work here. Why does semConv exist as a
-      # separate proc from fitNode?
       if op.kind == nkSym and op.sym.isGenericRoutine:
         result.sons[1] = fitNode(c, result.typ, result.sons[1])
       elif op.kind == nkPar and targetType.kind == tyTuple:
@@ -202,8 +198,10 @@ proc semConv(c: PContext, n: PNode): PNode =
     of convNotNeedeed:
       message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
     of convNotLegal:
-      localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)%
-        [op.typ.typeToString, result.typ.typeToString])
+      result = fitNode(c, result.typ, result.sons[1])
+      if result == nil:
+        localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)%
+          [op.typ.typeToString, result.typ.typeToString])
   else:
     for i in countup(0, sonsLen(op) - 1):
       let it = op.sons[i]
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 79581e4cb..f59acd7be 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1352,7 +1352,21 @@ proc semMethod(c: PContext, n: PNode): PNode =
   # macros can transform methods to nothing:
   if namePos >= result.safeLen: return result
   var s = result.sons[namePos].sym
-  if not isGenericRoutine(s):
+  if isGenericRoutine(s):
+    let tt = s.typ
+    var foundObj = false
+    # we start at 1 for now so that tparsecombnum continues to compile.
+    # XXX Revisit this problem later.
+    for col in countup(1, sonsLen(tt)-1):
+      let t = tt.sons[col]
+      if t != nil and t.kind == tyGenericInvocation:
+        var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, tyGenericInvocation, tyGenericBody})
+        if x.kind == tyObject and t.len-1 == result.sons[genericParamsPos].len:
+          foundObj = true
+          x.methods.safeAdd((col,s))
+    if not foundObj:
+      message(n.info, warnDeprecated, "generic method not attachable to object type")
+  else:
     # why check for the body? bug #2400 has none. Checking for sfForward makes
     # no sense either.
     # and result.sons[bodyPos].kind != nkEmpty:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 922071ba3..076679bbf 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -289,7 +289,8 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
     # but we already raised an error!
     rawAddSon(result, header.sons[i])
 
-  var newbody = replaceTypeVarsT(cl, lastSon(body))
+  let bbody = lastSon body
+  var newbody = replaceTypeVarsT(cl, bbody)
   cl.skipTypedesc = oldSkipTypedesc
   newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
   result.flags = result.flags + newbody.flags - tfInstClearedFlags
@@ -306,12 +307,18 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
     # 'deepCopy' needs to be instantiated for
     # generics *when the type is constructed*:
     newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
-                                            attachedDeepCopy)
+                                            attachedDeepCopy, 1)
   let asgn = newbody.assignment
   if asgn != nil and sfFromGeneric notin asgn.flags:
     # '=' needs to be instantiated for generics when the type is constructed:
     newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
-                                              attachedAsgn)
+                                              attachedAsgn, 1)
+  let methods = skipTypes(bbody, abstractPtrs).methods
+  for col, meth in items(methods):
+    # we instantiate the known methods belonging to that type, this causes
+    # them to be registered and that's enough, so we 'discard' the result.
+    discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
+      attachedAsgn, col)
 
 proc eraseVoidParams*(t: PType) =
   # transform '(): void' into '()' because old parts of the compiler really
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 7a5aa8dbb..9a8f865a6 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1796,16 +1796,19 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
   result = res != nil
 
 proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
-                      op: TTypeAttachedOp): PSym {.procvar.} =
+                      op: TTypeAttachedOp; col: int): PSym {.procvar.} =
   var m: TCandidate
   initCandidate(c, m, dc.typ)
-  var f = dc.typ.sons[1]
+  if col >= dc.typ.len:
+    localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
+    return nil
+  var f = dc.typ.sons[col]
   if op == attachedDeepCopy:
     if f.kind in {tyRef, tyPtr}: f = f.lastSon
   else:
     if f.kind == tyVar: f = f.lastSon
   if typeRel(m, f, t) == isNone:
-    localError(info, errGenerated, "cannot instantiate 'deepCopy'")
+    localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
   else:
     result = c.semGenerateInstance(c, dc, m.bindings, info)
     assert sfFromGeneric in result.flags
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index bcab6b04a..f35ff2142 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -393,6 +393,8 @@ proc suggestSym*(info: TLineInfo; s: PSym; isDecl=true) {.inline.} =
 
 proc markUsed(info: TLineInfo; s: PSym) =
   incl(s.flags, sfUsed)
+  if s.kind == skEnumField and s.owner != nil:
+    incl(s.owner.flags, sfUsed)
   if {sfDeprecated, sfError} * s.flags != {}:
     if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
     if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
diff --git a/compiler/types.nim b/compiler/types.nim
index a87f9470f..5fbab85b9 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -803,6 +803,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
           result = x.name.id == y.name.id
           if not result: break
         else: internalError(a.n.info, "sameTuple")
+    elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags:
+      result = false
 
 template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
   if tfFromGeneric notin a.flags + b.flags:
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index fd58bed25..1fe0b297b 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -464,12 +464,18 @@ proc untilElementEnd(x: var XmlParser, result: XmlNode,
     case x.kind
     of xmlElementStart, xmlElementOpen:
       case result.htmlTag
-      of tagLi, tagP, tagDt, tagDd, tagInput, tagOption:
-        # some tags are common to have no ``</end>``, like ``<li>``:
+      of tagP, tagInput, tagOption:
+        # some tags are common to have no ``</end>``, like ``<li>`` but
+        # allow ``<p>`` in `<dd>`, `<dt>` and ``<li>`` in next case
         if htmlTag(x.elemName) in {tagLi, tagP, tagDt, tagDd, tagInput,
                                    tagOption}:
           errors.add(expected(x, result))
           break
+      of tagDd, tagDt, tagLi:
+        if htmlTag(x.elemName) in {tagLi, tagDt, tagDd, tagInput,
+                                   tagOption}:
+          errors.add(expected(x, result))
+          break
       of tagTd, tagTh:
         if htmlTag(x.elemName) in {tagTr, tagTd, tagTh, tagTfoot, tagThead}:
           errors.add(expected(x, result))
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index bc964861d..37bc5d8f4 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -423,6 +423,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
   add(headers, extraHeaders)
   add(headers, "\c\L")
   var s = newSocket()
+  defer: s.close()
   if s == nil: raiseOSError(osLastError())
   var port = net.Port(80)
   if r.scheme == "https":
@@ -444,7 +445,6 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
     s.send(body)
 
   result = parseResponse(s, httpMethod != "httpHEAD", timeout)
-  s.close()
 
 proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
               body = "", sslContext = defaultSSLContext, timeout = -1,
diff --git a/tests/converter/texplicit_conversion.nim b/tests/converter/texplicit_conversion.nim
new file mode 100644
index 000000000..6b2e96faf
--- /dev/null
+++ b/tests/converter/texplicit_conversion.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "234"
+"""
+
+# bug #4432
+
+import strutils
+
+converter toInt(s: string): int =
+  result = parseInt(s)
+
+let x = (int)"234"
+echo x
diff --git a/tests/method/tgeneric_methods.nim b/tests/method/tgeneric_methods.nim
new file mode 100644
index 000000000..76a68fbb0
--- /dev/null
+++ b/tests/method/tgeneric_methods.nim
@@ -0,0 +1,24 @@
+discard """
+  output: "wow2"
+"""
+type
+  First[T] = ref object of RootObj
+    value: T
+
+  Second[T] = ref object of First[T]
+    value2: T
+
+method wow[T](y: int; x: First[T]) {.base.} =
+  echo "wow1"
+
+method wow[T](y: int; x: Second[T]) =
+  echo "wow2"
+
+var
+  x: Second[int]
+new(x)
+
+proc takeFirst(x: First[int]) =
+  wow(2, x)
+
+takeFirst(x)
diff --git a/tests/method/tmultim6.nim b/tests/method/tmultim6.nim
index 97ed2845c..2c622b832 100644
--- a/tests/method/tmultim6.nim
+++ b/tests/method/tmultim6.nim
@@ -4,27 +4,27 @@ discard """
 # Test multi methods
 
 type
-  TThing = object {.inheritable.}
-  TUnit[T] = object of TThing
+  Thing = object {.inheritable.}
+  Unit[T] = object of Thing
     x: T
-  TParticle = object of TThing
+  Particle = object of Thing
     a, b: int
 
-method collide(a, b: TThing) {.base, inline.} =
+method collide(a, b: Thing) {.base, inline.} =
   quit "to override!"
 
-method collide[T](a: TThing, b: TUnit[T]) {.inline.} =
+method collide[T](a: Thing, b: Unit[T]) {.inline.} =
   write stdout, "collide: thing, unit | "
 
-method collide[T](a: TUnit[T], b: TThing) {.inline.} =
+method collide[T](a: Unit[T], b: Thing) {.inline.} =
   write stdout, "collide: unit, thing | "
 
-proc test(a, b: TThing) {.inline.} =
+proc test(a, b: Thing) {.inline.} =
   collide(a, b)
 
 var
-  a: TThing
-  b, c: TUnit[string]
-collide(b, TThing(c))
+  a: Thing
+  b, c: Unit[string]
+collide(b, Thing(c))
 test(b, c)
 collide(a, b)
diff --git a/tests/stdlib/thtmlparser2814.nim b/tests/stdlib/thtmlparser2814.nim
new file mode 100644
index 000000000..968d390f1
--- /dev/null
+++ b/tests/stdlib/thtmlparser2814.nim
@@ -0,0 +1,44 @@
+discard """
+  output: true
+"""
+import htmlparser
+import xmltree
+import strutils
+from streams import newStringStream
+
+
+## builds the two cases below and test that
+## ``//[dd,li]`` has "<p>that</p>" as children
+##
+##  <dl>
+##    <dt>this</dt>
+##    <dd>
+##      <p>that</p>
+##    </dd>
+##  </dl>
+
+##
+## <ul>
+##   <li>
+##     <p>that</p>
+##   </li>
+## </ul>
+
+
+for ltype in [["dl","dd"], ["ul","li"]]:
+  let desc_item = if ltype[0]=="dl": "<dt>this</dt>" else: ""
+  let item = "$1<$2><p>that</p></$2>" % [desc_item, ltype[1]]
+  let list = """ <$1>
+   $2
+</$1> """ % [ltype[0], item]
+
+  var errors : seq[string] = @[]
+
+  let parseH = parseHtml(newStringStream(list),"statichtml", errors =errors)
+
+  if $parseH.findAll(ltype[1])[0].child("p") != "<p>that</p>":
+    echo "case " & ltype[0] & " failed !"
+    quit(2)
+
+
+echo "true"
diff --git a/tests/tuples/twrong_generic_caching.nim b/tests/tuples/twrong_generic_caching.nim
new file mode 100644
index 000000000..32ef344d2
--- /dev/null
+++ b/tests/tuples/twrong_generic_caching.nim
@@ -0,0 +1,4 @@
+
+import parsecfg
+
+import asynchttpserver
diff --git a/todo.txt b/todo.txt
index 745daa7c7..235d79b78 100644
--- a/todo.txt
+++ b/todo.txt
@@ -2,7 +2,6 @@ version 1.0 battle plan
 =======================
 
 - Deprecate ``immediate`` for templates and macros
-- fix generic multi-methods
 - fix "high priority" bugs
 - try to fix as many compiler crashes as reasonable