Skip to content

poc: move object equality out of system using macro #24220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/ic/packed_ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ type
module*: LitId # 0 if it's this module
item*: int32 # same as the in-memory representation

proc `==`*(a, b: PackedItemId): bool {.inline.} =
a.module == b.module and a.item == b.item

const
nilItemId* = PackedItemId(module: LitId(0), item: 0.int32)

Expand Down
6 changes: 6 additions & 0 deletions compiler/lineinfos.nim
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,12 @@ type

proc `==`*(a, b: FileIndex): bool {.borrow.}

proc `==`*(a, b: TLineInfo): bool {.inline.} =
result = a.line == b.line and a.fileIndex == b.fileIndex

proc exactEquals*(a, b: TLineInfo): bool {.inline.} =
result = a.fileIndex == b.fileIndex and a.line == b.line and a.col == b.col

proc hash*(i: TLineInfo): Hash =
hash (i.line.int, i.col.int, i.fileIndex.int)

Expand Down
6 changes: 0 additions & 6 deletions compiler/msgs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -448,12 +448,6 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string,
elif eh == doRaise:
raiseRecoverableError(s)

proc `==`*(a, b: TLineInfo): bool =
result = a.line == b.line and a.fileIndex == b.fileIndex

proc exactEquals*(a, b: TLineInfo): bool =
result = a.fileIndex == b.fileIndex and a.line == b.line and a.col == b.col

proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
const instantiationFrom = "template/generic instantiation from here"
const instantiationOfFrom = "template/generic instantiation of `$1` from here"
Expand Down
5 changes: 5 additions & 0 deletions lib/packages/docutils/dochelpers.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import std/strutils

when defined(nimPreviewSlimSystem):
import std/[assertions, syncio]
from std/objectequals import nil


type
Expand All @@ -42,6 +43,10 @@ proc `$`*(s: LangSymbol): string = # for debug
s.symKind, s.symTypeKind , s.name, s.generics, $s.isGroup,
$s.parametersProvided, $s.parameters, s.outType]

when defined(nimPreviewSlimSystem):
proc `==`*(a, b: LangSymbol): bool {.inline.} =
result = objectequals.`==`(a, b)

func nimIdentBackticksNormalize*(s: string): string =
## Normalizes the string `s` as a Nim identifier.
##
Expand Down
3 changes: 3 additions & 0 deletions lib/packages/docutils/rst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2661,6 +2661,9 @@ type
first, last: int
ColSeq = seq[ColumnLimits]

proc `==`*(a, b: ColSpec): bool {.inline.} =
a.start == b.start and a.stop == b.stop

proc tokStart(p: RstParser, idx: int): int =
result = p.tok[idx].col

Expand Down
3 changes: 3 additions & 0 deletions lib/packages/docutils/rstidx.nim
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ type
module*: string ## origin file, NOT a field in ``.idx`` file
aux*: string ## auxuliary field, NOT a field in ``.idx`` file

proc `==`*(a, b: IndexEntry): bool =
a.keyword == b.keyword and a.link == b.link

proc isDocumentationTitle*(hyperlink: string): bool =
## Returns true if the hyperlink is actually a documentation title.
##
Expand Down
4 changes: 4 additions & 0 deletions lib/pure/collections/heapqueue.nim
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,7 @@ proc `$`*[T](heap: HeapQueue[T]): string =
if result.len > 1: result.add(", ")
result.addQuoted(x)
result.add("]")

proc `==`*[T](a, b: HeapQueue[T]): bool {.inline.} =
## Equality operator for heaps.
result = a.data == b.data
53 changes: 53 additions & 0 deletions lib/std/objectequals.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
## This module implements a generic `==` operator for any given object type
## based on the given fields. `-d:nimPreviewSlimSystem` is recommended to use,
## the original version in `system` did not support object variants.

import std/macros

proc build(val1, val2, body, rl: NimNode, name1, name2: string): NimNode =
template useField(f): untyped =
newBlockStmt(
newStmtList(
newLetStmt(ident name1, newDotExpr(val1, f)),
newLetStmt(ident name2, newDotExpr(val2, f)),
copy body))
result = newStmtList()
for r in rl:
case r.kind
of nnkIdentDefs:
for f in r[0..^3]:
result.add(useField(f))
of nnkRecCase:
let kind = r[0][0]
result.add(useField(kind))
result.add quote do:
assert `val1`.`kind` == `val2`.`kind`, "case discriminators must be equal for zipFields"
var cs = newTree(nnkCaseStmt, newDotExpr(val1, kind))
for b in r[1..^1]:
var nb = copy(b)
nb[^1] = build(val1, val2, body, nb[^1], name1, name2)
cs.add(nb)
result.add(cs)
of nnkRecWhen:
var ws = newTree(nnkWhenStmt)
for b in r[1..^1]:
var nb = copy(b)
nb[^1] = build(val1, val2, body, nb[^1], name1, name2)
ws.add(nb)
result.add(ws)
else: error("unexpected record node " & $r.kind, r)

macro zipFields(val1, val2: object, name1, name2, body: untyped): untyped =
# requires that `val1` and `val2` have the same case branches!
var t = val1.getTypeImpl()
t.expectKind nnkObjectTy
result = build(val1, val2, body, t[^1], $name1, $name2)

proc `==`*[T: object](x, y: T): bool =
## Generic `==` operator for objects that is lifted from the fields
## of `x` and `y`. Works with object variants.
mixin `==`
zipFields(x, y, xf, yf):
if xf != yf:
return false
true
26 changes: 20 additions & 6 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1778,12 +1778,26 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
result = s[L]
setLen(s, L)

