From cc984217a98438de5a36447ea6574eb2c5da4ae4 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Tue, 2 Nov 2021 02:02:53 -0600 Subject: [PATCH] Fix VM's sametype impl to work for generics/typedescs (#19073) * Fix vm's sametype implementation to properly handle generics and typedescs * actually fixed sametype + have test * added comments and removed unsafe code --- compiler/types.nim | 5 ++++ compiler/vm.nim | 3 ++- tests/stdlib/tmacros.nim | 58 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/compiler/types.nim b/compiler/types.nim index 2c7b91d9f7..7cf02c2405 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1128,6 +1128,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = a = a.skipTypes({tyDistinct, tyGenericInst}) if a.kind != b.kind: return false + #[ + The following code should not run in the case either side is an generic alias, + but it's not presently possible to distinguish the genericinsts from aliases of + objects ie `type A[T] = SomeObject` + ]# # this is required by tunique_type but makes no sense really: if tyDistinct notin {x.kind, y.kind} and x.kind == tyGenericInst and IgnoreTupleFields notin c.flags: let diff --git a/compiler/vm.nim b/compiler/vm.nim index 1b443aff18..b645450817 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1044,7 +1044,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = strictSymEquality=true)) of opcSameNodeType: decodeBC(rkInt) - regs[ra].intVal = ord(regs[rb].node.typ.sameTypeOrNil regs[rc].node.typ) + regs[ra].intVal = ord(regs[rb].node.typ.sameTypeOrNil(regs[rc].node.typ, {ExactTypeDescValues, ExactGenericParams})) + # The types should exactly match which is why we pass `{ExactTypeDescValues..ExactGcSafety}`. of opcXor: decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal) diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim index 18cfdc75c4..64a474743b 100644 --- a/tests/stdlib/tmacros.nim +++ b/tests/stdlib/tmacros.nim @@ -66,3 +66,61 @@ block: # unpackVarargs doAssert call1(toString) == "" doAssert call1(toString, 10) == "10" doAssert call1(toString, 10, 11) == "1011" + +block: # SameType + type + A = int + B = distinct int + C = object + Generic[T, Y] = object + macro isSameType(a, b: typed): untyped = + newLit(sameType(a, b)) + + static: + assert Generic[int, int].isSameType(Generic[int, int]) + assert Generic[A, string].isSameType(Generic[int, string]) + assert not Generic[A, string].isSameType(Generic[B, string]) + assert not Generic[int, string].isSameType(Generic[int, int]) + assert isSameType(int, A) + assert isSameType(10, 20) + assert isSameType("Hello", "world") + assert not isSameType("Hello", cstring"world") + assert not isSameType(int, B) + assert not isSameType(int, Generic[int, int]) + assert not isSameType(C, string) + assert not isSameType(C, int) + + + #[ + # compiler sameType fails for the following, read more in `types.nim`'s `sameTypeAux`. + type + D[T] = C + G[T] = T + static: + assert isSameType(D[int], C) + assert isSameType(D[int], D[float]) + assert isSameType(G[float](1.0), float(1.0)) + assert isSameType(float(1.0), G[float](1.0)) + ]# + + type Tensor[T] = object + data: T + + macro testTensorInt(x: typed): untyped = + let + tensorIntType = getTypeInst(Tensor[int])[1] + xTyp = x.getTypeInst + + newLit(xTyp.sameType(tensorIntType)) + + var + x: Tensor[int] + x1 = Tensor[float]() + x2 = Tensor[A]() + x3 = Tensor[B]() + + static: + assert testTensorInt(x) + assert not testTensorInt(x1) + assert testTensorInt(x2) + assert not testTensorInt(x3)