-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sem all call nodes in generic type bodies + many required fixes (#23983)
fixes #23406, closes #23854, closes #23855 (test code of both compiles but separate issue exists), refs #23432, follows #23411 In generic bodies, previously all regular `nkCall` nodes like `foo(a, b)` were directly treated as generic statements and delayed immediately, but other call kinds like `a.foo(b)`, `foo a, b` etc underwent typechecking before making sure they have to be delayed, as implemented in #22029. Since the behavior for `nkCall` was slightly buggy (as in However the vast majority of calls in generic bodies out there are `nkCall`, and while there isn't a difference in the expected behavior, this exposes many issues with the implementation started in #22029 given how much more code uses it now. The portion of these issues that CI has caught are fixed in this PR but it's possible there are more. 1. Deref expressions, dot expressions and calls to dot expressions now handle and propagate `tyFromExpr`. This is most of the changes in `semexprs`. 2. For deref expressions to work in `typeof`, a new type flag `tfNonConstExpr` is added for `tyFromExpr` that calls `semExprWithType` with `efInTypeof` on the expression instead of `semConstExpr`. This type flag is set for every `tyFromExpr` type of a node that `prepareNode` encounters, so that the node itself isn't evaluated at compile time when just trying to get the type of the node. 3. Unresolved `static` types matching `static` parameters is now treated the same as unresolved generic types matching `typedesc` parameters in generic type bodies, it causes a failed match which delays the call instantiation. 4. `typedesc` parameters now reject all types containing unresolved generic types like `seq[T]`, not just generic param types by themselves. (using `containsGenericType`) 5. `semgnrc` now doesn't leave generic param symbols it encounters in generic type contexts as just identifiers, and instead turns them into symbol nodes. Normally in generic procs, this isn't a problem since the generic param symbols will be provided again at instantiation time (and in fact creating symbol nodes causes issues since `seminst` doesn't actually instantiate proc body node types). But generic types can try to be instantiated early in `sigmatch` which will give an undeclared identifier error when the param is not provided. Nodes in generic types (specifically in `tyFromExpr` which should be the only use for `semGenericStmt`) undergo full generic type instantiation with `prepareNode`, so there is no issue of these symbols remaining as uninstantiated generic types. 6. `prepareNode` now has more logic for which nodes to avoid instantiating. Subscripts and subscripts turned into calls to `[]` by `semgnrc` need to avoid instantiating the first operand, since it may be a generic body type like `Generic` in an expression like `Generic[int]`. Dot expressions cannot instantiate their RHS as it may be a generic proc symbol or even an undeclared identifier for generic param fields, but have to instantiate their LHS, so calls and subscripts need to still instantiate their first node if it's a dot expression. This logic still isn't perfect and needs the same level of detail as in `semexprs` for which nodes can be left as "untyped" for overloading/dot exprs/subscripts to handle, but should handle the majority of cases. Also the `efDetermineType` requirement for which calls become `tyFromExpr` is removed and as a result `efDetermineType` is entirely unused again. (cherry picked from commit ab18962)
- Loading branch information
Showing
13 changed files
with
381 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# issue #23854, not entirely fixed | ||
|
||
import std/bitops | ||
|
||
const WordBitWidth = sizeof(pointer) * 8 | ||
|
||
func wordsRequired*(bits: int): int {.inline.} = | ||
const divShiftor = fastLog2(uint32(WordBitWidth)) | ||
result = (bits + WordBitWidth - 1) shr divShiftor | ||
|
||
type | ||
Algebra* = enum | ||
BLS12_381 | ||
|
||
BigInt*[bits: static int] = object | ||
limbs*: array[wordsRequired(bits), uint] | ||
|
||
Fr*[Name: static Algebra] = object | ||
residue_form*: BigInt[255] | ||
|
||
Fp*[Name: static Algebra] = object | ||
residue_form*: BigInt[381] | ||
|
||
FF*[Name: static Algebra] = Fp[Name] or Fr[Name] | ||
|
||
template getBigInt*[Name: static Algebra](T: type FF[Name]): untyped = | ||
## Get the underlying BigInt type. | ||
typeof(default(T).residue_form) | ||
|
||
type | ||
EC_ShortW_Aff*[F] = object | ||
## Elliptic curve point for a curve in Short Weierstrass form | ||
## y² = x³ + a x + b | ||
## | ||
## over a field F | ||
x*, y*: F | ||
|
||
type FieldKind* = enum | ||
kBaseField | ||
kScalarField | ||
|
||
func bits*[Name: static Algebra](T: type FF[Name]): static int = | ||
T.getBigInt().bits | ||
|
||
template getScalarField*(EC: type EC_ShortW_Aff): untyped = | ||
Fr[EC.F.Name] | ||
|
||
# ------------------------------------------------------------------------------ | ||
|
||
type | ||
ECFFT_Descriptor*[EC] = object | ||
## Metadata for FFT on Elliptic Curve | ||
order*: int | ||
rootsOfUnity1*: ptr UncheckedArray[BigInt[EC.getScalarField().bits()]] # Error: in expression 'EC.getScalarField()': identifier expected, but found 'EC.getScalarField' | ||
rootsOfUnity2*: ptr UncheckedArray[BigInt[getScalarField(EC).bits()]] # Compiler SIGSEGV: Illegal Storage Access | ||
|
||
func new*(T: type ECFFT_Descriptor): T = | ||
discard | ||
|
||
# ------------------------------------------------------------------------------ | ||
|
||
template getBits[bits: static int](x: ptr UncheckedArray[BigInt[bits]]): int = bits | ||
|
||
proc main() = | ||
let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new() | ||
when false: echo getBits(ctx.rootsOfUnity2) # doesn't work yet? | ||
doAssert ctx.rootsOfUnity1[0].limbs.len == wordsRequired(255) | ||
doAssert ctx.rootsOfUnity2[0].limbs.len == wordsRequired(255) | ||
|
||
main() |
Oops, something went wrong.