Skip to content

Commit

Permalink
fix is with generic types; fix genericHead(Foo[T]) (#13303)
Browse files Browse the repository at this point in the history
* fix #9855, fix #9855, fix genericHead
* render TTypeKind via toHumanStr
  • Loading branch information
timotheecour authored Feb 9, 2020
1 parent debe7ff commit 7939319
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 20 deletions.
16 changes: 15 additions & 1 deletion compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import
lineinfos, hashes, options, ropes, idents, idgen, int128
from strutils import toLowerAscii

export int128

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
4 changes: 0 additions & 4 deletions compiler/semcall.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
11 changes: 10 additions & 1 deletion compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 16 additions & 10 deletions compiler/semmagic.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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":
Expand All @@ -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))
Expand Down
4 changes: 2 additions & 2 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
33 changes: 31 additions & 2 deletions tests/metatype/ttypetraits.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
20 changes: 20 additions & 0 deletions tests/types/tisopr.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 7939319

Please sign in to comment.