Implement the is operator for the new static and typedesc type classes

This also makes the first baby steps towards a sound treatment of
higher-order kinds (type type int).

Adds test cases showcasing the new features.

* Also fixes breakage after the rebase
This commit is contained in:
Zahary Karadjov 2018-04-23 17:23:14 +03:00
commit a49b06a52a
10 changed files with 210 additions and 55 deletions

View file

@ -194,7 +194,7 @@ proc semConv(c: PContext, n: PNode): PNode =
var targetType = semTypeNode(c, n.sons[0], nil)
if targetType.kind == tyTypeDesc:
internalAssert targetType.len > 0
internalAssert c.config, targetType.len > 0
if targetType.base.kind == tyNone:
return semTypeOf(c, n[1])
else:
@ -316,57 +316,98 @@ proc semSizeof(c: PContext, n: PNode): PNode =
n.typ = getSysType(c.graph, n.info, tyInt)
result = n
proc fixupStaticType(c: PContext, n: PNode) =
# This proc can be applied to evaluated expressions to assign
# them a static type.
#
# XXX: with implicit static, this should not be necessary,
# because the output type of operations such as `semConstExpr`
# should be a static type (as well as the type of any other
# expression that can be implicitly evaluated). For now, we
# apply this measure only in code that is enlightened to work
# with static types.
if n.typ.kind != tyStatic:
n.typ = newTypeWithSons(getCurrOwner(c), tyStatic, @[n.typ])
n.typ.n = n # XXX: cycles like the one here look dangerous.
# Consider using `n.copyTree`
proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
internalAssert c.config, n.sonsLen == 3 and
n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
internalAssert c.config,
n.sonsLen == 3 and
n[1].typ != nil and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = n[1].typ.skipTypes({tyTypeDesc})
var
res = false
t1 = n[1].typ
t2 = n[2].typ
if t1.kind == tyTypeDesc and t2.kind != tyTypeDesc:
t1 = t1.base
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
of "closure":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator notin t.flags))
res = t.kind == tyProc and
t.callConv == ccClosure and
tfIterator notin t.flags
else:
result = newIntNode(nkIntLit, 0)
res = false
else:
var rhsOrigType = n[2].typ
var t2 = rhsOrigType.skipTypes({tyTypeDesc})
maybeLiftType(t2, c, n.info)
var m: TCandidate
initCandidate(c, m, t2)
if efExplain in flags:
m.diagnostics = @[]
m.diagnosticsEnabled = true
let match = typeRel(m, t2, t1) >= isSubtype # isNone
result = newIntNode(nkIntLit, ord(match))
res = typeRel(m, t2, t1) >= isSubtype # isNone
result = newIntNode(nkIntLit, ord(res))
result.typ = n.typ
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
if sonsLen(n) != 3:
localError(c.config, n.info, "'is' operator takes 2 arguments")
let boolType = getSysType(c.graph, n.info, tyBool)
result = n
n.typ = getSysType(c.graph, n.info, tyBool)
n.typ = boolType
var liftLhs = true
n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
let t2 = semTypeNode(c, n[2], nil)
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
if t2.kind == tyStatic:
let evaluated = tryConstExpr(c, n[1])
if evaluated != nil:
c.fixupStaticType(evaluated)
n[1] = evaluated
else:
result = newIntNode(nkIntLit, 0)
result.typ = boolType
return
elif t2.kind == tyTypeDesc and
(t2.base.kind == tyNone or tfExplicit in t2.flags):
# When the right-hand side is an explicit type, we must
# not allow regular values to be matched against the type:
liftLhs = false
let lhsType = n[1].typ
var lhsType = n[1].typ
if lhsType.kind != tyTypeDesc:
n.sons[1] = makeTypeSymNode(c, lhsType, n[1].info)
elif lhsType.base.kind == tyNone:
# this is a typedesc variable, leave for evals
return
if liftLhs:
n[1] = makeTypeSymNode(c, lhsType, n[1].info)
lhsType = n[1].typ
else:
if lhsType.base.kind == tyNone:
# this is a typedesc variable, leave for evals
return
if lhsType.base.containsGenericType:
# BUGFIX: don't evaluate this too early: ``T is void``
return
# BUGFIX: don't evaluate this too early: ``T is void``
if not n[1].typ.base.containsGenericType: result = isOpImpl(c, n, flags)
result = isOpImpl(c, n, flags)
proc semOpAux(c: PContext, n: PNode) =
const flags = {efDetermineType}