Revert "leave type section symbols unchanged on resem, fix overly general double semcheck for forward types (#24888)"

This reverts commit cfe89097e7.
This commit is contained in:
narimiran
2025-04-21 23:07:52 +02:00
parent 1db543e8b2
commit f7145dd26e
6 changed files with 37 additions and 141 deletions

View File

@@ -172,9 +172,7 @@ type
sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index
inUncheckedAssignSection*: int
importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
forwardTypeUpdates*: seq[(PType, PNode)]
# types that need to be updated in a type section
# due to containing forward types, and their corresponding nodes
skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies.
inTypeofContext*: int
semAsgnOpr*: proc (c: PContext; n: PNode; k: TNodeKind): PNode {.nimcall.}

View File

@@ -1460,13 +1460,8 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) =
else:
s = semIdentDef(c, name, skType)
onDef(name.info, s)
if s.typ != nil:
# name node is a symbol with a type already, probably in resem, don't touch it
discard
else:
s.typ = newTypeS(tyForward, c)
s.typ.sym = s
# process pragmas:
s.typ = newTypeS(tyForward, c)
s.typ.sym = s # process pragmas:
if name.kind == nkPragmaExpr:
let rewritten = applyTypeSectionPragmas(c, name[1], typeDef)
if rewritten != nil:
@@ -1604,26 +1599,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
localError(c.config, a.info, errImplOfXexpected % s.name.s)
if s.magic != mNone: processMagicType(c, s)
let oldFlags = s.typ.flags
let preserveSym = s.typ != nil and s.typ.kind != tyForward and sfForward notin s.flags and
s.magic == mNone # magic might have received type above but still needs processing
if preserveSym:
# symbol already has a type, probably in resem, do not modify it
# but still semcheck the RHS to handle any defined symbols
# nominal type nodes are still ignored in semtypes
if a[1].kind != nkEmpty:
openScope(c)
pushOwner(c, s)
a[1] = semGenericParamList(c, a[1], nil)
inc c.inGenericContext
discard semTypeNode(c, a[2], s.typ)
dec c.inGenericContext
popOwner(c)
closeScope(c)
elif a[2].kind != nkEmpty:
pushOwner(c, s)
discard semTypeNode(c, a[2], s.typ)
popOwner(c)
elif a[1].kind != nkEmpty:
if a[1].kind != nkEmpty:
# We have a generic type declaration here. In generic types,
# symbol lookup needs to be done here.
openScope(c)
@@ -1713,7 +1689,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
localError(c.config, name.info, "only a 'distinct' type can borrow `.`")
let aa = a[2]
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
aa[0].kind == nkObjectTy and not preserveSym:
aa[0].kind == nkObjectTy:
# give anonymous object a dummy symbol:
var st = s.typ
if st.kind == tyGenericBody: st = st.typeBodyImpl
@@ -1754,6 +1730,9 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
obj.flags.incl sfPure
obj.typ = objTy
objTy.sym = obj
for sk in c.skipTypes:
discard semTypeNode(c, sk, nil)
c.skipTypes = @[]
proc checkForMetaFields(c: PContext; n: PNode; hasError: var bool) =
proc checkMeta(c: PContext; n: PNode; t: PType; hasError: var bool; parent: PType) =
@@ -1789,15 +1768,6 @@ proc checkForMetaFields(c: PContext; n: PNode; hasError: var bool) =
internalAssert c.config, false
proc typeSectionFinalPass(c: PContext, n: PNode) =
for (typ, typeNode) in c.forwardTypeUpdates:
# types that need to be updated due to containing forward types
# and their corresponding type nodes
# for example generic invocations of forward types end up here
var reified = semTypeNode(c, typeNode, nil)
assert reified != nil
assignType(typ, reified)
typ.itemId = reified.itemId # same id
c.forwardTypeUpdates = @[]
for i in 0..<n.len:
var a = n[i]
if a.kind == nkCommentStmt: continue
@@ -1824,15 +1794,29 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
else:
while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0:
x = x.lastSon
# we need the 'safeSkipTypes' here because illegally recursive types
# can enter at this point, see bug #13763
if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and
s.typ.safeSkipTypes(abstractPtrs).kind notin {tyObject, tyEnum}:
# type aliases are hard:
var t = semTypeNode(c, x, nil)
assert t != nil
if s.typ != nil and s.typ.kind notin {tyAlias, tySink}:
if t.kind in {tyProc, tyGenericInst} and not t.isMetaType:
assignType(s.typ, t)
s.typ.itemId = t.itemId
elif t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
assignType(s.typ, t)
s.typ.itemId = t.itemId # same id
var hasError = false
if x.kind in {nkObjectTy, nkTupleTy} or
let baseType = s.typ.safeSkipTypes(abstractPtrs)
if baseType.kind in {tyObject, tyTuple} and not baseType.n.isNil and
(x.kind in {nkObjectTy, nkTupleTy} or
(x.kind in {nkRefTy, nkPtrTy} and x.len == 1 and
x[0].kind in {nkObjectTy, nkTupleTy}):
# we need the 'safeSkipTypes' here because illegally recursive types
# can enter at this point, see bug #13763
let baseType = s.typ.safeSkipTypes(abstractPtrs)
if baseType.kind in {tyObject, tyTuple} and not baseType.n.isNil:
checkForMetaFields(c, baseType.n, hasError)
x[0].kind in {nkObjectTy, nkTupleTy})
):
checkForMetaFields(c, baseType.n, hasError)
if not hasError:
checkConstructedType(c.config, s.info, s.typ)
#instAllTypeBoundOp(c, n.info)

