diff --git a/compiler/semdata.nim b/compiler/semdata.nim index fa697f90cd..5eb8086f45 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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.} diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 01307cc516..1ca9ebefff 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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.. 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) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 9ebc930079..96206a0757 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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..