mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 22:10:33 +00:00
This commit is contained in:
committed by
Andreas Rumpf
parent
06438ed143
commit
e63b673ce2
@@ -2655,6 +2655,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
return
|
||||
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
of nkStmtListType:
|
||||
let typ = semTypeNode(c, n, nil)
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||
# check if it is an expression macro:
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
|
||||
@@ -1720,12 +1720,43 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
case n.len
|
||||
of 3:
|
||||
result = semTypeNode(c, n[1], prev)
|
||||
if result.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).kind in NilableTypes+GenericTypes+{tyForward} and
|
||||
n[2].kind == nkNilLit:
|
||||
if result.kind == tyTypeDesc and tfUnresolved notin result.flags:
|
||||
result = result.base
|
||||
if n[2].kind != nkNilLit:
|
||||
localError(c.config, n.info,
|
||||
"Invalid syntax. When used with a type, 'not' can be followed only by 'nil'")
|
||||
if notnil notin c.features:
|
||||
localError(c.config, n.info,
|
||||
"enable the 'not nil' annotation with {.experimental: \"notnil\".}")
|
||||
let resolvedType = result.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned})
|
||||
case resolvedType.kind
|
||||
of tyGenericParam, tyTypeDesc, tyFromExpr:
|
||||
# XXX: This is a really inappropraite hack, but it solves
|
||||
# https://github.com/nim-lang/Nim/issues/4907 for now.
|
||||
#
|
||||
# A proper solution is to introduce a new type kind such
|
||||
# as `tyNotNil[tyRef[SomeGenericParam]]`. This will allow
|
||||
# semtypinst to replace the generic param correctly in
|
||||
# situations like the following:
|
||||
#
|
||||
# type Foo[T] = object
|
||||
# bar: ref T not nil
|
||||
# baz: ref T
|
||||
#
|
||||
# The root of the problem is that `T` here must have a specific
|
||||
# ID that is bound to a concrete type during instantiation.
|
||||
# The use of `freshType` below breaks this. Another hack would
|
||||
# be to reuse the same ID for the not nil type, but this will
|
||||
# fail if the `T` parameter is referenced multiple times as in
|
||||
# the example above.
|
||||
#
|
||||
# I suggest revisiting this once the language decides on whether
|
||||
# `not nil` should be the default. We can then map nilable refs
|
||||
# to other types such as `Option[T]`.
|
||||
result = makeTypeFromExpr(c, newTree(nkStmtListType, n.copyTree))
|
||||
of NilableTypes + {tyGenericInvocation, tyForward}:
|
||||
result = freshType(result, prev)
|
||||
result.flags.incl(tfNotNil)
|
||||
if notnil notin c.features:
|
||||
localError(c.config, n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}")
|
||||
else:
|
||||
localError(c.config, n.info, errGenerated, "invalid type")
|
||||
of 2:
|
||||
|
||||
@@ -267,4 +267,43 @@ block:
|
||||
of C: r: range[1..1] # DateTime
|
||||
|
||||
# Fine to not initialize 'r' because this is implicitly initialized and known to be branch 'A'.
|
||||
let someThing = Thing()
|
||||
var x = Thing()
|
||||
discard x
|
||||
|
||||
block:
|
||||
# https://github.com/nim-lang/Nim/issues/4907
|
||||
type
|
||||
Foo = ref object
|
||||
Bar = object
|
||||
|
||||
Thing[A, B] = ref object
|
||||
a: A not nil
|
||||
b: ref B
|
||||
c: ref B not nil
|
||||
|
||||
proc allocNotNil(T: typedesc): T not nil =
|
||||
new result
|
||||
|
||||
proc mutateThing(t: var Thing[Foo, Bar]) =
|
||||
let fooNotNil = allocNotNil(Foo)
|
||||
var foo: Foo
|
||||
|
||||
let barNotNil = allocNotNil(ref Bar)
|
||||
var bar: ref Bar
|
||||
|
||||
t.a = fooNotNil
|
||||
t.b = bar
|
||||
t.b = barNotNil
|
||||
t.c = barNotNil
|
||||
|
||||
reject:
|
||||
t.a = foo
|
||||
|
||||
reject:
|
||||
t.c = bar
|
||||
|
||||
var thing = Thing[Foo, Bar](a: allocNotNil(Foo),
|
||||
b: allocNotNil(ref Bar),
|
||||
c: allocNotNil(ref Bar))
|
||||
mutateThing thing
|
||||
|
||||
|
||||
Reference in New Issue
Block a user