diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 52b236883c..6996082c32 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -448,6 +448,10 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = styleCheckDef(c.config, a.sons[j].info, field) onDef(field.info, field) if result.n.len == 0: result.n = nil + if isTupleRecursive(result): + localError(c.config, n.info, errIllegalRecursionInTypeX % typeToString(result)) + + proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym = diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 152a75ee36..9203f64373 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -24,7 +24,7 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) = if t.kind in tyTypeClasses: discard elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: localError(conf, info, "type 'var var' is not allowed") - elif computeSize(conf, t) == szIllegalRecursion: + elif computeSize(conf, t) == szIllegalRecursion or isTupleRecursive(t): localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'") when false: if t.kind == tyObject and t.sons[0] != nil: @@ -682,4 +682,3 @@ proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo, template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode, t: PType): untyped = generateTypeInstance(p, pt, arg.info, t) - diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index af2f0ad400..665f4b1abf 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -272,14 +272,6 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.align = szIllegalRecursion return - # recursive tuplers are not allowed and should be detected in the frontend - if base.kind == tyTuple: - computeSizeAlign(conf, base) - if base.size < 0: - typ.size = base.size - typ.align = base.align - return - typ.align = int16(conf.target.ptrSize) if typ.kind == tySequence and conf.selectedGC == gcDestructors: typ.size = conf.target.ptrSize * 2 diff --git a/compiler/types.nim b/compiler/types.nim index ddd299a862..069d663acd 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1514,3 +1514,23 @@ proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType) = of efLockLevelsDiffer: msg.add "\nlock levels differ" localError(conf, info, msg) + +proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = + if t == nil: return + case t.kind: + of tyTuple: + if cycleDetector.containsOrIncl(t.id): + return true + var cycleDetectorCopy: IntSet + for i in 0..