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

make empty seq literals work #470

Open
metagn opened this issue Feb 6, 2025 · 3 comments
Open

make empty seq literals work #470

metagn opened this issue Feb 6, 2025 · 3 comments
Assignees

Comments

@metagn
Copy link
Collaborator

metagn commented Feb 6, 2025

Could use something like --experimental:inferGenericParams and depend on top down type inference, but this probably wouldn't be able to handle:

proc foo(x: seq[int]) = discard

foo(@[])

So we might still need to use an Empty type as in the old compiler but make sure it always gets checked.

This case already doesn't work in the old compiler:

proc foo(x: seq[int]) = discard
proc bar[T](x: seq[T]): seq[T] = x

foo(bar(@[]))
@metagn
Copy link
Collaborator Author

metagn commented Feb 8, 2025

Thought about it for a while, best I've come up with so far is:

  • Call arguments whitelist empty array/set literals. Semchecking them gives the type auto
  • If necessary, a call argument with type auto is checked to be an empty array/set literal and allowed
  • Array/set types check for these in sigmatch and convert the empty literal argument, probably by adding Hconv as we should be able to handle stuff like set[int8]({}) anyway

For seqs, provided they stay completely independent from the compiler:

  • If an array/set type has an unbound generic element type and matches to an empty literal, a flag is set for the entire match that it is an empty literal call
    • Can be whitelisted by call arguments again, otherwise producing an error "cannot infer type of empty literal"
  • Empty literal calls do not instantiate procs or expand templates, they stay as calls and have the type auto
  • If a call argument has type auto after semchecking and is a call with an empty literal argument, the argument item is marked as an empty literal call
  • When empty literal call arguments are matched to a parameter in sigmatch, a flipped match is performed between the return type of the call symbol and the (instantiated?) parameter type:
  • If the full call match succeeds, the inferred parameters from the flipped match are used to call sigmatch on the empty literal call itself and the argument becomes the fully instantiated empty literal call (probably in addArgsInstConverters)

This does not have to stack with converters as it already doesn't in the old compiler.

What calls are allowed to be "empty literal calls" can be restricted as much as necessary given they match @. They might have to consider multiple overloads though.

Instantiating the parameter type to perform the flipped match imply that should be done in sem and not in sigmatch, but it doesn't really make sense to do this after the matches fail like converters given that the empty literal call arguments will always fail to match if not handled. Doing them in sigmatch would mean we still need context.instantiateType etc though, but maybe this is an OK exception.

Another option might be to make the compiler aware of seq and @, but this would need @[] to compile to a node that the compiler can treat like the normal empty literals, which would mean sigmatch has to check if it is matching seq against it, something that is not even done for string, not to mention generic/instantiated variants of seq.

Final note: To make [] work with converters i.e. to openarray, we might have to somehow match the instantiated parameter type to the converter return type (the inverse of the final match) before matching the converter input just to use the inferred generic parameters. But this cannot bind to any remaining generic parameters in the instantiated parameter type. I'm not sure if we can reuse this logic to work for @.

@Araq
Copy link
Member

Araq commented Feb 9, 2025

Random idea: Just make [] compatible with seq somehow so that var x: seq[int] = [] works. Then add a nop @ template to system:

template `@`[I, T](x: array[I, T]): array[I, T] = x

@Araq
Copy link
Member

Araq commented Feb 9, 2025

Though ideally @ is just:

proc `@`*[I, T](a: array[I, T]): seq[T] {.nodestroy.} =
  result = newSeqUninit[T](a.len)
  var i = 0
  while i < result.len:
    (result.data[i]) = `=dup`(a[i])
    inc i

Maybe if we make @ a magic that has a special typing rule allowing for the empty array [] and is mapped to a toSeqImpl proc that is the above...

This was referenced Feb 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants