mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 19:33:42 +00:00
fixes #26132
This commit is contained in:
@@ -2160,47 +2160,54 @@ proc checkedForDestructor(t: PType): bool =
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc whereToBindTypeHook(c: PContext; t: PType): PType =
|
||||
proc normalizeTypeHook(t: PType; markAsgn = false): PType =
|
||||
result = t
|
||||
while true:
|
||||
if result.kind in {tyGenericBody, tyGenericInst}: result = result.skipModifier
|
||||
elif result.kind == tyGenericInvocation: result = result[0]
|
||||
else: break
|
||||
if markAsgn:
|
||||
incl(result, tfHasAsgn)
|
||||
if result.kind == tyCompositeTypeClass and result.base.kind == tyGenericBody:
|
||||
result = result.base
|
||||
elif result.kind in {tyGenericBody, tyGenericInst}:
|
||||
result = result.skipModifier
|
||||
elif result.kind == tyGenericInvocation:
|
||||
result = result.genericHead
|
||||
else:
|
||||
break
|
||||
|
||||
proc whereToBindTypeHook(c: PContext; t: PType): PType =
|
||||
result = normalizeTypeHook(t)
|
||||
if result.kind in {tyObject, tyDistinct, tySequence, tyString}:
|
||||
result = canonType(c, result)
|
||||
|
||||
proc bindHookToType(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp;
|
||||
typeToBind: PType): bool =
|
||||
var obj = typeToBind
|
||||
if obj.kind notin {tyObject, tyDistinct, tySequence, tyString}:
|
||||
return false
|
||||
obj = canonType(c, obj)
|
||||
let ao = getAttachedOp(c.graph, obj, op)
|
||||
if ao == s:
|
||||
discard "forward declared hook"
|
||||
elif ao.isNil and not checkedForDestructor(obj):
|
||||
setAttachedOp(c.graph, c.module.position, obj, op, s)
|
||||
else:
|
||||
prevDestructor(c, op, ao, obj, n.info)
|
||||
if obj.owner.getModule != s.getModule:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
result = true
|
||||
|
||||
proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
|
||||
let t = s.typ
|
||||
var noError = false
|
||||
let cond = t.len == 2 and t.returnType != nil
|
||||
|
||||
if cond:
|
||||
var obj = t.firstParamType
|
||||
while true:
|
||||
incl(obj, tfHasAsgn)
|
||||
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier
|
||||
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
|
||||
else: break
|
||||
var obj = normalizeTypeHook(t.firstParamType, markAsgn = true)
|
||||
let res = normalizeTypeHook(t.returnType)
|
||||
|
||||
var res = t.returnType
|
||||
while true:
|
||||
if res.kind in {tyGenericBody, tyGenericInst}: res = res.skipModifier
|
||||
elif res.kind == tyGenericInvocation: res = res.genericHead
|
||||
else: break
|
||||
|
||||
if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, res):
|
||||
obj = canonType(c, obj)
|
||||
let ao = getAttachedOp(c.graph, obj, op)
|
||||
if ao == s:
|
||||
discard "forward declared destructor"
|
||||
elif ao.isNil and not checkedForDestructor(obj):
|
||||
setAttachedOp(c.graph, c.module.position, obj, op, s)
|
||||
else:
|
||||
prevDestructor(c, op, ao, obj, n.info)
|
||||
noError = true
|
||||
if obj.owner.getModule != s.getModule:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
if sameType(obj, res):
|
||||
noError = bindHookToType(c, s, n, op, obj)
|
||||
|
||||
if not noError and sfSystemModule notin s.owner.flags:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
@@ -2230,25 +2237,8 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
|
||||
t.len >= 2 and t.returnType == nil
|
||||
|
||||
if cond:
|
||||
var obj = t.firstParamType.skipTypes({tyVar})
|
||||
while true:
|
||||
incl(obj, tfHasAsgn)
|
||||
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier
|
||||
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
|
||||
else: break
|
||||
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
|
||||
obj = canonType(c, obj)
|
||||
let ao = getAttachedOp(c.graph, obj, op)
|
||||
if ao == s:
|
||||
discard "forward declared destructor"
|
||||
elif ao.isNil and not checkedForDestructor(obj):
|
||||
setAttachedOp(c.graph, c.module.position, obj, op, s)
|
||||
else:
|
||||
prevDestructor(c, op, ao, obj, n.info)
|
||||
noError = true
|
||||
if obj.owner.getModule != s.getModule:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
var obj = normalizeTypeHook(t.firstParamType.skipTypes({tyVar}), markAsgn = true)
|
||||
noError = bindHookToType(c, s, n, op, obj)
|
||||
if not noError and sfSystemModule notin s.owner.flags:
|
||||
case op
|
||||
of attachedTrace:
|
||||
@@ -2315,35 +2305,12 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
message(c.config, n.info, warnDeprecated, "Overriding `=` hook is deprecated; Override `=copy` hook instead")
|
||||
let t = s.typ
|
||||
if t.len == 3 and t.returnType == nil and t.firstParamType.kind == tyVar:
|
||||
var obj = t.firstParamType.elementType
|
||||
while true:
|
||||
incl(obj, tfHasAsgn)
|
||||
if obj.kind == tyGenericBody: obj = obj.skipModifier
|
||||
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
|
||||
else: break
|
||||
var objB = t[2]
|
||||
while true:
|
||||
if objB.kind == tyGenericBody: objB = objB.skipModifier
|
||||
elif objB.kind in {tyGenericInvocation, tyGenericInst}:
|
||||
objB = objB.genericHead
|
||||
else: break
|
||||
if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, objB):
|
||||
var obj = normalizeTypeHook(t.firstParamType.elementType, markAsgn = true)
|
||||
let objB = normalizeTypeHook(t[2])
|
||||
if sameType(obj, objB):
|
||||
# attach these ops to the canonical tySequence
|
||||
obj = canonType(c, obj)
|
||||
#echo "ATTACHING TO ", obj.id, " ", s.name.s, " ", cast[int](obj)
|
||||
let k = if name == "=" or name == "=copy": attachedAsgn else: attachedSink
|
||||
let ao = getAttachedOp(c.graph, obj, k)
|
||||
if ao == s:
|
||||
discard "forward declared op"
|
||||
elif ao.isNil and not checkedForDestructor(obj):
|
||||
setAttachedOp(c.graph, c.module.position, obj, k, s)
|
||||
else:
|
||||
prevDestructor(c, k, ao, obj, n.info)
|
||||
if obj.owner.getModule != s.getModule:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & name & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
|
||||
return
|
||||
if bindHookToType(c, s, n, k, obj): return
|
||||
if sfSystemModule notin s.owner.flags:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"signature for '" & s.name.s & "' must be proc[T: object](x: var T; y: T)")
|
||||
|
||||
@@ -166,3 +166,99 @@ type Vector*[T] = object
|
||||
# proc `=destroy`*(x: var Vector[int]) = discard # this will remove error
|
||||
proc `=destroy`*[T](x: var Vector[T]) = discard
|
||||
var a: Vector[int] # Error: unresolved generic parameter
|
||||
|
||||
# issue #26132
|
||||
|
||||
block:
|
||||
type UnparameterizedGeneric[T] = object
|
||||
|
||||
proc `=destroy`(x: var UnparameterizedGeneric) = discard
|
||||
proc `=wasMoved`(x: var UnparameterizedGeneric) = discard
|
||||
proc `=trace`(x: var UnparameterizedGeneric; env: pointer) = discard
|
||||
|
||||
var x: UnparameterizedGeneric[int]
|
||||
discard x
|
||||
|
||||
# Exercise every type-bound hook with the generic parameter omitted.
|
||||
block:
|
||||
type
|
||||
Generic[T] = object
|
||||
value: T
|
||||
|
||||
var destroys, moves, traces, copies, sinks, dups: int
|
||||
|
||||
proc `=destroy`(x: var Generic) = inc destroys
|
||||
proc `=wasMoved`(x: var Generic) =
|
||||
inc moves
|
||||
x.value = default(typeof(x.value))
|
||||
proc `=trace`(x: var Generic; env: pointer) = inc traces
|
||||
proc `=copy`(dest: var Generic; src: Generic) =
|
||||
inc copies
|
||||
dest.value = src.value
|
||||
proc `=sink`(dest: var Generic; src: Generic) =
|
||||
inc sinks
|
||||
dest.value = src.value
|
||||
proc `=dup`(src: Generic): Generic =
|
||||
inc dups
|
||||
Generic(value: src.value)
|
||||
proc deepCopy(src: ref Generic): ref Generic = src
|
||||
|
||||
proc exercise[T]() =
|
||||
var first = Generic[T](value: default(T))
|
||||
var second = Generic[T](value: default(T))
|
||||
second = first
|
||||
doAssert second.value == first.value
|
||||
second = Generic[T](value: default(T))
|
||||
doAssert second.value == default(T)
|
||||
`=trace`(first, nil)
|
||||
`=wasMoved`(first)
|
||||
let implicitDuplicate = first
|
||||
discard implicitDuplicate
|
||||
let duplicate = `=dup`(first)
|
||||
discard duplicate
|
||||
let original = new(Generic[T])
|
||||
doAssert deepCopy(original) == original
|
||||
|
||||
exercise[string]()
|
||||
exercise[int]()
|
||||
exercise[seq[int]]()
|
||||
|
||||
doAssert copies > 0
|
||||
doAssert sinks > 0
|
||||
doAssert dups > 0
|
||||
doAssert moves > 0
|
||||
doAssert traces > 0
|
||||
doAssert destroys > 0
|
||||
|
||||
block:
|
||||
type GenericDistinct[T] = distinct Generic[T]
|
||||
|
||||
proc `=destroy`(x: var GenericDistinct) = discard
|
||||
proc `=wasMoved`(x: var GenericDistinct) = discard
|
||||
proc `=trace`(x: var GenericDistinct; env: pointer) = discard
|
||||
proc `=copy`(dest: var GenericDistinct; src: GenericDistinct) = discard
|
||||
proc `=sink`(dest: var GenericDistinct; src: GenericDistinct) = discard
|
||||
proc `=dup`(src: GenericDistinct): GenericDistinct = src
|
||||
proc deepCopy(src: ref GenericDistinct): ref GenericDistinct = src
|
||||
|
||||
var first = GenericDistinct[string](Generic[string](value: "first"))
|
||||
var second = GenericDistinct[string](Generic[string](value: "second"))
|
||||
second = first
|
||||
second = GenericDistinct[string](Generic[string](value: "third"))
|
||||
`=trace`(first, nil)
|
||||
`=wasMoved`(first)
|
||||
let moved = move(first)
|
||||
let duplicate = `=dup`(moved)
|
||||
discard duplicate
|
||||
let original = new(GenericDistinct[string])
|
||||
doAssert deepCopy(original) == original
|
||||
|
||||
block:
|
||||
type GenericPair[A, B] = object
|
||||
left: A
|
||||
right: B
|
||||
|
||||
proc `=destroy`(x: var GenericPair) = discard
|
||||
|
||||
var pair = GenericPair[int, string](left: 42, right: "pair")
|
||||
discard pair
|
||||
|
||||
Reference in New Issue
Block a user