View File

@@ -59,31 +59,11 @@ proc newConstraint(c: PContext, k: TTypeKind): PType =
result.flags.incl tfCheckedForDestructor
result.addSonSkipIntLit(newTypeS(k, c), c.idgen)
proc skipGenericPrev(prev: PType): PType =
result = prev
if prev.kind == tyGenericBody and prev.last.kind != tyNone:
result = prev.last
proc prevIsKind(prev: PType, kind: TTypeKind): bool {.inline.} =
result = prev != nil and skipGenericPrev(prev).kind == kind
proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if n.len == 0: return newConstraint(c, tyEnum)
elif n.len == 1:
# don't create an empty tyEnum; fixes #3052
return errorType(c)
if prevIsKind(prev, tyEnum):
# the symbol already has an enum type (likely resem), don't define a new enum
# but add the enum fields to scope from the original type
let isPure = sfPure in prev.sym.flags
for enumField in prev.n:
assert enumField.kind == nkSym
let e = enumField.sym
if not isPure:
addInterfaceOverloadableSymAt(c, c.currentScope, e)
else:
declarePureEnumField(c, e)
return prev
var
counter, x: BiggestInt = 0
e: PSym = nil
@@ -217,7 +197,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
if base.kind in {tyGenericInst, tyAlias, tySink}: base = skipModifier(base)
if base.kind notin {tyGenericParam, tyGenericInvocation}:
if base.kind == tyForward:
c.forwardTypeUpdates.add (base, n[1])
c.skipTypes.add n
elif not isOrdinalType(base, allowEnumWithHoles = true):
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(base, preferDesc))
elif lengthOrd(c.config, base) > MaxSetElements:
@@ -327,9 +307,6 @@ proc addSonSkipIntLitChecked(c: PContext; father, son: PType; it: PNode, id: IdG
proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
if n.len == 0: return newConstraint(c, tyDistinct)
if prevIsKind(prev, tyDistinct):
# the symbol already has a distinct type (likely resem), don't create a new type
return skipGenericPrev(prev)
result = newOrPrevType(tyDistinct, prev, c)
addSonSkipIntLitChecked(c, result, semTypeNode(c, n[0], nil), n[0], c.idgen)
if n.len > 1: result.n = n[1]
@@ -1017,15 +994,11 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
result = nil
if n.len == 0:
return newConstraint(c, tyObject)
if prevIsKind(prev, tyObject) and sfForward notin prev.sym.flags:
# the symbol already has an object type (likely resem), don't create a new type
return skipGenericPrev(prev)
var check = initIntSet()
var pos = 0
var base, realBase: PType = nil
# n[0] contains the pragmas (if any). We process these later...
checkSonsLen(n, 3, c.config)
var needsForwardUpdate = false
if n[1].kind != nkEmpty:
realBase = semTypeNode(c, n[1][0], nil)
base = skipTypesOrNil(realBase, skipPtrs)
@@ -1047,7 +1020,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
return newType(tyError, c.idgen, result.owner)
elif concreteBase.kind == tyForward:
needsForwardUpdate = true
c.skipTypes.add n #we retry in the final pass
else:
if concreteBase.kind != tyError:
localError(c.config, n[1].info, "inheritance only works with non-final objects; " &
@@ -1057,10 +1030,6 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
realBase = nil
if n.kind != nkObjectTy: internalError(c.config, n.info, "semObjectNode")
result = newOrPrevType(tyObject, prev, c)
if needsForwardUpdate:
# if the inherited object is a forward type,
# the entire object needs to be checked again
c.forwardTypeUpdates.add (result, n) #we retry in the final pass
rawAddSon(result, realBase)
if realBase == nil and tfInheritable in flags:
result.flags.incl tfInheritable
@@ -1087,9 +1056,6 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
if n.len < 1:
result = newConstraint(c, kind)
else:
if prevIsKind(prev, kind) and tfRefsAnonObj in prev.skipTypes({tyGenericBody}).flags:
# the symbol already has an object type (likely resem), don't create a new type
return skipGenericPrev(prev)
let isCall = int ord(n.kind in nkCallKinds+{nkBracketExpr})
let n = if n[0].kind == nkBracket: n[0] else: n
checkMinSonsLen(n, 1, c.config)
@@ -1698,7 +1664,6 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
for i in 1..<n.len:
var elem = semGenericParamInInvocation(c, n[i])
addToResult(elem, true)
c.forwardTypeUpdates.add (result, n)
return
elif t.kind != tyGenericBody:
# we likely got code of the form TypeA[TypeB] where TypeA is
@@ -1747,7 +1712,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
localError(c.config, n.info, errCannotInstantiateX % s.name.s)
result = newOrPrevType(tyError, prev, c)
elif containsGenericInvocationWithForward(n[0]):
c.forwardTypeUpdates.add (result, n) #fixes 1500
c.skipTypes.add n #fixes 1500
else:
result = instGenericContainer(c, n.info, result,
allowMetaTypes = false)

View File

@@ -526,7 +526,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
let t = typ
if t == nil: return
if prefer in preferToResolveSymbols and t.sym != nil and
sfAnon notin t.sym.flags and t.kind notin {tySequence, tyInferred}:
sfAnon notin t.sym.flags and t.kind != tySequence:
if t.kind == tyInt and isIntLit(t):
if prefer == preferInlayHint:
result = t.sym.name.s

View File

@@ -20,4 +20,8 @@ highlight;;skType;;4;;33;;3
highlight;;skType;;5;;13;;1
highlight;;skType;;6;;25;;5
highlight;;skType;;6;;34;;3
highlight;;skType;;2;;10;;3
highlight;;skType;;3;;11;;3
highlight;;skType;;4;;33;;3
highlight;;skType;;6;;34;;3
"""

View File

@@ -1,55 +0,0 @@
discard """
output: '''
NONE
a
NONE
a
'''
"""
# issue #24887
macro foo(x: typed) =
result = x
foo:
type
Flags64 = distinct uint64
const NONE = Flags64(0'u64)
const MAX: Flags64 = Flags64(uint64.high)
proc `$`(x: Flags64): string =
case x:
of NONE:
return "NONE"
of MAX:
return "MAX"
else:
return "UNKNOWN"
let okay = Flags64(128'u64)
echo $NONE
type Foo = ref object
x: int
discard Foo(x: 123)
type Enum = enum a, b, c
echo a
type Bar[T] = object
x: T
discard Bar[int](x: 123)
discard Bar[string](x: "abc")
# regression test:
template templ(): untyped =
proc injected() {.inject.} = discard
int
type TestInject = templ()
var x1: TestInject
injected() # normally works
echo $NONE
echo a
var x2: TestInject
injected()