mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-29 18:53:58 +00:00
object construction: test cases and manual additions
This commit is contained in:
122
tests/constructors/tinvalid_construction.nim
Normal file
122
tests/constructors/tinvalid_construction.nim
Normal file
@@ -0,0 +1,122 @@
|
||||
template accept(x) =
|
||||
static: assert compiles(x)
|
||||
|
||||
template reject(x) =
|
||||
static: assert(not compiles(x))
|
||||
|
||||
type
|
||||
TRefObj = ref object
|
||||
x: int
|
||||
|
||||
THasNotNils = object of TObject
|
||||
a: TRefObj not nil
|
||||
b: TRefObj not nil
|
||||
c: TRefObj
|
||||
|
||||
THasNotNilsRef = ref THasNotNils
|
||||
|
||||
TChoice = enum A, B, C, D, E, F
|
||||
|
||||
TBaseHasNotNils = object of THasNotNils
|
||||
case choice: TChoice
|
||||
of A:
|
||||
moreNotNils: THasNotNils
|
||||
of B:
|
||||
indirectNotNils: ref THasNotNils
|
||||
else:
|
||||
discard
|
||||
|
||||
TObj = object
|
||||
case choice: TChoice
|
||||
of A:
|
||||
a: int
|
||||
of B, C:
|
||||
bc: int
|
||||
of D:
|
||||
d: TRefObj
|
||||
of E:
|
||||
e1: TRefObj
|
||||
e2: int
|
||||
else:
|
||||
f: string
|
||||
|
||||
TNestedChoices = object
|
||||
case outerChoice: bool
|
||||
of true:
|
||||
truthy: int
|
||||
else:
|
||||
case innerChoice: TChoice
|
||||
of A:
|
||||
a: int
|
||||
of B:
|
||||
b: int
|
||||
else:
|
||||
notnil: TRefObj not nil
|
||||
|
||||
var x = D
|
||||
var nilRef: TRefObj
|
||||
var notNilRef = TRefObj(x: 20)
|
||||
|
||||
proc makeHasNotNils: ref THasNotNils =
|
||||
result.a = TRefObj(x: 10)
|
||||
result.b = TRefObj(x: 20)
|
||||
|
||||
accept TObj()
|
||||
accept TObj(choice: A)
|
||||
reject TObj(choice: A, bc: 10) # bc is in the wrong branch
|
||||
accept TObj(choice: B, bc: 20)
|
||||
reject TObj(a: 10) # branch selected without providing discriminator
|
||||
reject TObj(choice: x, a: 10) # the discrimantor must be a compile-time value when a branch is selected
|
||||
accept TObj(choice: x) # it's OK to use run-time value when a branch is not selected
|
||||
accept TObj(choice: F, f: "") # match an else clause
|
||||
reject TObj(f: "") # the discriminator must still be provided for an else clause
|
||||
reject TObj(a: 10, f: "") # conflicting fields
|
||||
accept TObj(choice: E, e1: TRefObj(x: 10), e2: 10)
|
||||
|
||||
accept THasNotNils(a: notNilRef, b: notNilRef, c: nilRef)
|
||||
# XXX: the "not nil" logic in the compiler is not strong enough to catch this one yet:
|
||||
# reject THasNotNils(a: notNilRef, b: nilRef, c: nilRef)
|
||||
reject THasNotNils(b: notNilRef, c: notNilRef) # there is a missing not nil field
|
||||
reject THasNotNils() # again, missing fields
|
||||
accept THasNotNils(a: notNilRef, b: notNilRef) # it's OK to omit a non-mandatory field
|
||||
|
||||
# missing not nils in base
|
||||
reject TBaseHasNotNils()
|
||||
|
||||
# once you take care of them, it's ok
|
||||
accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: D)
|
||||
|
||||
# this one is tricky!
|
||||
# it has to be rejected, because choice gets value A by default (0) and this means
|
||||
# that the THasNotNils field will be active (and it will demand more initialized fields).
|
||||
reject TBaseHasNotNils(a: notNilRef, b: notNilRef)
|
||||
|
||||
# you can select a branch without mandatory fields
|
||||
accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B)
|
||||
accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: nil)
|
||||
|
||||
# but once you select a branch with mandatory fields, you must specify them
|
||||
reject TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: A)
|
||||
reject TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: A, indirectNotNils: nil)
|
||||
reject TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: A, moreNotNils: THasNotNils())
|
||||
accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: A, moreNotNils: THasNotNils(a: notNilRef, b: notNilRef))
|
||||
|
||||
# all rules apply to sub-objects as well
|
||||
accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: makeHasNotNils())
|
||||
reject TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: THasNotNilsRef())
|
||||
accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: THasNotNilsRef(a: notNilRef, b: notNilRef))
|
||||
|
||||
# this will be accepted, because the false outer branch will be taken and the inner A branch
|
||||
accept TNestedChoices()
|
||||
|
||||
# but if we supply a run-time value for the inner branch, the compiler won't be able to prove
|
||||
# that the notnil field was initialized
|
||||
reject TNestedChoices(outerChoice: false, innerChoice: x) # XXX: The error message is not very good here
|
||||
reject TNestedChoices(outerChoice: true, innerChoice: A) # XXX: The error message is not very good here
|
||||
|
||||
accept TNestedChoices(outerChoice: false, innerChoice: B)
|
||||
|
||||
reject TNestedChoices(outerChoice: false, innerChoice: C)
|
||||
accept TNestedChoices(outerChoice: false, innerChoice: C, notnil: notNilRef)
|
||||
reject TNestedChoices(outerChoice: false, innerChoice: C, notnil: nil)
|
||||
|
||||
Reference in New Issue
Block a user