fixes#15959
Another followup of #22029 and #24005, subscript expressions now
recognize when their parameters are generic types, then generating
tyFromExpr. `typeof` also now properly sets `tfNonConstExpr` to make it
usable in proc signatures. `lent` with brackets like `lent[T]` is also
now allowed.
I noticed after #24005 the auto-reported boot time in PRs increased from
around 8 seconds to 8.8 seconds, but I wasn't sure what could cause a
performance problem that made the compiler itself compile slower, most
of the changes were related to `static` which the compiler code doesn't
use too often. So I figured it was unrelated.
However there is still a performance problem with the changes to
`tryReadingGenericParam`. If an expression like `a.b` doesn't match any
of the default dot field behavior (for example, is actually a call
`b(a)`), the compiler does a final check to see if `b` is a generic
parameter of `a`. Since #24005, if the type of `a` is not
`tyGenericInst` or an old concept type, the compiler does a full
traversal of the type of `a` to see if it contains a generic type, only
then checking for `c.inGenericContext > 0` to not return `nil`. This
happens on *every* dot call.
Instead, we now check for `c.inGenericContext > 0` first, only then
checking if it contains a generic type, saving performance by virtue of
`c.inGenericContext > 0` being both cheap and less commonly true. The
`containsGenericType` could also be swapped out for more generic type
kind checks, but I think this is incorrect even if it might pass CI.
fixes#22342, fixes#22607
Another followup of #22029, `when` expressions in general in generic
type bodies now behave like `nkRecWhen` does since #24042, leaving them
as `tyFromExpr` if a condition is uncertain. The tests for the issues
were originally added but left disabled in #24005.
fixes#16700, fixes#20916, refs #24010
Fixes the instantiation issues for proc param default values encountered
in #24010 by:
1. semchecking generic default param values with `inGenericContext` for
#22029 and followups to apply (the bigger change in semtypes),
2. rejecting explicit generic instantiations with unresolved generic
types inside `inGenericContext` (sigmatch change),
3. instantiating the default param values using `prepareNode` rather
than an insufficient manual method (the bigger change in seminst).
This had an important side effect of references to other parameters not
working since they would be resolved as a symbol belonging to the
uninstantiated original generic proc rather than the later instantiated
proc. There is a more radical way to fix this which is generating ident
nodes with `tyFromExpr` in specifically this context, but instead we
just count them as belonging to the same proc in
`hoistParamsUsedInDefault`.
Other minor bugfixes:
* To make the error message in t20883 make sense, we now give a "cannot
instantiate" error when trying to instantiate a proc generic param with
`tyFromExpr`.
* Object constructors as default param values generated default values
of private fields going through `evalConstExpr` more than once, but the
VM doesn't mark the object fields as `nfSkipFieldChecking` which gives a
"cannot access field" error. So the VM now marks object fields it
generates as `nfSkipFieldChecking`. Not sure if this affects VM
performance, don't see why it would.
* The nkRecWhen changes in #24042 didn't cover the case where all
conditions are constantly false correctly, this is fixed with a minor
change. This isn't needed for this PR now but I encountered it after
forgetting to `dec c.inGenericContext`.
The magic `mArrGet`/`mArrPut` subscript overloads always match, so if a
subscript doesn't match any other subscript overloads and isn't a
regular language-handled subscript, it creates a fake overload mismatch
error in `semArrGet` that doesn't have any information (gives stuff like
"first mismatch at index: 0" for every single mismatch). Instead of
generating the fake mismatches, we only generate the fake mismatch for
`mArrGet`/`mArrPut`, and process every overload except them as a real
call and get the errors from there.
refs #21682, refs #24038
The `rangeBase` typetrait added in #21682 which gives the base type of a
range type is now added publicly to `typetraits`. Previously it was only
privately used in `repr_v2` and in `enumutils` since #24052
(coincidentally I didn't see this until now). This is part of an effort
to make range types easier to work with in generics, as mentioned in
#24038. Its use combined with #24037 is also tested.
The condition for the "enum to enum conversion" warning is now also
restricted to conversions between different enum base types, i.e.
conversion between an enum type and a range type of itself doesn't give
a warning. I put this in this PR since the test gave the warning and so
works as a regression test.
fixes#13979
Fixes templates in generics that use identifiers that aren't defined
yet, giving an early `undeclared identifier` error, by just marking
template bodies as in a mixin context in `semgnrc`.
in https://forum.nim-lang.org/t/12463 which seems reasonable enough to
me.
stdlib has several dozens of places doing result.setLen now, but if
`experimental:strictDefs` move sot on by default and there is no easy
way to locally suppress the warning we can revisit this.
fixes#24054
`readData` is not implemented for the VM as mentioned in the issue, but
`readDataStr` is, so that is used for `readStr` instead on the VM. We
could also just use it in general since it falls back to `readData`
anyway but it's kept the same otherwise for now.
Also where and why streams in general don't work in VM is now documented
on the top level `streams` module documentation.
refs #24032, split from #24036
Conversion from variables of range types or base types of range types to
the other are now considered mutable for `var` params, similar to how
distinct types are mutable when converted to their base type or vice
versa. There are 2 main differences:
1. Conversions from base types to range types need to emit
`nkChckRange`, which is not generated for things like tuple/object
fields.
2. Range types can still correspond to different types in the backend
when nested in other types, such as `set[range[3..5]]` vs
`set[range[0..5]]`.
Since the convertibility check for `var` params and a check whether to
emit a no-op for `nkConv` (and now also `nkChckRange`) so that the
output is still addressable both use `sameType`, we accomplish this by
adding a new flag to `sameType` that ignores range types, but only when
they're not nested in other types. The implementation for this might be
flawed, I didn't include children of some metatypes as "nested in other
types", but stuff like `tyGenericInst` params are respected.
fixes#24044
When matching a `tyFromExpr` against a `static` generic parameter,
`paramTypesMatch` tries to evaluate it as a constant expression, which
causes a segfault in the case of #24044. In #24005 a consequence of the
same behavior was an issue where `nkStaticExpr` was created for
`tyFromExpr` which made it not instantiate, so only the generation of
`nkStaticExpr` was disabled. Instead we now just completely ignore
`tyFromExpr` matching a `static` generic parameter in generic contexts
and keep it untouched.
fixes#24048
Generic lambdas get instantiated via `replaceTypesInBody` which calls
`replaceTypeVarsN` on the body of the lambda. This body can contain sym
nodes of gensym symbols generated by macros, which have `nil` type. But
a piece of code in `replaceTypeVarsN` checks whether the type of a
symbol is equal to `void` without checking if it's `nil` first, which
causes a segfault. Now it also checks that the type of the symbol isn't
`nil` for it to be `void`.
fixes#16376
The way the compiler handled generic proc instantiations in calls (like
`foo[int](...)`) up to this point was to instantiate `foo[int]`, create
a symbol for the instantiated proc (or a symchoice for multiple procs
excluding ones with mismatching generic param counts), then perform
overload resolution on this symbol/symchoice. The exception to this was
when the called symbol was already a symchoice node, in which case it
wasn't instantiated and overloading was called directly ([these
lines](b7b1313d21/compiler/semexprs.nim (L3366-L3371))).
This has several problems:
* Templates and macros can't create instantiated symbols, so they
couldn't participate in overloaded explicit generic instantiations,
causing the issue #16376.
* Every single proc that can be instantiated with the given generic
params is fully instantiated including the body. #9997 is about this but
isn't fixed here since the instantiation isn't in a call.
The way overload resolution handles explicit instantiations by itself is
also buggy:
* It doesn't check constraints.
* It allows only partially providing the generic parameters, which makes
sense for implicit generics, but can cause ambiguity in overloading.
Here is how this PR deals with these problems:
* Overload resolution now always handles explicit generic instantiations
in calls, in `initCandidate`, as long as the symbol resolves to a
routine symbol.
* Overload resolution now checks the generic params for constraints and
correct parameter count (ignoring implicit params). If these don't
match, the entire overload is considered as not matching and not
instantiated.
* Special error messages are added for mismatching/missing/extra generic
params. This is almost all of the diff in `semcall`.
* Procs with matching generic parameters now instantiate only the type
of the signature in overload resolution, not the proc itself, which also
works for templates and macros.
Unfortunately we can't entirely remove instantiations because overload
resolution can't handle some cases with uninstantiated types even though
it's resolved in the binding (see the last 2 blocks in
`texplicitgenerics`). There are also some instantiation issues with
default params that #24005 didn't fix but I didn't want this to become
the 3rd huge generics PR in a row so I didn't dive too deep into trying
to fix them. There is still a minor instantiation fix in `semtypinst`
though for subscripts in calls.
Additional changes:
* Overloading of `[]` wasn't documented properly, it somewhat is now
because we need to mention the limitation that it can't be done for
generic procs/types.
* Tests can now enable the new type mismatch errors with just
`-d:testsConciseTypeMismatch` in the command.
Package PRs:
- using fork for now:
[combparser](https://github.com/PMunch/combparser/pull/7) (partial
generic instantiation)
- merged: [cligen](https://github.com/c-blake/cligen/pull/233) (partial
generic instantiation but non-overloaded + template)
- merged: [neo](https://github.com/andreaferretti/neo/pull/56) (trying
to instantiate template with no generic param)
fixes#24041
`when` statements in generic object types normally just leave their
conditions as expressions and still typecheck their branch bodies.
Instead of this, when the condition can be evaluated as a constant as
well as the ones before it and it resolves to `true`, it now uses the
body of that branch without typechecking the remaining ones.
closes#1969, closes#7547, closes#7737, closes#11838, closes#12283,
closes#12714, closes#12720, closes#14053, closes#16118, closes
#19670, closes#22645
I was going to wait on these but regression tests even for recent PRs
are turning out to be important in wide reaching PRs like #24010.
The other issues with the working label felt either finnicky (#7385,
#9156, #12732, #15247), excessive to test (#12405, #12424, #17527), or I
just don't know what fixed them/what the issue was (#16128: the PR link
gives a server error by Github, #12457, #12487).
Removes some noise from the bug report issue template so people who
aren't familiar can submit issues with less friction. Some of these
might be a bit subjective, feel free to call out any nitpicky parts, I
didn't want to rewrite entirely. Mostly fixed typos & language issues,
other than that:
* Just "detailed information", no need to say "descriptive", and changed
"reproducible code and detailed information" to "or detailed
information" because code is good enough
* Simplified description label, mention code example can go there
* Changed "Possible Solution" to "Known Workarounds" because it's what
issue authors are more likely to know (and usually write anyway) and is
more useful to most readers.
* Doc link for "rebuilding the compiler" was broken, replaced it with
mentioning choosenim, nightlies and building a temp compiler which is
hopefully less offputting
Weird looking preview
[here](https://github.com/metagn/Nim/blob/issue-templates/.github/ISSUE_TEMPLATE/bug_report.yml)
Just to complain: Github issue forms have some problems themselves,
there's no option to disable the "No response" text when an optional
area is unfilled, and the textboxes are really small at least on Firefox
(though you can expand them). The alternative, issue templates, isn't
much better. Github also hides the ability to open a blank issue in a
text link in a small line after all the issue form buttons, I'm guessing
this is intentional for repositories which don't want blank issues but
we don't have such a problem. Worst comes to worst we can add a button
for a minimal/empty issue template.
fixes#12539, refs #21636
`evalInclude` now uses `getPIdent` to check if a symbol isn't `/`
anymore instead of assuming it's an ident, which it's not when used in
templates. Also it just checks if the symbol is `as` now, because there
are other infix operators that could be used like `/../`.
It also works with prefix operators now by copying what was done in
#21636.
#23992 The test case provided does not cover the Windows situation, I
fixed it in this new PR.
Fixed an issue where errorCode was always 0 when startProcess didn't use
the poEvalCommand flag.
Tthe sleep command might not be available in all Windows installations,
so I skipped the relevant test.
Added a test case, tested on my fedora and windows systems.
fixes#15314, fixes#24002
The OpenSym behavior first added to generics in #23091 now also applies
to templates, since templates can also capture symbols that are meant to
be replaced by local symbols if the context imports symbols with the
same name, as in the issue #24002. The experimental switch
`templateOpenSym` is added to enable this behavior for templates only,
and the experimental switch `openSym` is added to enable it for both
templates and generics, and the documentation now mainly mentions this
switch.
Additionally the logic for `nkOpenSymChoice` nodes that were previously
wrapped in `nkOpenSym` now apply to all `nkOpenSymChoice` nodes, and so
these nodes aren't wrapped in `nkOpenSym` anymore. This means
`nkOpenSym` can only have children of kind `nkSym` again, so it is more
in line with the structure of symchoice nodes. As for why they aren't
merged with `nkOpenSymChoice` nodes yet, we need some way to signal that
the node shouldn't become ambiguous if other options exist at
instantiation time, we already captured a symbol at the beginning and
another symbol can only replace it if it's closer in scope and
unambiguous.
updated version of #22193
After #22029 and the followups #23983 and #24005 which fixed issues with
it, `tyFromExpr` no longer match any proc params in generic type bodies
but delay all non-matching calls until the type is instantiated.
Previously the mechanism `fauxMatch` was used to pretend that any
failing match against `tyFromExpr` actually matched, but prevented the
instantiation of the type until later.
Since this mechanism is not needed anymore for `tyFromExpr`, it is now
only used for `tyError` to prevent cascading errors and changed to a
bool field for simplicity. A change in `semtypes` was also needed to
prevent calling `fitNode` on default param values resolving to type
`tyFromExpr` in generic procs for params with non-generic types, as this
would try to coerce the expression into a concrete type when it can't be
instantiated yet.
The aliases `tyProxy` and `tyUnknown` for `tyError` and `tyFromExpr` are
also removed for uniformity.
Follow up of #23927 which solves the build error.
This is still only a partial fix as it doesn't take into account
unordered enums. I'll make a separate issue for those.
---------
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
This is a very niche case encountered in #24012, where an int literal
got a `range` type as a result of a generic instantiation (in
`tgenericcomputedrange`), I can't think of another test case. The base
type of the range being `int` made it match `int` with `isSubrange` as
in the first `if` branch, but other int types like `int32` matched with
`isFromIntLit` which is a better match.
Instead, int literals with range type now:
1. match their base type with `isFromIntLit`,
2. don't match other int types with `isFromIntLit`, instead giving
`isConvertible` as in the last `if` branch in `handleRange`.
fixes#4228, fixes#4990, fixes#7006, fixes#7008, fixes#8406, fixes
#8551, fixes#11112, fixes#20027, fixes#22647, refs #23854 and #23855
(remaining issue fixed), refs #8545 (works properly now with
`cast[static[bool]]` changed to `cast[bool]`), refs #22342 and #22607
(disabled tests added), succeeds #23194
Parameter and return type nodes in generic procs now undergo the same
`inGenericContext` treatment that nodes in generic type bodies do. This
allows many of the fixes in #22029 and followups to also apply to
generic proc signatures. Like #23983 however this needs some more
compiler fixes, but this time mostly in `sigmatch` and type
instantiations.
1. `tryReadingGenericParam` no longer treats `tyCompositeTypeClass` like
a concrete type anymore, so expressions like `Foo.T` where `Foo` is a
generic type don't look for a parameter of `Foo` in non-generic code
anymore. It also doesn't generate `tyFromExpr` in non-generic code for
any generic LHS. This is to handle a very specific case in `asyncmacro`
which used `FutureVar.astToStr` where `FutureVar` is generic.
2. The `tryResolvingStaticExpr` call when matching `tyFromExpr` in
sigmatch now doesn't consider call nodes in general unresolved, only
nodes with `tyFromExpr` type, which is emitted on unresolved expressions
by increasing `c.inGenericContext`. `c.inGenericContext == 0` is also
now required to attempt instantiating `tyFromExpr`. So matching against
`tyFromExpr` in proc signatures works in general now, but I'm
speculating it depends on constant folding in `semExpr` for statics to
match against it properly.
3. `paramTypesMatch` now doesn't try to change nodes with `tyFromExpr`
type into `tyStatic` type when fitting to a static type, because it
doesn't need to, they'll be handled the same way (this was a workaround
in place of the static type instantiation changes, only one of the
fields in the #22647 test doesn't work with it).
4. `tyStatic` matching now uses `inferStaticParam` instead of just range
type matching, so `Foo[N div 2]` can infer `N` in the same way `array[N
div 2, int]` can. `inferStaticParam` also disabled itself if the
inferred static param type already had a node, but `makeStaticExpr`
generates static types with unresolved nodes, so we only disable it if
it also doesn't have a binding. This might not work very well but the
static type instantiation changes should really lower the amount of
cases where it's encountered.
5. Static types now undergo type instantiation. Previously the branch
for `tyStatic` in `semtypinst` was a no-op, now it acts similarly to
instantiating any other type with the following differences:
- Other types only need instantiation if `containsGenericType` is true,
static types also get instantiated if their value node isn't a literal
node. Ideally any value node that is "already evaluated" should be
ignored, but I'm not sure of a better way to check this, maybe if
`evalConstExpr` emitted a flag. This is purely for optimization though.
- After instantiation, `semConstExpr` is called on the value node if
`not cl.allowMetaTypes` and the type isn't literally a `static` type.
Then the type of the node is set to the base type of the static type to
deal with `semConstExpr` stripping abstract types.
We need to do this because calls like `foo(N)` where `N` is `static int`
and `foo`'s first parameter is just `int` do not generate `tyFromExpr`,
they are fully typed and so `makeStaticExpr` is called on them, giving a
static type with an unresolved node.
fixes#23898, supersedes #23966 and #23990
Since #20631 ambiguous type symbols in templates are rejected outright,
now we generate a symchoice for type nodes if they're ambiguous, a
generalization of what was done in #22375. This is done for generics as
well. Symchoices also handle type symbols better now, ensuring their
type is a `typedesc` type; this probably isn't necessary for everything
to work but it makes the logic more robust.
Similar to #23989, we have to prepare for the fact that ambiguous type
symbols behave differently than normal type symbols and either error
normally or relegate to other routine symbols if the symbol is being
called. Generating a symchoice emulates this behavior, `semExpr` will
find the type symbol first, but since the symchoice has other symbols,
it will count as an ambiguous type symbol.
I know it seems spammy to carry around an ambiguity flag everywhere, but
in the future when we have something like #23104 we could just always
generate a symchoice, and the symchoice itself would carry the info of
whether the first symbol was ambiguous. But this could harm compiler
performance/memory use, it might be better to generate it only when we
have to, which in the case of type symbols is only when they're
ambiguous.
It speeds up
```nim
proc foo =
let piece = cast[seq[char]](newSeqUninit[uint8](5220600386'i64))
foo()
```
Notes that `cast[ref](...)` is excluded because we need to keep the ref
alive if the parameter is something with pointer types (e.g.
`cast[ref](pointer)`or `cast[ref](makePointer(...))`)
---------
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
fixes#21258
When a generic proc is instantiated, if one of the default values
doesn't match the type of the parameter, `seminst` sets the default
parameter node to an `nkEmpty` node with `tyError` type. `sigmatch`
checks for this to give an error message if the default param is
actually used, but only while actively matching the proc signature,
before the proc is even instantiated. The error message also gives very
little information.
Now, we check for this in `updateDefaultParams` at the end of
`semResolvedCall`, after the proc has been instantiated. The `nkEmpty`
node also is given the original mismatching type instead rather than
`tyError`, only setting `tyError` after erroring to prevent cascading
errors. The error message is changed to the standard type mismatch error
also giving the instantiation info of the routine.
fixes#19737
As in the diff, `semResolvedCall` sets the return type of a call to a
proc to the type of the call. But in the case of the [subscript
magic](https://nim-lang.org/docs/system.html#%5B%5D%2CT%2CI), this type
is the first generic param which is also supposed to be the type of the
first argument, but this is invalid, the correct type is the element
type eventually given by `semSubscript`. Some lines above also [prevent
the subscript magics from instantiating their
params](dda638c1ba/compiler/semcall.nim (L699))
so this type ends up being an unresolved generic param.
Since the type of the node is not `nil`, `prepareOperand` doesn't try to
type it again, and this unresolved generic param type ends up being the
final type of the node. To prevent this, we just never set the type of
the node if we encountered a subscript magic.
Maybe we could also rename the generic parameters of the subscript
magics to stuff like `DummyT`, `DummyI` if we want this to be easier to
debug in the future.