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

delay resolved procvar check for proc params + acknowledge unresolved statics #23188

Merged
merged 6 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,6 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# same as 'semExprWithType' but doesn't check for proc vars
result = semExpr(c, n, flags + {efOperand, efAllowSymChoice})
if result.typ != nil:
# XXX tyGenericInst here?
if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}):
#and tfUnresolved in result.typ.flags:
let owner = result.typ.owner
let err =
# consistent error message with evaltempl/semMacroExpr
if owner != nil and owner.kind in {skTemplate, skMacro}:
errMissingGenericParamsForTemplate % n.renderTree
else:
errProcHasNoConcreteType % n.renderTree
localError(c.config, n.info, err)
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyVoid, c)
Expand Down Expand Up @@ -1013,6 +1002,30 @@ proc bracketedMacro(n: PNode): PSym =
else:
result = nil

proc finishOperand(c: PContext, a: PNode): PNode =
if a.typ.isNil:
result = c.semOperand(c, a, {efDetermineType})
else:
result = a
# XXX tyGenericInst here?
if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}):
#and tfUnresolved in result.typ.flags:
let owner = result.typ.owner
let err =
# consistent error message with evaltempl/semMacroExpr
if owner != nil and owner.kind in {skTemplate, skMacro}:
errMissingGenericParamsForTemplate % a.renderTree
else:
errProcHasNoConcreteType % a.renderTree
localError(c.config, a.info, err)
considerGenSyms(c, result)

proc semFinishOperands(c: PContext; n: PNode) =
# this needs to be called to ensure that after overloading resolution every
# argument has been sem'checked:
for i in 1..<n.len:
n[i] = finishOperand(c, n[i])

proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
return errorNode(c, n)
Expand Down
9 changes: 9 additions & 0 deletions compiler/seminst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym
elif t.kind in {tyGenericParam, tyConcept}:
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif isUnresolvedStatic(t) and c.inGenericContext == 0 and
c.matchedConcept == nil:
# generic/concept type bodies will try to instantiate static values but
# won't actually use them
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif t.kind == tyGenericInvocation:
#t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t)
Expand Down Expand Up @@ -377,10 +383,13 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
# see ttypeor.nim test.
var i = 0
newSeq(entry.concreteTypes, fn.typ.paramsLen+gp.len)
# let param instantiation know we are in a concept for unresolved statics:
c.matchedConcept = oldMatchedConcept
for s in instantiateGenericParamList(c, gp, pt):
addDecl(c, s)
entry.concreteTypes[i] = s.typ
inc i
c.matchedConcept = nil
pushProcCon(c, result)
instantiateProcType(c, pt, result, info)
for _, param in paramTypes(result.typ):
Expand Down
6 changes: 0 additions & 6 deletions compiler/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2704,12 +2704,6 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
m.firstMismatch.arg = a
m.firstMismatch.formal = formal

proc semFinishOperands*(c: PContext, n: PNode) =
# this needs to be called to ensure that after overloading resolution every
# argument has been sem'checked:
for i in 1..<n.len:
n[i] = prepareOperand(c, n[i])

proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
# for 'suggest' support:
var marker = initIntSet()
Expand Down
4 changes: 2 additions & 2 deletions tests/errmsgs/t5167_5.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ proc bar(x: proc (x: int)) =
let x = t #[tt.Error
^ 't' has unspecified generic parameters]#
bar t #[tt.Error
^ 't' has unspecified generic parameters]#
^ type mismatch: got <template [*missing parameters*]()>]#

let y = m #[tt.Error
^ 'm' has unspecified generic parameters]#
bar m #[tt.Error
^ 'm' has unspecified generic parameters]#
^ type mismatch: got <macro [*missing parameters*](): untyped{.noSideEffect, gcsafe.}>]#
155 changes: 155 additions & 0 deletions tests/generics/t23186.nim
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)
4 changes: 2 additions & 2 deletions tests/generics/t6137.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
discard """
errormsg: "\'vectFunc\' doesn't have a concrete type, due to unspecified generic parameters."
line: 28
errormsg: "cannot instantiate: 'T'"
line: 19
"""

type
Expand Down
3 changes: 2 additions & 1 deletion tests/generics/timplicit_and_explicit.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ block: #15622
proc test1[T](a: T, b: static[string] = "") = discard
test1[int64](123)
proc test2[T](a: T, b: static[string] = "") = discard
test2[int64, static[string]](123)
doAssert not (compiles do:
test2[int64, static[string]](123))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh? Previously this worked and now it doesn't? But it should work as you can pass 123 to T = int64. What am I missing?

Copy link
Collaborator Author

@metagn metagn Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is the extra generic parameter static[string], test2 only accepts one generic parameter, and even the implicit generic param which would be the value of b doesn't make sense to be set to literally the type static[string] (which is why this errors now).


block: #4688
proc convertTo[T](v: int or float): T = (T)(v)
Expand Down
3 changes: 2 additions & 1 deletion tests/misc/t8545.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
discard """
targets: "c cpp js"
# just tests that this doesn't crash the compiler
errormsg: "cannot instantiate: 'a:type'"
Copy link
Collaborator Author

@metagn metagn Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test only compiled before because a was never used, if you tried to use it you would get this same error. I have a stashed diff that gets this test working and lets you actually use a (except cast[static[bool]](a) which makes no sense) but this PR is already crowded. (edit: #23194)

"""

# bug #8545
Expand Down