summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/semexprs.nim39
-rw-r--r--compiler/sigmatch.nim20
-rw-r--r--compiler/types.nim20
-rw-r--r--compiler/vmdeps.nim11
6 files changed, 52 insertions, 45 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index bd244fb97..f13691d54 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -428,6 +428,7 @@ const
                     tyAnd, tyOr, tyNot, tyAnything}
 
   tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
+  tyUserTypeClasses* = {tyUserTypeClass, tyUserTypeClassInst}
 
 type
   TTypeKinds* = set[TTypeKind]
@@ -471,6 +472,8 @@ type
                       # can be attached to generic procs with free standing
                       # type parameters: e.g. proc foo[T]()
                       # depends on unresolved static params.
+    tfResolved        # marks a user type class, after it has been bound to a
+                      # concrete type (lastSon becomes the concrete type)
     tfRetType,        # marks return types in proc (used to detect type classes
                       # used as return types for return type inference)
     tfCapturesEnv,    # whether proc really captures some environment
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 309fb1f20..6e10379e6 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -890,7 +890,7 @@ proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
               rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.s)
 
 proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
-  var ty = skipTypes(n.sons[0].typ, abstractVarRange)
+  var ty = skipTypes(n.sons[0].typ, abstractVarRange + tyUserTypeClasses)
   if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
   case ty.kind
   of tyArray: genArrayElem(p, n.sons[0], n.sons[1], d)
@@ -1359,7 +1359,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
 proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   var a = e.sons[1]
   if a.kind == nkHiddenAddr: a = a.sons[0]
-  let typ = skipTypes(a.typ, abstractVar)
+  var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses)
   case typ.kind
   of tyOpenArray, tyVarargs:
     if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 475f496f1..3ec2cd391 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -136,6 +136,7 @@ proc isCastable(dst, src: PType): bool =
   #  castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
   #                       tySequence, tyPointer, tyNil, tyOpenArray,
   #                       tyProc, tySet, tyEnum, tyBool, tyChar}
+  let src = src.skipTypes(tyUserTypeClasses)
   if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray:
     return false
   if skipTypes(src, abstractInst-{tyTypeDesc}).kind == tyTypeDesc:
@@ -908,28 +909,14 @@ proc makeDeref(n: PNode): PNode =
     t = skipTypes(baseTyp, {tyGenericInst, tyAlias})
 
 const
-  tyTypeParamsHolders = {tyGenericInst, tyUserTypeClassInst, tyCompositeTypeClass}
+  tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass,
+                         tyUserTypeClass, tyUserTypeClassInst}
   tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias}
 
 proc readTypeParameter(c: PContext, typ: PType,
                        paramName: PIdent, info: TLineInfo): PNode =
-  let ty = if typ.kind in {tyGenericInst, tyUserTypeClassInst}: typ.skipGenericAlias
-           else: (internalAssert(typ.kind == tyCompositeTypeClass);
-                  typ.sons[1].skipGenericAlias)
-
-  let tbody = ty.sons[0]
-  for s in countup(0, tbody.len-2):
-    let tParam = tbody.sons[s]
-    if tParam.sym.name.id == paramName.id:
-      let rawTyp = ty.sons[s + 1]
-      if rawTyp.kind == tyStatic:
-        return rawTyp.n
-      else:
-        let foundTyp = makeTypeDesc(c, rawTyp)
-        return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
-
-  if ty.n != nil:
-    for statement in ty.n:
+  if typ.kind in {tyUserTypeClass, tyUserTypeClassInst}:
+    for statement in typ.n:
       case statement.kind
       of nkTypeSection:
         for def in statement:
