Skip to content
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

Compiler internalError when using operations on empty untyped built-in set #23496

Open
n1kolasM opened this issue Apr 11, 2024 · 2 comments
Open

Comments

@n1kolasM
Copy link

Description

Operations on built-in set literal {} cause compiler internal error.
Code examples:

assert card({}) == 0
assert {} <= {}

Also, according to manual

The empty set is type compatible with any concrete set type.

So, binary operations with empty set literal and typed set should also work:

assert {} <= {1'u8}

Nim Version

Since nim 0.19.0 to devel, introduced in #7558
Directly tested version:

Nim Compiler Version 1.0.0 [Linux: amd64]
Compiled at 2024-04-11
Copyright (c) 2006-2019 by Andreas Rumpf

git hash: f7a8fc46c0012033917582eb740dc0343c093e35
active boot switches: -d:release
Nim Compiler Version 1.6.14 [Linux: amd64]
Compiled at 2023-06-27
Copyright (c) 2006-2023 by Andreas Rumpf

active boot switches: -d:release

Current Output

Error: internal error: invalid kind for firstOrd(tyEmpty)

Expected Output

# Code compiles, all asserts pass

Possible Solution

For operations only on empty set literal it is enough to add early return in toBitSet in compiler/nimsets.nim

proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
  result = @[]
  # Added early return
  if s.len == 0:
    return
  # Below is implementation from devel
  var first: Int128 = Zero
  var j: Int128 = Zero
  first = firstOrd(conf, s.typ.elementType)
  bitSetInit(result, int(getSize(conf, s.typ)))
  for i in 0..<s.len:
    if s[i].kind == nkRange:
      j = getOrdValue(s[i][0], first)
      while j <= getOrdValue(s[i][1], first):
        bitSetIncl(result, toInt64(j - first))
        inc(j)
    else:
      bitSetIncl(result, toInt64(getOrdValue(s[i]) - first))

Additional Information

No response

@Araq
Copy link
Member

Araq commented Apr 11, 2024

While what you say is true the compiler rejecting {} == {} with an error message like "cannot deduce the set's type" is also acceptable.

@n1kolasM
Copy link
Author

I agree that it may be acceptable to reject binary operations between empty set literal and typed set, because they are declared requiring same type is system, but consistency in cardinality on empty set literals is very useful for macros:

macro someMacro(body: untyped): untyped =
  template helperGenerateChecks(s: untyped): untyped =
    proc check(val: int): bool =
      when card(s) > 0:
        result = true # do some expensive check
      else:
        result = false # do some short-circuit

  var someSet = newNimNode(nnkCurly)
  # fill someSet based on body, possibly empty
  result = getAst(helperGenerateChecks(someSet))

And binary operations on empty sets are useful when comparing two sets generated by macros

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants