summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim16
-rw-r--r--compiler/semcall.nim4
-rw-r--r--compiler/semexprs.nim11
-rw-r--r--compiler/semmagic.nim26
-rw-r--r--compiler/semtypes.nim4
-rw-r--r--tests/metatype/ttypetraits.nim33
-rw-r--r--tests/types/tisopr.nim20
7 files changed, 94 insertions, 20 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 6ac4a7175..5938d4e53 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -11,6 +11,7 @@
 
 import
   lineinfos, hashes, options, ropes, idents, idgen, int128
+from strutils import toLowerAscii
 
 export int128
 
@@ -977,7 +978,7 @@ const
     tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
     tyUInt..tyUInt64}
   IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64,
-    tyFloat..tyFloat128, tyUInt..tyUInt64}
+    tyFloat..tyFloat128, tyUInt..tyUInt64} # weird name because it contains tyFloat
   ConstantDataTypes*: TTypeKinds = {tyArray, tySet,
                                     tyTuple, tySequence}
   NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr,
@@ -1908,3 +1909,16 @@ proc canRaise*(fn: PNode): bool =
     result = fn.typ != nil and fn.typ.n != nil and ((fn.typ.n[0].len < effectListLen) or
       (fn.typ.n[0][exceptionEffects] != nil and
       fn.typ.n[0][exceptionEffects].safeLen > 0))
+
+proc toHumanStrImpl[T](kind: T, num: static int): string =
+  result = $kind
+  result = result[num..^1]
+  result[0] = result[0].toLowerAscii
+
+proc toHumanStr*(kind: TSymKind): string =
+  ## strips leading `sk`
+  result = toHumanStrImpl(kind, 2)
+
+proc toHumanStr*(kind: TTypeKind): string =
+  ## strips leading `tk`
+  result = toHumanStrImpl(kind, 2)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 7124d9240..c0227db19 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -288,10 +288,6 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
     var o: TOverloadIter
     var sym = initOverloadIter(o, c, f)
     while sym != nil:
-      proc toHumanStr(kind: TSymKind): string =
-        result = $kind
-        assert result.startsWith "sk"
-        result = result[2..^1].toLowerAscii
       result &= "\n  found '$1' of kind '$2'" % [getSymRepr(c.config, sym), sym.kind.toHumanStr]
       sym = nextOverloadIter(o, c, f)
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index cbdb5ce77..375ea1cb1 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -396,12 +396,21 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
     else:
       res = false
   else:
-    maybeLiftType(t2, c, n.info)
+    if t1.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct}).kind != tyGenericBody:
+      maybeLiftType(t2, c, n.info)
+    else:
+      #[
+      for this case:
+      type Foo = object[T]
+      Foo is Foo
+      ]#
+      discard
     var m = newCandidate(c, t2)
     if efExplain in flags:
       m.diagnostics = @[]
       m.diagnosticsEnabled = true
     res = typeRel(m, t2, t1) >= isSubtype # isNone
+    # `res = sameType(t1, t2)` would be wrong, eg for `int is (int|float)`
 
   result = newIntNode(nkIntLit, ord(res))
   result.typ = n.typ
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 30ff73d7f..0571032dc 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -121,6 +121,11 @@ proc uninstantiate(t: PType): PType =
     of tyCompositeTypeClass: uninstantiate t[1]
     else: t
 
+proc getTypeDescNode(typ: PType, sym: PSym, info: TLineInfo): PNode =
+  var resType = newType(tyTypeDesc, sym)
+  rawAddSon(resType, typ)
+  result = toNode(resType, info)
+
 proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym): PNode =
   const skippedTypes = {tyTypeDesc, tyAlias, tySink}
   let trait = traitCall[0]
@@ -161,13 +166,16 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
     result.typ = newType(tyInt, context)
     result.info = traitCall.info
   of "genericHead":
-    var res = uninstantiate(operand)
-    if res == operand and res.kind notin tyMagicGenerics:
-      localError(c.config, traitCall.info,
-        "genericHead expects a generic type. The given type was " &
-        typeToString(operand))
-      return newType(tyError, context).toNode(traitCall.info)
-    result = res.base.toNode(traitCall.info)
+    var arg = operand
+    case arg.kind
+    of tyGenericInst:
+      result = getTypeDescNode(arg.base, operand.owner, traitCall.info)
+    # of tySequence: # this doesn't work
+    #   var resType = newType(tySequence, operand.owner)
+    #   result = toNode(resType, traitCall.info) # doesn't work yet
+    else:
+      localError(c.config, traitCall.info, "expected generic type, got: type $2 of kind $1" % [arg.kind.toHumanStr, typeToString(operand)])
+      result = newType(tyError, context).toNode(traitCall.info)
   of "stripGenericParams":
     result = uninstantiate(operand).toNode(traitCall.info)
   of "supportsCopyMem":
