Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
008ffa4
Infer generic bindings
Jul 22, 2023
bc08ff2
Simple test
Jul 22, 2023
257fd33
Add t
Jul 22, 2023
0c6d8bb
Allow it to work for templates too
Jul 22, 2023
d5cbc7e
Fix some builds by putting bindings in a template
Jul 22, 2023
f2ed402
Fix builtins
Jul 23, 2023
cf36fa8
Slightly more exotic seq test
Jul 23, 2023
a235f14
Test value-based generics using array
Jul 23, 2023
e331214
Pass expectedType into buildBindings
Jul 23, 2023
851fbcf
Put buildBindings into a proc
Jul 23, 2023
04f7e08
Manual entry
Jul 23, 2023
d607d26
Remove leftover `
Jul 23, 2023
f915036
Improve language used in the manual
Jul 24, 2023
165673b
Experimental flag and fix basic constructors
Jul 24, 2023
9e42bbc
Tiny commend cleanup
Jul 24, 2023
e66af09
Move to experimental manual
Jul 24, 2023
444c169
Use 'kind' so tuples continue to fail like before
Jul 24, 2023
b554162
Explicitly disallow tuples
Jul 24, 2023
1cad79f
Table test and document tuples
Jul 24, 2023
189c9e1
Test type reduction
Jul 24, 2023
6d85aeb
Disable inferGenericTypes check for CI tests
Jul 24, 2023
b006c4e
Remove tuple info in manual
Jul 24, 2023
347eb20
Always reduce types. Testing CI
Jul 26, 2023
2a8353c
Fixes
Jul 26, 2023
dccee38
Ignore tyGenericInst
Jul 26, 2023
be98387
Prevent binding already bound generic params
Jul 29, 2023
fe2b42e
tyUncheckedArray
Jul 29, 2023
524a289
Few more types
Jul 29, 2023
d926772
Update manual and check for flag again
Jul 29, 2023
fbde75b
Update tests/generics/treturn_inference.nim
Araq Aug 2, 2023
970fafc
var candidate, remove flag check again for CI
Aug 2, 2023
18465fa
Enable check once more
Aug 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Experimental flag and fix basic constructors
  • Loading branch information
SirOlaf committed Jul 24, 2023
commit 165673b3691e34fef7ad6d544348b464e56e76c0
3 changes: 2 additions & 1 deletion compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ type
unicodeOperators, # deadcode
flexibleOptionalParams,
strictDefs,
strictCaseObjects
strictCaseObjects,
inferGenericTypes

LegacyFeature* = enum
allowSemcheckedAstModification,
Expand Down
25 changes: 17 additions & 8 deletions compiler/semcall.nim
Original file line number Diff line number Diff line change
Expand Up @@ -562,18 +562,27 @@ proc getCallLineInfo(n: PNode): TLineInfo =
discard
result = n.info

proc inheritBindings(x: TCandidate, expectedType: PType): TIdTable =
## helper proc to inherit bound generic parameters from expectedType into a new TIdTable
proc inheritBindings(c: PContext, x: TCandidate, expectedType: PType): TIdTable =
## Helper proc to inherit bound generic parameters from expectedType into a new TIdTable.
## Returns existing bindings if 'inferGenericTypes' isn't in c.features
result = x.bindings
if expectedType != nil and expectedType.sons.len() > 0 and expectedType.sons[0] != nil:
let y = x.calleeSym.ast[genericParamsPos]
# concrete types give us just the list of generic params
if inferGenericTypes notin c.features: return
if expectedType == nil: return

let y = x.calleeSym.ast[genericParamsPos]
if expectedType.sons.len() > 0 and expectedType.sons[0] != nil:
#let y = x.calleeSym.ast[genericParamsPos]
# concrete types provide just the list of generic params
let startIdx = if expectedType.kind in ConcreteTypes: 0 else: 1
for i in startIdx ..< expectedType.len-startIdx:
let j = i - startIdx # idx of unbound param in callee
if result.idTableGet(y[j].typ) != nil:
break # let's not overwrite existing ones
break # don't not overwrite existing ones
result.idTablePut(y[j].typ, expectedType[i])
elif expectedType.sons.len() == 0 and y.len() == 1:
# Already a base type, just pass it along
if result.idTableGet(y[0].typ) == nil:
result.idTablePut(y[0].typ, expectedType)

proc semResolvedCall(c: PContext, x: TCandidate,
n: PNode, flags: TExprFlags;
Expand All @@ -597,11 +606,11 @@ proc semResolvedCall(c: PContext, x: TCandidate,
if x.calleeSym.magic in {mArrGet, mArrPut}:
finalCallee = x.calleeSym
else:
finalCallee = generateInstance(c, x.calleeSym, x.inheritBindings(expectedType), n.info)
finalCallee = generateInstance(c, x.calleeSym, c.inheritBindings(x, expectedType), n.info)
else:
# For macros and templates, the resolved generic params
# are added as normal params.
for s in instantiateGenericParamList(c, gp, x.inheritBindings(expectedType)):
for s in instantiateGenericParamList(c, gp, c.inheritBindings(x, expectedType)):
case s.kind
of skConst:
if not s.astdef.isNil:
Expand Down
8 changes: 4 additions & 4 deletions doc/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -5749,7 +5749,7 @@ Inferred generic parameters
---------------------------

In expressions making use of generic procs or templates, the expected
(unbound) types are often able to be inferred based on context.
(unbound) types are often able to be inferred based on context:

```nim test = "nim c $1"
import std/options
Expand Down Expand Up @@ -5782,10 +5782,10 @@ that would be necessary at the given location.

If that is the case, the unmapped generic parameters are mapped to the expected ones.

If bindings cannot be inferred, compilation will fail and manual specification is required.
If bindings *cannot be inferred*, compilation will fail and manual specification is required.

A limitation of this approach is that an expression as part of a function call
is unable to be inferred and has to be specified:
An example for failing inference can be found when passing a generic expression
to a function/template call:

```nim test = "nim c $1" status = 1
proc myProc[T](a, b: T) = discard
Expand Down
26 changes: 25 additions & 1 deletion tests/generics/treturn_inference.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

{.experimental: "inferGenericTypes".}


block:
type
MyOption[T, Z] = object
Expand Down Expand Up @@ -75,4 +78,25 @@ block:
for i in 0 .. N.high:
result[i] = i
var x: array[2, int] = giveArray()
doAssert x == [0, 1]
doAssert x == [0, 1]


# 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