-
-
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.
delay resolved procvar check for proc params + acknowledge unresolved…
… statics (#23188) fixes #23186 As explained in #23186, generics can transform `genericProc[int]` into a call `` `[]`(genericProc, int) `` which causes a problem when `genericProc` is resemmed, since it is not a resolved generic proc. `[]` needs unresolved generic procs since `mArrGet` also handles explicit generic instantiations, so delay the resolved generic proc check to `semFinishOperands` which is intentionally not called for `mArrGet`. The root issue for [t6137](https://github.com/nim-lang/Nim/blob/devel/tests/generics/t6137.nim) is also fixed (because this change breaks it otherwise), the compiler doesn't consider the possibility that an assigned generic param can be an unresolved static value (note the line `if t.kind == tyStatic: s.ast = t.n` below the change in sigmatch), now it properly errors that it couldn't instantiate it as it would for a type param. ~~The change in semtypinst is just for symmetry with the code above it which also gives a `cannot instantiate` error, it may or may not be necessary/correct.~~ Now removed, I don't think it was correct. Still possible that this has unintended consequences.
- Loading branch information
Showing
8 changed files
with
196 additions
and
23 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
# issue #23186 | ||
|
||
block: # simplified | ||
template typedTempl(x: int, body): untyped = | ||
body | ||
proc generic1[T]() = | ||
discard | ||
proc generic2[T]() = | ||
typedTempl(1): | ||
let x = generic1[T] | ||
generic2[int]() | ||
|
||
import std/macros | ||
|
||
when not compiles(len((1, 2))): | ||
import std/typetraits | ||
|
||
func len(x: tuple): int = | ||
arity(type(x)) | ||
|
||
block: # full issue example | ||
type FieldDescription = object | ||
name: NimNode | ||
func isTuple(t: NimNode): bool = | ||
t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple") | ||
proc collectFieldsFromRecList(result: var seq[FieldDescription], | ||
n: NimNode, | ||
parentCaseField: NimNode = nil, | ||
parentCaseBranch: NimNode = nil, | ||
isDiscriminator = false) = | ||
case n.kind | ||
of nnkRecList: | ||
for entry in n: | ||
collectFieldsFromRecList result, entry, | ||
parentCaseField, parentCaseBranch | ||
of nnkIdentDefs: | ||
for i in 0 ..< n.len - 2: | ||
var field: FieldDescription | ||
field.name = n[i] | ||
if field.name.kind == nnkPragmaExpr: | ||
field.name = field.name[0] | ||
if field.name.kind == nnkPostfix: | ||
field.name = field.name[1] | ||
result.add field | ||
of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty: | ||
discard | ||
else: | ||
doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr | ||
proc collectFieldsInHierarchy(result: var seq[FieldDescription], | ||
objectType: NimNode) = | ||
var objectType = objectType | ||
if objectType.kind == nnkRefTy: | ||
objectType = objectType[0] | ||
let recList = objectType[2] | ||
collectFieldsFromRecList result, recList | ||
proc recordFields(typeImpl: NimNode): seq[FieldDescription] = | ||
let objectType = case typeImpl.kind | ||
of nnkObjectTy: typeImpl | ||
of nnkTypeDef: typeImpl[2] | ||
else: | ||
macros.error("object type expected", typeImpl) | ||
return | ||
collectFieldsInHierarchy(result, objectType) | ||
proc skipPragma(n: NimNode): NimNode = | ||
if n.kind == nnkPragmaExpr: n[0] | ||
else: n | ||
func declval(T: type): T = | ||
doAssert false, | ||
"declval should be used only in `typeof` expressions and concepts" | ||
default(ptr T)[] | ||
macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped = | ||
var typeAst = getType(T)[1] | ||
var typeImpl: NimNode | ||
let isSymbol = not typeAst.isTuple | ||
if not isSymbol: | ||
typeImpl = typeAst | ||
else: | ||
typeImpl = getImpl(typeAst) | ||
result = newStmtList() | ||
var i = 0 | ||
for field in recordFields(typeImpl): | ||
let | ||
fieldIdent = field.name | ||
realFieldName = newLit($fieldIdent.skipPragma) | ||
fieldName = realFieldName | ||
fieldIndex = newLit(i) | ||
let fieldNameDefs = | ||
if isSymbol: | ||
quote: | ||
const fieldName {.inject, used.} = `fieldName` | ||
const realFieldName {.inject, used.} = `realFieldName` | ||
else: | ||
quote: | ||
const fieldName {.inject, used.} = $`fieldIndex` | ||
const realFieldName {.inject, used.} = $`fieldIndex` | ||
# we can't access .Fieldn, so our helper knows | ||
# to parseInt this | ||
let field = | ||
if isSymbol: | ||
quote do: declval(`T`).`fieldIdent` | ||
else: | ||
quote do: declval(`T`)[`fieldIndex`] | ||
result.add quote do: | ||
block: | ||
`fieldNameDefs` | ||
type FieldType {.inject, used.} = type(`field`) | ||
`body` | ||
i += 1 | ||
template enumAllSerializedFields(T: type, body): untyped = | ||
when T is ref|ptr: | ||
type TT = type(default(T)[]) | ||
enumAllSerializedFieldsImpl(TT, body) | ||
else: | ||
enumAllSerializedFieldsImpl(T, body) | ||
type | ||
MemRange = object | ||
startAddr: ptr byte | ||
length: int | ||
SszNavigator[T] = object | ||
m: MemRange | ||
func sszMount(data: openArray[byte], T: type): SszNavigator[T] = | ||
let startAddr = unsafeAddr data[0] | ||
SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len)) | ||
func sszMount(data: openArray[char], T: type): SszNavigator[T] = | ||
let startAddr = cast[ptr byte](unsafeAddr data[0]) | ||
SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len)) | ||
template sszMount(data: MemRange, T: type): SszNavigator[T] = | ||
SszNavigator[T](m: data) | ||
func navigateToField[T]( | ||
n: SszNavigator[T], | ||
FieldType: type): SszNavigator[FieldType] = | ||
default(SszNavigator[FieldType]) | ||
type | ||
FieldInfo = ref object | ||
navigator: proc (m: MemRange): MemRange {. | ||
gcsafe, noSideEffect, raises: [IOError] .} | ||
func fieldNavigatorImpl[RecordType; FieldType; fieldName: static string]( | ||
m: MemRange): MemRange = | ||
var typedNavigator = sszMount(m, RecordType) | ||
discard navigateToField(typedNavigator, FieldType) | ||
default(MemRange) | ||
func genTypeInfo(T: type) = | ||
when T is object: | ||
enumAllSerializedFields(T): | ||
discard FieldInfo(navigator: fieldNavigatorImpl[T, FieldType, fieldName]) | ||
type | ||
Foo = object | ||
bar: Bar | ||
BarList = seq[uint64] | ||
Bar = object | ||
b: BarList | ||
baz: Baz | ||
Baz = object | ||
i: uint64 | ||
genTypeInfo(Foo) |
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