mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
Fixed generic parameters failing to be used in inheritance (#21866)
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
39
tests/types/tinheritgenericparameter.nim
Normal file
39
tests/types/tinheritgenericparameter.nim
Normal file
@@ -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]]()
|
||||
|
||||
Reference in New Issue
Block a user