diff options
Diffstat (limited to 'compiler/semexprs.nim')
-rw-r--r-- | compiler/semexprs.nim | 81 |
1 files changed, 61 insertions, 20 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 4b45ccf87..a072deb7d 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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} |