diff options
Diffstat (limited to 'tests/generics')
68 files changed, 2444 insertions, 88 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 3112c133f..090b97771 100644 --- a/tests/generics/mdotlookup.nim +++ b/tests/generics/mdotlookup.nim @@ -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/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/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/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/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/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/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/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/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 78183c7ca..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 ''' """ @@ -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 db7a16569..3068a22f2 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -872,3 +872,23 @@ block: # Ensure no segfault from constraint 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 6c76502e1..53661236e 100644 --- a/tests/generics/tgenerics_various.nim +++ b/tests/generics/tgenerics_various.nim @@ -127,42 +127,6 @@ 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: - 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 - - - block tmap_auto: let x = map(@[1, 2, 3], x => x+10) doAssert x == @[11, 12, 13] @@ -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 index ba24b79e9..7220b7429 100644 --- a/tests/generics/timplicit_and_explicit.nim +++ b/tests/generics/timplicit_and_explicit.nim @@ -3,8 +3,8 @@ 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](100, 1.0)) is float - assert typeof(doStuff[int](100, "Hello")) is string + 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) @@ -34,7 +34,8 @@ block: #15622 proc test1[T](a: T, b: static[string] = "") = discard test1[int64](123) proc test2[T](a: T, b: static[string] = "") = discard - test2[int64, static[string]](123) + doAssert not (compiles do: + test2[int64, static[string]](123)) block: #4688 proc convertTo[T](v: int or float): T = (T)(v) @@ -42,4 +43,23 @@ block: #4688 block: #4164 proc printStr[T](s: static[string]): T = discard - discard printStr[int]("hello static") \ No newline at end of file + 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/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/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/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/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/treentranttypes.nim b/tests/generics/treentranttypes.nim index 40ff1647b..801f0e444 100644 --- a/tests/generics/treentranttypes.nim +++ b/tests/generics/treentranttypes.nim @@ -101,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/tstatic_constrained.nim b/tests/generics/tstatic_constrained.nim index 3c9201548..d356b9d1c 100644 --- a/tests/generics/tstatic_constrained.nim +++ b/tests/generics/tstatic_constrained.nim @@ -8,7 +8,7 @@ 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 [proxy] +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> @@ -16,7 +16,7 @@ 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 [proxy] +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> @@ -76,4 +76,4 @@ block: b: MyType[string, "hello"] c: MyType[float, 10d] d: MyOtherType[MyOtherConstraint[float],MyOtherConstraint[float]()] - e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()] \ No newline at end of file + 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 |