mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
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:
@@ -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.}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user