proc `==`*[T: tuple|object](x, y: T): bool =
## Generic `==` operator for tuples that is lifted from the components.
## of `x` and `y`.
for a, b in fields(x, y):
if a != b: return false
return true
proc `==`*[T, U](x, y: HSlice[T, U]): bool {.inline.} =
## Equality operator for slices.
mixin `==`
result = x.a == y.a and x.b == y.b

when defined(nimPreviewSlimSystem):
# no `object`, moved to std/objectequals
proc `==`*[T: tuple](x, y: T): bool =
## Generic `==` operator for tuples that is lifted from the components.
## of `x` and `y`.
for a, b in fields(x, y):
if a != b: return false
return true
else:
proc `==`*[T: tuple|object](x, y: T): bool =
## Generic `==` operator for tuples that is lifted from the components.
## of `x` and `y`.
for a, b in fields(x, y):
if a != b: return false
return true

proc `<=`*[T: tuple](x, y: T): bool =
## Generic lexicographic `<=` operator for tuples that is lifted from the
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/concurrency/tatomics.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ discard """
# test atomic operations

import std/[atomics, bitops]
import std/assertions
import std/[assertions, objectequals]


type
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/talgorithm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ discard """
#12928,10456

import std/[sequtils, algorithm, json, sugar]
import std/assertions
import std/[assertions, objectequals]

proc test() =
try:
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/tgenast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ discard """
import std/genasts
import std/macros
from std/strformat import `&`
import std/assertions
import std/[assertions, objectequals]
import ./mgenast

proc main =
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/timportutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ discard """
matrix: "--mm:refc; --mm:orc"
"""

import std/[importutils, assertions]
import std/[importutils, assertions, objectequals]
import stdtest/testutils
import mimportutils

Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/tjson.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ when not defined(js):
import std/streams
import stdtest/testutils
from std/fenv import epsilon
import std/[assertions, objectdollar]
import std/[assertions, objectdollar, objectequals]

proc testRoundtrip[T](t: T, expected: string) =
# checks that `T => json => T2 => json2` is such that json2 = json
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/tjsonmacro.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ discard """
"""

import json, strutils, options, tables
import std/assertions
import std/[assertions, objectequals]

# The definition of the `%` proc needs to be here, since the `% c` calls below
# can only find our custom `%` proc for `Pix` if defined in global scope.
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/tjsonutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import std/json
from std/math import isNaN, signbit
from std/fenv import epsilon
from stdtest/testutils import whenRuntimeJs
import std/[assertions, objectdollar]
import std/[assertions, objectdollar, objectequals]

proc testRoundtrip[T](t: T, expected: string) =
# checks that `T => json => T2 => json2` is such that json2 = json
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/tmarshal.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ discard """
"""

import std/marshal
import std/[assertions, objectdollar, streams]
import std/[assertions, objectdollar, objectequals, streams]

# TODO: add static tests

Expand Down
19 changes: 19 additions & 0 deletions tests/stdlib/tobjectequals.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
discard """
matrix: "-d:nimPreviewSlimSystem"
targets: "c cpp js"
"""

import std/[assertions, objectequals]

type Foo = object
a: int
case b: bool
of false:
c: string
else:
d: float

doAssert Foo(a: 1, b: false, c: "abc") == Foo(a: 1, b: false, c: "abc")
doAssert Foo(a: 1, b: false, c: "abc") != Foo(a: 2, b: false, c: "abc")
doAssert Foo(a: 1, b: false, c: "abc") != Foo(a: 1, b: true, d: 3.14)
doAssert Foo(a: 1, b: false, c: "abc") != Foo(a: 1, b: false, c: "def")
2 changes: 1 addition & 1 deletion tests/stdlib/tposix.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ discard """
when not defined(windows):

import posix
import std/[assertions, syncio]
import std/[assertions, syncio, objectequals]

var
u: Utsname
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/trandom.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ discard """
joinable: false # to avoid messing with global rand state
matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
"""
import std/[assertions, formatfloat]
import std/[assertions, formatfloat, objectequals]
import std/[random, math, stats, sets, tables]
import std/private/jsutils
when not defined(js):
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/tsequtils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ discard """
import std/sequtils
import strutils
from algorithm import sorted
import std/assertions
import std/[assertions, objectequals]

{.experimental: "strictEffects".}
{.push warningAsError[Effect]: on.}
Expand Down
1 change: 1 addition & 0 deletions tests/stdlib/tsortcall.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ discard """

import algorithm
import unittest
import std/objectequals


suite "test sort, sorted, and isSorted procs":
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/tsugar.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ x + y = 30
'''
"""
import std/[sugar, algorithm, random, sets, tables, strutils, sequtils]
import std/[syncio, assertions]
import std/[syncio, assertions, objectequals]

type # for capture test, ref #20679
FooCapture = ref object
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/ttables.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ discard """
"""

import tables, hashes
import std/assertions
import std/[assertions, objectequals]

type
Person = object
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/ttimes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ discard """
"""

import times, strutils, unittest
import std/assertions
import std/[assertions, objectequals]

when not defined(js):
import os
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/tunittest.nim
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ matrix: "--mm:refc; --mm:orc"
targets: "c js"
"""

import std/[unittest, sequtils, assertions]
import std/[unittest, sequtils, assertions, objectequals]
from std/unittest {.all.} import matchFilter

proc doThings(spuds: var int): int =
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/turi.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ discard """
import std/uri
from std/uri {.all.} as uri2 import removeDotSegments
from std/sequtils import toSeq
import std/assertions
import std/[assertions, objectequals]

template main() =
block: # encodeUrl, decodeUrl
Expand Down
2 changes: 1 addition & 1 deletion tests/stdlib/twrapnils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ discard """

import std/wrapnils
from std/options import get, isSome
import std/assertions
import std/[assertions, objectequals]

proc checkNotZero(x: float): float =
doAssert x != 0
Expand Down
Loading