diff options
author | Jason Beetham <beefers331@gmail.com> | 2023-05-21 12:10:32 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-21 20:10:32 +0200 |
commit | 28a116a47701462a5f22e0fa496a91daff2c1816 (patch) | |
tree | 32f8450d028bb506958d8bcef2c2321c7a39e350 | |
parent | 5606702e6d9aa583141c975f45534d0f55d9acc9 (diff) | |
download | Nim-28a116a47701462a5f22e0fa496a91daff2c1816.tar.gz |
Fixed generic parameters failing to be used in inheritance (#21866)
-rw-r--r-- | compiler/semtypes.nim | 35 | ||||
-rw-r--r-- | tests/types/tinheritgenericparameter.nim | 39 |
2 files changed, 63 insertions, 11 deletions
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f4b284f7e..fc59b6f91 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -854,12 +854,18 @@ proc skipGenericInvocation(t: PType): PType {.inline.} = while result.kind in {tyGenericInst, tyGenericBody, tyRef, tyPtr, tyAlias, tySink, tyOwned}: result = lastSon(result) -proc addInheritedFields(c: PContext, check: var IntSet, pos: var int, - obj: PType) = - assert obj.kind == tyObject - if (obj.len > 0) and (obj[0] != nil): - addInheritedFields(c, check, pos, obj[0].skipGenericInvocation) - addInheritedFieldsAux(c, check, pos, obj.n) +proc tryAddInheritedFields(c: PContext, check: var IntSet, pos: var int, + obj: PType, n: PNode, isPartial = false): bool = + if (not isPartial) and (obj.kind notin {tyObject, tyGenericParam} or tfFinal in obj.flags): + localError(c.config, n.info, "Cannot inherit from: '" & $obj & "'") + result = false + elif obj.kind == tyObject: + result = true + if (obj.len > 0) and (obj[0] != nil): + result = result and tryAddInheritedFields(c, check, pos, obj[0].skipGenericInvocation, n) + addInheritedFieldsAux(c, check, pos, obj.n) + else: + result = true proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType = if n.len == 0: @@ -886,7 +892,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType if concreteBase.sym != nil and concreteBase.sym.magic == mException and sfSystemModule notin c.module.flags: message(c.config, n.info, warnInheritFromException, "") - addInheritedFields(c, check, pos, concreteBase) + if not tryAddInheritedFields(c, check, pos, concreteBase, n): + return newType(tyError, nextTypeId c.idgen, result.owner) + else: if concreteBase.kind != tyError: localError(c.config, n[1].info, "inheritance only works with non-final objects; " & @@ -904,7 +912,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType result.n = newNodeI(nkRecList, n.info) else: # partial object so add things to the check - addInheritedFields(c, check, pos, result) + if not tryAddInheritedFields(c, check, pos, result, n, isPartial = true): + return newType(tyError, nextTypeId c.idgen, result.owner) + semRecordNodeAux(c, n[2], check, pos, result.n, result) if n[0].kind != nkEmpty: # dummy symbol for `pragma`: @@ -1435,19 +1445,21 @@ proc semGenericParamInInvocation(c: PContext, n: PNode): PType = result = semTypeNode(c, n, nil) n.typ = makeTypeDesc(c, result) -proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) = +proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): bool = var check = initIntSet() pos = 0 let realBase = t[0] base = skipTypesOrNil(realBase, skipPtrs) + result = true if base.isNil: localError(c.config, n.info, errIllegalRecursionInTypeX % "object") else: let concreteBase = skipGenericInvocation(base) if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: - addInheritedFields(c, check, pos, concreteBase) + if not tryAddInheritedFields(c, check, pos, concreteBase, n): + return false else: if concreteBase.kind != tyError: localError(c.config, n.info, errInheritanceOnlyWithNonFinalObjects) @@ -1527,7 +1539,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = return errorType(c) if tx != result and tx.kind == tyObject: if tx[0] != nil: - semObjectTypeForInheritedGenericInst(c, n, tx) + if not trySemObjectTypeForInheritedGenericInst(c, n, tx): + return newOrPrevType(tyError, prev, c) var position = 0 recomputeFieldPositions(tx, tx.n, position) diff --git a/tests/types/tinheritgenericparameter.nim b/tests/types/tinheritgenericparameter.nim new file mode 100644 index 000000000..c88c50b7b --- /dev/null +++ b/tests/types/tinheritgenericparameter.nim @@ -0,0 +1,39 @@ +discard """ + cmd: "nim check --hints:off --warnings:off $file" + action: "reject" + nimout:''' +tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject' +tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject' +tinheritgenericparameter.nim(36, 23) Error: object constructor needs an object type [proxy] +tinheritgenericparameter.nim(36, 23) Error: expression '' has no type (or is ambiguous) +tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int' +tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int' +tinheritgenericparameter.nim(37, 23) Error: object constructor needs an object type [proxy] +tinheritgenericparameter.nim(37, 23) Error: expression '' has no type (or is ambiguous) +''' +""" + +type + MyObject = object + HorzLayout[Base, T] = ref object of Base + data: seq[T] + VertLayout[T, Base] = ref object of Base + data: seq[T] + UiElement = ref object of RootObj + a: int + MyType[T] = ref object of RootObj + data: seq[T] + OtherElement[T] = ref object of T + Child[T] = ref object of HorzLayout[UiElement, T] + Child2[T] = ref object of VertLayout[T, UiElement] + Child3[T] = ref object of HorzLayout[MyObject, T] + Child4[T] = ref object of HorzLayout[int, T] +static: + var a = Child[int](a: 300, data: @[100, 200, 300]) + assert a.a == 300 + assert a.data == @[100, 200, 300] +discard Child2[string]() +discard Child3[string]() +discard Child4[string]() +discard OtherElement[MyType[int]]() + |