Merge pull request #7681 from nim-lang/typedesc-reforms

Typedesc reforms
This commit is contained in:
Andreas Rumpf 2018-06-26 23:53:30 +02:00 • committed by GitHub
commit 7cec5d1cfb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 1702 additions and 270 deletions

View file

@ -0,0 +1,26 @@
import
hashes, tables, trie_database
type
MemDBTable = Table[KeccakHash, string]
MemDB* = object
tbl: MemDBTable
proc hash*(key: KeccakHash): int =
hashes.hash(key.data)
proc get*(db: MemDB, key: KeccakHash): string =
db.tbl[key]
proc del*(db: var MemDB, key: KeccakHash): bool =
if db.tbl.hasKey(key):
db.tbl.del(key)
return true
else:
return false
proc put*(db: var MemDB, key: KeccakHash, value: string): bool =
db.tbl[key] = value
return true

View file

@ -0,0 +1,12 @@
type
KeccakHash* = object
data*: string
BytesRange* = object
bytes*: string
TrieDatabase* = concept db
put(var db, KeccakHash, string) is bool
del(var db, KeccakHash) is bool
get(db, KeccakHash) is string

View file

@ -0,0 +1,7 @@
import libs/[trie_database, trie]
proc takeDb(d: TrieDatabase) = discard
var mdb: MemDB
takeDb(mdb)

View file

@ -0,0 +1,145 @@
discard """
output: "1\n10\n1\n10"
nimout: '''
bar instantiated with 1
bar instantiated with 10
'''
"""
import typetraits
type
Foo = object
proc defaultFoo: Foo = discard
proc defaultInt: int = 1
proc defaultTInt(T: type): int = 2
proc defaultTFoo[T](x: typedesc[T]): Foo = discard
proc defaultTOldSchool[T](x: typedesc[T]): T = discard
proc defaultTModern(T: type): T = discard
proc specializedDefault(T: type int): int = 10
proc specializedDefault(T: type string): string = "default"
converter intFromFoo(x: Foo): int = 3
proc consumeInt(x: int) =
discard
const activeTests = {1..100}
when true:
template test(n, body) =
when n in activeTests:
block:
body
template reject(x) =
static: assert(not compiles(x))
test 1:
proc t[T](val: T = defaultInt()) =
consumeInt val
t[int]()
reject t[string]()
test 2:
proc t1[T](val: T = defaultFoo()) =
static:
assert type(val).name == "int"
assert T.name == "int"
consumeInt val
# here, the converter should kick in, but notice
# how `val` is still typed `int` inside the proc.
t1[int]()
proc t2[T](val: T = defaultFoo()) =
discard
reject t2[string]()
test 3:
proc tInt[T](val = defaultInt()): string =
return type(val).name
doAssert tInt[int]() == "int"
doAssert tInt[string]() == "int"
proc tInt2[T](val = defaultTInt(T)): string =
return type(val).name
doAssert tInt2[int]() == "int"
doAssert tInt2[string]() == "int"
proc tDefTModern[T](val = defaultTModern(T)): string =
return type(val).name
doAssert tDefTModern[int]() == "int"
doAssert tDefTModern[string]() == "string"
doAssert tDefTModern[Foo]() == "Foo"
proc tDefTOld[T](val = defaultTOldSchool(T)): string =
return type(val).name
doAssert tDefTOld[int]() == "int"
doAssert tDefTOld[string]() == "string"
doAssert tDefTOld[Foo]() == "Foo"
test 4:
proc t[T](val: T = defaultTFoo(T)): string =
return type(val).name
doAssert t[int]() == "int"
doAssert t[Foo]() == "Foo"
reject t[string]()
test 5:
proc t1[T](a: T = specializedDefault(T)): T =
return a
doAssert t1[int]() == 10
doAssert t1[string]() == "default"
proc t2[T](a: T, b = specializedDefault(T)): auto =
return $a & $b
doAssert t2(5) == "510"
doAssert t2("string ") == "string default"
proc t3[T](a: T, b = specializedDefault(type(a))): auto =
return $a & $b
doAssert t3(100) == "10010"
doAssert t3("another ") == "another default"
test 6:
# https://github.com/nim-lang/Nim/issues/5595
type
Point[T] = object
x, y: T
proc getOrigin[T](): Point[T] = Point[T](x: 0, y: 0)
proc rotate[T](point: Point[T], radians: float,
origin = getOrigin[T]()): Point[T] =
discard
var p = getOrigin[float]()
var rotated = p.rotate(2.1)
test 7:
proc bar(x: static[int]) =
static: echo "bar instantiated with ", x
echo x
proc foo(x: static[int] = 1) =
bar(x)
foo()
foo(10)
foo(1)
foo(10)

