diff options
-rw-r--r-- | compiler/ast.nim | 16 | ||||
-rw-r--r-- | compiler/semcall.nim | 4 | ||||
-rw-r--r-- | compiler/semexprs.nim | 11 | ||||
-rw-r--r-- | compiler/semmagic.nim | 26 | ||||
-rw-r--r-- | compiler/semtypes.nim | 4 | ||||
-rw-r--r-- | tests/metatype/ttypetraits.nim | 33 | ||||
-rw-r--r-- | tests/types/tisopr.nim | 20 |
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) |