diff options
Diffstat (limited to 'tests/generics')
84 files changed, 3089 insertions, 778 deletions
diff --git a/tests/generics/m14509.nim b/tests/generics/m14509.nim new file mode 100644 index 000000000..cabc4f308 --- /dev/null +++ b/tests/generics/m14509.nim @@ -0,0 +1,16 @@ +import macros + +type float32x4 = array[4, float32] +type float32x8 = array[8, float32] + +{.experimental: "dynamicBindSym".} +macro dispatch(N: static int, T: type SomeNumber): untyped = + let BaseT = getTypeInst(T)[1] + result = bindSym($BaseT & "x" & $N) + +type + VecIntrin*[N: static int, T: SomeNumber] = dispatch(N, T) + +func `$`*[N, T](vec: VecIntrin[N, T]): string = + ## Display a vector + $cast[array[N, T]](vec) diff --git a/tests/generics/m22373a.nim b/tests/generics/m22373a.nim new file mode 100644 index 000000000..28e087ca6 --- /dev/null +++ b/tests/generics/m22373a.nim @@ -0,0 +1,7 @@ +# module a for t22373 + +# original: +type LightClientHeader* = object + +# simplified: +type TypeOrTemplate* = object diff --git a/tests/generics/m22373b.nim b/tests/generics/m22373b.nim new file mode 100644 index 000000000..67ee4211b --- /dev/null +++ b/tests/generics/m22373b.nim @@ -0,0 +1,18 @@ +# module b for t22373 + +import m22373a + +# original: +type + LightClientDataFork* {.pure.} = enum + None = 0, + Altair = 1 +template LightClientHeader*(kind: static LightClientDataFork): auto = + when kind == LightClientDataFork.Altair: + typedesc[m22373a.LightClientHeader] + else: + static: raiseAssert "Unreachable" + +# simplified: +template TypeOrTemplate*(num: int): untyped = + typedesc[m22373a.TypeOrTemplate] diff --git a/tests/generics/m3770.nim b/tests/generics/m3770.nim new file mode 100644 index 000000000..7f5714a2b --- /dev/null +++ b/tests/generics/m3770.nim @@ -0,0 +1,11 @@ +type + Noice* = object + hidden: int + +template jjj*: Noice = + Noice(hidden: 15) + +type Opt* = object + o: int + +template none*(O: type Opt): Opt = Opt(o: 0) diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim index 470fa0a51..090b97771 100644 --- a/tests/generics/mdotlookup.nim +++ b/tests/generics/mdotlookup.nim @@ -1,9 +1,9 @@ -proc baz(o: any): int = 5 # if bar is exported, it works +proc baz(o: auto): int = 5 # if bar is exported, it works type MyObj = object x: int -proc foo*(b: any) = +proc foo*(b: auto) = var o: MyObj echo b.baz, " ", o.x.baz, " ", b.baz() @@ -14,3 +14,15 @@ var intset = initHashSet[int]() proc fn*[T](a: T) = if a in intset: echo("true") else: echo("false") + +import strutils + +proc doStrip*[T](a: T): string = + result = ($a).strip() + +type Foo = int32 +proc baz2*[T](y: int): auto = + result = y.Foo + +proc set*(x: var int, a, b: string) = + x = a.len + b.len diff --git a/tests/generics/mfriends.nim b/tests/generics/mfriends.nim new file mode 100644 index 000000000..19672289e --- /dev/null +++ b/tests/generics/mfriends.nim @@ -0,0 +1,11 @@ + +type + TMyObj = object + x: int + +proc gen*[T](): T = + var d: TMyObj + # access private field here + d.x = 3 + result = d.x + diff --git a/tests/generics/module_with_generics.nim b/tests/generics/module_with_generics.nim index e801a4790..960a694d7 100644 --- a/tests/generics/module_with_generics.nim +++ b/tests/generics/module_with_generics.nim @@ -1,5 +1,5 @@ type - Base[T] = ref object {.inheritable.} + Base[T] {.inheritable.} = ref object value*: T Derived[T] = ref object of Base[T] diff --git a/tests/generics/mopensymimport1.nim b/tests/generics/mopensymimport1.nim new file mode 100644 index 000000000..912db1302 --- /dev/null +++ b/tests/generics/mopensymimport1.nim @@ -0,0 +1,34 @@ +type + Result*[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + +template valueOr*[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def diff --git a/tests/generics/mopensymimport2.nim b/tests/generics/mopensymimport2.nim new file mode 100644 index 000000000..c17aafd00 --- /dev/null +++ b/tests/generics/mopensymimport2.nim @@ -0,0 +1,16 @@ +{.experimental: "openSym".} + +import mopensymimport1 + +type Xxx = enum + error + value + +proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + +proc g*(T: type): string = + let x = f().valueOr: + return $error + + "ok" diff --git a/tests/generics/mtypenodes.nim b/tests/generics/mtypenodes.nim new file mode 100644 index 000000000..e1132241b --- /dev/null +++ b/tests/generics/mtypenodes.nim @@ -0,0 +1,6 @@ +# issue #22699 + +type Private = distinct int + +proc chop*[T](x: int): int = + cast[int](cast[tuple[field: Private]](x)) diff --git a/tests/generics/muninstantiatedgenericcalls.nim b/tests/generics/muninstantiatedgenericcalls.nim new file mode 100644 index 000000000..caed07c98 --- /dev/null +++ b/tests/generics/muninstantiatedgenericcalls.nim @@ -0,0 +1,26 @@ +import std/bitops + +const + lengths = block: + var v: array[64, int8] + for i in 0..<64: + v[i] = int8((i + 7) div 7) + v + +type + Leb128* = object + +{.push checks: off.} +func len(T: type Leb128, x: SomeUnsignedInt): int8 = + if x == 0: 1 + else: lengths[fastLog2(x)] +{.pop.} + +# note private to test scoping issue: +func maxLen(T: type Leb128, I: type): int8 = + Leb128.len(I.high) + +type + Leb128Buf*[T: SomeUnsignedInt] = object + data*: array[maxLen(Leb128, T), byte] + len*: int8 diff --git a/tests/generics/t12938.nim b/tests/generics/t12938.nim new file mode 100644 index 000000000..e09d65c7a --- /dev/null +++ b/tests/generics/t12938.nim @@ -0,0 +1,9 @@ +type + ExampleArray[Size, T] = array[Size, T] + +var integerArray: ExampleArray[32, int] # Compiler crash! +doAssert integerArray.len == 32 + +const Size = 2 +var integerArray2: ExampleArray[Size, int] +doAssert integerArray2.len == 2 diff --git a/tests/generics/t13525.nim b/tests/generics/t13525.nim index d1b8df78c..1fd84852b 100644 --- a/tests/generics/t13525.nim +++ b/tests/generics/t13525.nim @@ -1,6 +1,6 @@ # https://github.com/nim-lang/Nim/issues/13524 template fun(field): untyped = astToStr(field) -proc test1(): string = fun(nonexistant1) -proc test2[T](): string = fun(nonexistant2) # used to cause: Error: undeclared identifier: 'nonexistant2' -doAssert test1() == "nonexistant1" -doAssert test2[int]() == "nonexistant2" +proc test1(): string = fun(nonexistent1) +proc test2[T](): string = fun(nonexistent2) # used to cause: Error: undeclared identifier: 'nonexistent2' +doAssert test1() == "nonexistent1" +doAssert test2[int]() == "nonexistent2" diff --git a/tests/generics/t14193.nim b/tests/generics/t14193.nim new file mode 100644 index 000000000..213b1a8e6 --- /dev/null +++ b/tests/generics/t14193.nim @@ -0,0 +1,6 @@ +type + Task*[N: int] = object + env*: array[N, byte] + +var task14193: Task[20] +doAssert task14193.env.len == 20 diff --git a/tests/generics/t14509.nim b/tests/generics/t14509.nim new file mode 100644 index 000000000..ef3143ee4 --- /dev/null +++ b/tests/generics/t14509.nim @@ -0,0 +1,4 @@ +import m14509 + +var v: VecIntrin[4, float32] +doAssert $v == "[0.0, 0.0, 0.0, 0.0]" diff --git a/tests/generics/t1500.nim b/tests/generics/t1500.nim new file mode 100644 index 000000000..6dd457d33 --- /dev/null +++ b/tests/generics/t1500.nim @@ -0,0 +1,8 @@ +#issue 1500 + +type + TFtpBase*[SockType] = object + job: TFTPJob[SockType] + PFtpBase*[SockType] = ref TFtpBase[SockType] + TFtpClient* = TFtpBase[string] + TFTPJob[T] = object \ No newline at end of file diff --git a/tests/generics/t17509.nim b/tests/generics/t17509.nim new file mode 100644 index 000000000..89f507577 --- /dev/null +++ b/tests/generics/t17509.nim @@ -0,0 +1,25 @@ +type List[O] = object + next: ptr List[O] + +proc initList[O](l: ptr List[O]) = + l[].next = l + +type + PolytopeVertex[R] = object + list: List[PolytopeVertex[R]] + + PolytopeEdge[R] = object + list: List[PolytopeEdge[R]] + + Polytope[R] = object + vertices: List[PolytopeVertex[R]] + edges: List[PolytopeEdge[R]] + +var pt: Polytope[float] + +static: + doAssert pt.vertices.next is (ptr List[PolytopeVertex[float]]) + doAssert pt.edges.next is (ptr List[PolytopeEdge[float]]) + +initList(addr pt.vertices) +initList(addr pt.edges) \ No newline at end of file diff --git a/tests/generics/t18823.nim b/tests/generics/t18823.nim new file mode 100644 index 000000000..94c79aebe --- /dev/null +++ b/tests/generics/t18823.nim @@ -0,0 +1,6 @@ +type BitsRange[T] = range[0..sizeof(T)*8-1] + +proc bar[T](a: T; b: BitsRange[T]) = + discard + +bar(1, 2.Natural) diff --git a/tests/generics/t18859.nim b/tests/generics/t18859.nim new file mode 100644 index 000000000..ca6c3d10b --- /dev/null +++ b/tests/generics/t18859.nim @@ -0,0 +1,17 @@ +import macros + +macro symFromDesc(T: typedesc): untyped = + let typ = getType(T) + typ[1] + +template produceType(T: typedesc): untyped = + type + XT = object + x: symFromDesc(T) + + XT + +type + X[T] = produceType(T) + +var x: X[int] diff --git a/tests/generics/t19848.nim b/tests/generics/t19848.nim new file mode 100644 index 000000000..f80f0e298 --- /dev/null +++ b/tests/generics/t19848.nim @@ -0,0 +1,16 @@ +discard """ + output: ''' +todo +''' +""" + +type + Maybe[T] = object + List[T] = object + +proc dump[M: Maybe](a: List[M]) = + echo "todo" + +var a: List[Maybe[int]] + +dump(a) diff --git a/tests/generics/t20996.nim b/tests/generics/t20996.nim new file mode 100644 index 000000000..8aa83c4e2 --- /dev/null +++ b/tests/generics/t20996.nim @@ -0,0 +1,15 @@ +discard """ + action: compile +""" + +import std/macros + +macro matchMe(x: typed): untyped = + discard x.getTypeImpl + +type + ElementRT = object + Element[Z] = ElementRT # this version is needed, even though we don't use it + +let ar = ElementRT() +matchMe(ar) diff --git a/tests/generics/t21742.nim b/tests/generics/t21742.nim new file mode 100644 index 000000000..c49c8ee97 --- /dev/null +++ b/tests/generics/t21742.nim @@ -0,0 +1,10 @@ +type + Foo[T] = object + x:T + Bar[T,R] = Foo[T] + Baz = Bar[int,float] + +proc qux[T,R](x: Bar[T,R]) = discard + +var b:Baz +b.qux() \ No newline at end of file diff --git a/tests/generics/t21760.nim b/tests/generics/t21760.nim new file mode 100644 index 000000000..5343279bb --- /dev/null +++ b/tests/generics/t21760.nim @@ -0,0 +1,8 @@ +import std/tables + +type Url = object + +proc myInit(_: type[Url], params = default(Table[string, string])): Url = + discard + +discard myInit(Url) \ No newline at end of file diff --git a/tests/generics/t21958.nim b/tests/generics/t21958.nim new file mode 100644 index 000000000..f566b57cb --- /dev/null +++ b/tests/generics/t21958.nim @@ -0,0 +1,11 @@ +discard """ + action: compile +""" + +type + Ct*[T: SomeUnsignedInt] = distinct T + +template `shr`*[T: Ct](x: T, y: SomeInteger): T = T(T.T(x) shr y) + +var x: Ct[uint64] +let y {.used.} = x shr 2 \ No newline at end of file diff --git a/tests/generics/t22373.nim b/tests/generics/t22373.nim new file mode 100644 index 000000000..ecfaf0f1b --- /dev/null +++ b/tests/generics/t22373.nim @@ -0,0 +1,16 @@ +# issue #22373 + +import m22373a +import m22373b + +# original: +template lazy_header(name: untyped): untyped {.dirty.} = + var `name _ ptr`: ptr[data_fork.LightClientHeader] # this data_fork.Foo part seems required to reproduce +proc createLightClientUpdates(data_fork: static LightClientDataFork) = + lazy_header(attested_header) +createLightClientUpdates(LightClientDataFork.Altair) + +# simplified: +proc generic[T](abc: T) = + var x: abc.TypeOrTemplate +generic(123) diff --git a/tests/generics/t22826.nim b/tests/generics/t22826.nim new file mode 100644 index 000000000..914d4243a --- /dev/null +++ b/tests/generics/t22826.nim @@ -0,0 +1,8 @@ +import std/tables + +var a: Table[string, float] + +type Value*[T] = object + table: Table[string, Value[T]] + +discard toTable({"a": Value[float]()}) \ No newline at end of file diff --git a/tests/generics/t23186.nim b/tests/generics/t23186.nim new file mode 100644 index 000000000..76f38da6b --- /dev/null +++ b/tests/generics/t23186.nim @@ -0,0 +1,155 @@ +# issue #23186 + +block: # simplified + template typedTempl(x: int, body): untyped = + body + proc generic1[T]() = + discard + proc generic2[T]() = + typedTempl(1): + let x = generic1[T] + generic2[int]() + +import std/macros + +when not compiles(len((1, 2))): + import std/typetraits + + func len(x: tuple): int = + arity(type(x)) + +block: # full issue example + type FieldDescription = object + name: NimNode + func isTuple(t: NimNode): bool = + t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple") + proc collectFieldsFromRecList(result: var seq[FieldDescription], + n: NimNode, + parentCaseField: NimNode = nil, + parentCaseBranch: NimNode = nil, + isDiscriminator = false) = + case n.kind + of nnkRecList: + for entry in n: + collectFieldsFromRecList result, entry, + parentCaseField, parentCaseBranch + of nnkIdentDefs: + for i in 0 ..< n.len - 2: + var field: FieldDescription + field.name = n[i] + if field.name.kind == nnkPragmaExpr: + field.name = field.name[0] + if field.name.kind == nnkPostfix: + field.name = field.name[1] + result.add field + of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty: + discard + else: + doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr + proc collectFieldsInHierarchy(result: var seq[FieldDescription], + objectType: NimNode) = + var objectType = objectType + if objectType.kind == nnkRefTy: + objectType = objectType[0] + let recList = objectType[2] + collectFieldsFromRecList result, recList + proc recordFields(typeImpl: NimNode): seq[FieldDescription] = + let objectType = case typeImpl.kind + of nnkObjectTy: typeImpl + of nnkTypeDef: typeImpl[2] + else: + macros.error("object type expected", typeImpl) + return + collectFieldsInHierarchy(result, objectType) + proc skipPragma(n: NimNode): NimNode = + if n.kind == nnkPragmaExpr: n[0] + else: n + func declval(T: type): T = + doAssert false, + "declval should be used only in `typeof` expressions and concepts" + default(ptr T)[] + macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped = + var typeAst = getType(T)[1] + var typeImpl: NimNode + let isSymbol = not typeAst.isTuple + if not isSymbol: + typeImpl = typeAst + else: + typeImpl = getImpl(typeAst) + result = newStmtList() + var i = 0 + for field in recordFields(typeImpl): + let + fieldIdent = field.name + realFieldName = newLit($fieldIdent.skipPragma) + fieldName = realFieldName + fieldIndex = newLit(i) + let fieldNameDefs = + if isSymbol: + quote: + const fieldName {.inject, used.} = `fieldName` + const realFieldName {.inject, used.} = `realFieldName` + else: + quote: + const fieldName {.inject, used.} = $`fieldIndex` + const realFieldName {.inject, used.} = $`fieldIndex` + # we can't access .Fieldn, so our helper knows + # to parseInt this + let field = + if isSymbol: + quote do: declval(`T`).`fieldIdent` + else: + quote do: declval(`T`)[`fieldIndex`] + result.add quote do: + block: + `fieldNameDefs` + type FieldType {.inject, used.} = type(`field`) + `body` + i += 1 + template enumAllSerializedFields(T: type, body): untyped = + when T is ref|ptr: + type TT = type(default(T)[]) + enumAllSerializedFieldsImpl(TT, body) + else: + enumAllSerializedFieldsImpl(T, body) + type + MemRange = object + startAddr: ptr byte + length: int + SszNavigator[T] = object + m: MemRange + func sszMount(data: openArray[byte], T: type): SszNavigator[T] = + let startAddr = unsafeAddr data[0] + SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len)) + func sszMount(data: openArray[char], T: type): SszNavigator[T] = + let startAddr = cast[ptr byte](unsafeAddr data[0]) + SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len)) + template sszMount(data: MemRange, T: type): SszNavigator[T] = + SszNavigator[T](m: data) + func navigateToField[T]( + n: SszNavigator[T], + FieldType: type): SszNavigator[FieldType] = + default(SszNavigator[FieldType]) + type + FieldInfo = ref object + navigator: proc (m: MemRange): MemRange {. + gcsafe, noSideEffect, raises: [IOError] .} + func fieldNavigatorImpl[RecordType; FieldType; fieldName: static string]( + m: MemRange): MemRange = + var typedNavigator = sszMount(m, RecordType) + discard navigateToField(typedNavigator, FieldType) + default(MemRange) + func genTypeInfo(T: type) = + when T is object: + enumAllSerializedFields(T): + discard FieldInfo(navigator: fieldNavigatorImpl[T, FieldType, fieldName]) + type + Foo = object + bar: Bar + BarList = seq[uint64] + Bar = object + b: BarList + baz: Baz + Baz = object + i: uint64 + genTypeInfo(Foo) diff --git a/tests/generics/t23790.nim b/tests/generics/t23790.nim new file mode 100644 index 000000000..9ac0df6a1 --- /dev/null +++ b/tests/generics/t23790.nim @@ -0,0 +1,14 @@ +# bug #23790 + +discard compiles($default(seq[seq[ref int]])) +discard compiles($default(seq[seq[ref uint]])) +discard compiles($default(seq[seq[ref int8]])) +discard compiles($default(seq[seq[ref uint8]])) +discard compiles($default(seq[seq[ref int16]])) +discard compiles($default(seq[seq[ref uint16]])) +discard compiles($default(seq[seq[ref int32]])) +discard compiles($default(seq[seq[ref uint32]])) +discard compiles($default(seq[seq[ref int64]])) +discard compiles($default(seq[seq[ref uint64]])) +proc s(_: int | string) = discard +s(0) diff --git a/tests/generics/t23853.nim b/tests/generics/t23853.nim new file mode 100644 index 000000000..bc9514a53 --- /dev/null +++ b/tests/generics/t23853.nim @@ -0,0 +1,91 @@ +# issue #23853 + +block simplified: + type QuadraticExt[F] = object + coords: array[2, F] + template Name(E: type QuadraticExt): int = 123 + template getBigInt(Name: static int): untyped = int + type Foo[GT] = object + a: getBigInt(GT.Name) + var x: Foo[QuadraticExt[int]] + +import std/macros + +type + Algebra* = enum + BN254_Snarks + BLS12_381 + + Fp*[Name: static Algebra] = object + limbs*: array[4, uint64] + + QuadraticExt*[F] = object + ## Quadratic Extension field + coords*: array[2, F] + + CubicExt*[F] = object + ## Cubic Extension field + coords*: array[3, F] + + ExtensionField*[F] = QuadraticExt[F] or CubicExt[F] + + Fp2*[Name: static Algebra] = + QuadraticExt[Fp[Name]] + + Fp4*[Name: static Algebra] = + QuadraticExt[Fp2[Name]] + + Fp6*[Name: static Algebra] = + CubicExt[Fp2[Name]] + + Fp12*[Name: static Algebra] = + CubicExt[Fp4[Name]] + # QuadraticExt[Fp6[Name]] + +template Name*(E: type ExtensionField): Algebra = + E.F.Name + +const BLS12_381_Order = [uint64 0x1, 0x2, 0x3, 0x4] +const BLS12_381_Modulus = [uint64 0x5, 0x6, 0x7, 0x8] + + +{.experimental: "dynamicBindSym".} + +macro baseFieldModulus*(Name: static Algebra): untyped = + result = bindSym($Name & "_Modulus") + +macro scalarFieldModulus*(Name: static Algebra): untyped = + result = bindSym($Name & "_Order") + +type FieldKind* = enum + kBaseField + kScalarField + +template getBigInt*(Name: static Algebra, kind: static FieldKind): untyped = + # Workaround: + # in `ptr UncheckedArray[BigInt[EC.getScalarField().bits()]] + # EC.getScalarField is not accepted by the compiler + # + # and `ptr UncheckedArray[BigInt[Fr[EC.F.Name].bits]]` gets undeclared field: 'Name' + # + # but `ptr UncheckedArray[getBigInt(EC.getName(), kScalarField)]` works fine + when kind == kBaseField: + Name.baseFieldModulus().typeof() + else: + Name.scalarFieldModulus().typeof() + +# ------------------------------------------------------------------------------ + +type BenchMultiexpContext*[GT] = object + elems: seq[GT] + exponents: seq[getBigInt(GT.Name, kScalarField)] + +proc createBenchMultiExpContext*(GT: typedesc, inputSizes: openArray[int]): BenchMultiexpContext[GT] = + discard + +# ------------------------------------------------------------------------------ + +proc main() = + let ctx = createBenchMultiExpContext(Fp12[BLS12_381], [2, 4, 8, 16]) + +main() diff --git a/tests/generics/t23854.nim b/tests/generics/t23854.nim new file mode 100644 index 000000000..f1175c8b2 --- /dev/null +++ b/tests/generics/t23854.nim @@ -0,0 +1,71 @@ +# issue #23854, not entirely fixed + +import std/bitops + +const WordBitWidth = sizeof(pointer) * 8 + +func wordsRequired*(bits: int): int {.inline.} = + const divShiftor = fastLog2(uint32(WordBitWidth)) + result = (bits + WordBitWidth - 1) shr divShiftor + +type + Algebra* = enum + BLS12_381 + + BigInt*[bits: static int] = object + limbs*: array[wordsRequired(bits), uint] + + Fr*[Name: static Algebra] = object + residue_form*: BigInt[255] + + Fp*[Name: static Algebra] = object + residue_form*: BigInt[381] + + FF*[Name: static Algebra] = Fp[Name] or Fr[Name] + +template getBigInt*[Name: static Algebra](T: type FF[Name]): untyped = + ## Get the underlying BigInt type. + typeof(default(T).residue_form) + +type + EC_ShortW_Aff*[F] = object + ## Elliptic curve point for a curve in Short Weierstrass form + ## y² = x³ + a x + b + ## + ## over a field F + x*, y*: F + +type FieldKind* = enum + kBaseField + kScalarField + +func bits*[Name: static Algebra](T: type FF[Name]): static int = + T.getBigInt().bits + +template getScalarField*(EC: type EC_ShortW_Aff): untyped = + Fr[EC.F.Name] + +# ------------------------------------------------------------------------------ + +type + ECFFT_Descriptor*[EC] = object + ## Metadata for FFT on Elliptic Curve + order*: int + rootsOfUnity1*: ptr UncheckedArray[BigInt[EC.getScalarField().bits()]] # Error: in expression 'EC.getScalarField()': identifier expected, but found 'EC.getScalarField' + rootsOfUnity2*: ptr UncheckedArray[BigInt[getScalarField(EC).bits()]] # Compiler SIGSEGV: Illegal Storage Access + +func new*(T: type ECFFT_Descriptor): T = + discard + +# ------------------------------------------------------------------------------ + +template getBits[bits: static int](x: ptr UncheckedArray[BigInt[bits]]): int = bits + +proc main() = + let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new() + doAssert getBits(ctx.rootsOfUnity1) == 255 + doAssert getBits(ctx.rootsOfUnity2) == 255 + doAssert ctx.rootsOfUnity1[0].limbs.len == wordsRequired(255) + doAssert ctx.rootsOfUnity2[0].limbs.len == wordsRequired(255) + +main() diff --git a/tests/generics/t23855.nim b/tests/generics/t23855.nim new file mode 100644 index 000000000..da8135a98 --- /dev/null +++ b/tests/generics/t23855.nim @@ -0,0 +1,61 @@ +# issue #23855, not entirely fixed + +import std/bitops + +const WordBitWidth = sizeof(pointer) * 8 + +func wordsRequired*(bits: int): int {.inline.} = + const divShiftor = fastLog2(uint32(WordBitWidth)) + result = (bits + WordBitWidth - 1) shr divShiftor + +type + Algebra* = enum + BLS12_381 + + BigInt*[bits: static int] = object + limbs*: array[wordsRequired(bits), uint] + + Fr*[Name: static Algebra] = object + residue_form*: BigInt[255] + + Fp*[Name: static Algebra] = object + residue_form*: BigInt[381] + + FF*[Name: static Algebra] = Fp[Name] or Fr[Name] + +template getBigInt*[Name: static Algebra](T: type FF[Name]): untyped = + ## Get the underlying BigInt type. + typeof(default(T).residue_form) + +type + EC_ShortW_Aff*[F] = object + ## Elliptic curve point for a curve in Short Weierstrass form + ## y² = x³ + a x + b + ## + ## over a field F + x*, y*: F + +func bits*[Name: static Algebra](T: type FF[Name]): static int = + T.getBigInt().bits + +# ------------------------------------------------------------------------------ + +type + ECFFT_Descriptor*[EC] = object + ## Metadata for FFT on Elliptic Curve + order*: int + rootsOfUnity*: ptr UncheckedArray[BigInt[Fr[EC.F.Name].bits()]] # Undeclared identifier `Name` + +func new*(T: type ECFFT_Descriptor): T = + discard + +# ------------------------------------------------------------------------------ + +template getBits[bits: static int](x: ptr UncheckedArray[BigInt[bits]]): int = bits + +proc main() = + let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new() + doAssert getBits(ctx.rootsOfUnity) == 255 + doAssert ctx.rootsOfUnity[0].limbs.len == wordsRequired(255) + +main() diff --git a/tests/generics/t3770.nim b/tests/generics/t3770.nim new file mode 100644 index 000000000..ffccbeeb5 --- /dev/null +++ b/tests/generics/t3770.nim @@ -0,0 +1,13 @@ +# bug #3770 +import m3770 + +doAssert $jjj() == "(hidden: 15)" # works + +proc someGeneric(_: type) = + doAssert $jjj() == "(hidden: 15)" # fails: "Error: the field 'hidden' is not accessible." + +someGeneric(int) + +# bug #20900 +proc c(y: int | int, w: Opt = Opt.none) = discard +c(0) diff --git a/tests/generics/t4668.nim b/tests/generics/t4668.nim new file mode 100644 index 000000000..bd44cc975 --- /dev/null +++ b/tests/generics/t4668.nim @@ -0,0 +1,166 @@ +discard """ + output: ''' +foo1 +foo2 +''' +""" + +block: + type + FooObj[T] = object + v: T + Foo1[T] = FooObj[T] + Foo2 = FooObj + + proc foo1(x: Foo1) = echo "foo1" + proc foo2(x: Foo2) = echo "foo2" + + var x: FooObj[float] + foo1(x) # works + foo2(x) # works + +block: + type + FooObj[T] = T + Foo1[T] = FooObj[T] + Foo2 = FooObj + Foo3 = Foo1 + Foo4x = FooObj[SomeInteger] + Foo4 = FooObj[SomeFloat] + Foo5x = Foo1[SomeInteger] + Foo5 = Foo1[SomeFloat] + + proc foo0(x: FooObj): int = 0 + proc foo1(x: Foo1): int = 1 + proc foo2(x: Foo2): int = 2 + proc foo3(x: Foo3): int = 3 + proc foo4(x: Foo4x): int = 40 + proc foo4(x: Foo4): int = 4 + proc foo5(x: Foo5x): int = 50 + proc foo5(x: Foo5): int = 5 + + block: + var x: FooObj[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + block: + var x: Foo1[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + block: + var x: Foo2[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + +block: + type + FooObj[T,U] = object + x: T + y: U + Foo1[U,T] = FooObj[T,U] + Foo2 = FooObj + Foo3 = Foo1 + Foo4x = FooObj[SomeInteger,SomeInteger] + Foo4y = FooObj[SomeInteger,SomeFloat] + Foo4z = FooObj[SomeFloat,SomeFloat] + Foo4 = FooObj[SomeFloat,SomeInteger] + Foo5x = Foo1[SomeInteger,SomeInteger] + Foo5y = Foo1[SomeFloat,SomeInteger] + Foo5z = Foo1[SomeFloat,SomeFloat] + Foo5 = Foo1[SomeInteger,SomeFloat] + + proc foo0(x: FooObj): int = 0 + proc foo1(x: Foo1): int = 1 + proc foo2(x: Foo2): int = 2 + proc foo3(x: Foo3): int = 3 + proc foo4(x: Foo4x): int = 40 + proc foo4(x: Foo4y): int = 41 + proc foo4(x: Foo4z): int = 42 + proc foo4(x: Foo4): int = 4 + proc foo5(x: Foo5x): int = 50 + proc foo5(x: Foo5y): int = 51 + proc foo5(x: Foo5z): int = 52 + proc foo5(x: Foo5): int = 5 + + block: + var x: FooObj[float,int] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + block: + var x: Foo1[int,float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + +block: + type + FooObj[T] = object of RootObj + v: T + FooObj2[T] = object of FooObj[T] + Foo1[T] = FooObj[T] + Foo2 = FooObj + Foo3 = Foo1 + Foo4x = FooObj[SomeInteger] + Foo4 = FooObj[SomeFloat] + Foo5x = Foo1[SomeInteger] + Foo5 = Foo1[SomeFloat] + + proc foo0(x: FooObj): int = 0 + proc foo1(x: Foo1): int = 1 + proc foo2(x: Foo2): int = 2 + proc foo3(x: Foo3): int = 3 + proc foo4(x: Foo4x): int = 40 + proc foo4(x: Foo4): int = 4 + proc foo5(x: Foo5x): int = 50 + proc foo5(x: Foo5): int = 5 + + block: + var x: FooObj[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + block: + var x: Foo1[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + + #[ XXX These still fail + block: + var x: FooObj2[float] + doAssert(foo0(x) == 0) + doAssert(foo1(x) == 1) + doAssert(foo2(x) == 2) + doAssert(foo3(x) == 3) + doAssert(foo4(x) == 4) + doAssert(foo5(x) == 5) + ]# diff --git a/tests/generics/t500.nim b/tests/generics/t500.nim new file mode 100644 index 000000000..2486359aa --- /dev/null +++ b/tests/generics/t500.nim @@ -0,0 +1,8 @@ +discard """ +action: compile +""" + +type + TTest = tuple[x: range[0..80], y: range[0..25]] + +let x: TTest = (2, 23) diff --git a/tests/generics/t5926.nim b/tests/generics/t5926.nim new file mode 100644 index 000000000..bb14c3af5 --- /dev/null +++ b/tests/generics/t5926.nim @@ -0,0 +1,22 @@ +discard """ +action: compile +""" + +type + SomeObj[T] = object + +template useSomeObj[T]() = + var retObj: SomeObj[T] + +useSomeObj[void]() +useSomeObj[int]() + + +type + Data*[T] = object + x: T + +template test*[T](xxx: T) = + let data = Data[T](x: xxx) + +test(1) diff --git a/tests/generics/t6060.nim b/tests/generics/t6060.nim new file mode 100644 index 000000000..6b1856f1c --- /dev/null +++ b/tests/generics/t6060.nim @@ -0,0 +1,11 @@ +import tables + +type MyTab[A,B] = distinct TableRef[A,B] + +proc `$`[A,B](t: MyTab[A,B]): string = + "My special table " & $TableRef[A,B](t) + +proc create[A,B](): MyTab[A,B] = MyTab(newTable[A,B]()) + +var a = create[int,int]() +doAssert $a == "My special table {:}" diff --git a/tests/generics/t6137.nim b/tests/generics/t6137.nim index 991f39dd1..fb7db22f8 100644 --- a/tests/generics/t6137.nim +++ b/tests/generics/t6137.nim @@ -1,6 +1,6 @@ discard """ - errormsg: "\'vectFunc\' doesn't have a concrete type, due to unspecified generic parameters." - line: 28 + errormsg: "cannot instantiate: 'T'" + line: 19 """ type diff --git a/tests/generics/t6637.nim b/tests/generics/t6637.nim new file mode 100644 index 000000000..dd4f339a2 --- /dev/null +++ b/tests/generics/t6637.nim @@ -0,0 +1,9 @@ + +type + Grid2D*[I: SomeInteger, w, h: static[I], T] = object + grid: array[w, array[h, T]] + Grid2DIns = Grid2D[int, 2, 3, uint8] + +let a = Grid2DIns() +doAssert a.grid.len == 2 +doAssert a.grid[0].len == 3 diff --git a/tests/generics/t7446.nim b/tests/generics/t7446.nim new file mode 100644 index 000000000..71aa8f0e8 --- /dev/null +++ b/tests/generics/t7446.nim @@ -0,0 +1,10 @@ +proc foo(x: Natural or SomeUnsignedInt):int = + when x is int: + result = 1 + else: + result = 2 +let a = 10 +doAssert foo(a) == 1 + +let b = 10'u8 +doAssert foo(b) == 2 \ No newline at end of file diff --git a/tests/generics/t7839.nim b/tests/generics/t7839.nim new file mode 100644 index 000000000..4d17b438b --- /dev/null +++ b/tests/generics/t7839.nim @@ -0,0 +1,9 @@ +type A[I: SomeOrdinal, E] = tuple # same for object + length: int + +doAssert A.sizeof == sizeof(int) # works without the following proc + +proc newA*[I: SomeOrdinal, E](): A[I, E] = # works without `SomeOrdinal` + discard + +discard newA[uint8, int]() diff --git a/tests/generics/taliashijack.nim b/tests/generics/taliashijack.nim new file mode 100644 index 000000000..fdebadded --- /dev/null +++ b/tests/generics/taliashijack.nim @@ -0,0 +1,8 @@ +# issue #23977 + +type Foo[T] = int + +proc foo(T: typedesc) = + var a: T + +foo(int) diff --git a/tests/generics/tbadcache.nim b/tests/generics/tbadcache.nim new file mode 100644 index 000000000..33e65be3a --- /dev/null +++ b/tests/generics/tbadcache.nim @@ -0,0 +1,26 @@ +# issue #16128 + +import std/[tables, hashes] + +type + NodeId*[L] = object + isSource: bool + index: Table[NodeId[L], seq[NodeId[L]]] + +func hash*[L](id: NodeId[L]): Hash = discard +func `==`[L](a, b: NodeId[L]): bool = discard + +proc makeIndex*[T, L](tree: T) = + var parent = NodeId[L]() + var tmp: Table[NodeId[L], seq[NodeId[L]]] + tmp[parent] = @[parent] + +proc simpleTreeDiff*[T, L](source, target: T) = + # Swapping these two lines makes error disappear + var m: Table[NodeId[L], NodeId[L]] + makeIndex[T, L](target) + +var tmp: Table[string, seq[string]] # removing this forward declaration also removes error + +proc diff(x1, x2: string): auto = + simpleTreeDiff[int, string](12, 12) diff --git a/tests/generics/tbaddeprecated.nim b/tests/generics/tbaddeprecated.nim new file mode 100644 index 000000000..335234a25 --- /dev/null +++ b/tests/generics/tbaddeprecated.nim @@ -0,0 +1,55 @@ +discard """ + output: ''' +not deprecated +not deprecated +not error +not error +''' +""" + +# issue #21724 + +block: # deprecated + {.push warningAsError[Deprecated]: on.} + type + SomeObj = object + hey: bool + proc hey() {.deprecated: "Shouldn't use this".} = echo "hey" + proc gen(o: auto) = + doAssert not compiles(o.hey()) + if o.hey: + echo "not deprecated" + gen(SomeObj(hey: true)) + doAssert not (compiles do: + proc hey(o: SomeObj) {.deprecated: "Shouldn't use this".} = echo "hey" + proc gen2(o: auto) = + if o.hey(): + echo "not deprecated" + gen2(SomeObj(hey: true))) + proc hey(o: SomeObj) {.deprecated: "Shouldn't use this".} = echo "hey" + proc gen3(o: auto) = + if o.hey: + echo "not deprecated" + gen3(SomeObj(hey: true)) + {.pop.} +block: # error + type + SomeObj = object + hey: bool + proc hey() {.error: "Shouldn't use this".} = echo "hey" + proc gen(o: auto) = + doAssert not compiles(o.hey()) + if o.hey: + echo "not error" + gen(SomeObj(hey: true)) + doAssert not (compiles do: + proc hey(o: SomeObj) {.error: "Shouldn't use this".} = echo "hey" + proc gen2(o: auto) = + if o.hey(): + echo "not error" + gen2(SomeObj(hey: true))) + proc hey(o: SomeObj) {.error: "Shouldn't use this".} = echo "hey" + proc gen3(o: auto) = + if o.hey: + echo "not error" + gen3(SomeObj(hey: true)) diff --git a/tests/generics/tbintree.nim b/tests/generics/tbintree.nim index a1a13c7b5..83f14406b 100644 --- a/tests/generics/tbintree.nim +++ b/tests/generics/tbintree.nim @@ -55,8 +55,8 @@ proc find*[Ty2](b: PBinaryTree[Ty2], data: Ty2): bool = iterator preorder*[T](root: PBinaryTree[T]): T = # Preorder traversal of a binary tree. - # Since recursive iterators are not yet implemented, - # this uses an explicit stack: + # This uses an explicit stack (which is more efficient than + # a recursive iterator factory). var stack: seq[PBinaryTree[T]] = @[root] while stack.len > 0: var n = stack.pop() diff --git a/tests/generics/tbracketinstantiation.nim b/tests/generics/tbracketinstantiation.nim new file mode 100644 index 000000000..22a86af4c --- /dev/null +++ b/tests/generics/tbracketinstantiation.nim @@ -0,0 +1,86 @@ +discard """ + nimout: ''' +type + Bob = object +type + Another = object +''' +""" + +block: # issue #22645 + type + Opt[T] = object + FutureBase = ref object of RootObj + Future[T] = ref object of FutureBase ## Typed future. + internalValue: T ## Stored value + template err[T](E: type Opt[T]): E = E() + proc works(): Future[Opt[int]] {.stackTrace: off, gcsafe, raises: [].} = + var chronosInternalRetFuture: FutureBase + template result(): untyped {.used.} = + Future[Opt[int]](chronosInternalRetFuture).internalValue + result = err(type(result)) + proc breaks(): Future[Opt[int]] {.stackTrace: off, gcsafe, raises: [].} = + var chronosInternalRetFuture: FutureBase + template result(): untyped {.used.} = + cast[Future[Opt[int]]](chronosInternalRetFuture).internalValue + result = err(type(result)) + +import macros + +block: # issue #16118 + macro thing(name: static[string]) = + result = newStmtList( + nnkTypeSection.newTree( + nnkTypeDef.newTree( + ident(name), + newEmptyNode(), + nnkObjectTy.newTree( + newEmptyNode(), + newEmptyNode(), + nnkRecList.newTree())))) + template foo(name: string): untyped = + thing(name) + expandMacros: + foo("Bob") + block: + expandMacros: + foo("Another") + +block: # issue #19670 + type + Past[Z] = object + OpenObject = object + + macro rewriter(prc: untyped): untyped = + prc.body.add(nnkCall.newTree( + prc.params[0] + )) + prc + + macro macroAsync(name, restype: untyped): untyped = + quote do: + proc `name`(): Past[seq[`restype`]] {.rewriter.} = discard + + macroAsync(testMacro, OpenObject) + +import asyncdispatch + +block: # issue #11838 long + type + R[P] = object + updates: seq[P] + D[T, P] = ref object + ps: seq[P] + t: T + proc newD[T, P](ps: seq[P], t: T): D[T, P] = + D[T, P](ps: ps, t: t) + proc loop[T, P](d: D[T, P]) = + var results = newSeq[Future[R[P]]](10) + let d = newD[string, int](@[1], "") + d.loop() + +block: # issue #11838 minimal + type R[T] = object + proc loop[T]() = + discard newSeq[R[R[T]]]() + loop[int]() diff --git a/tests/generics/tcalltype.nim b/tests/generics/tcalltype.nim new file mode 100644 index 000000000..cba691f77 --- /dev/null +++ b/tests/generics/tcalltype.nim @@ -0,0 +1,26 @@ +discard """ + joinable: false # breaks everything because of #23977 +""" + +# issue #23406 + +template helper(_: untyped): untyped = + int + +type # Each of them should always be `int`. + GenA[T] = helper int + GenB[T] = helper(int) + GenC[T] = helper helper(int) + +block: + template helper(_: untyped): untyped = + float + + type + A = GenA[int] + B = GenB[int] + C = GenC[int] + + assert A is int # OK. + assert B is int # Fails; it is `float`! + assert C is int # OK. diff --git a/tests/generics/tcan.nim b/tests/generics/tcan.nim index eea69cdb7..bbefa7233 100644 --- a/tests/generics/tcan.nim +++ b/tests/generics/tcan.nim @@ -31,7 +31,7 @@ block tinherit: block tspecialise: type - TGen[T] = object {.inheritable.} + TGen[T] {.inheritable.} = object TSpef = object of TGen[string] diff --git a/tests/generics/tconstraints.nim b/tests/generics/tconstraints.nim new file mode 100644 index 000000000..3ca01cfd5 --- /dev/null +++ b/tests/generics/tconstraints.nim @@ -0,0 +1,16 @@ +discard """ + errormsg: "type mismatch: got <int literal(232)>" + line: 16 +""" + +proc myGenericProc[T: object|tuple|ptr|ref|distinct](x: T): string = + result = $x + +type + TMyObj = tuple[x, y: int] + +var + x: TMyObj + +assert myGenericProc(x) == "(x: 0, y: 0)" +assert myGenericProc(232) == "232" diff --git a/tests/generics/texplicitgeneric2.nim b/tests/generics/texplicitgeneric2.nim index 573b10ae8..37b133130 100644 --- a/tests/generics/texplicitgeneric2.nim +++ b/tests/generics/texplicitgeneric2.nim @@ -1,6 +1,5 @@ discard """ output: "Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13" - disabled: true """ # test explicit type instantiation @@ -14,12 +13,12 @@ proc newDict*[TKey, TValue](): PDict[TKey, TValue] = new(result) result.data = @[] -proc add*(d: PDict, k: TKey, v: TValue) = +proc add*(d: PDict, k: d.TKey, v: d.TValue) = d.data.add((k, v)) -#iterator items*(d: PDict): tuple[k: TKey, v: TValue] = -# for k, v in items(d.data): yield (k, v) +iterator items*(d: PDict): tuple[k: d.TKey, v: d.TValue] = + for k, v in items(d.data): yield (k, v) var d = newDict[int, string]() d.add(12, "12") diff --git a/tests/generics/tfriends.nim b/tests/generics/tfriends.nim new file mode 100644 index 000000000..1e70d50a5 --- /dev/null +++ b/tests/generics/tfriends.nim @@ -0,0 +1,11 @@ +discard """ + output: "3" +""" + +# Tests that a generic instantiation from a different module may access +# private object fields: + +import mfriends + +echo gen[int]() + diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim index 44c34917d..16a148f7b 100644 --- a/tests/generics/tgeneric0.nim +++ b/tests/generics/tgeneric0.nim @@ -9,7 +9,7 @@ float32 """ -import tables +import std/tables block tgeneric0: @@ -153,3 +153,44 @@ proc unzip*[T,U](xs: List[tuple[t: T, u: U]]): (List[T], List[U]) = discard proc unzip2*[T,U](xs: List[(T,U)]): (List[T], List[U]) = discard +type + AtomicType = pointer|ptr|int + + Atomic[T: AtomicType] = distinct T + + Block[T: AtomicType] = object + + AtomicContainer[T: AtomicType] = object + b: Atomic[ptr Block[T]] + +# bug #8295 +var x = AtomicContainer[int]() +doAssert (ptr Block[int])(x.b) == nil + + +# bug #23233 +type + JsonObjectType*[T: string or uint64] = Table[string, JsonValueRef[T]] + + JsonValueRef*[T: string or uint64] = object + objVal*: JsonObjectType[T] + +proc scanValue[K](val: var K) = + var map: JsonObjectType[K.T] + var newVal: K + map["one"] = newVal + +block: + var a: JsonValueRef[uint64] + scanValue(a) + + var b: JsonValueRef[string] + scanValue(b) + +block: # bug #21347 + type K[T] = object + template s[T]() = discard + proc b1(n: bool | bool) = s[K[K[int]]]() + proc b2(n: bool) = s[K[K[int]]]() + b1(false) # Error: 's' has unspecified generic parameters + b2(false) # Builds, on its own diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim index 4cb12f91b..29a73afc6 100644 --- a/tests/generics/tgeneric3.nim +++ b/tests/generics/tgeneric3.nim @@ -1,9 +1,9 @@ discard """ output: ''' 312 -1000000 -1000000 -500000 +1000 +1000 +500 0 ''' """ @@ -12,7 +12,7 @@ import strutils type PNode[T,D] = ref TNode[T,D] - TItem {.acyclic, pure, final, shallow.} [T,D] = object + TItem[T,D] {.acyclic, pure, final, shallow.} = object key: T value: D node: PNode[T,D] @@ -20,7 +20,7 @@ type val_set: bool TItems[T,D] = seq[ref TItem[T,D]] - TNode {.acyclic, pure, final, shallow.} [T,D] = object + TNode[T,D] {.acyclic, pure, final, shallow.} = object slots: TItems[T,D] left: PNode[T,D] count: int32 @@ -243,7 +243,7 @@ proc InsertItem[T,D](APath: RPath[T,D], ANode:PNode[T,D], Akey: T, Avalue: D) = of cLenCenter: setLen(APath.Nd.slots, cLen4) of cLen4: setLen(APath.Nd.slots, cLenMax) else: discard - for i in countdown(APath.Nd.count.int - 1, x + 1): shallowCopy(APath.Nd.slots[i], APath.Nd.slots[i - 1]) + for i in countdown(APath.Nd.count.int - 1, x + 1): APath.Nd.slots[i] = move APath.Nd.slots[i - 1] APath.Nd.slots[x] = setItem(Akey, Avalue, ANode) @@ -255,31 +255,39 @@ proc SplitPage[T,D](n, left: PNode[T,D], xi: int, Akey:var T, Avalue:var D): PNo result.slots.newSeq(cLenCenter) result.count = cCenter if x == cCenter: - for i in 0..cCenter-1: shallowCopy(it1[i], left.slots[i]) - for i in 0..cCenter-1: shallowCopy(result.slots[i], left.slots[cCenter + i]) + for i in 0..cCenter-1: + it1[i] = move left.slots[i] + for i in 0..cCenter-1: + result.slots[i] = move left.slots[cCenter + i] result.left = n else : if x < cCenter : - for i in 0..x-1: shallowCopy(it1[i], left.slots[i]) + for i in 0..x-1: + it1[i] = move left.slots[i] it1[x] = setItem(Akey, Avalue, n) - for i in x+1 .. cCenter-1: shallowCopy(it1[i], left.slots[i-1]) + for i in x+1 .. cCenter-1: + it1[i] = move left.slots[i-1] var w = left.slots[cCenter-1] Akey = w.key Avalue = w.value result.left = w.node - for i in 0..cCenter-1: shallowCopy(result.slots[i], left.slots[cCenter + i]) + for i in 0..cCenter-1: + result.slots[i] = move left.slots[cCenter + i] else : - for i in 0..cCenter-1: shallowCopy(it1[i], left.slots[i]) + for i in 0..cCenter-1: + it1[i] = move left.slots[i] x = x - (cCenter + 1) - for i in 0..x-1: shallowCopy(result.slots[i], left.slots[cCenter + i + 1]) + for i in 0..x-1: + result.slots[i] = move left.slots[cCenter + i + 1] result.slots[x] = setItem(Akey, Avalue, n) - for i in x+1 .. cCenter-1: shallowCopy(result.slots[i], left.slots[cCenter + i]) + for i in x+1 .. cCenter-1: + result.slots[i] = move left.slots[cCenter + i] var w = left.slots[cCenter] Akey = w.key Avalue = w.value result.left = w.node left.count = cCenter - shallowCopy(left.slots, it1) + left.slots = move it1 proc internalPut[T,D](ANode: ref TNode[T,D], Akey: T, Avalue: D, Oldvalue: var D): ref TNode[T,D] = @@ -437,7 +445,7 @@ proc test() = var it1 = internalFind(root, 312) echo it1.value - for i in 1..1_000_000: + for i in 1..1_000: root = internalPut(root, i, i, oldvalue) var cnt = 0 diff --git a/tests/generics/tgeneric_recursionlimit.nim b/tests/generics/tgeneric_recursionlimit.nim new file mode 100644 index 000000000..5fe9b43c6 --- /dev/null +++ b/tests/generics/tgeneric_recursionlimit.nim @@ -0,0 +1,123 @@ +discard """ + action: "compile" +""" + +# https://github.com/nim-lang/Nim/issues/20348 + +type + Payload[T] = object + payload: T + Carrier[T] = object + val: T + +type + Payload0*[T] = object + payload: Payload[T] + Payload1*[T] = object + payload: Payload[T] + Payload2*[T] = object + payload: Payload[T] + Payload3*[T] = object + payload: Payload[T] + Payload4*[T] = object + payload: Payload[T] + Payload5*[T] = object + payload: Payload[T] + Payload6*[T] = object + payload: Payload[T] + Payload7*[T] = object + payload: Payload[T] + Payload8*[T] = object + payload: Payload[T] + Payload9*[T] = object + payload: Payload[T] + Payload10*[T] = object + payload: Payload[T] + Payload11*[T] = object + payload: Payload[T] + Payload12*[T] = object + payload: Payload[T] + Payload13*[T] = object + payload: Payload[T] + Payload14*[T] = object + payload: Payload[T] + Payload15*[T] = object + payload: Payload[T] + Payload16*[T] = object + payload: Payload[T] + Payload17*[T] = object + payload: Payload[T] + Payload18*[T] = object + payload: Payload[T] + Payload19*[T] = object + payload: Payload[T] + Payload20*[T] = object + payload: Payload[T] + Payload21*[T] = object + payload: Payload[T] + Payload22*[T] = object + payload: Payload[T] + Payload23*[T] = object + payload: Payload[T] + Payload24*[T] = object + payload: Payload[T] + Payload25*[T] = object + payload: Payload[T] + Payload26*[T] = object + payload: Payload[T] + Payload27*[T] = object + payload: Payload[T] + Payload28*[T] = object + payload: Payload[T] + Payload29*[T] = object + payload: Payload[T] + Payload30*[T] = object + payload: Payload[T] + Payload31*[T] = object + payload: Payload[T] + Payload32*[T] = object + payload: Payload[T] + Payload33*[T] = object + payload: Payload[T] + +type + Carriers*[T] = object + c0*: Carrier[Payload0[T]] + c1*: Carrier[Payload1[T]] + c2*: Carrier[Payload2[T]] + c3*: Carrier[Payload3[T]] + c4*: Carrier[Payload4[T]] + c5*: Carrier[Payload5[T]] + c6*: Carrier[Payload6[T]] + c7*: Carrier[Payload7[T]] + c8*: Carrier[Payload8[T]] + c9*: Carrier[Payload9[T]] + c10*: Carrier[Payload10[T]] + c11*: Carrier[Payload11[T]] + c12*: Carrier[Payload12[T]] + c13*: Carrier[Payload13[T]] + c14*: Carrier[Payload14[T]] + c15*: Carrier[Payload15[T]] + c16*: Carrier[Payload16[T]] + c17*: Carrier[Payload17[T]] + c18*: Carrier[Payload18[T]] + c19*: Carrier[Payload19[T]] + c20*: Carrier[Payload20[T]] + c21*: Carrier[Payload21[T]] + c22*: Carrier[Payload22[T]] + c23*: Carrier[Payload23[T]] + c24*: Carrier[Payload24[T]] + c25*: Carrier[Payload25[T]] + c26*: Carrier[Payload26[T]] + c27*: Carrier[Payload27[T]] + c28*: Carrier[Payload28[T]] + c29*: Carrier[Payload29[T]] + c30*: Carrier[Payload30[T]] + c31*: Carrier[Payload31[T]] + c32*: Carrier[Payload32[T]] + c33*: Carrier[Payload33[T]] + +var carriers : Carriers[int] + +static: + assert $(typeof(carriers.c33.val)) == "Payload33[system.int]" diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index 54360f178..3068a22f2 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -23,6 +23,10 @@ concrete 88 G:0,1:0.1 G:0,1:0.1 H:1:0.1 +0 +(foo: none(seq[Foo]), s: "") +(foo: some(@[(a: "world", bar: none(Bar))]), s: "hello,") +@[(a: "hey", bar: none(Bar))] ''' joinable: false """ @@ -51,8 +55,8 @@ block t88: let c = ChildClass[string].new("Base", "Child") - assert c.baseMethod == "Base" - assert c.overriddenMethod == "Child" + doAssert c.baseMethod == "Base" + doAssert c.overriddenMethod == "Child" @@ -124,7 +128,7 @@ block t1789: bar: array[N, T] proc `[]`[N, T](f: Bar[N, T], n: range[0..(N - 1)]): T = - assert high(n) == N-1 + doAssert high(n) == N-1 result = f.bar[n] var b: Bar[3, int] @@ -599,7 +603,7 @@ block t7854: block t5864: - proc defaultStatic(s: openarray, N: static[int] = 1): int = N + proc defaultStatic(s: openArray, N: static[int] = 1): int = N proc defaultGeneric[T](a: T = 2): int = a let a = [1, 2, 3, 4].defaultStatic() @@ -730,7 +734,7 @@ block t1684: proc newDerived(idx: int): DerivedType {.inline.} = DerivedType(idx: idx) let d = newDerived(2) - assert(d.index == 2) + doAssert(d.index == 2) @@ -770,13 +774,121 @@ block: # issue #9458 Option[T] = object val: T has: bool - + Bar = object proc none(T: typedesc): Option[T] = discard - proc foo[T](self: T; x: Option[Bar] = Bar.none) = + proc foo[T](self: T; x: Option[Bar] = Bar.none) = discard foo(1) + + +# bug #8426 +type + MyBool[T: uint] = range[T(0)..T(1)] # Works + +var x: MyBool[uint] +echo x + +# x = 2 # correctly prevented + +type + MyBool2 = range[uint(0)..uint(1)] # Error ordinal or float type expected + + +# bug #10396 +import options, strutils + +type + Foo {.acyclic.} = object + a: string + bar: Option[Bar] + + Bar {.acyclic.} = object + foo: Option[seq[Foo]] # if this was just Option[Foo], everything works fine + s: string + +proc getBar(x: string): Bar + +proc intoFoos(ss: seq[string]): seq[Foo] = + result = @[] + for s in ss: + let spl = s.split(',') + if spl.len > 1: + result.add Foo(a: spl[0], + bar: some(getBar(spl[1]))) + else: + result.add Foo(a: s, + bar: none[Bar]()) + +proc getBar(x: string): Bar = + let spl = x.split(' ') + result = + if spl.len > 1: + Bar(foo: some(spl[1..high(spl)].intoFoos), + s: spl[0]) + else: + Bar(foo: none[seq[Foo]](), + s: "") + +proc fakeReadLine(): string = "hey" + +echo getBar(fakeReadLine()) # causes error + +echo getBar("hello, world") # causes error + +discard $getBar(fakeReadLine()) # causes error + +discard $getBar("hello, world") # causes error + +discard getBar(fakeReadLine()) # no error + +discard getBar("hello, world") # no error + +echo intoFoos(fakeReadLine().split(' ')) # no error, works as expected + + +# bug #14990 +type + Tile3 = Tile2 + Tile2 = Tile + Tile[n] = object + a: n + +var a: Tile3[int] + +block: # Ensure no segfault from constraint + type + Regex[A: SomeOrdinal] = ref object + val: Regex[A] + MyConstraint = (seq or enum or set) + MyOtherType[A: MyConstraint] = ref object + val: MyOtherType[A] + + var + a = Regex[int]() + b = Regex[bool]() + c = MyOtherType[seq[int]]() + +block: # https://github.com/nim-lang/Nim/issues/20416 + type + Item[T] = object + link:ptr Item[T] + data:T + + KVSeq[A,B] = seq[(A,B)] + + MyTable[A,B] = object + data: KVSeq[A,B] + + Container[T] = object + a: MyTable[int,ref Item[T]] + + proc p1(sg:Container) = discard # Make sure that a non parameterized 'Container' argument still compiles + + proc p2[T](sg:Container[T]) = discard + var v : Container[int] + p2(v) diff --git a/tests/generics/tgenerics_various.nim b/tests/generics/tgenerics_various.nim index 22d3cff7a..53661236e 100644 --- a/tests/generics/tgenerics_various.nim +++ b/tests/generics/tgenerics_various.nim @@ -58,23 +58,23 @@ block tgenericdefaults: var x1: TFoo[int, float] static: - assert type(x1.x) is int - assert type(x1.y) is float - assert type(x1.z) is int + doAssert type(x1.x) is int + doAssert type(x1.y) is float + doAssert type(x1.z) is int var x2: TFoo[string, R = float, U = seq[int]] static: - assert type(x2.x) is string - assert type(x2.y) is seq[int] - assert type(x2.z) is float + doAssert type(x2.x) is string + doAssert type(x2.y) is seq[int] + doAssert type(x2.z) is float var x3: TBar[float] static: - assert type(x3.x) is float - assert type(x3.y) is array[4, float] - assert type(x3.z) is float + doAssert type(x3.x) is float + doAssert type(x3.y) is array[4, float] + doAssert type(x3.z) is float @@ -127,54 +127,18 @@ block trefs: -block tsharedcases: - proc typeNameLen(x: typedesc): int {.compileTime.} = - result = x.name.len - macro selectType(a, b: typedesc): typedesc = - result = a - - type - Foo[T] = object - data1: array[T.high, int] - data2: array[typeNameLen(T), float] - data3: array[0..T.typeNameLen, selectType(float, int)] - MyEnum = enum A, B, C, D - - var f1: Foo[MyEnum] - var f2: Foo[int8] - - doAssert high(f1.data1) == 2 # (D = 3) - 1 == 2 - doAssert high(f1.data2) == 5 # (MyEnum.len = 6) - 1 == 5 - - doAssert high(f2.data1) == 126 # 127 - 1 == 126 - doAssert high(f2.data2) == 3 # int8.len - 1 == 3 - - static: - assert high(f1.data1) == ord(C) - assert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high - - assert high(f2.data1) == 126 - assert high(f2.data2) == 3 - - assert high(f1.data3) == 6 # length of MyEnum - assert high(f2.data3) == 4 # length of int8 - - assert f2.data3[0] is float - - - block tmap_auto: let x = map(@[1, 2, 3], x => x+10) - assert x == @[11, 12, 13] + doAssert x == @[11, 12, 13] let y = map(@[(1,"a"), (2,"b"), (3,"c")], x => $x[0] & x[1]) - assert y == @["1a", "2b", "3c"] + doAssert y == @["1a", "2b", "3c"] proc eatsTwoArgProc[T,S,U](a: T, b: S, f: proc(t: T, s: S): U): U = f(a,b) let z = eatsTwoArgProc(1, "a", (t,s) => $t & s) - assert z == "1a" + doAssert z == "1a" @@ -230,8 +194,8 @@ block tvarargs_vs_generics: echo "direct" proc withDirectType[T](arg: T) = echo "generic" - proc withOpenArray(args: openarray[string]) = - echo "openarray" + proc withOpenArray(args: openArray[string]) = + echo "openArray" proc withOpenArray[T](arg: T) = echo "generic" proc withVarargs(args: varargs[string]) = @@ -253,3 +217,38 @@ block: var x: Que[int] doAssert(x.x == 0) + + +# bug #4466 +proc identity[T](t: T): T = t + +proc doSomething[A, B](t: tuple[a: A, b: B]) = discard + +discard identity((c: 1, d: 2)) +doSomething(identity((1, 2))) + +# bug #6231 +proc myProc[T, U](x: T or U) = discard + +myProc[int, string](x = 2) + +block: # issue #8390 + proc x[T:SomeFloat](q: openarray[T], y: T = 1): string = + doAssert $q.type == $openarray[y.type] + $y.type + + doAssert x(@[1.0]) == $1.0.type + + +block: # issue #9381 + var evalCount {.compileTime.} = 0 + + macro test(t: typed): untyped = + inc evalCount + t + + type GenericObj[T] = object + f: test(T) + + var x: GenericObj[int] + static: doAssert evalCount == 1 diff --git a/tests/generics/tgenericwhen.nim b/tests/generics/tgenericwhen.nim new file mode 100644 index 000000000..87672a699 --- /dev/null +++ b/tests/generics/tgenericwhen.nim @@ -0,0 +1,58 @@ +discard """ + targets: "c js" +""" + +block: # issue #24041 + type ArrayBuf[N: static int, T = byte] = object + when sizeof(int) > sizeof(uint8): + when N <= int(uint8.high): + n: uint8 + else: + when sizeof(int) > sizeof(uint16): + when N <= int(uint16.high): + n: uint16 + else: + when sizeof(int) > sizeof(uint32): + when N <= int(uint32.high): + n: uint32 + else: + n: int + else: + n: int + else: + n: int + else: + n: int + + var x: ArrayBuf[8] + doAssert x.n is uint8 + when sizeof(int) > sizeof(uint32): + var y: ArrayBuf[int(uint32.high) * 8] + doAssert y.n is int + +block: # constant condition after dynamic one + type Foo[T] = object + when T is int: + a: int + elif true: + a: string + else: + a: bool + var x: Foo[string] + doAssert x.a is string + var y: Foo[int] + doAssert y.a is int + var z: Foo[float] + doAssert z.a is string + +block: # issue #4774, but not with threads + const hasThreadSupport = not defined(js) + when hasThreadSupport: + type Channel[T] = object + value: T + type + SomeObj[T] = object + when hasThreadSupport: + channel: ptr Channel[T] + var x: SomeObj[int] + doAssert compiles(x.channel) == hasThreadSupport diff --git a/tests/generics/tgensyminst.nim b/tests/generics/tgensyminst.nim new file mode 100644 index 000000000..3f30188d8 --- /dev/null +++ b/tests/generics/tgensyminst.nim @@ -0,0 +1,29 @@ +# issue #24048 + +import macros + +proc map(fn: proc(val: int): void) = fn(1) + +# This works fine, and is the exact same function call as what's +# generated by the macro `aBug`. +map proc(val: auto): void = + let variable = 123 + +macro aBug() = + # 1. let sym = ident("variable") + let sym = genSym(nskLet, "variable") + let letStmt = newLetStmt(sym, newLit(123)) + + let lambda = newProc( + params = @[ + ident("void"), + newIdentDefs(ident("val"), ident("auto")), + # 2. newIdentDefs(ident("val"), ident("int")), + ], + body = newStmtList(letStmt), + procType = nnkLambda + ) + + result = newCall(bindSym("map"), lambda) + +aBug() diff --git a/tests/generics/timpl_ast.nim b/tests/generics/timpl_ast.nim new file mode 100644 index 000000000..97fe128cd --- /dev/null +++ b/tests/generics/timpl_ast.nim @@ -0,0 +1,80 @@ +import std/macros +import std/assertions + +block: # issue #16639 + type Foo[T] = object + when true: + x: float + + type Bar = object + when true: + x: float + + macro test() = + let a = getImpl(bindSym"Foo")[^1] + let b = getImpl(bindSym"Bar")[^1] + doAssert treeRepr(a) == treeRepr(b) + + test() + +import strutils + +block: # issues #9899, ##14708 + macro implRepr(a: typed): string = + result = newLit(repr(a.getImpl)) + + type + Option[T] = object + when false: discard # issue #14708 + when false: x: int + when T is (ref | ptr): + val: T + else: + val: T + has: bool + + static: # check information is retained + let r = implRepr(Option) + doAssert "when T is" in r + doAssert r.count("val: T") == 2 + doAssert "has: bool" in r + + block: # try to compile the output + macro parse(s: static string) = + result = parseStmt(s) + parse("type " & implRepr(Option)) + +block: # issue #22639 + type + Spectrum[N: static int] = object + data: array[N, float] + AngleInterpolator = object + data: seq[Spectrum[60]] + proc initInterpolator(num: int): AngleInterpolator = + result = AngleInterpolator() + for i in 0 ..< num: + result.data.add Spectrum[60]() + macro genCompatibleTuple(t: typed): untyped = + let typ = t.getType[1].getTypeImpl[2] + result = nnkTupleTy.newTree() + for i, ch in typ: # is `nnkObjectTy` + result.add nnkIdentDefs.newTree(ident(ch[0].strVal), # ch is `nnkIdentDefs` + ch[1], + newEmptyNode()) + proc fullSize[T: object | tuple](x: T): int = + var tmp: genCompatibleTuple(T) + result = 0 + for field, val in fieldPairs(x): + result += sizeof(val) + doAssert result == sizeof(tmp) + + let reflectivity = initInterpolator(1) + for el in reflectivity.data: + doAssert fullSize(el) == sizeof(el) + doAssert fullSize(reflectivity.data[0]) == sizeof(reflectivity.data[0]) + doAssert genCompatibleTuple(Spectrum[60]) is tuple[data: array[60, float]] + doAssert genCompatibleTuple(Spectrum[120]) is tuple[data: array[120, float]] + type Foo[T] = object + data: T + doAssert genCompatibleTuple(Foo[int]) is tuple[data: int] + doAssert genCompatibleTuple(Foo[float]) is tuple[data: float] diff --git a/tests/generics/timplicit_and_explicit.nim b/tests/generics/timplicit_and_explicit.nim new file mode 100644 index 000000000..7220b7429 --- /dev/null +++ b/tests/generics/timplicit_and_explicit.nim @@ -0,0 +1,65 @@ + +block: # basic test + proc doStuff[T](a: SomeInteger): T = discard + proc doStuff[T;Y](a: SomeInteger, b: Y): Y = discard + assert typeof(doStuff[int](100)) is int + assert typeof(doStuff[int, float](100, 1.0)) is float + assert typeof(doStuff[int, string](100, "Hello")) is string + + proc t[T](x: T; z: int | float): seq[T] = result.add(x & $z) + + assert t[string]("Hallo", 2.0) == @["Hallo" & $2.0] + + proc t2[T](z: int | float): seq[T] = result.add($z) + + assert t2[string](2.0) == @[$2.0] + +block: # template test + template someThing[T;Y](a: SomeFloat, b: SomeOrdinal): (T, Y) = (a, b) + assert typeof(someThing[float64, int](1.0, 100)) is (float64, int) + +block: # static test + proc t[T](s: static bool) = discard + proc t2[T](s: static string) = discard + t[string](true) + t2[int]("hello") + t2[string]("world") + t2[float]("test222222") + +block: #11152 + proc f[T](X: typedesc) = discard + f[int](string) + +block: #15622 + proc test1[T](a: T, b: static[string] = "") = discard + test1[int64](123) + proc test2[T](a: T, b: static[string] = "") = discard + doAssert not (compiles do: + test2[int64, static[string]](123)) + +block: #4688 + proc convertTo[T](v: int or float): T = (T)(v) + discard convertTo[float](1) + +block: #4164 + proc printStr[T](s: static[string]): T = discard + discard printStr[int]("hello static") + +import macros + +block: # issue #9040, statics with template, macro, symchoice explicit generics + block: # macro + macro fun[N: static int](): untyped = + newLit 1 + const a = fun[2]() + doAssert a == 1 + block: # template + template fun[N: static int](): untyped = + 1 + const a = fun[2]() + doAssert a == 1 + block: # symchoice + proc newSeq[x: static int](): int = 1 + template foo: int = + newSeq[2]() + doAssert foo() == 1 diff --git a/tests/generics/timports.nim b/tests/generics/timports.nim index 800ae7f88..e252ad194 100644 --- a/tests/generics/timports.nim +++ b/tests/generics/timports.nim @@ -7,7 +7,7 @@ false ''' """ -import mbind_bracket, mclosed_sym, mdotlookup, mmodule_same_as_proc +import mbind_bracket, mclosed_sym, mdotlookup, mmodule_same_as_proc, mtypenodes block tbind_bracket: @@ -31,15 +31,33 @@ block tclosed_sym: proc same(r:R, d:int) = echo "TEST1" doIt(Data[int](d:123), R()) +import strutils, unicode # ambiguous `strip` block tdotlookup: foo(7) # bug #1444 fn(4) - + doAssert doStrip(123) == "123" + # bug #14254 + doAssert baz2[float](1'i8) == 1 + # bug #21883 + proc abc[T: not not int](x: T): T = + var x = x + x.set("hello", "world") + result = x + doAssert abc(5) == 10 + block: # ensure normal call is consistent with dot call + proc T(x: int): float = x.float + proc foo[T](x: int) = + doAssert typeof(T(x)) is typeof(x.T) + foo[uint](123) block tmodule_same_as_proc: # bug #1965 proc test[T](t: T) = mmodule_same_as_proc"a" test(0) + +block ttypenodes: + # issue #22699 + doAssert chop[bool](42) == 42 diff --git a/tests/generics/tinheritable_importcpp.nim b/tests/generics/tinheritable_importcpp.nim new file mode 100644 index 000000000..8ee18b70b --- /dev/null +++ b/tests/generics/tinheritable_importcpp.nim @@ -0,0 +1,10 @@ +discard """ + targets: "cpp" + action: compile +""" + +# #4651 +type + Vector[T] {.importcpp: "std::vector<'0 >", header: "vector", inheritable.} = object + VectorDerived {.importcpp: "SomeVectorDerived", nodecl.} = object of Vector[int] + # Error: inheritance only works with non-final objects diff --git a/tests/generics/tmacroinjectedsym.nim b/tests/generics/tmacroinjectedsym.nim new file mode 100644 index 000000000..985e415f2 --- /dev/null +++ b/tests/generics/tmacroinjectedsym.nim @@ -0,0 +1,186 @@ +{.experimental: "openSym".} + +block: # issue #22605, normal call syntax + const error = "bad" + + template valueOr(self: int, def: untyped): untyped = + case false + of true: "" + of false: + template error: untyped {.used, inject.} = "good" + def + + proc g(T: type): string = + let x = valueOr 123: + return $error + + "ok" + + doAssert g(int) == "good" + + proc g2(T: type): string = + bind error # use the bad version on purpose + let x = valueOr 123: + return $error + + "ok" + + doAssert g2(int) == "bad" + +block: # issue #22605, method call syntax + const error = "bad" + + template valueOr(self: int, def: untyped): untyped = + case false + of true: "" + of false: + template error: untyped {.used, inject.} = "good" + def + + proc g(T: type): string = + let x = 123.valueOr: + return $error + + "ok" + + doAssert g(int) == "good" + + proc g2(T: type): string = + bind error # use the bad version on purpose + let x = 123.valueOr: + return $error + + "ok" + + doAssert g2(int) == "bad" + +block: # issue #22605, original complex example + type Xxx = enum + error + value + + type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + + template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + + proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + + proc g(T: type): string = + let x = f().valueOr: + return $error + + "ok" + + doAssert g(int) == "f" + + proc g2(T: type): string = + bind error # use the bad version on purpose + let x = f().valueOr: + return $error + + "ok" + + doAssert g2(int) == "error" + +block: # issue #23865 + type Xxx = enum + error + value + + type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate: bool + else: + case oResultPrivate: bool + of false: + eResultPrivate: E + of true: + discard + else: + when E is void: + case oResultPrivate: bool + of false: + discard + of true: + vResultPrivate: T + else: + case oResultPrivate: bool + of false: + eResultPrivate: E + of true: + vResultPrivate: T + + func error[T, E](self: Result[T, E]): E = + ## Fetch error of result if set, or raise Defect + case self.oResultPrivate + of true: + when T isnot void: + raiseResultDefect("Trying to access error when value is set", self.vResultPrivate) + else: + raiseResultDefect("Trying to access error when value is set") + of false: + when E isnot void: + self.eResultPrivate + + template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + proc g(T: type): string = + let x = f().valueOr: + return $error + "ok" + doAssert g(int) == "f" + +import sequtils + +block: # issue #12283 + var b = 5 + type Foo[T] = object + h, w: int + proc bar[T](foos: seq[Foo[T]]): T = + let w = foldl(foos, a + b.w, 0) + w + let foos = @[Foo[int](h: 3, w: 5), Foo[int](h: 4, w: 6)] + doAssert bar(foos) == 11 diff --git a/tests/generics/tmacroinjectedsymwarning.nim b/tests/generics/tmacroinjectedsymwarning.nim new file mode 100644 index 000000000..77119004b --- /dev/null +++ b/tests/generics/tmacroinjectedsymwarning.nim @@ -0,0 +1,59 @@ +discard """ + matrix: "--skipParentCfg --filenames:legacyRelProj" +""" + +type Xxx = enum + error + value + +type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + +template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + +proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + +proc g(T: type): string = + let x = f().valueOr: + {.push warningAsError[IgnoredSymbolInjection]: on.} + # test spurious error + discard true + let _ = f + {.pop.} + return $error #[tt.Warning + ^ a new symbol 'error' has been injected during template or generic instantiation, however 'error' [enumField declared in tmacroinjectedsymwarning.nim(6, 3)] captured at the proc declaration will be used instead; either enable --experimental:openSym to use the injected symbol, or `bind` this captured symbol explicitly [IgnoredSymbolInjection]]# + + "ok" + +discard g(int) diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim index 7a2375abe..cf30a936d 100644 --- a/tests/generics/tmetafield.nim +++ b/tests/generics/tmetafield.nim @@ -1,10 +1,23 @@ discard """ cmd: "nim check $options $file" - errormsg: "'proc' is not a concrete type" - errormsg: "'Foo' is not a concrete type." - errormsg: "invalid type: 'proc' in this context: 'TBaseMed'" + action: "reject" + nimout: ''' +tmetafield.nim(26, 5) Error: 'proc' is not a concrete type; for a callback without parameters use 'proc()' +tmetafield.nim(27, 5) Error: 'Foo' is not a concrete type +tmetafield.nim(29, 5) Error: invalid type: 'proc' in this context: 'TBaseMed' for var +''' """ +# bug #188 + + + + + + + + +# line 20 type Foo[T] = object x: T @@ -15,4 +28,3 @@ type var a: TBaseMed -# issue 188 diff --git a/tests/generics/tnestedissues.nim b/tests/generics/tnestedissues.nim new file mode 100644 index 000000000..e96a1927e --- /dev/null +++ b/tests/generics/tnestedissues.nim @@ -0,0 +1,24 @@ +block: # issue #23568 + type G[T] = object + j: T + proc s[T](u: int) = discard + proc s[T]() = discard + proc c(e: int | int): G[G[G[int]]] = s[G[G[int]]]() + discard c(0) + +import std/options + +block: # issue #23310 + type + BID = string or uint64 + Future[T] = ref object of RootObj + internalValue: T + InternalRaisesFuture[T] = ref object of Future[T] + proc newInternalRaisesFutureImpl[T](): InternalRaisesFuture[T] = + let fut = InternalRaisesFuture[T]() + template newFuture[T](): auto = + newInternalRaisesFutureImpl[T]() + proc problematic(blockId: BID): Future[Option[seq[int]]] = + let resultFuture = newFuture[Option[seq[int]]]() + return resultFuture + let x = problematic("latest") diff --git a/tests/generics/tnestedtemplate.nim b/tests/generics/tnestedtemplate.nim new file mode 100644 index 000000000..22d0a2d3c --- /dev/null +++ b/tests/generics/tnestedtemplate.nim @@ -0,0 +1,9 @@ +block: # issue #13979 + var s: seq[int] + proc filterScanline[T](input: openArray[T]) = + template currPix: untyped = input[i] + for i in 0..<input.len: + s.add currPix + let pix = [1, 2, 3] + filterScanline(pix) + doAssert s == @[1, 2, 3] diff --git a/tests/generics/tnullary_generics.nim b/tests/generics/tnullary_generics.nim new file mode 100644 index 000000000..c79558ee3 --- /dev/null +++ b/tests/generics/tnullary_generics.nim @@ -0,0 +1,26 @@ +discard """ + nimout: ''' +hah +hey +hey +hah +''' +""" + +# non-generic +proc foo(s: string) = + static: echo "hah" + echo s + +static: echo "hey" + +foo("hoo") + +# nullary generic +proc bar[](s: string) = + static: echo "hah" + echo s + +static: echo "hey" + +bar("hoo") diff --git a/tests/generics/tobjecttyperel.nim b/tests/generics/tobjecttyperel.nim index 80fe23459..6f223c154 100644 --- a/tests/generics/tobjecttyperel.nim +++ b/tests/generics/tobjecttyperel.nim @@ -1,4 +1,5 @@ discard """ + matrix: "-d:nimInternalNonVtablesTesting" output: '''(peel: 0, color: 15) (color: 15) 17 diff --git a/tests/generics/topensymimport.nim b/tests/generics/topensymimport.nim new file mode 100644 index 000000000..a47496827 --- /dev/null +++ b/tests/generics/topensymimport.nim @@ -0,0 +1,5 @@ +# issue #23386 + +import mopensymimport2 + +doAssert g(int) == "f" diff --git a/tests/generics/toverloading_typedesc.nim b/tests/generics/toverloading_typedesc.nim index 5ab700828..4d748bfee 100644 --- a/tests/generics/toverloading_typedesc.nim +++ b/tests/generics/toverloading_typedesc.nim @@ -1,7 +1,3 @@ -discard """ - exitcode: 0 - disabled: '''true''' -""" import moverloading_typedesc import tables @@ -9,7 +5,6 @@ type LFoo = object LBar = object - when true: doAssert FBar.new() == 3 diff --git a/tests/generics/tparam_binding.nim b/tests/generics/tparam_binding.nim index cd0d58e02..fa7558613 100644 --- a/tests/generics/tparam_binding.nim +++ b/tests/generics/tparam_binding.nim @@ -1,6 +1,7 @@ discard """ + matrix: "--mm:arc; --mm:refc" errormsg: "got <ref Matrix[2, 2, system.float], ref Matrix[2, 1, system.float]>" - line: 27 + line: 28 """ type diff --git a/tests/generics/tparser_generator.nim b/tests/generics/tparser_generator.nim index 8f8fea382..ac921c0e5 100644 --- a/tests/generics/tparser_generator.nim +++ b/tests/generics/tparser_generator.nim @@ -147,7 +147,7 @@ proc literal*[N, T, P](pattern: P, kind: N): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = if start == len(text): return -1 - assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) when P is string or P is seq[N]: debug(debugLex, "Literal[" & $kind & "]: testing " & $pattern & " at " & $start & ": " & $text[start..start+len(pattern)-1]) if text.continuesWith(pattern, start): @@ -177,7 +177,7 @@ proc token[N, T](pattern: T, kind: N): Rule[N, T] = debug(debugLex, "Token[" & $kind & "]: testing " & pattern & " at " & $start) if start == len(text): return -1 - assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) let m = text.match(re(pattern), start) if m.isSome: let node = initNode(start, len(m.get.match), kind) @@ -192,7 +192,7 @@ proc chartest[N, T, S](testfunc: proc(s: S): bool, kind: N): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = if start == len(text): return -1 - assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) if testfunc(text[start]): nodes.add(initNode(start, 1, kind)) result = 1 @@ -252,11 +252,11 @@ proc fail*[N, T](message: string, kind: N): Rule[N, T] = proc `+`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = var mynodes = newSeq[Node[N]]() - assert(not isNil(left.parser), "Left hand side parser is nil") + doAssert(not isNil(left.parser), "Left hand side parser is nil") let leftlength = left.parser(text, start, mynodes) if leftlength == -1: return leftlength - assert(not isNil(right.parser), "Right hand side parser is nil") + doAssert(not isNil(right.parser), "Right hand side parser is nil") let rightlength = right.parser(text, start+leftlength, mynodes) if rightlength == -1: return rightlength @@ -267,13 +267,13 @@ proc `+`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] = proc `/`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] = let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int = var mynodes = newSeq[Node[N]]() - assert(not isNil(left.parser), "Left hand side of / is not fully defined") + doAssert(not isNil(left.parser), "Left hand side of / is not fully defined") let leftlength = left.parser(text, start, mynodes) if leftlength != -1: nodes.add(mynodes) return leftlength mynodes = newSeq[Node[N]]() - assert(not isNil(right.parser), "Right hand side of / is not fully defined") + doAssert(not isNil(right.parser), "Right hand side of / is not fully defined") let rightlength = right.parser(text, start, mynodes) if rightlength == -1: return rightlength @@ -360,7 +360,7 @@ proc `/`*[N, T](rule: Rule[N, T]): Rule[N, T] = result = newRule[N, T](parser, rule.kind) proc `->`*(rule: Rule, production: Rule) = - assert(not isnil(production.parser), "Right hand side of -> is nil - has the rule been defined yet?") + doAssert(not isnil(production.parser), "Right hand side of -> is nil - has the rule been defined yet?") rule.parser = production.parser template grammar*[K](Kind, Text, Symbol: typedesc; default: K, code: untyped): typed {.hint[XDeclaredButNotUsed]: off.} = diff --git a/tests/generics/tpointerprocs.nim b/tests/generics/tpointerprocs.nim new file mode 100644 index 000000000..2bcaf15b3 --- /dev/null +++ b/tests/generics/tpointerprocs.nim @@ -0,0 +1,28 @@ +discard """ +cmd: "nim check $options --hints:off $file" +action: "reject" +nimout:''' +tpointerprocs.nim(15, 11) Error: 'foo' doesn't have a concrete type, due to unspecified generic parameters. +tpointerprocs.nim(27, 11) Error: cannot instantiate: 'foo[int]'; got 1 typeof(s) but expected 2 +tpointerprocs.nim(27, 14) Error: expression 'foo[int]' has no type (or is ambiguous) +tpointerprocs.nim(28, 11) Error: expression 'bar' has no type (or is ambiguous) +''' +""" + +block: + proc foo(x: int | float): float = result = 1.0 + let + bar = foo + baz = bar + +block: + proc foo(x: int | float): float = result = 1.0 + let + bar = foo[int] + baz = bar + +block: + proc foo(x: int | float, y: int or string): float = result = 1.0 + let + bar = foo[int] + baz = bar \ No newline at end of file diff --git a/tests/generics/tprevent_double_bind.nim b/tests/generics/tprevent_double_bind.nim index 86e080ab6..d8fc6e5d3 100644 --- a/tests/generics/tprevent_double_bind.nim +++ b/tests/generics/tprevent_double_bind.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got <TT[seq[string]], proc (v: int){.gcsafe, locks: 0.}>" + errormsg: "type mismatch: got <TT[seq[string]], proc (v: int){.gcsafe.}>" line: 20 """ diff --git a/tests/generics/trecursivegenerics.nim b/tests/generics/trecursivegenerics.nim new file mode 100644 index 000000000..1b152b063 --- /dev/null +++ b/tests/generics/trecursivegenerics.nim @@ -0,0 +1,96 @@ +block: # Replicates #18728 + type + FlipFlop[A, B] = ref object + val: A + next: FlipFlop[B, A] + + Trinary[A, B, C] = ref object + next: Trinary[B, C, A] + + assert typeof(FlipFlop[int, string]().next) is FlipFlop[string, int] + assert typeof(FlipFlop[string, int]().next) is FlipFlop[int, string] + assert typeof(Trinary[int, float, string]().next) is Trinary[float, string, int] + assert typeof(Trinary[int, float, string]().next.next) is Trinary[string, int, float] + var a = FlipFlop[int, string](val: 100, next: FlipFlop[string, int](val: "Hello")) + assert a.val == 100 + assert a.next.val == "Hello" + +block: # 18838 + type + DoublyLinkedNodeObj[T] = object + value: T + + DoublyLinkedNode[T] = ref DoublyLinkedNodeObj[T] + + Item[T] = ref object + link: DoublyLinkedNode[Item[T]] + + Box = object + + proc newDoublyLinkedNode[T](value: T): DoublyLinkedNode[T] = + new(result) + result.value = value + + let link = newDoublyLinkedNode(Item[Box]()) + +import lists +block: + type + Box = object + Item[T] = ref object + link:DoublyLinkedNode[ Item[T] ] + + ItemSimple = ref object + link:DoublyLinkedNode[ ItemSimple ] + + let link = newDoublyLinkedNode( Item[Box]() ) + +block: #18897 + type + SkipListObj[T] = object + over: SkipList[T] + down: SkipList[T] + value: T + + SkipList[T] = ref SkipListObj[T] + + GraphObj[N, E; F: static[int]] = object + nodes: SkipList[Node[N, E]] + + Graph[N, E; F: static[int]] = ref GraphObj[N, E, F] + + Node[N, E] = ref NodeObj[N, E] + + NodeObj[N, E] = object + value: N + incoming: SkipList[Edge[N, E]] + outgoing: SkipList[Edge[N, E]] + + Edge[N, E] = ref EdgeObj[N, E] + + EdgeObj[N, E] = object + value: E + id: int + source: Node[N, E] + target: Node[N, E] + + EdgeResult[N, E] = tuple + source: Node[N, E] + edge: Edge[N, E] + target: Node[N, E] + + proc newSkipList[T](value: T): SkipList[T] = + static: echo T, " ", typeof(result.value) + result = SkipList[T](value: value) + + proc toSkipList[T](values: openArray[T] = @[]): SkipList[T] = + for item in items(values): + if result.isNil: + result = newSkipList(item) + + proc newContainer[N, E, F](graph: Graph[N, E, F]; form: typedesc): auto = + result = toSkipList[form]([]) + + var + result = Graph[int, string, 0]() + result.nodes = result.newContainer(Node[int, string]) \ No newline at end of file diff --git a/tests/generics/treentranttypes.nim b/tests/generics/treentranttypes.nim index 31fa25293..801f0e444 100644 --- a/tests/generics/treentranttypes.nim +++ b/tests/generics/treentranttypes.nim @@ -2,21 +2,13 @@ discard """ output: ''' (10, ("test", 1.2)) 3x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0], [2.0, 0.0, 5.0]] - 2x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]] - 2x3 Literal [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]] - 2x3 Matrix [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - 2x2 ArrayArray[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - 2x3 ArrayVector[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - 2x3 VectorVector [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - 2x3 VectorArray [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - @[1, 2] @[1, 2] @[1, 2]@[3, 4] @@ -109,3 +101,14 @@ echo @(b.arr[0].arr), @(b.arr[1].arr) let y = b echo @(y.arr[0].arr), @(y.arr[1].arr) +import macros + +block: # issue #5121 + type + A = object + AConst[X] = A + + macro dumpType(t: typedesc): untyped = + result = newTree(nnkTupleConstr, newLit $t.getType[1].typeKind, newLit t.getType[1].treeRepr) + + doAssert dumpType(A) == ("ntyObject", "Sym \"A\"") diff --git a/tests/generics/treturn_inference.nim b/tests/generics/treturn_inference.nim new file mode 100644 index 000000000..331a9d4db --- /dev/null +++ b/tests/generics/treturn_inference.nim @@ -0,0 +1,184 @@ + +{.experimental: "inferGenericTypes".} + +import std/tables + +block: + type + MyOption[T, Z] = object + x: T + y: Z + + proc none[T, Z](): MyOption[T, Z] = + when T is int: + result.x = 22 + when Z is float: + result.y = 12.0 + + proc myGenericProc[T, Z](): MyOption[T, Z] = + none() # implied by return type + + let a = myGenericProc[int, float]() + doAssert a.x == 22 + doAssert a.y == 12.0 + + let b: MyOption[int, float] = none() # implied by type of b + doAssert b.x == 22 + doAssert b.y == 12.0 + +# Simple template based result with inferred type for errors +block: + type + ResultKind {.pure.} = enum + Ok + Err + + Result[T] = object + case kind: ResultKind + of Ok: + data: T + of Err: + errmsg: cstring + + template err[T](msg: static cstring): Result[T] = + Result[T](kind : ResultKind.Err, errmsg : msg) + + proc testproc(): Result[int] = + err("Inferred error!") # implied by proc return + let r = testproc() + doAssert r.kind == ResultKind.Err + doAssert r.errmsg == "Inferred error!" + +# Builtin seq +block: + let x: seq[int] = newSeq(1) + doAssert x is seq[int] + doAssert x.len() == 1 + + type + MyType[T, Z] = object + x: T + y: Z + + let y: seq[MyType[int, float]] = newSeq(2) + doAssert y is seq[MyType[int, float]] + doAssert y.len() == 2 + + let z = MyType[seq[float], string]( + x : newSeq(3), + y : "test" + ) + doAssert z.x is seq[float] + doAssert z.x.len() == 3 + doAssert z.y is string + doAssert z.y == "test" + +# array +block: + proc giveArray[N, T](): array[N, T] = + for i in 0 .. N.high: + result[i] = i + var x: array[2, int] = giveArray() + doAssert x == [0, 1] + +# tuples +block: + proc giveTuple[T, Z]: (T, Z, T) = discard + let x: (int, float, int) = giveTuple() + doAssert x is (int, float, int) + doAssert x == (0, 0.0, 0) + + proc giveNamedTuple[T, Z]: tuple[a: T, b: Z] = discard + let y: tuple[a: int, b: float] = giveNamedTuple() + doAssert y is (int, float) + doAssert y is tuple[a: int, b: float] + doAssert y == (0, 0.0) + + proc giveNestedTuple[T, Z]: ((T, Z), Z) = discard + let z: ((int, float), float) = giveNestedTuple() + doAssert z is ((int, float), float) + doAssert z == ((0, 0.0), 0.0) + + # nesting inside a generic type + type MyType[T] = object + x: T + let a = MyType[(int, MyType[float])](x : giveNamedTuple()) + doAssert a.x is (int, MyType[float]) + + +# basic constructors +block: + type MyType[T] = object + x: T + + proc giveValue[T](): T = + when T is int: + 12 + else: + default(T) + + let x = MyType[int](x : giveValue()) + doAssert x.x is int + doAssert x.x == 12 + + let y = MyType[MyType[float]](x : MyType[float](x : giveValue())) + doAssert y.x is MyType[float] + doAssert y.x.x is float + doAssert y.x.x == 0.0 + + # 'MyType[float]' is bound to 'T' directly + # instead of mapping 'T' to 'float' + let z = MyType[MyType[float]](x : giveValue()) + doAssert z.x is MyType[float] + doAssert z.x.x == 0.0 + + type Foo = object + x: Table[int, float] + + let a = Foo(x: initTable()) + doAssert a.x is Table[int, float] + +# partial binding +block: + type + ResultKind = enum + Ok, Error + + Result[T, E] = object + case kind: ResultKind + of Ok: + okVal: T + of Error: + errVal: E + + proc err[T, E](myParam: E): Result[T, E] = + Result[T, E](kind : Error, errVal : myParam) + + proc doStuff(): Result[int, string] = + err("Error") + + let res = doStuff() + doAssert res.kind == Error + doAssert res.errVal == "Error" + +# ufcs +block: + proc getValue[T](_: string): T = + doAssert T is int + 44 + + proc `'test`[T](_: string): T = + 55 + + let a: int = getValue("") + let b: int = "".getValue() + let c: int = "".getValue + let d: int = getValue "" + let e: int = getValue"" + let f: int = 12345'test + doAssert a == 44 + doAssert b == 44 + doAssert c == 44 + doAssert d == 44 + doAssert e == 44 + doAssert f == 55 diff --git a/tests/generics/trtree.nim b/tests/generics/trtree.nim deleted file mode 100644 index b45ac8c83..000000000 --- a/tests/generics/trtree.nim +++ /dev/null @@ -1,640 +0,0 @@ -discard """ - output: '''1 [2, 3, 4, 7] -[0, 0]''' - target: "c" - joinable: false -disabled: 32bit - cmd: "nim c --gc:arc $file" -""" - -# bug #13110: This test failed with --gc:arc. - -# this test wasn't written for 32 bit -# don't join because the code is too messy. - -# Nim RTree and R*Tree implementation -# S. Salewski, 06-JAN-2018 - -# http://www-db.deis.unibo.it/courses/SI-LS/papers/Gut84.pdf -# http://dbs.mathematik.uni-marburg.de/publications/myPapers/1990/BKSS90.pdf - -# RT: range type like float, int -# D: Dimension -# M: Max entries in one node -# LT: leaf type - -type - Dim* = static[int] - Ext[RT] = tuple[a, b: RT] # extend (range) - Box*[D: Dim; RT] = array[D, Ext[RT]] # Rectangle for 2D - BoxCenter*[D: Dim; RT] = array[D, RT] - L*[D: Dim; RT, LT] = tuple[b: Box[D, RT]; l: LT] # called Index Entry or index record in the Guttman paper - H[M, D: Dim; RT, LT] = ref object of RootRef - parent: H[M, D, RT, LT] - numEntries: int - level: int - N[M, D: Dim; RT, LT] = tuple[b: Box[D, RT]; n: H[M, D, RT, LT]] - LA[M, D: Dim; RT, LT] = array[M, L[D, RT, LT]] - NA[M, D: Dim; RT, LT] = array[M, N[M, D, RT, LT]] - Leaf[M, D: Dim; RT, LT] = ref object of H[M, D, RT, LT] - a: LA[M, D, RT, LT] - Node[M, D: Dim; RT, LT] = ref object of H[M, D, RT, LT] - a: NA[M, D, RT, LT] - - RTree*[M, D: Dim; RT, LT] = ref object of RootRef - root: H[M, D, RT, LT] - bigM: int - m: int - - RStarTree*[M, D: Dim; RT, LT] = ref object of RTree[M, D, RT, LT] - firstOverflow: array[32, bool] - p: int - -proc newLeaf[M, D: Dim; RT, LT](): Leaf[M, D, RT, LT] = - new result - -proc newNode[M, D: Dim; RT, LT](): Node[M, D, RT, LT] = - new result - -proc newRTree*[M, D: Dim; RT, LT](minFill: range[30 .. 50] = 40): RTree[M, D, RT, LT] = - assert(M > 1 and M < 101) - new result - result.bigM = M - result.m = M * minFill div 100 - result.root = newLeaf[M, D, RT, LT]() - -proc newRStarTree*[M, D: Dim; RT, LT](minFill: range[30 .. 50] = 40): RStarTree[M, D, RT, LT] = - assert(M > 1 and M < 101) - new result - result.bigM = M - result.m = M * minFill div 100 - result.p = M * 30 div 100 - result.root = newLeaf[M, D, RT, LT]() - -proc center(r: Box): auto =#BoxCenter[r.len, type(r[0].a)] = - var res: BoxCenter[r.len, type(r[0].a)] - for i in 0 .. r.high: - when r[0].a is SomeInteger: - res[i] = (r[i].a + r[i].b) div 2 - elif r[0].a is SomeFloat: - res[i] = (r[i].a + r[i].b) / 2 - else: assert false - return res - -proc distance(c1, c2: BoxCenter): auto = - var res: type(c1[0]) - for i in 0 .. c1.high: - res += (c1[i] - c2[i]) * (c1[i] - c2[i]) - return res - -proc overlap(r1, r2: Box): auto = - result = type(r1[0].a)(1) - for i in 0 .. r1.high: - result *= (min(r1[i].b, r2[i].b) - max(r1[i].a, r2[i].a)) - if result <= 0: return 0 - -proc union(r1, r2: Box): Box = - for i in 0 .. r1.high: - result[i].a = min(r1[i].a, r2[i].a) - result[i].b = max(r1[i].b, r2[i].b) - -proc intersect(r1, r2: Box): bool = - for i in 0 .. r1.high: - if r1[i].b < r2[i].a or r1[i].a > r2[i].b: - return false - return true - -proc area(r: Box): auto = #type(r[0].a) = - result = type(r[0].a)(1) - for i in 0 .. r.high: - result *= r[i].b - r[i].a - -proc margin(r: Box): auto = #type(r[0].a) = - result = type(r[0].a)(0) - for i in 0 .. r.high: - result += r[i].b - r[i].a - -# how much enlargement does r1 need to include r2 -proc enlargement(r1, r2: Box): auto = - area(union(r1, r2)) - area(r1) - -proc search*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]): seq[LT] = - proc s[M, D: Dim; RT, LT](n: H[M, D, RT, LT]; b: Box[D, RT]; res: var seq[LT]) = - if n of Node[M, D, RT, LT]: - let h = Node[M, D, RT, LT](n) - for i in 0 ..< n.numEntries: - if intersect(h.a[i].b, b): - s(h.a[i].n, b, res) - elif n of Leaf[M, D, RT, LT]: - let h = Leaf[M, D, RT, LT](n) - for i in 0 ..< n.numEntries: - if intersect(h.a[i].b, b): - res.add(h.a[i].l) - else: assert false - result = newSeq[LT]() - s(t.root, b, result) - -# Insertion -# a R*TREE proc -proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; level: int): H[M, D, RT, LT] = - assert level >= 0 - var n = t.root - while n.level > level: - let nn = Node[M, D, RT, LT](n) - var i0 = 0 # selected index - var minLoss = type(b[0].a).high - if n.level == 1: # childreen are leaves -- determine the minimum overlap costs - for i in 0 ..< n.numEntries: - let nx = union(nn.a[i].b, b) - var loss = 0 - for j in 0 ..< n.numEntries: - if i == j: continue - loss += (overlap(nx, nn.a[j].b) - overlap(nn.a[i].b, nn.a[j].b)) # overlap (i, j) == (j, i), so maybe cache that? - var rep = loss < minLoss - if loss == minLoss: - let l2 = enlargement(nn.a[i].b, b) - enlargement(nn.a[i0].b, b) - rep = l2 < 0 - if l2 == 0: - let l3 = area(nn.a[i].b) - area(nn.a[i0].b) - rep = l3 < 0 - if l3 == 0: - rep = nn.a[i].n.numEntries < nn.a[i0].n.numEntries - if rep: - i0 = i - minLoss = loss - else: - for i in 0 ..< n.numEntries: - let loss = enlargement(nn.a[i].b, b) - var rep = loss < minLoss - if loss == minLoss: - let l3 = area(nn.a[i].b) - area(nn.a[i0].b) - rep = l3 < 0 - if l3 == 0: - rep = nn.a[i].n.numEntries < nn.a[i0].n.numEntries - if rep: - i0 = i - minLoss = loss - n = nn.a[i0].n - return n - -proc pickSeeds[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: Node[M, D, RT, LT] | Leaf[M, D, RT, LT]; bx: Box[D, RT]): (int, int) = - var i0, j0: int - var bi, bj: type(bx) - var largestWaste = type(bx[0].a).low - for i in -1 .. n.a.high: - for j in 0 .. n.a.high: - if unlikely(i == j): continue - if unlikely(i < 0): - bi = bx - else: - bi = n.a[i].b - bj = n.a[j].b - let b = union(bi, bj) - let h = area(b) - area(bi) - area(bj) - if h > largestWaste: - largestWaste = h - i0 = i - j0 = j - return (i0, j0) - -proc pickNext[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n0, n1, n2: Node[M, D, RT, LT] | Leaf[M, D, RT, LT]; b1, b2: Box[D, RT]): int = - let a1 = area(b1) - let a2 = area(b2) - var d = type(a1).low - for i in 0 ..< n0.numEntries: - let d1 = area(union(b1, n0.a[i].b)) - a1 - let d2 = area(union(b2, n0.a[i].b)) - a2 - if (d1 - d2) * (d1 - d2) > d: - result = i - d = (d1 - d2) * (d1 - d2) - -from algorithm import SortOrder, sort -proc sortPlus[T](a: var openArray[T], ax: var T, cmp: proc (x, y: T): int {.closure.}, order = algorithm.SortOrder.Ascending) = - var j = 0 - let sign = if order == algorithm.SortOrder.Ascending: 1 else: -1 - for i in 1 .. a.high: - if cmp(a[i], a[j]) * sign < 0: - j = i - if cmp(a[j], ax) * sign < 0: - swap(ax, a[j]) - a.sort(cmp, order) - -# R*TREE procs -proc rstarSplit[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): type(n) = - type NL = type(lx) - var nBest: type(n) - new nBest - var lx = lx - when n is Node[M, D, RT, LT]: - lx.n.parent = n - var lxbest: type(lx) - var m0 = lx.b[0].a.high - for d2 in 0 ..< 2 * D: - let d = d2 div 2 - if d2 mod 2 == 0: - sortPlus(n.a, lx, proc (x, y: NL): int = cmp(x.b[d].a, y.b[d].a)) - else: - sortPlus(n.a, lx, proc (x, y: NL): int = cmp(x.b[d].b, y.b[d].b)) - for i in t.m - 1 .. n.a.high - t.m + 1: - var b = lx.b - for j in 0 ..< i: # we can precalculate union() for range 0 .. t.m - 1, but that seems to give no real benefit.Maybe for very large M? - #echo "x",j - b = union(n.a[j].b, b) - var m = margin(b) - b = n.a[^1].b - for j in i ..< n.a.high: # again, precalculation of tail would be possible - #echo "y",j - b = union(n.a[j].b, b) - m += margin(b) - if m < m0: - nbest[] = n[] - lxbest = lx - m0 = m - var i0 = -1 - var o0 = lx.b[0].a.high - for i in t.m - 1 .. n.a.high - t.m + 1: - var b1 = lxbest.b - for j in 0 ..< i: - b1 = union(nbest.a[j].b, b1) - var b2 = nbest.a[^1].b - for j in i ..< n.a.high: - b2 = union(nbest.a[j].b, b2) - let o = overlap(b1, b2) - if o < o0: - i0 = i - o0 = o - n.a[0] = lxbest - for i in 0 ..< i0: - n.a[i + 1] = nbest.a[i] - new result - result.level = n.level - result.parent = n.parent - for i in i0 .. n.a.high: - result.a[i - i0] = nbest.a[i] - n.numEntries = i0 + 1 - result.numEntries = M - i0 - when n is Node[M, D, RT, LT]: - for i in 0 ..< result.numEntries: - result.a[i].n.parent = result - -proc quadraticSplit[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): type(n) = - var n1, n2: type(n) - var s1, s2: int - new n1 - new n2 - n1.parent = n.parent - n2.parent = n.parent - n1.level = n.level - n2.level = n.level - var lx = lx - when n is Node[M, D, RT, LT]: - lx.n.parent = n - (s1, s2) = pickSeeds(t, n, lx.b) - assert s1 >= -1 and s2 >= 0 - if unlikely(s1 < 0): - n1.a[0] = lx - else: - n1.a[0] = n.a[s1] - dec(n.numEntries) - if s2 == n.numEntries: # important fix - s2 = s1 - n.a[s1] = n.a[n.numEntries] - inc(n1.numEntries) - var b1 = n1.a[0].b - n2.a[0] = n.a[s2] - dec(n.numEntries) - n.a[s2] = n.a[n.numEntries] - inc(n2.numEntries) - var b2 = n2.a[0].b - if s1 >= 0: - n.a[n.numEntries] = lx - inc(n.numEntries) - while n.numEntries > 0 and n1.numEntries < (t.bigM + 1 - t.m) and n2.numEntries < (t.bigM + 1 - t.m): - let next = pickNext(t, n, n1, n2, b1, b2) - let d1 = area(union(b1, n.a[next].b)) - area(b1) - let d2 = area(union(b2, n.a[next].b)) - area(b2) - if (d1 < d2) or (d1 == d2 and ((area(b1) < area(b2)) or (area(b1) == area(b2) and n1.numEntries < n2.numEntries))): - n1.a[n1.numEntries] = n.a[next] - b1 = union(b1, n.a[next].b) - inc(n1.numEntries) - else: - n2.a[n2.numEntries] = n.a[next] - b2 = union(b2, n.a[next].b) - inc(n2.numEntries) - dec(n.numEntries) - n.a[next] = n.a[n.numEntries] - if n.numEntries == 0: - discard - elif n1.numEntries == (t.bigM + 1 - t.m): - while n.numEntries > 0: - dec(n.numEntries) - n2.a[n2.numEntries] = n.a[n.numEntries] - inc(n2.numEntries) - elif n2.numEntries == (t.bigM + 1 - t.m): - while n.numEntries > 0: - dec(n.numEntries) - n1.a[n1.numEntries] = n.a[n.numEntries] - inc(n1.numEntries) - when n is Node[M, D, RT, LT]: - for i in 0 ..< n2.numEntries: - n2.a[i].n.parent = n2 - n[] = n1[] - return n2 - -proc overflowTreatment[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): type(n) - -proc adjustTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; l, ll: H[M, D, RT, LT]; hb: Box[D, RT]) = - var n = l - var nn = ll - assert n != nil - while true: - if n == t.root: - if nn == nil: - break - t.root = newNode[M, D, RT, LT]() - t.root.level = n.level + 1 - Node[M, D, RT, LT](t.root).a[0].n = n - n.parent = t.root - nn.parent = t.root - t.root.numEntries = 1 - let p = Node[M, D, RT, LT](n.parent) - var i = 0 - while p.a[i].n != n: - inc(i) - var b: type(p.a[0].b) - if n of Leaf[M, D, RT, LT]: - when false:#if likely(nn.isNil): # no performance gain - b = union(p.a[i].b, Leaf[M, D, RT, LT](n).a[n.numEntries - 1].b) - else: - b = Leaf[M, D, RT, LT](n).a[0].b - for j in 1 ..< n.numEntries: - b = trtree.union(b, Leaf[M, D, RT, LT](n).a[j].b) - elif n of Node[M, D, RT, LT]: - b = Node[M, D, RT, LT](n).a[0].b - for j in 1 ..< n.numEntries: - b = union(b, Node[M, D, RT, LT](n).a[j].b) - else: - assert false - #if nn.isNil and p.a[i].b == b: break # no performance gain - p.a[i].b = b - n = H[M, D, RT, LT](p) - if unlikely(nn != nil): - if nn of Leaf[M, D, RT, LT]: - b = Leaf[M, D, RT, LT](nn).a[0].b - for j in 1 ..< nn.numEntries: - b = union(b, Leaf[M, D, RT, LT](nn).a[j].b) - elif nn of Node[M, D, RT, LT]: - b = Node[M, D, RT, LT](nn).a[0].b - for j in 1 ..< nn.numEntries: - b = union(b, Node[M, D, RT, LT](nn).a[j].b) - else: - assert false - if p.numEntries < p.a.len: - p.a[p.numEntries].b = b - p.a[p.numEntries].n = nn - inc(p.numEntries) - assert n != nil - nn = nil - else: - let h: N[M, D, RT, LT] = (b, nn) - nn = quadraticSplit(t, p, h) - assert n == H[M, D, RT, LT](p) - assert n != nil - assert t.root != nil - -proc insert*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: N[M, D, RT, LT] | L[D, RT, LT]; level: int = 0) = - when leaf is N[M, D, RT, LT]: - assert level > 0 - type NodeLeaf = Node[M, D, RT, LT] - else: - assert level == 0 - type NodeLeaf = Leaf[M, D, RT, LT] - for d in leaf.b: - assert d.a <= d.b - let l = NodeLeaf(chooseSubtree(t, leaf.b, level)) - if l.numEntries < l.a.len: - l.a[l.numEntries] = leaf - inc(l.numEntries) - when leaf is N[M, D, RT, LT]: - leaf.n.parent = l - adjustTree(t, l, nil, leaf.b) - else: - let l2 = quadraticSplit(t, l, leaf) - assert l2.level == l.level - adjustTree(t, l, l2, leaf.b) - -# R*Tree insert procs -proc rsinsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; leaf: N[M, D, RT, LT] | L[D, RT, LT]; level: int) - -proc reInsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]) = - type NL = type(lx) - var lx = lx - var buf: type(n.a) - let p = Node[M, D, RT, LT](n.parent) - var i = 0 - while p.a[i].n != n: - inc(i) - let c = center(p.a[i].b) - sortPlus(n.a, lx, proc (x, y: NL): int = cmp(distance(center(x.b), c), distance(center(y.b), c))) - n.numEntries = M - t.p - swap(n.a[n.numEntries], lx) - inc n.numEntries - var b = n.a[0].b - for i in 1 ..< n.numEntries: - b = union(b, n.a[i].b) - p.a[i].b = b - for i in M - t.p + 1 .. n.a.high: - buf[i] = n.a[i] - rsinsert(t, lx, n.level) - for i in M - t.p + 1 .. n.a.high: - rsinsert(t, buf[i], n.level) - -proc overflowTreatment[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): type(n) = - if n.level != t.root.level and t.firstOverflow[n.level]: - t.firstOverflow[n.level] = false - reInsert(t, n, lx) - return nil - else: - let l2 = rstarSplit(t, n, lx) - assert l2.level == n.level - return l2 - -proc rsinsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; leaf: N[M, D, RT, LT] | L[D, RT, LT]; level: int) = - when leaf is N[M, D, RT, LT]: - assert level > 0 - type NodeLeaf = Node[M, D, RT, LT] - else: - assert level == 0 - type NodeLeaf = Leaf[M, D, RT, LT] - let l = NodeLeaf(chooseSubtree(t, leaf.b, level)) - if l.numEntries < l.a.len: - l.a[l.numEntries] = leaf - inc(l.numEntries) - when leaf is N[M, D, RT, LT]: - leaf.n.parent = l - adjustTree(t, l, nil, leaf.b) - else: - when leaf is N[M, D, RT, LT]: # TODO do we need this? - leaf.n.parent = l - let l2 = overflowTreatment(t, l, leaf) - if l2 != nil: - assert l2.level == l.level - adjustTree(t, l, l2, leaf.b) - -proc insert*[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; leaf: L[D, RT, LT]) = - for d in leaf.b: - assert d.a <= d.b - for i in mitems(t.firstOverflow): - i = true - rsinsert(t, leaf, 0) - -# delete -proc findLeaf[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: L[D, RT, LT]): Leaf[M, D, RT, LT] = - proc fl[M, D: Dim; RT, LT](h: H[M, D, RT, LT]; leaf: L[D, RT, LT]): Leaf[M, D, RT, LT] = - var n = h - if n of Node[M, D, RT, LT]: - for i in 0 ..< n.numEntries: - if intersect(Node[M, D, RT, LT](n).a[i].b, leaf.b): - let l = fl(Node[M, D, RT, LT](n).a[i].n, leaf) - if l != nil: - return l - elif n of Leaf[M, D, RT, LT]: - for i in 0 ..< n.numEntries: - if Leaf[M, D, RT, LT](n).a[i] == leaf: - return Leaf[M, D, RT, LT](n) - else: - assert false - return nil - fl(t.root, leaf) - -proc condenseTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: Leaf[M, D, RT, LT]) = - var n: H[M, D, RT, LT] = leaf - var q = newSeq[H[M, D, RT, LT]]() - var b: typeof(leaf.a[0].b) - while n != t.root: - let p = Node[M, D, RT, LT](n.parent) - var i = 0 - while p.a[i].n != n: - inc(i) - if n.numEntries < t.m: - dec(p.numEntries) - p.a[i] = p.a[p.numEntries] - q.add(n) - else: - if n of Leaf[M, D, RT, LT]: - b = Leaf[M, D, RT, LT](n).a[0].b - for j in 1 ..< n.numEntries: - b = union(b, Leaf[M, D, RT, LT](n).a[j].b) - elif n of Node[M, D, RT, LT]: - b = Node[M, D, RT, LT](n).a[0].b - for j in 1 ..< n.numEntries: - b = union(b, Node[M, D, RT, LT](n).a[j].b) - else: - assert false - p.a[i].b = b - n = n.parent - if t of RStarTree[M, D, RT, LT]: - for n in q: - if n of Leaf[M, D, RT, LT]: - for i in 0 ..< n.numEntries: - for i in mitems(RStarTree[M, D, RT, LT](t).firstOverflow): - i = true - rsinsert(RStarTree[M, D, RT, LT](t), Leaf[M, D, RT, LT](n).a[i], 0) - elif n of Node[M, D, RT, LT]: - for i in 0 ..< n.numEntries: - for i in mitems(RStarTree[M, D, RT, LT](t).firstOverflow): - i = true - rsinsert(RStarTree[M, D, RT, LT](t), Node[M, D, RT, LT](n).a[i], n.level) - else: - assert false - else: - for n in q: - if n of Leaf[M, D, RT, LT]: - for i in 0 ..< n.numEntries: - insert(t, Leaf[M, D, RT, LT](n).a[i]) - elif n of Node[M, D, RT, LT]: - for i in 0 ..< n.numEntries: - insert(t, Node[M, D, RT, LT](n).a[i], n.level) - else: - assert false - -proc delete*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: L[D, RT, LT]): bool {.discardable.} = - let l = findLeaf(t, leaf) - if l.isNil: - return false - else: - var i = 0 - while l.a[i] != leaf: - inc(i) - dec(l.numEntries) - l.a[i] = l.a[l.numEntries] - condenseTree(t, l) - if t.root.numEntries == 1: - if t.root of Node[M, D, RT, LT]: - t.root = Node[M, D, RT, LT](t.root).a[0].n - t.root.parent = nil - return true - - -var t = [4, 1, 3, 2] -var xt = 7 -sortPlus(t, xt, system.cmp, SortOrder.Ascending) -echo xt, " ", t - -type - RSE = L[2, int, int] - RSeq = seq[RSE] - -proc rseq_search(rs: RSeq; rse: RSE): seq[int] = - result = newSeq[int]() - for i in rs: - if intersect(i.b, rse.b): - result.add(i.l) - -proc rseq_delete(rs: var RSeq; rse: RSE): bool = - for i in 0 .. rs.high: - if rs[i] == rse: - #rs.delete(i) - rs[i] = rs[rs.high] - rs.setLen(rs.len - 1) - return true - -import random, algorithm - -proc test(n: int) = - var b: Box[2, int] - echo center(b) - var x1, x2, y1, y2: int - var t = newRStarTree[8, 2, int, int]() - #var t = newRTree[8, 2, int, int]() - var rs = newSeq[RSE]() - for i in 0 .. 5: - for i in 0 .. n - 1: - x1 = rand(1000) - y1 = rand(1000) - x2 = x1 + rand(25) - y2 = y1 + rand(25) - b = [(x1, x2), (y1, y2)] - let el: L[2, int, int] = (b, i + 7) - t.insert(el) - rs.add(el) - - for i in 0 .. (n div 4): - let j = rand(rs.high) - var el = rs[j] - assert t.delete(el) - assert rs.rseq_delete(el) - - for i in 0 .. n - 1: - x1 = rand(1000) - y1 = rand(1000) - x2 = x1 + rand(100) - y2 = y1 + rand(100) - b = [(x1, x2), (y1, y2)] - let el: L[2, int, int] = (b, i) - let r = search(t, b) - let r2 = rseq_search(rs, el) - assert r.len == r2.len - assert r.sorted(system.cmp) == r2.sorted(system.cmp) - -test(500) diff --git a/tests/generics/tstatic_constrained.nim b/tests/generics/tstatic_constrained.nim new file mode 100644 index 000000000..d356b9d1c --- /dev/null +++ b/tests/generics/tstatic_constrained.nim @@ -0,0 +1,79 @@ +discard """ + cmd: "nim check --hints:off --warnings:off $file" + action: "reject" + nimout:''' +tstatic_constrained.nim(44, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] +got: <typedesc[int], int literal(10)> +but expected: <T: float or string, Y> +tstatic_constrained.nim(44, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] +got: <typedesc[int], int literal(10)> +but expected: <T: float or string, Y> +tstatic_constrained.nim(44, 31) Error: object constructor needs an object type [error] +tstatic_constrained.nim(44, 31) Error: expression '' has no type (or is ambiguous) +tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] +got: <typedesc[byte], uint8> +but expected: <T: float or string, Y> +tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] +got: <typedesc[byte], uint8> +but expected: <T: float or string, Y> +tstatic_constrained.nim(45, 34) Error: object constructor needs an object type [error] +tstatic_constrained.nim(45, 34) Error: expression '' has no type (or is ambiguous) +tstatic_constrained.nim(77, 14) Error: cannot instantiate MyType [type declared in tstatic_constrained.nim(71, 5)] +got: <typedesc[float], float64> +but expected: <T: MyConstraint, Y> +''' +""" +block: + type + MyType[T; X: static T] = object + data: T + MyOtherType[T: float or string, Y: static T] = object + + func f[T,X](a: MyType[T,X]): MyType[T,X] = + when T is string: + MyType[T,X](data: a.data & X) + else: + MyType[T,X](data: a.data + X) + + discard MyType[int, 2](data: 1) + discard MyType[string, "Helelello"](data: "Hmmm") + discard MyType[int, 2](data: 1).f() + discard MyType[string, "Helelello"](data: "Hmmm").f() + discard MyOtherType[float, 1.3]() + discard MyOtherType[string, "Hello"]() + discard MyOtherType[int, 10]() + discard MyOtherType[byte, 10u8]() + +block: + type + Moduloable = concept m, type M + m mod m is M + Addable = concept a, type A + a + a is A + Modulo[T: Moduloable; Mod: static T] = distinct T + ModuloAdd[T: Moduloable or Addable; Mod: static T] = distinct T + ModuAddable = Addable or Moduloable + ModdAddClass[T: ModuAddable; Mod: static T] = distinct T + + proc toMod[T](val: T, modVal: static T): Modulo[T, modVal] = + mixin `mod` + Modulo[T, modVal](val mod modVal) + var + a = 3231.toMod(10) + b = 5483.toMod(10) + discard ModuloAdd[int, 3](0) + discard ModdAddClass[int, 3](0) + +block: + type + MyConstraint = int or string + MyOtherConstraint[T] = object + MyType[T: MyConstraint; Y: static T] = object + MyOtherType[T: MyOtherConstraint; Y: static T] = object + + var + a: MyType[int, 10] + b: MyType[string, "hello"] + c: MyType[float, 10d] + d: MyOtherType[MyOtherConstraint[float],MyOtherConstraint[float]()] + e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()] diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim index 2af5a7615..300da56a6 100644 --- a/tests/generics/tthread_generic.nim +++ b/tests/generics/tthread_generic.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim $target --hints:on --threads:on $options $file" + matrix: "--mm:refc; --mm:orc" action: compile """ diff --git a/tests/generics/tuninstantiated_failure.nim b/tests/generics/tuninstantiated_failure.nim new file mode 100644 index 000000000..f3d5b34b8 --- /dev/null +++ b/tests/generics/tuninstantiated_failure.nim @@ -0,0 +1,16 @@ +discard """ +cmd: "nim check $file" +""" + +type + Test[T, K] = object + name: string + Something = Test[int] + +func `[]`[T, K](x: var Test[T, K], idx: int): var Test[T, K] = + x + +var b: Something +# Should give an error since Something isn't a valid Test +b[0].name = "Test" #[tt.Error + ^ expression '' has no type (or is ambiguous)]# diff --git a/tests/generics/tuninstantiatedgenericcalls.nim b/tests/generics/tuninstantiatedgenericcalls.nim new file mode 100644 index 000000000..f33fc8967 --- /dev/null +++ b/tests/generics/tuninstantiatedgenericcalls.nim @@ -0,0 +1,517 @@ +# Cases that used to only work due to weird workarounds in the compiler +# involving not instantiating calls in generic bodies which are removed +# due to breaking statics. +# The issue was that these calls are compiled as regular expressions at +# the generic declaration with unresolved generic parameter types, +# which are special cased in some places in the compiler, but sometimes +# treated like real types. + +block: + type Base10 = object + + func maxLen(T: typedesc[Base10], I: type): int8 = + when I is uint8: + 3 + elif I is uint16: + 5 + elif I is uint32: + 10 + elif I is uint64: + 20 + else: + when sizeof(uint) == 4: + 10 + else: + 20 + + type + Base10Buf[T: SomeUnsignedInt] = object + data: array[maxLen(Base10, T), byte] + len: int8 + + var x: Base10Buf[uint32] + doAssert x.data.len == 10 + var y: Base10Buf[uint16] + doAssert y.data.len == 5 + +import typetraits + +block thardcases: + proc typeNameLen(x: typedesc): int {.compileTime.} = + result = x.name.len + macro selectType(a, b: typedesc): typedesc = + result = a + + type + Foo[T] = object + data1: array[T.high, int] + data2: array[typeNameLen(T), float] + data3: array[0..T.typeNameLen, selectType(float, int)] + + type MyEnum = enum A, B, C, D + + var f1: Foo[MyEnum] + var f2: Foo[int8] + + doAssert high(f1.data1) == 2 # (D = 3) - 1 == 2 + doAssert high(f1.data2) == 5 # (MyEnum.len = 6) - 1 == 5 + + doAssert high(f2.data1) == 126 # 127 - 1 == 126 + doAssert high(f2.data2) == 3 # int8.len - 1 == 3 + + static: + doAssert high(f1.data1) == ord(C) + doAssert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high + + doAssert high(f2.data1) == 126 + doAssert high(f2.data2) == 3 + + doAssert high(f1.data3) == 6 # length of MyEnum + doAssert high(f2.data3) == 4 # length of int8 + + doAssert f2.data3[0] is float + +import muninstantiatedgenericcalls + +block: + var x: Leb128Buf[uint32] + doAssert x.data.len == 5 + var y: Leb128Buf[uint16] + doAssert y.data.len == 3 + +import macros + +block: # issue #12415 + macro isSomePointerImpl(t: typedesc): bool = + var impl = t.getTypeInst[1].getTypeImpl + if impl.kind == nnkDistinctTy: + impl = impl[0].getTypeImpl + if impl.kind in {nnkPtrTy,nnkRefTy}: + result = newLit(true) + elif impl.kind == nnkSym and impl.eqIdent("pointer"): + result = newLit(true) + else: + result = newLit(false) + + proc isSomePointer[T](t: typedesc[T]): bool {.compileTime.} = + isSomePointerImpl(t) + + type + Option[T] = object + ## An optional type that stores its value and state separately in a boolean. + when isSomePointer(typedesc(T)): + val: T + else: + val: T + has: bool + var x: Option[ref int] + doAssert not compiles(x.has) + var y: Option[int] + doAssert compiles(y.has) + +block: # issue #2002 + proc isNillable(T: typedesc): bool = + when compiles((let v: T = nil)): + return true + else: + return false + + type + Foo[T] = object + when isNillable(T): + nillable: float + else: + notnillable: int + + var val1: Foo[ref int] + doAssert compiles(val1.nillable) + doAssert not compiles(val1.notnillable) + var val2: Foo[int] + doAssert not compiles(val2.nillable) + doAssert compiles(val2.notnillable) + +block: # issue #1771 + type + Foo[X, T] = object + bar: array[X.low..X.high, T] + + proc test[X, T](f: Foo[X, T]): T = + f.bar[X.low] + + var a: Foo[range[0..2], float] + doAssert test(a) == 0.0 + +block: # issue #23730 + proc test(M: static[int]): array[1 shl M, int] = discard + doAssert len(test(3)) == 8 + doAssert len(test(5)) == 32 + +block: # issue #19819 + type + Example[N: static int] = distinct int + What[E: Example] = Example[E.N + E.N] + +block: # issue #23339 + type + A = object + B = object + template aToB(t: typedesc[A]): typedesc = B + type + Inner[I] = object + innerField: I + Outer[O] = object + outerField: Inner[O.aToB] + var x: Outer[A] + doAssert typeof(x.outerField.innerField) is B + +block: # deref syntax + type + Enqueueable = concept x + x is ptr + Foo[T: Enqueueable] = object + x: typeof(default(T)[]) + + proc p[T](f: Foo[T]) = + var bar: Foo[T] + discard + var foo: Foo[ptr int] + p(foo) + doAssert foo.x is int + foo.x = 123 + doAssert foo.x == 123 + inc foo.x + doAssert foo.x == 124 + +block: + type Generic[T] = object + field: T + macro foo(x: typed): untyped = x + macro bar[T](x: typedesc[Generic[T]]): untyped = x + type + Foo[T] = object + field: Generic[int].foo() + Foo2[T] = object + field: Generic[T].foo() + Bar[T] = object + field: Generic[int].bar() + Bar2[T] = object + field: Generic[T].bar() + var x: Foo[int] + var x2: Foo2[int] + var y: Bar[int] + var y2: Bar2[int] + +block: + macro pick(x: static int): untyped = + if x < 100: + result = bindSym"int" + else: + result = bindSym"float" + + type Foo[T: static int] = object + fixed1: pick(25) + fixed2: pick(125) + unknown: pick(T) + + var a: Foo[123] + doAssert a.fixed1 is int + doAssert a.fixed2 is float + doAssert a.unknown is float + var b: Foo[23] + doAssert b.fixed1 is int + doAssert b.fixed2 is float + doAssert b.unknown is int + +import std/sequtils + +block: # version of #23432 with `typed`, don't delay instantiation + type + Future[T] = object + InternalRaisesFuture[T, E] = object + macro Raising[T](F: typedesc[Future[T]], E: varargs[typed]): untyped = + let raises = nnkTupleConstr.newTree(E.mapIt(it)) + nnkBracketExpr.newTree( + ident "InternalRaisesFuture", + nnkDotExpr.newTree(F, ident"T"), + raises + ) + type X[E] = Future[void].Raising(E) + proc f(x: X) = discard + var v: Future[void].Raising([ValueError]) + f(v) + +block: # issue #22647 + proc c0(n: static int): int = 8 + proc c1(n: static int): int = n div 2 + proc c2(n: static int): int = n * 2 + proc c3(n: static int, n2: int): int = n * n2 + proc `**`(n: static int, n2: int): int = n * n2 + proc c4(n: int, n2: int): int = n * n2 + + type + a[N: static int] = object + f0 : array[N, int] + + b[N: static int] = object + f0 : a[c0(N)] # does not work + f1 : a[c1(N)] # does not work + f2 : a[c2(N)] # does not work + f3 : a[N * 2] # does not work + f4 : a[N] # works + f5: a[c3(N, 2)] + f6: a[N ** 2] + f7: a[2 * N] + f8: a[c4(N, 2)] + + proc p[N: static int](x : a[N]) = discard x.f0[0] + template check(x, s: untyped) = + p(x) + doAssert x is a[s] + doAssert x.N == s + doAssert typeof(x).N == s + doAssert x.f0 == default(array[s, int]) + doAssert x.f0.len == s + proc p2[N: static int](y : a[N]) {.gensym.} = + doAssert y is a[s] + doAssert y.N == s + doAssert typeof(y).N == s + doAssert y.f0 == default(array[s, int]) + doAssert y.f0.len == s + p2(x) + proc p3(z: typeof(x)) {.gensym.} = discard + p3(default(a[s])) + proc p[N: static int](x : b[N]) = + x.f0.check(8) + x.f1.check(2) + x.f2.check(8) + x.f3.check(8) + x.f4.check(4) + x.f5.check(8) + x.f6.check(8) + x.f7.check(8) + x.f8.check(8) + + var x: b[4] + x.p() + +block: # issue #1969 + type ZeroGenerator = object + proc next(g: ZeroGenerator): int = 0 + # This compiles. + type TripleOfInts = tuple + a, b, c: typeof(new(ZeroGenerator)[].next) + # This raises a compiler error before it's even instantiated. + # The `new` proc can't be resolved because `Generator` is not defined. + type TripleLike[Generator] = tuple + a, b, c: typeof(new(Generator)[].next) + +import std/atomics + +block: # issue #12720 + const CacheLineSize = 128 + type + Enqueueable = concept x, type T + x is ptr + x.next is Atomic[pointer] + MyChannel[T: Enqueueable] = object + pad: array[CacheLineSize - sizeof(default(T)[]), byte] + dummy: typeof(default(T)[]) + +block: # issue #12714 + type + Enqueueable = concept x, type T + x is ptr + x.next is Atomic[pointer] + MyChannel[T: Enqueueable] = object + dummy: type(default(T)[]) + +block: # issue #24044 + type ArrayBuf[N: static int, T = byte] = object + buf: array[N, T] + template maxLen(T: type): int = + sizeof(T) * 2 + type MyBuf[I] = ArrayBuf[maxLen(I)] + var v: MyBuf[int] + +block: # issue #15959 + proc my[T](a: T): typeof(a[0]) = discard + proc my2[T](a: T): array[sizeof(a[0]), T] = discard + proc byLent2[T](a: T): lent type(a[0]) = a[0] # Error: type mismatch: got <T, int literal(0)> + proc byLent3[T](a: T): lent typeof(a[0]) = a[0] # ditto + proc byLent4[T](a: T): lent[type(a[0])] = a[0] # Error: no generic parameters allowed for lent + var x = @[1, 2, 3] + doAssert my(x) is int + doAssert my2(x) is array[sizeof(int), seq[int]] + doAssert byLent2(x) == 1 + doAssert byLent2(x) is lent int + doAssert byLent3(x) == 1 + doAssert byLent3(x) is lent int + doAssert byLent4(x) == 1 + doAssert byLent4(x) is lent int + proc fn[U](a: U): auto = a + proc my3[T](a: T, b: typeof(fn(a))) = discard + my3(x, x) + doAssert not compiles(my3(x, x[0])) + +block: # issue #22342, type section version of #22607 + type GenAlias[isInt: static bool] = ( + when isInt: + int + else: + float + ) + doAssert GenAlias[true] is int + doAssert GenAlias[false] is float + proc foo(T: static bool): GenAlias[T] = discard + doAssert foo(true) is int + doAssert foo(false) is float + proc foo[T: static bool](v: var GenAlias[T]) = + v += 1 + var x: int + foo[true](x) + doAssert not compiles(foo[false](x)) + foo[true](x) + doAssert x == 2 + var y: float + foo[false](y) + doAssert not compiles(foo[true](y)) + foo[false](y) + doAssert y == 2 + +block: # `when`, test no constant semchecks + type Foo[T] = ( + when false: + {.error: "bad".} + elif defined(neverDefined): + {.error: "bad 2".} + else: + T + ) + var x: Foo[int] + type Bar[T] = ( + when true: + T + elif defined(js): + {.error: "bad".} + else: + {.error: "bad 2".} + ) + var y: Bar[int] + +block: # weird regression + type + Foo[T] = distinct int + Bar[T, U] = distinct int + proc foo[T, U](x: static Foo[T], y: static Bar[T, U]): Foo[T] = + # signature gives: + # Error: cannot instantiate Bar + # got: <typedesc[T], U> + # but expected: <T, U> + x + doAssert foo(Foo[int](1), Bar[int, int](2)).int == 1 + +block: # issue #24090 + type M[V] = object + template y[V](N: type M, v: V): M[V] = default(M[V]) + proc d(x: int | int, f: M[int] = M.y(0)) = discard + d(0, M.y(0)) + type Foo[T] = object + x: typeof(M.y(default(T))) + var a: Foo[int] + doAssert a.x is M[int] + var b: Foo[float] + doAssert b.x is M[float] + doAssert not (compiles do: + type Bar[T] = object + x: typeof(M()) # actually fails here immediately + var bar: Bar[int]) + doAssert not (compiles do: + type Bar[T] = object + x: typeof(default(M)) + var bar: Bar[int] + # gives "undeclared identifier x" because of #24091, + # normally it should fail in the line above + echo bar.x) + proc foo[T: M](x: T = default(T)) = discard x + foo[M[int]]() + doAssert not compiles(foo()) + +block: # above but encountered by sigmatch using replaceTypeVarsN + type Opt[T] = object + x: T + proc none[T](x: type Opt, y: typedesc[T]): Opt[T] = discard + proc foo[T](x: T, a = Opt.none(int)) = discard + foo(1, a = Opt.none(int)) + foo(1) + +block: # real version of above + type Opt[T] = object + x: T + template none(x: type Opt, T: type): Opt[T] = Opt[T]() + proc foo[T](x: T, a = Opt.none(int)) = discard + foo(1, a = Opt.none(int)) + foo(1) + +block: # issue #20880 + type + Child[n: static int] = object + data: array[n, int] + Parent[n: static int] = object + child: Child[3*n] + const n = 3 + doAssert $(typeof Parent[n*3]()) == "Parent[9]" + doAssert $(typeof Parent[1]().child) == "Child[3]" + doAssert Parent[1]().child.data.len == 3 + +{.experimental: "dynamicBindSym".} +block: # issue #16774 + type SecretWord = distinct uint64 + const WordBitWidth = 8 * sizeof(uint64) + func wordsRequired(bits: int): int {.compileTime.} = + ## Compute the number of limbs required + # from the **announced** bit length + (bits + WordBitWidth - 1) div WordBitWidth + type + Curve = enum BLS12_381 + BigInt[bits: static int] = object + limbs: array[bits.wordsRequired, SecretWord] + const BLS12_381_Modulus = default(BigInt[381]) + macro Mod(C: static Curve): untyped = + ## Get the Modulus associated to a curve + result = bindSym($C & "_Modulus") + macro getCurveBitwidth(C: static Curve): untyped = + result = nnkDotExpr.newTree( + getAST(Mod(C)), + ident"bits" + ) + type Fp[C: static Curve] = object + ## Finite Fields / Modular arithmetic + ## modulo the curve modulus + mres: BigInt[getCurveBitwidth(C)] + var x: Fp[BLS12_381] + doAssert x.mres.limbs.len == wordsRequired(getCurveBitWidth(BLS12_381)) + # minimized, as if we haven't tested it already: + macro makeIntLit(c: static int): untyped = + result = newLit(c) + type Test[T: static int] = object + myArray: array[makeIntLit(T), int] + var y: Test[2] + doAssert y.myArray.len == 2 + var z: Test[4] + doAssert z.myArray.len == 4 + +block: # issue #16175 + type + Thing[D: static uint] = object + when D == 0: + kid: char + else: + kid: Thing[D-1] + var t2 = Thing[3]() + doAssert t2.kid is Thing[2.uint] + doAssert t2.kid.kid is Thing[1.uint] + doAssert t2.kid.kid.kid is Thing[0.uint] + doAssert t2.kid.kid.kid.kid is char + var s = Thing[1]() + doAssert s.kid is Thing[0.uint] + doAssert s.kid.kid is char diff --git a/tests/generics/twrong_explicit_typeargs.nim b/tests/generics/twrong_explicit_typeargs.nim deleted file mode 100644 index e47b38e99..000000000 --- a/tests/generics/twrong_explicit_typeargs.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - errormsg: "cannot instantiate: 'newImage[string]'" - line: 16 -""" - -# bug #4084 -type - Image[T] = object - data: seq[T] - -proc newImage[T: int32|int64](w, h: int): ref Image[T] = - new(result) - result.data = newSeq[T](w * h) - -var correct = newImage[int32](320, 200) -var wrong = newImage[string](320, 200) diff --git a/tests/generics/twrong_generic_object.nim b/tests/generics/twrong_generic_object.nim index 442b89ea1..4951f735f 100644 --- a/tests/generics/twrong_generic_object.nim +++ b/tests/generics/twrong_generic_object.nim @@ -1,6 +1,6 @@ discard """ - errormsg: "cannot instantiate: 'GenericNodeObj[T]'; Maybe generic arguments are missing?" - line: 21 + errormsg: "'Node' is not a concrete type" + line: 11 """ # bug #2509 type |