View file

@ -4,7 +4,7 @@ discard """
errormsg: "invalid indentation"
"""
import strutils var s: seq[int] = @[0, 1, 2, 3, 4, 5, 6]
import strutils let s: seq[int] = @[0, 1, 2, 3, 4, 5, 6]
#s[1..3] = @[]

View file

@ -5,15 +5,16 @@ type
x: T
y: U
proc getTypeName(t: typedesc): string = t.name
proc getTypeName1(t: typedesc): string = t.name
proc getTypeName2(t: type): string = t.name
proc foo(T: typedesc[float], a: auto): string =
proc foo(T: type float, a: auto): string =
result = "float " & $(a.len > 5)
proc foo(T: typedesc[TFoo], a: int): string =
result = "TFoo " & $(a)
proc foo(T: typedesc[int or bool]): string =
proc foo(T: type[int or bool]): string =
var a: T
a = 10
result = "int or bool " & ($a)
@ -23,8 +24,8 @@ template foo(T: typedesc[seq]): string = "seq"
test "types can be used as proc params":
# XXX: `check` needs to know that TFoo[int, float] is a type and
# cannot be assigned for a local variable for later inspection
check ((string.getTypeName == "string"))
check ((getTypeName(int) == "int"))
check ((string.getTypeName1 == "string"))
check ((getTypeName2(int) == "int"))
check ((foo(TFoo[int, float], 1000) == "TFoo 1000"))
@ -37,6 +38,25 @@ test "types can be used as proc params":
check ((foo(seq[int]) == "seq"))
check ((foo(seq[TFoo[bool, string]]) == "seq"))
when false:
proc foo(T: typedesc[seq], s: T) = nil
template accept(x) =
static: assert(compiles(x))
template reject(x) =
static: assert(not compiles(x))
var
si: seq[int]
ss: seq[string]
proc foo(T: typedesc[seq], s: T) =
discard
accept:
foo seq[int], si
reject:
foo seq[string], si
reject:
foo seq[int], ss

View file

@ -34,3 +34,17 @@ when true:
type Point[T] = tuple[x, y: T]
proc origin(T: typedesc): Point[T] = discard
discard origin(int)
# https://github.com/nim-lang/Nim/issues/7516
import typetraits
proc hasDefault1(T: type = int): auto = return T.name
doAssert hasDefault1(int) == "int"
doAssert hasDefault1(string) == "string"
doAssert hasDefault1() == "int"
proc hasDefault2(T = string): auto = return T.name
doAssert hasDefault2(int) == "int"
doAssert hasDefault2(string) == "string"
doAssert hasDefault2() == "string"

View file

@ -4,9 +4,9 @@ type
Base = object of RootObj
Child = object of Base
proc pr(T: typedesc[Base]) = echo "proc " & T.name
method me(T: typedesc[Base]) = echo "method " & T.name
iterator it(T: typedesc[Base]): auto = yield "yield " & T.name
proc pr(T: type[Base]) = echo "proc " & T.name
method me(T: type[Base]) = echo "method " & T.name
iterator it(T: type[Base]): auto = yield "yield " & T.name
Base.pr
Child.pr

View file

@ -5,16 +5,16 @@ output: "8\n8\n4"
import
macros, typetraits
template selectType(x: int): typeDesc =
template selectType(x: int): type =
when x < 10:
int
else:
string
template simpleTypeTempl: typeDesc =
template simpleTypeTempl: type =
string
macro typeFromMacro: typedesc = string
macro typeFromMacro: type = string
# The tests below check that the result variable of the
# selected type matches the literal types in the code:

View file