@@ -939,7 +926,7 @@ proc readTypeParameter(c: PContext, typ: PType,
             # This seems semantically correct and then we'll be able
             # to return the section symbol directly here
             let foundType = makeTypeDesc(c, def[2].typ)
-            return newSymNode(copySym(def[2].sym).linkTo(foundType), info)
+            return newSymNode(copySym(def[0].sym).linkTo(foundType), info)
 
       of nkConstSection:
         for def in statement:
@@ -948,6 +935,20 @@ proc readTypeParameter(c: PContext, typ: PType,
 
       else:
         discard
+  
+  if typ.kind != tyUserTypeClass:
+    let ty = if typ.kind == tyCompositeTypeClass: typ.sons[1].skipGenericAlias
+             else: typ.skipGenericAlias
+    let tbody = ty.sons[0]
+    for s in countup(0, tbody.len-2):
+      let tParam = tbody.sons[s]
+      if tParam.sym.name.id == paramName.id:
+        let rawTyp = ty.sons[s + 1]
+        if rawTyp.kind == tyStatic:
+          return rawTyp.n
+        else:
+          let foundTyp = makeTypeDesc(c, rawTyp)
+          return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
 
   return nil
 
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index f33ac76e7..162385e6d 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1197,22 +1197,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       else:
         return isNone
 
-  of tyUserTypeClass:
-    considerPreviousT:
-      var matched = matchUserTypeClass(c.c, c, f, aOrig)
-      if matched != nil:
-        # TODO, make user type classes skipable too
-        put(c, f, a)
-        result = isGeneric
-      else:
-        result = isNone
-
-  of tyUserTypeClassInst:
-    considerPreviousT:
+  of tyUserTypeClassInst, tyUserTypeClass:
+    if f.isResolvedUserTypeClass:
+      result = typeRel(c, f.lastSon, a)
+    else:
       var matched = matchUserTypeClass(c.c, c, f, aOrig)
       if matched != nil:
-        matched.sons.add a
-        put(c.bindings, f, matched)
+        bindConcreteTypeToUserTypeClass(matched, a)
+        put(c, f, matched)
         result = isGeneric
       else:
         result = isNone
diff --git a/compiler/types.nim b/compiler/types.nim
index 3e124412b..be7028f9c 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -63,7 +63,7 @@ const
   abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
                        tyTypeDesc, tyAlias, tyInferred}
   abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias,
-                   tyInferred}
+                   tyInferred} + tyTypeClasses
   skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyTypeDesc, tyAlias,
                tyInferred}
   # typedescX is used if we're sure tyTypeDesc should be included (or skipped)
@@ -417,6 +417,13 @@ const
 
 const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
 
+template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
+  tc.sons.safeAdd concrete
+  tc.flags.incl tfResolved
+
+template isResolvedUserTypeClass*(t: PType): bool =
+  tfResolved in t.flags
+
 proc addTypeFlags(name: var string, typ: PType) {.inline.} =
   if tfNotNil in typ.flags: name.add(" not nil")
 
@@ -461,6 +468,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       if t.n != nil: result.add "(" & renderTree(t.n) & ")"
   of tyUserTypeClass:
     internalAssert t.sym != nil and t.sym.owner != nil
+    if t.isResolvedUserTypeClass: return typeToString(t.lastSon)
     return t.sym.owner.name.s
   of tyBuiltInTypeClass:
     result = case t.base.kind:
@@ -1314,12 +1322,15 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     result = align(result, a)
   of tyGenericInst, tyDistinct, tyGenericBody, tyAlias:
     result = computeSizeAux(lastSon(typ), a)
+  of tyTypeClasses:
+    result = if typ.isResolvedUserTypeClass: computeSizeAux(typ.lastSon, a)
+             else: szUnknownSize
   of tyTypeDesc:
     result = computeSizeAux(typ.base, a)
   of tyForward: return szIllegalRecursion
   of tyStatic:
-    if typ.n != nil: result = computeSizeAux(lastSon(typ), a)
-    else: result = szUnknownSize
+    result = if typ.n != nil: computeSizeAux(typ.lastSon, a)
+             else: szUnknownSize
   else:
     #internalError("computeSizeAux()")
     result = szUnknownSize
@@ -1492,9 +1503,6 @@ proc isEmptyContainer*(t: PType): bool =
   of tyGenericInst, tyAlias: result = isEmptyContainer(t.lastSon)
   else: result = false
 
-proc isResolvedUserTypeClass*(t: PType): bool =
-  t.kind in {tyUserTypeClassInst} and t.base.sonsLen == t.sonsLen - 2
-
 proc takeType*(formal, arg: PType): PType =
   # param: openArray[string] = []
   # [] is an array constructor of length 0 of type string!
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 7094d174b..8c7388643 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -175,7 +175,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
           result.add mapTypeToAst(t.sons[i], info)
     else:
       result = mapTypeToAstX(t.lastSon, info, inst, allowRecursion)
-  of tyGenericBody, tyOrdinal, tyUserTypeClassInst:
+  of tyGenericBody, tyOrdinal:
     result = mapTypeToAst(t.lastSon, info)
   of tyDistinct:
     if inst:
@@ -285,9 +285,12 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
   of tyProxy: result = atomicType("error", mNone)
   of tyBuiltInTypeClass:
     result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
-  of tyUserTypeClass:
-    result = mapTypeToBracket("concept", mNone, t, info)
-    result.add t.n.copyTree
+  of tyUserTypeClass, tyUserTypeClassInst:
+    if t.isResolvedUserTypeClass:
+      result = mapTypeToAst(t.lastSon, info)
+    else:
+      result = mapTypeToBracket("concept", mNone, t, info)
+      result.add t.n.copyTree
   of tyCompositeTypeClass:
     result = mapTypeToBracket("compositeTypeClass", mNone, t, info)
   of tyAnd: result = mapTypeToBracket("and", mAnd, t, info)