-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add experimental inferGenericTypes switch #22317
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
Conversation
|
Seems to work surprisingly well, think this would be quite nice for things like |
|
This is superb stuff, thank you so much! But you need to document well how it works in the manual and what its restrictions are. Especially mention that this does not allow for overloading based on the return type ( |
|
Thanks for the kind words, was honestly half expecting you to shut it down 😛 I assume this should go in a new section under generics? |
I suppose. |
|
Done, if there's any more I should specify or generally things to change let me know |
|
It would be super nice to have this for 2.0 but it needs to be behind an experimental flag for that. Also, watch your language in the manual, it should be more formal, there is no "you" and "the compiler", there is only how the type inference is performed, "who" does this is irrelevant. |
|
Manual (hopefully) fixed, what should the name of this flag be? Also does this mean it should go into the experimental manual instead? |
|
Also please add a test that ensures this works within object constructors where it comes up all the time too. |
|
It does not currently work in constructors as that is done differently, but gonna look into it |
|
Should it be allowed to infer only A) or also B)? type MyType[T] = object
x : T
proc giveValue[T]: T = discard
# A)
let x = MyType[int](x : giveValue())
# B)
let y: MyType[int] = MyType(x : giveValue())Edit: Case A works now, will look into B if desired |
|
Gonna wait for tests and your opinion before continuing. Does this type reduction make sense or is it too expensive? |
|
Сurrent implementation does not support auto type. proc giveValue[T]: auto = default(T)
let a: int = giveValue()To fix it i propose to change elif resNode.kind == nkIdent:to elif resNode.kind == nkIdent or resNode.typ != nil and resNode.typ.kind == tyAnything:in inheritBindings proc |
|
Thanks for pointing that out, completely forgot about auto. After looking at it though I don't really see a way to integrate auto into this smoothly for now because it acts weird when combined with "normal" generics. Will be easier to see in a moment, am experimenting with that type reduction for the entire pass (seems broken though) |
|
Now that this is ready for review once more, what changed since last time is that types now get reduced until only a flat generic parameter such as This makes nesting much more consistent and allows tuples to participate as well. Allowed the previous commit's CI run to finish with the flag not checked to verify that everything (that is tested) works as before. |
| flatUnbound: seq[PType] | ||
| flatBound: seq[PType] | ||
| # seq[(result type, expected type)] | ||
| var typeStack = newSeq[(PType, PType)]() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the effects of this computation on the overall compile-times?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, asked the same before without receiving a response. Will copy and paste a million lines or so to test (on that note it seems that hints/errors are all on the same line after line of uint16's max is reached)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using this code to generate two files, they both take about the same amount of time (immeasurable, they go back and forth. If you know of a better way to test please tell me). The cache was cleared before each compile. Memory usage in this specific test seems to be slightly better for the inferred version, but for other tests the one without inference uses less memory. The version of the nim compiler I used had the check for inferGenericTypes enabled.
Code
const copies = 10_000
block:
var code = """{.experimental: "inferGenericTypes".}
type
TestType[A, B, C, D, E, F, G, H, I, J] = object
proc giveData[A, B, C, D, E, F, G, H, I, J](): TestType[A, B, C, D, seq[E], F, G, H, I, seq[seq[J]]] = discard
var x: TestType[int, float, int, char, seq[byte], int16, uint32, seq[float], int, seq[seq[int]]] = giveData()
"""
for i in 0 ..< copies:
code.add("x = giveData()" & "\n")
writeFile("out1.nim", code)
block:
var code = """type
TestType[A, B, C, D, E, F, G, H, I, J] = object
proc giveData[A, B, C, D, E, F, G, H, I, J](): TestType[A, B, C, D, seq[E], F, G, H, I, seq[seq[J]]] = discard
var x = giveData[int, float, int, char, seq[byte], int16, uint32, seq[float], int, seq[seq[int]]]()
"""
for i in 0 ..< copies:
code.add("x = giveData[int, float, int, char, seq[byte], int16, uint32, seq[float], int, seq[seq[int]]]()" & "\n")
writeFile("out2.nim", code)|
I playing with your code and added auto type support (not full because it not retrieve generic parameter from out type in procedures) and simple case B) implementation |
|
Thanks for your hard work on this PR! Hint: mm: orc; opt: speed; options: -d:release |
This PR aims to allow generic procs and templates to inherit generic parameters from their expected type, so either the lhs or a result expression.
Snippet adapted from tests, which contain other examples for how to use it
{.experimental: "inferGenericTypes".} var x: seq[int] x = newSeq(1) doAssert x is seq[int] doAssert x.len() == 1Previously this would fail at compiletime with the error
Error: cannot instantiate: 'T'No existing code should break or be incompatible, this is a purely additive feature that in my opinion makes generics a bit nicer to use