@ -0,0 +1,114 @@
discard """
output: '''
@[1, 2, 3]@[1, 2, 3]
a
a
1
3 is an int
2 is an int
miau is a string
f1 1 1 1
f1 2 3 3
f1 10 20 30
f2 100 100 100
f2 200 300 300
f2 300 400 400
f3 10 10 20
f3 10 15 25
true true
false true
world
'''
"""
template reject(x) =
assert(not compiles(x))
block:
# https://github.com/nim-lang/Nim/issues/7756
proc foo[T](x: seq[T], y: seq[T] = x) =
echo x, y
let a = @[1, 2, 3]
foo(a)
block:
# https://github.com/nim-lang/Nim/issues/1201
proc issue1201(x: char|int = 'a') = echo x
issue1201()
issue1201('a')
issue1201(1)
# https://github.com/nim-lang/Nim/issues/7000
proc test(a: int|string = 2) =
when a is int:
echo a, " is an int"
elif a is string:
echo a, " is a string"
test(3) # works
test() # works
test("miau")
block:
# https://github.com/nim-lang/Nim/issues/3002 and similar
proc f1(a: int, b = a, c = b) =
echo "f1 ", a, " ", b, " ", c
proc f2(a: int, b = a, c: int = b) =
echo "f2 ", a, " ", b, " ", c
proc f3(a: int, b = a, c = a + b) =
echo "f3 ", a, " ", b, " ", c
f1 1
f1(2, 3)
f1 10, 20, 30
100.f2
200.f2 300
300.f2(400)
10.f3()
10.f3(15)
reject:
# This is a type mismatch error:
proc f4(a: int, b = a, c: float = b) = discard
reject:
# undeclared identifier
proc f5(a: int, b = c, c = 10) = discard
reject:
# undeclared identifier
proc f6(a: int, b = b) = discard
reject:
# undeclared identifier
proc f7(a = a) = discard
block:
proc f(a: var int, b: ptr int, c = addr(a)) =
echo addr(a) == b, " ", b == c
var x = 10
f(x, addr(x))
f(x, nil, nil)
block:
# https://github.com/nim-lang/Nim/issues/1046
proc pySubstr(s: string, start: int, endd = s.len()): string =
var
revStart = start
revEnd = endd
if start < 0:
revStart = s.len() + start
if endd < 0:
revEnd = s.len() + endd
return s[revStart .. revEnd-1]
echo pySubstr("Hello world", -5)

View file

@ -1,17 +1,42 @@
discard """
action: run
"""
type
R = ref
V = var
D = distinct
P = ptr
T = type
S = static
OBJ = object
TPL = tuple
SEQ = seq
var i: int
var x: ref int
var y: distinct int
var z: ptr int
const C = @[1, 2, 3]
static:
assert x is ref
assert y is distinct
assert z is ptr
assert C is static
assert C[1] is static[int]
assert C[0] is static[SomeInteger]
assert C isnot static[string]
assert C is SEQ|OBJ
assert C isnot OBJ|TPL
assert int is int
assert int is T
assert int is SomeInteger
assert seq[int] is type
assert seq[int] is type[seq]
assert seq[int] isnot type[seq[float]]
assert i isnot type[int]
assert type(i) is type[int]
assert x isnot T
assert y isnot S
assert z isnot enum
assert x isnot object
assert y isnot tuple
assert z isnot seq
doAssert x is ref
doAssert y is distinct
doAssert z is ptr

View file

