mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-21 14:55:24 +00:00
fix is with generic types; fix genericHead(Foo[T]) (#13303)
* fix #9855, fix #9855, fix genericHead * render TTypeKind via toHumanStr
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user