@@ -185,9 +193,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
       while arg.kind == tyDistinct:
         arg = arg.base
         arg = arg.skipTypes(skippedTypes + {tyGenericInst})
-      var resType = newType(tyTypeDesc, operand.owner)
-      rawAddSon(resType, arg)
-      result = toNode(resType, traitCall.info)
+      result = getTypeDescNode(arg, operand.owner, traitCall.info)
     else:
       localError(c.config, traitCall.info,
         "distinctBase expects a distinct type as argument. The given type was " & typeToString(operand))
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index ed59ce36a..61cbecec6 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1383,7 +1383,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     return newOrPrevType(tyError, prev, c)
 
   var t = s.typ
-  if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
+  if t.kind in {tyCompositeTypeClass, tyAlias} and t.base.kind == tyGenericBody:
     t = t.base
 
   result = newOrPrevType(tyGenericInvocation, prev, c)
@@ -1454,7 +1454,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     recomputeFieldPositions(tx, tx.n, position)
 
 proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
-  if typeExpr.kind in {tyObject, tyEnum, tyDistinct, tyForward} and prev != nil:
+  if typeExpr.kind in {tyObject, tyEnum, tyDistinct, tyForward, tyGenericBody} and prev != nil:
     result = newTypeS(tyAlias, c)
     result.rawAddSon typeExpr
     result.sym = prev.sym
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
index c4fb9beef..218ffadc2 100644
--- a/tests/metatype/ttypetraits.nim
+++ b/tests/metatype/ttypetraits.nim
@@ -47,7 +47,7 @@ block: # typeToString
   doAssert MyInt.name3 == "MyInt{int}"
   doAssert (tuple[a: MyInt, b: float]).name3 == "tuple[a: MyInt{int}, b: float]"
   doAssert (tuple[a: C2b[MyInt, C4[cstring]], b: cint, c: float]).name3 ==
-    "tuple[a: C2b{C}[MyInt{int}, C4[cstring]], b: cint{int32}, c: float]"
+    "tuple[a: C[MyInt{int}, C4[cstring]], b: cint{int32}, c: float]"
 
 block distinctBase:
   block:
@@ -125,4 +125,33 @@ var x = CpuStorage[string]()
 static:
   doAssert(not string.supportsCopyMem)
   doAssert x.T is string          # true
-  doAssert x.raw_buffer is seq
\ No newline at end of file
+  doAssert x.raw_buffer is seq
+
+block genericHead:
+  type Foo[T1,T2] = object
+    x1: T1
+    x2: T2
+  type FooInst = Foo[int, float]
+  type Foo2 = genericHead(FooInst)
+  doAssert Foo2 is Foo # issue #13066
+
+  block:
+    type Goo[T] = object
+    type Moo[U] = object
+    type Hoo = Goo[Moo[float]]
+    type Koo = genericHead(Hoo)
+    doAssert Koo is Goo
+    doAssert genericParams(Hoo) is (Moo[float],)
+    doAssert genericParams(Hoo).get(0) is Moo[float]
+    doAssert genericHead(genericParams(Hoo).get(0)) is Moo
+
+  type Foo2Inst = Foo2[int, float]
+  doAssert FooInst.default == Foo2Inst.default
+  doAssert FooInst.default.x2 == 0.0
+  doAssert Foo2Inst is FooInst
+  doAssert FooInst is Foo2Inst
+  doAssert compiles(genericHead(FooInst))
+  doAssert not compiles(genericHead(Foo))
+  type Bar = object
+  doAssert not compiles(genericHead(Bar))
+  # doAssert seq[int].genericHead is seq
diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim
index 636377301..1bbd0da94 100644
--- a/tests/types/tisopr.nim
+++ b/tests/types/tisopr.nim
@@ -89,3 +89,23 @@ proc test[T](x: T) =
     echo "no"
 
 test(7)
+
+block:
+  # bug #13066
+  type Bar[T1,T2] = object
+  type Foo[T1,T2] = object
+  type Foo2 = Foo
+  doAssert Foo2 is Foo
+  doAssert Foo is Foo2
+  doAssert Foo is Foo
+  doAssert Foo2 is Foo2
+  doAssert Foo2 isnot Bar
+  doAssert Foo[int,float] is Foo2[int,float]
+
+  # other
+  doAssert Foo[int,float] isnot Foo2[float,float]
+  doAssert Foo[int,float] is Foo2
+  doAssert Foo[int,float|int] is Foo2
+  doAssert Foo2[int,float|int] is Foo
+  doAssert Foo2[int,float|int] isnot Bar
+  doAssert int is (int|float)