@ -0,0 +1,527 @@
discard """
nimout: '''
StmtList
TypeSection
TypeDef
Ident "BarePtr"
Empty
PtrTy
TypeDef
Ident "GenericPtr"
Empty
PtrTy
Bracket
Ident "int"
TypeDef
Ident "PrefixPtr"
Empty
PtrTy
Ident "int"
TypeDef
Ident "PtrTuple"
Empty
PtrTy
Par
Ident "int"
Ident "string"
TypeDef
Ident "BareRef"
Empty
RefTy
TypeDef
Ident "GenericRef"
Empty
RefTy
Bracket
Ident "int"
TypeDef
Ident "RefTupleCl"
Empty
RefTy
TupleTy
TypeDef
Ident "RefTupleType"
Empty
RefTy
Par
Ident "int"
Ident "string"
TypeDef
Ident "RefTupleVars"
Empty
RefTy
Par
Ident "a"
Ident "b"
TypeDef
Ident "BareStatic"
Empty
Ident "static"
TypeDef
Ident "GenericStatic"
Empty
BracketExpr
Ident "static"
Ident "int"
TypeDef
Ident "PrefixStatic"
Empty
Command
Ident "static"
Ident "int"
TypeDef
Ident "StaticTupleCl"
Empty
Command
Ident "static"
TupleClassTy
TypeDef
Ident "StaticTuple"
Empty
Command
Ident "static"
Par
Ident "int"
Ident "string"
TypeDef
Ident "BareType"
Empty
Ident "type"
TypeDef
Ident "GenericType"
Empty
BracketExpr
Ident "type"
Ident "float"
TypeDef
Ident "TypeTupleGen"
Empty
BracketExpr
Ident "type"
TupleClassTy
TypeDef
Ident "TypeTupleCl"
Empty
Command
Ident "type"
TupleClassTy
TypeDef
Ident "TypeInstance"
Empty
Command
Ident "type"
BracketExpr
Ident "Foo"
RefTy
TypeDef
Ident "bareTypeDesc"
Empty
Ident "typedesc"
TypeDef
Ident "TypeOfVar"
Empty
Call
Ident "type"
Ident "a"
TypeDef
Ident "TypeOfVarAlt"
Empty
Command
Ident "type"
Par
Ident "a"
TypeDef
Ident "TypeOfTuple1"
Empty
Call
Ident "type"
Ident "a"
TypeDef
Ident "TypeOfTuple2"
Empty
Call
Ident "type"
Ident "a"
Ident "b"
TypeDef
Ident "TypeOfTuple1A"
Empty
Command
Ident "type"
TupleConstr
Ident "a"
TypeDef
Ident "TypeOfTuple2A"
Empty
Command
Ident "type"
Par
Ident "a"
Ident "b"
TypeDef
Ident "TypeTuple"
Empty
Command
Ident "type"
Par
Ident "int"
Ident "string"
TypeDef
Ident "GenericTypedesc"
Empty
BracketExpr
Ident "typedesc"
Ident "int"
TypeDef
Ident "T"
Empty
Ident "type"
ProcDef
Ident "foo"
Empty
Empty
FormalParams
Ident "type"
IdentDefs
Ident "bareType"
Ident "type"
Empty
IdentDefs
Ident "genType"
BracketExpr
Ident "type"
Ident "int"
Empty
IdentDefs
Ident "typeInt"
Command
Ident "type"
Ident "int"
Empty
IdentDefs
Ident "typeIntAlt"
Call
Ident "type"
Ident "int"
Empty
IdentDefs
Ident "typeOfVar"
Call
Ident "type"
Ident "a"
Empty
IdentDefs
Ident "typeDotType"
DotExpr
Ident "foo"
Ident "type"
Empty
IdentDefs
Ident "typeTupleCl"
Command
Ident "type"
TupleClassTy
Empty
IdentDefs
Ident "bareStatic"
Ident "static"
Empty
IdentDefs
Ident "genStatic"
BracketExpr
Ident "static"
Ident "int"
Empty
IdentDefs
Ident "staticInt"
Command
Ident "static"
Ident "int"
Empty
IdentDefs
Ident "staticVal1"
Command
Ident "static"
IntLit 10
Empty
IdentDefs
Ident "staticVal2"
Call
Ident "static"
StrLit "str"
Empty
IdentDefs
Ident "staticVal3"
Command
Ident "static"
StrLit "str"
Empty
IdentDefs
Ident "staticVal4"
CallStrLit
Ident "static"
RStrLit "str"
Empty
IdentDefs
Ident "staticDotVal"
DotExpr
IntLit 10
Ident "static"
Empty
IdentDefs
Ident "bareRef"
RefTy
Empty
IdentDefs
Ident "refTuple1"
RefTy
Par
Ident "int"
Empty
IdentDefs
Ident "refTuple1A"
RefTy
TupleConstr
Ident "int"
Empty
IdentDefs
Ident "refTuple2"
RefTy
Par
Ident "int"
Ident "string"
Empty
IdentDefs
Ident "genRef"
RefTy
Bracket
Ident "int"
Empty
IdentDefs
Ident "refInt"
RefTy
Ident "int"
Empty
IdentDefs
Ident "refCall"
RefTy
Par
Ident "a"
Empty
IdentDefs
Ident "macroCall1"
Command
Ident "foo"
Ident "bar"
Empty
IdentDefs
Ident "macroCall2"
Call
Ident "foo"
Ident "bar"
Empty
IdentDefs
Ident "macroCall3"
Call
DotExpr
Ident "foo"
Ident "bar"
Ident "baz"
Empty
IdentDefs
Ident "macroCall4"
Call
BracketExpr
Ident "foo"
Ident "bar"
Ident "baz"
Empty
IdentDefs
Ident "macroCall5"
Command
Ident "foo"
Command
Ident "bar"
Ident "baz"
IntLit 10
Empty
Empty
StmtList
Asgn
Ident "staticTen"
Command
Ident "static"
IntLit 10
Asgn
Ident "staticA"
Call
Ident "static"
Ident "a"
Asgn
Ident "staticCall"
Command
Ident "static"
Call
Ident "foo"
IntLit 1
Asgn
Ident "staticStrCall"
Command
Ident "static"
CallStrLit
Ident "foo"
RStrLit "x"
Asgn
Ident "staticChainCall"
Command
Ident "static"
Command
Ident "foo"
Ident "bar"
Asgn
Ident "typeTen"
Command
Ident "type"
IntLit 10
Asgn
Ident "typeA"
Call
Ident "type"
Ident "a"
Asgn
Ident "typeCall"
Command
Ident "type"
Call
Ident "foo"
IntLit 1
Asgn
Ident "typeStrCall"
Command
Ident "type"
CallStrLit
Ident "foo"
RStrLit "x"
Asgn
Ident "typeChainCall"
Command
Ident "type"
Command
Ident "foo"
Ident "bar"
Asgn
Ident "normalChainCall"
Command
Ident "foo"
Command
Ident "bar"
Ident "baz"
Asgn
Ident "normalTupleCall2"
Call
Ident "foo"
Ident "a"
Ident "b"
StaticStmt
StmtList
Ident "singleStaticStmt"
StaticStmt
StmtList
Ident "staticStmtList1"
Ident "staticStmtList2"
'''
"""
import macros
dumpTree:
type
BarePtr = ptr
GenericPtr = ptr[int]
PrefixPtr = ptr int
PtrTuple = ptr (int, string)
BareRef = ref
GenericRef = ref[int]
RefTupleCl = ref tuple
RefTupleType = ref (int, string)
RefTupleVars = ref (a, b)
BareStatic = static # Used to be Error: invalid indentation
GenericStatic = static[int]
PrefixStatic = static int
StaticTupleCl = static tuple
StaticTuple = static (int, string)
BareType = type
GenericType = type[float]
TypeTupleGen = type[tuple]
TypeTupleCl = type tuple # Used to be Error: invalid indentation
TypeInstance = type Foo[ref]
bareTypeDesc = typedesc
TypeOfVar = type(a)
TypeOfVarAlt = type (a) # Used to be Error: invalid indentation
TypeOfTuple1 = type(a,)
TypeOfTuple2 = type(a,b)
TypeOfTuple1A = type (a,) # Used to be Error: invalid indentation
TypeOfTuple2A = type (a,b) # Used to be Error: invalid indentation
TypeTuple = type (int, string) # Used to be Error: invalid indentation
GenericTypedesc = typedesc[int]
T = type
proc foo(
bareType : type,
genType : type[int],
typeInt : type int,
typeIntAlt : type(int),
typeOfVar : type(a),
typeDotType : foo.type,
typeTupleCl : type tuple, # Used to be Error: ')' expected
bareStatic : static, # Used to be Error: expression expected, but found ','
genStatic : static[int],
staticInt : static int,
staticVal1 : static 10,
staticVal2 : static("str"),
staticVal3 : static "str",
staticVal4 : static"str", # Used to be Error: expression expected, but found 'str'
staticDotVal : 10.static,
bareRef : ref,
refTuple1 : ref (int),
refTuple1A : ref (int,),
refTuple2 : ref (int,string),
genRef : ref[int],
refInt : ref int,
refCall : ref(a),
macroCall1 : foo bar,
macroCall2 : foo(bar),
macroCall3 : foo.bar(baz),
macroCall4 : foo[bar](baz),
macroCall5 : foo bar baz = 10
): type =
staticTen = static 10
staticA = static(a)
# staticAspace = static (a) # With newTypedesc: Error: invalid indentation
# staticAtuple = static (a,) # With newTypedesc: Error: invalid indentation
# staticTuple = static (a,b) # With newTypedesc: Error: invalid indentation
# staticTypeTuple = static (int,string) # With newTypedesc: Error: invalid indentation
staticCall = static foo(1)
staticStrCall = static foo"x"
staticChainCall = static foo bar
typeTen = type 10
typeA = type(a)
# typeAspace = type (a) # Error: invalid indentation
# typeAtuple = type (a,) # Error: invalid indentation
# typeTuple = type (a,b) # Error: invalid indentation
# typeTypeTuple = type (int,string) # Error: invalid indentation
typeCall = type foo(1)
typeStrCall = type foo"x"
typeChainCall = type foo bar
normalChainCall = foo bar baz
# normalTupleCall1 = foo(a,) # Error: invalid indentation
normalTupleCall2 = foo(a,b)
# normalTupleCall3 = foo (a,b) # Error: invalid indentation
static: singleStaticStmt
static:
staticStmtList1
staticStmtList2

View file

@ -0,0 +1,109 @@
discard """
nimout: '''
staticAlialProc instantiated with 358
staticAlialProc instantiated with 368
'''
output: '''
16
16
b is 2 times a
17
'''
"""
import macros
template ok(x) = assert(x)
template no(x) = assert(not x)
template accept(x) =
static: assert(compiles(x))
template reject(x) =
static: assert(not compiles(x))
proc plus(a, b: int): int = a + b
template isStatic(x: static): bool = true
template isStatic(x: auto): bool = false
var v = 1
when true:
# test that `isStatic` works as expected
const C = 2
static:
ok C.isStatic
ok isStatic(plus(1, 2))
ok plus(C, 2).isStatic
no isStatic(v)
no plus(1, v).isStatic
when true:
# test that proc instantiation works as expected
type
StaticTypeAlias = static[int]
proc staticAliasProc(a: StaticTypeAlias,
b: static[int],
c: static int) =
static:
assert a.isStatic and b.isStatic and c.isStatic
assert isStatic(a + plus(b, c))
echo "staticAlialProc instantiated with ", a, b, c
when b mod a == 0:
echo "b is ", b div a, " times a"
echo a + b + c
staticAliasProc 1+2, 5, 8
staticAliasProc 3, 2+3, 9-1
staticAliasProc 3, 3+3, 4+4
when true:
# test static coercions. normal cases that should work:
accept:
var s1 = static[int] plus(1, 2)
var s2 = static(plus(1,2))
var s3 = static plus(1,2)
var s4 = static[SomeInteger](1 + 2)
# the sub-script operator can be used only with types:
reject:
var just_static3 = static[plus(1,2)]
# static coercion takes into account the type:
reject:
var x = static[string](plus(1, 2))
reject:
var x = static[string] plus(1, 2)
reject:
var x = static[SomeFloat] plus(3, 4)
# you cannot coerce a run-time variable
reject:
var x = static(v)
when true:
type
ArrayWrapper1[S: static int] = object
data: array[S + 1, int]
ArrayWrapper2[S: static[int]] = object
data: array[S.plus(2), int]
ArrayWrapper3[S: static[(int, string)]] = object
data: array[S[0], int]
var aw1: ArrayWrapper1[5]
var aw2: ArrayWrapper2[5]
var aw3: ArrayWrapper3[(10, "str")]
static:
assert aw1.data.high == 5
assert aw2.data.high == 6
assert aw3.data.high == 9

View file

@ -5,7 +5,7 @@ false
false
true
true
no'''
yes'''
"""
proc IsVoid[T](): string =