summaryrefslogtreecommitdiffstats
path: root/test/typeparam
diff options
context:
space:
mode:
Diffstat (limited to 'test/typeparam')
-rw-r--r--test/typeparam/absdiff.go94
-rw-r--r--test/typeparam/absdiff2.go135
-rw-r--r--test/typeparam/absdiff3.go98
-rw-r--r--test/typeparam/absdiffimp.dir/a.go72
-rw-r--r--test/typeparam/absdiffimp.dir/main.go25
-rw-r--r--test/typeparam/absdiffimp.go7
-rw-r--r--test/typeparam/absdiffimp2.dir/a.go110
-rw-r--r--test/typeparam/absdiffimp2.dir/main.go29
-rw-r--r--test/typeparam/absdiffimp2.go7
-rw-r--r--test/typeparam/adder.go29
-rw-r--r--test/typeparam/aliasimp.dir/a.go9
-rw-r--r--test/typeparam/aliasimp.dir/main.go41
-rw-r--r--test/typeparam/aliasimp.go7
-rw-r--r--test/typeparam/append.go31
-rw-r--r--test/typeparam/boundmethod.go108
-rw-r--r--test/typeparam/builtins.go112
-rw-r--r--test/typeparam/chans.go413
-rw-r--r--test/typeparam/chansimp.dir/a.go232
-rw-r--r--test/typeparam/chansimp.dir/main.go189
-rw-r--r--test/typeparam/chansimp.go7
-rw-r--r--test/typeparam/combine.go65
-rw-r--r--test/typeparam/cons.go100
-rw-r--r--test/typeparam/dedup.dir/a.go10
-rw-r--r--test/typeparam/dedup.dir/b.go14
-rw-r--r--test/typeparam/dedup.dir/c.go14
-rw-r--r--test/typeparam/dedup.dir/main.go15
-rw-r--r--test/typeparam/dedup.go12
-rw-r--r--test/typeparam/dedup.out4
-rw-r--r--test/typeparam/devirtualize1.go22
-rw-r--r--test/typeparam/devirtualize2.go28
-rw-r--r--test/typeparam/dictionaryCapture-noinline.go126
-rw-r--r--test/typeparam/dictionaryCapture.go203
-rw-r--r--test/typeparam/dottype.go86
-rw-r--r--test/typeparam/dottype.out10
-rw-r--r--test/typeparam/double.go72
-rw-r--r--test/typeparam/eface.go67
-rw-r--r--test/typeparam/equal.go69
-rw-r--r--test/typeparam/fact.go32
-rw-r--r--test/typeparam/factimp.dir/a.go12
-rw-r--r--test/typeparam/factimp.dir/main.go26
-rw-r--r--test/typeparam/factimp.go7
-rw-r--r--test/typeparam/gencrawler.dir/a.go27
-rw-r--r--test/typeparam/gencrawler.dir/main.go12
-rw-r--r--test/typeparam/gencrawler.go10
-rw-r--r--test/typeparam/gencrawler.out2
-rw-r--r--test/typeparam/genembed.go52
-rw-r--r--test/typeparam/genembed2.go46
-rw-r--r--test/typeparam/geninline.dir/a.go56
-rw-r--r--test/typeparam/geninline.dir/main.go16
-rw-r--r--test/typeparam/geninline.go7
-rw-r--r--test/typeparam/graph.go230
-rw-r--r--test/typeparam/ifaceconv.go83
-rw-r--r--test/typeparam/importtest.go16
-rw-r--r--test/typeparam/index.go81
-rw-r--r--test/typeparam/index2.go67
-rw-r--r--test/typeparam/interfacearg.go46
-rw-r--r--test/typeparam/issue23536.go32
-rw-r--r--test/typeparam/issue376214.go20
-rw-r--r--test/typeparam/issue39755.go27
-rw-r--r--test/typeparam/issue42758.go19
-rw-r--r--test/typeparam/issue44688.go149
-rw-r--r--test/typeparam/issue45547.go20
-rw-r--r--test/typeparam/issue45722.go34
-rw-r--r--test/typeparam/issue45738.go18
-rw-r--r--test/typeparam/issue45817.go26
-rw-r--r--test/typeparam/issue46461.go13
-rw-r--r--test/typeparam/issue46461b.dir/a.go7
-rw-r--r--test/typeparam/issue46461b.dir/b.go13
-rw-r--r--test/typeparam/issue46461b.go7
-rw-r--r--test/typeparam/issue46472.go20
-rw-r--r--test/typeparam/issue46591.go22
-rw-r--r--test/typeparam/issue47258.go32
-rw-r--r--test/typeparam/issue47272.go55
-rw-r--r--test/typeparam/issue47272.out2
-rw-r--r--test/typeparam/issue47514.go20
-rw-r--r--test/typeparam/issue47514b.go19
-rw-r--r--test/typeparam/issue47514c.dir/a.go5
-rw-r--r--test/typeparam/issue47514c.dir/main.go10
-rw-r--r--test/typeparam/issue47514c.go7
-rw-r--r--test/typeparam/issue47631.go31
-rw-r--r--test/typeparam/issue47676.go23
-rw-r--r--test/typeparam/issue47684.go19
-rw-r--r--test/typeparam/issue47684b.go23
-rw-r--r--test/typeparam/issue47684c.go19
-rw-r--r--test/typeparam/issue47708.go37
-rw-r--r--test/typeparam/issue47710.go19
-rw-r--r--test/typeparam/issue47713.go52
-rw-r--r--test/typeparam/issue47713.out1
-rw-r--r--test/typeparam/issue47716.go68
-rw-r--r--test/typeparam/issue47723.go23
-rw-r--r--test/typeparam/issue47740.go40
-rw-r--r--test/typeparam/issue47740.out0
-rw-r--r--test/typeparam/issue47740b.go23
-rw-r--r--test/typeparam/issue47775.dir/b.go19
-rw-r--r--test/typeparam/issue47775.dir/main.go11
-rw-r--r--test/typeparam/issue47775.go7
-rw-r--r--test/typeparam/issue47775b.go28
-rw-r--r--test/typeparam/issue47797.go22
-rw-r--r--test/typeparam/issue47877.go23
-rw-r--r--test/typeparam/issue47878.go56
-rw-r--r--test/typeparam/issue47892.dir/a.go17
-rw-r--r--test/typeparam/issue47892.dir/main.go21
-rw-r--r--test/typeparam/issue47892.go7
-rw-r--r--test/typeparam/issue47892b.dir/a.go29
-rw-r--r--test/typeparam/issue47892b.dir/main.go17
-rw-r--r--test/typeparam/issue47892b.go7
-rw-r--r--test/typeparam/issue47896.go74
-rw-r--r--test/typeparam/issue47901.go21
-rw-r--r--test/typeparam/issue47924.go15
-rw-r--r--test/typeparam/issue47925.go20
-rw-r--r--test/typeparam/issue47925b.go33
-rw-r--r--test/typeparam/issue47925c.go36
-rw-r--r--test/typeparam/issue47925d.go47
-rw-r--r--test/typeparam/issue47929.go29
-rw-r--r--test/typeparam/issue47948.go18
-rw-r--r--test/typeparam/issue47966.go9
-rw-r--r--test/typeparam/issue48013.go39
-rw-r--r--test/typeparam/issue48016.go35
-rw-r--r--test/typeparam/issue48030.go26
-rw-r--r--test/typeparam/issue48042.go77
-rw-r--r--test/typeparam/issue48047.go30
-rw-r--r--test/typeparam/issue48049.go33
-rw-r--r--test/typeparam/issue48056.go27
-rw-r--r--test/typeparam/issue48094.dir/a.go26
-rw-r--r--test/typeparam/issue48094.dir/main.go20
-rw-r--r--test/typeparam/issue48094.go7
-rw-r--r--test/typeparam/issue48094b.dir/a.go8
-rw-r--r--test/typeparam/issue48094b.dir/b.go9
-rw-r--r--test/typeparam/issue48094b.go7
-rw-r--r--test/typeparam/issue48137.go25
-rw-r--r--test/typeparam/issue48185a.dir/p.go19
-rw-r--r--test/typeparam/issue48185a.dir/p_test.go11
-rw-r--r--test/typeparam/issue48185a.go7
-rw-r--r--test/typeparam/issue48185b.dir/a.go37
-rw-r--r--test/typeparam/issue48185b.dir/main.go18
-rw-r--r--test/typeparam/issue48185b.go7
-rw-r--r--test/typeparam/issue48191.go269
-rw-r--r--test/typeparam/issue48198.go22
-rw-r--r--test/typeparam/issue48225.go37
-rw-r--r--test/typeparam/issue48253.go34
-rw-r--r--test/typeparam/issue48276a.go19
-rw-r--r--test/typeparam/issue48276a.out1
-rw-r--r--test/typeparam/issue48276b.go15
-rw-r--r--test/typeparam/issue48280.dir/a.go11
-rw-r--r--test/typeparam/issue48280.dir/main.go11
-rw-r--r--test/typeparam/issue48280.go7
-rw-r--r--test/typeparam/issue48306.dir/a.go9
-rw-r--r--test/typeparam/issue48306.dir/main.go15
-rw-r--r--test/typeparam/issue48306.go7
-rw-r--r--test/typeparam/issue48317.go38
-rw-r--r--test/typeparam/issue48318.go33
-rw-r--r--test/typeparam/issue48337a.dir/a.go32
-rw-r--r--test/typeparam/issue48337a.dir/main.go12
-rw-r--r--test/typeparam/issue48337a.go7
-rw-r--r--test/typeparam/issue48337a.out1
-rw-r--r--test/typeparam/issue48337b.dir/a.go25
-rw-r--r--test/typeparam/issue48337b.dir/main.go11
-rw-r--r--test/typeparam/issue48337b.go7
-rw-r--r--test/typeparam/issue48344.go26
-rw-r--r--test/typeparam/issue48424.go54
-rw-r--r--test/typeparam/issue48453.go21
-rw-r--r--test/typeparam/issue48454.dir/a.go16
-rw-r--r--test/typeparam/issue48454.dir/b.go11
-rw-r--r--test/typeparam/issue48454.dir/main.go11
-rw-r--r--test/typeparam/issue48454.go7
-rw-r--r--test/typeparam/issue48462.dir/a.go22
-rw-r--r--test/typeparam/issue48462.dir/main.go23
-rw-r--r--test/typeparam/issue48462.go7
-rw-r--r--test/typeparam/issue48537.go21
-rw-r--r--test/typeparam/issue48538.go60
-rw-r--r--test/typeparam/issue48598.go28
-rw-r--r--test/typeparam/issue48602.go25
-rw-r--r--test/typeparam/issue48604.go25
-rw-r--r--test/typeparam/issue48609.go16
-rw-r--r--test/typeparam/issue48617.go29
-rw-r--r--test/typeparam/issue48645a.go31
-rw-r--r--test/typeparam/issue48645a.out1
-rw-r--r--test/typeparam/issue48645b.go81
-rw-r--r--test/typeparam/issue48711.go18
-rw-r--r--test/typeparam/issue48716.dir/a.go51
-rw-r--r--test/typeparam/issue48716.dir/main.go58
-rw-r--r--test/typeparam/issue48716.go7
-rw-r--r--test/typeparam/issue48838.go31
-rw-r--r--test/typeparam/issue48962.dir/a.go12
-rw-r--r--test/typeparam/issue48962.dir/b.go51
-rw-r--r--test/typeparam/issue48962.go7
-rw-r--r--test/typeparam/issue49027.dir/a.go55
-rw-r--r--test/typeparam/issue49027.dir/main.go33
-rw-r--r--test/typeparam/issue49027.go7
-rw-r--r--test/typeparam/issue49049.go27
-rw-r--r--test/typeparam/issue49241.dir/a.go13
-rw-r--r--test/typeparam/issue49241.dir/b.go17
-rw-r--r--test/typeparam/issue49241.dir/c.go17
-rw-r--r--test/typeparam/issue49241.dir/main.go21
-rw-r--r--test/typeparam/issue49241.go7
-rw-r--r--test/typeparam/issue49246.dir/a.go20
-rw-r--r--test/typeparam/issue49246.dir/b.go9
-rw-r--r--test/typeparam/issue49246.go7
-rw-r--r--test/typeparam/issue49295.go30
-rw-r--r--test/typeparam/issue49309.go26
-rw-r--r--test/typeparam/issue49421.go27
-rw-r--r--test/typeparam/issue49432.go22
-rw-r--r--test/typeparam/issue49497.dir/a.go26
-rw-r--r--test/typeparam/issue49497.dir/main.go11
-rw-r--r--test/typeparam/issue49497.go7
-rw-r--r--test/typeparam/issue49516.go26
-rw-r--r--test/typeparam/issue49524.dir/a.go8
-rw-r--r--test/typeparam/issue49524.dir/main.go11
-rw-r--r--test/typeparam/issue49524.go7
-rw-r--r--test/typeparam/issue49536.dir/a.go12
-rw-r--r--test/typeparam/issue49536.dir/b.go9
-rw-r--r--test/typeparam/issue49536.go7
-rw-r--r--test/typeparam/issue49538.go23
-rw-r--r--test/typeparam/issue49547.go22
-rw-r--r--test/typeparam/issue49611.go11
-rw-r--r--test/typeparam/issue49659.dir/a.go13
-rw-r--r--test/typeparam/issue49659.dir/b.go15
-rw-r--r--test/typeparam/issue49659.go7
-rw-r--r--test/typeparam/issue49659b.go28
-rw-r--r--test/typeparam/issue49667.dir/a.go12
-rw-r--r--test/typeparam/issue49667.dir/b.go11
-rw-r--r--test/typeparam/issue49667.dir/main.go11
-rw-r--r--test/typeparam/issue49667.go7
-rw-r--r--test/typeparam/issue49875.go14
-rw-r--r--test/typeparam/issue49893.dir/a.go15
-rw-r--r--test/typeparam/issue49893.dir/b.go15
-rw-r--r--test/typeparam/issue49893.dir/main.go15
-rw-r--r--test/typeparam/issue49893.go7
-rw-r--r--test/typeparam/issue50002.go64
-rw-r--r--test/typeparam/issue50109.go105
-rw-r--r--test/typeparam/issue50109.out1
-rw-r--r--test/typeparam/issue50109b.go29
-rw-r--r--test/typeparam/issue50121.dir/a.go26
-rw-r--r--test/typeparam/issue50121.dir/main.go18
-rw-r--r--test/typeparam/issue50121.go7
-rw-r--r--test/typeparam/issue50121b.dir/a.go16
-rw-r--r--test/typeparam/issue50121b.dir/b.go11
-rw-r--r--test/typeparam/issue50121b.dir/c.go13
-rw-r--r--test/typeparam/issue50121b.dir/d.go13
-rw-r--r--test/typeparam/issue50121b.dir/main.go12
-rw-r--r--test/typeparam/issue50121b.go7
-rw-r--r--test/typeparam/issue50147.go11
-rw-r--r--test/typeparam/issue50177.go101
-rw-r--r--test/typeparam/issue50193.go35
-rw-r--r--test/typeparam/issue50193.out6
-rw-r--r--test/typeparam/issue50259.go13
-rw-r--r--test/typeparam/issue50264.go45
-rw-r--r--test/typeparam/issue50317.go15
-rw-r--r--test/typeparam/issue50417.go146
-rw-r--r--test/typeparam/issue50417b.go58
-rw-r--r--test/typeparam/issue50419.go33
-rw-r--r--test/typeparam/issue50437.dir/a.go43
-rw-r--r--test/typeparam/issue50437.dir/b.go11
-rw-r--r--test/typeparam/issue50437.go7
-rw-r--r--test/typeparam/issue50481b.dir/b.go16
-rw-r--r--test/typeparam/issue50481b.dir/main.go23
-rw-r--r--test/typeparam/issue50481b.go7
-rw-r--r--test/typeparam/issue50481c.dir/a.go30
-rw-r--r--test/typeparam/issue50481c.dir/main.go18
-rw-r--r--test/typeparam/issue50481c.go7
-rw-r--r--test/typeparam/issue50481c.out1
-rw-r--r--test/typeparam/issue50485.dir/a.go239
-rw-r--r--test/typeparam/issue50485.dir/main.go9
-rw-r--r--test/typeparam/issue50485.go7
-rw-r--r--test/typeparam/issue50486.dir/goerror_fp.go75
-rw-r--r--test/typeparam/issue50486.dir/main.go16
-rw-r--r--test/typeparam/issue50486.go7
-rw-r--r--test/typeparam/issue50552.dir/a.go16
-rw-r--r--test/typeparam/issue50552.dir/main.go20
-rw-r--r--test/typeparam/issue50552.go7
-rw-r--r--test/typeparam/issue50561.dir/diameter.go86
-rw-r--r--test/typeparam/issue50561.dir/main.go13
-rw-r--r--test/typeparam/issue50561.go7
-rw-r--r--test/typeparam/issue50598.dir/a0.go23
-rw-r--r--test/typeparam/issue50598.dir/a1.go11
-rw-r--r--test/typeparam/issue50598.dir/a2.go11
-rw-r--r--test/typeparam/issue50598.dir/main.go22
-rw-r--r--test/typeparam/issue50598.go7
-rw-r--r--test/typeparam/issue50642.go63
-rw-r--r--test/typeparam/issue50690a.go75
-rw-r--r--test/typeparam/issue50690a.out1
-rw-r--r--test/typeparam/issue50690b.go51
-rw-r--r--test/typeparam/issue50690b.out1
-rw-r--r--test/typeparam/issue50690c.go50
-rw-r--r--test/typeparam/issue50690c.out1
-rw-r--r--test/typeparam/issue50833.go23
-rw-r--r--test/typeparam/issue50841.dir/a.go22
-rw-r--r--test/typeparam/issue50841.dir/b.go11
-rw-r--r--test/typeparam/issue50841.go7
-rw-r--r--test/typeparam/issue50993.go35
-rw-r--r--test/typeparam/issue51219.dir/a.go20
-rw-r--r--test/typeparam/issue51219.dir/main.go16
-rw-r--r--test/typeparam/issue51219.go7
-rw-r--r--test/typeparam/issue51219.out1
-rw-r--r--test/typeparam/issue51219b.dir/a.go37
-rw-r--r--test/typeparam/issue51219b.dir/b.go14
-rw-r--r--test/typeparam/issue51219b.dir/p.go14
-rw-r--r--test/typeparam/issue51219b.go7
-rw-r--r--test/typeparam/issue51232.go31
-rw-r--r--test/typeparam/issue51233.go28
-rw-r--r--test/typeparam/issue51236.go22
-rw-r--r--test/typeparam/issue51245.go16
-rw-r--r--test/typeparam/issue51250a.dir/a.go9
-rw-r--r--test/typeparam/issue51250a.dir/b.go24
-rw-r--r--test/typeparam/issue51250a.dir/main.go24
-rw-r--r--test/typeparam/issue51250a.go7
-rw-r--r--test/typeparam/issue51303.go65
-rw-r--r--test/typeparam/issue51303.out4
-rw-r--r--test/typeparam/issue51355.go31
-rw-r--r--test/typeparam/issue51367.dir/a.go14
-rw-r--r--test/typeparam/issue51367.dir/main.go13
-rw-r--r--test/typeparam/issue51367.go7
-rw-r--r--test/typeparam/issue51423.dir/a.go17
-rw-r--r--test/typeparam/issue51423.dir/b.go11
-rw-r--r--test/typeparam/issue51423.go7
-rw-r--r--test/typeparam/issue51521.go30
-rw-r--r--test/typeparam/issue51522a.go42
-rw-r--r--test/typeparam/issue51522b.go62
-rw-r--r--test/typeparam/issue51700.go26
-rw-r--r--test/typeparam/issue51765.go15
-rw-r--r--test/typeparam/issue51832.go25
-rw-r--r--test/typeparam/issue51836.dir/a.go8
-rw-r--r--test/typeparam/issue51836.dir/aa.go13
-rw-r--r--test/typeparam/issue51836.dir/p.go11
-rw-r--r--test/typeparam/issue51836.go7
-rw-r--r--test/typeparam/issue51840.go36
-rw-r--r--test/typeparam/issue51909.go30
-rw-r--r--test/typeparam/issue51925.go52
-rw-r--r--test/typeparam/issue52026.go50
-rw-r--r--test/typeparam/issue52117.dir/a.go15
-rw-r--r--test/typeparam/issue52117.dir/b.go7
-rw-r--r--test/typeparam/issue52117.go7
-rw-r--r--test/typeparam/issue52124.go21
-rw-r--r--test/typeparam/issue52228.go30
-rw-r--r--test/typeparam/issue52241.go22
-rw-r--r--test/typeparam/issue53087.go56
-rw-r--r--test/typeparam/issue53254.go19
-rw-r--r--test/typeparam/issue53390.go20
-rw-r--r--test/typeparam/issue53406.go22
-rw-r--r--test/typeparam/issue53419.go28
-rw-r--r--test/typeparam/issue53477.go34
-rw-r--r--test/typeparam/issue53762.go18
-rw-r--r--test/typeparam/issue54135.go32
-rw-r--r--test/typeparam/issue54225.go33
-rw-r--r--test/typeparam/issue54302.dir/a.go20
-rw-r--r--test/typeparam/issue54302.dir/main.go11
-rw-r--r--test/typeparam/issue54302.go7
-rw-r--r--test/typeparam/issue54456.go37
-rw-r--r--test/typeparam/issue54497.go19
-rw-r--r--test/typeparam/issue54535.go37
-rw-r--r--test/typeparam/issue54537.go22
-rw-r--r--test/typeparam/issue54765.go28
-rw-r--r--test/typeparam/issue55101.go16
-rw-r--r--test/typeparam/issue58513.go60
-rw-r--r--test/typeparam/list.go103
-rw-r--r--test/typeparam/list2.go608
-rw-r--r--test/typeparam/listimp.dir/a.go53
-rw-r--r--test/typeparam/listimp.dir/main.go52
-rw-r--r--test/typeparam/listimp.go7
-rw-r--r--test/typeparam/listimp2.dir/a.go298
-rw-r--r--test/typeparam/listimp2.dir/main.go315
-rw-r--r--test/typeparam/listimp2.go7
-rw-r--r--test/typeparam/lockable.go50
-rw-r--r--test/typeparam/map.go39
-rw-r--r--test/typeparam/mapimp.dir/a.go15
-rw-r--r--test/typeparam/mapimp.dir/main.go28
-rw-r--r--test/typeparam/mapimp.go7
-rw-r--r--test/typeparam/maps.go260
-rw-r--r--test/typeparam/mapsimp.dir/a.go108
-rw-r--r--test/typeparam/mapsimp.dir/main.go156
-rw-r--r--test/typeparam/mapsimp.go7
-rw-r--r--test/typeparam/mdempsky/1.dir/a.go9
-rw-r--r--test/typeparam/mdempsky/1.dir/b.go9
-rw-r--r--test/typeparam/mdempsky/1.go7
-rw-r--r--test/typeparam/mdempsky/10.dir/a.go7
-rw-r--r--test/typeparam/mdempsky/10.dir/b.go17
-rw-r--r--test/typeparam/mdempsky/10.go7
-rw-r--r--test/typeparam/mdempsky/12.dir/a.go11
-rw-r--r--test/typeparam/mdempsky/12.dir/main.go13
-rw-r--r--test/typeparam/mdempsky/12.go9
-rw-r--r--test/typeparam/mdempsky/13.go84
-rw-r--r--test/typeparam/mdempsky/14.go40
-rw-r--r--test/typeparam/mdempsky/15.go69
-rw-r--r--test/typeparam/mdempsky/16.go34
-rw-r--r--test/typeparam/mdempsky/17.go110
-rw-r--r--test/typeparam/mdempsky/18.go26
-rw-r--r--test/typeparam/mdempsky/18.out1
-rw-r--r--test/typeparam/mdempsky/19.go32
-rw-r--r--test/typeparam/mdempsky/2.go20
-rw-r--r--test/typeparam/mdempsky/20.go38
-rw-r--r--test/typeparam/mdempsky/21.go26
-rw-r--r--test/typeparam/mdempsky/3.dir/a.go7
-rw-r--r--test/typeparam/mdempsky/3.dir/b.go9
-rw-r--r--test/typeparam/mdempsky/3.go7
-rw-r--r--test/typeparam/mdempsky/4.dir/a.go12
-rw-r--r--test/typeparam/mdempsky/4.dir/b.go9
-rw-r--r--test/typeparam/mdempsky/4.go7
-rw-r--r--test/typeparam/mdempsky/5.go15
-rw-r--r--test/typeparam/mdempsky/6.go11
-rw-r--r--test/typeparam/mdempsky/7.dir/a.go9
-rw-r--r--test/typeparam/mdempsky/7.dir/b.go9
-rw-r--r--test/typeparam/mdempsky/7.go7
-rw-r--r--test/typeparam/mdempsky/8.dir/a.go7
-rw-r--r--test/typeparam/mdempsky/8.dir/b.go11
-rw-r--r--test/typeparam/mdempsky/8.go7
-rw-r--r--test/typeparam/mdempsky/9.go11
-rw-r--r--test/typeparam/metrics.go196
-rw-r--r--test/typeparam/min.go50
-rw-r--r--test/typeparam/mincheck.dir/a.go16
-rw-r--r--test/typeparam/mincheck.dir/main.go38
-rw-r--r--test/typeparam/mincheck.go7
-rw-r--r--test/typeparam/minimp.dir/a.go16
-rw-r--r--test/typeparam/minimp.dir/main.go38
-rw-r--r--test/typeparam/minimp.go7
-rw-r--r--test/typeparam/mutualimp.dir/a.go12
-rw-r--r--test/typeparam/mutualimp.dir/b.go12
-rw-r--r--test/typeparam/mutualimp.go7
-rw-r--r--test/typeparam/nested.go134
-rw-r--r--test/typeparam/nested.out4
-rw-r--r--test/typeparam/ordered.go95
-rw-r--r--test/typeparam/orderedmap.go286
-rw-r--r--test/typeparam/orderedmapsimp.dir/a.go226
-rw-r--r--test/typeparam/orderedmapsimp.dir/main.go64
-rw-r--r--test/typeparam/orderedmapsimp.go7
-rw-r--r--test/typeparam/pair.go36
-rw-r--r--test/typeparam/pairimp.dir/a.go10
-rw-r--r--test/typeparam/pairimp.dir/main.go30
-rw-r--r--test/typeparam/pairimp.go7
-rw-r--r--test/typeparam/pragma.go19
-rw-r--r--test/typeparam/recoverimp.dir/a.go16
-rw-r--r--test/typeparam/recoverimp.dir/main.go12
-rw-r--r--test/typeparam/recoverimp.go7
-rw-r--r--test/typeparam/recoverimp.out2
-rw-r--r--test/typeparam/select.dir/a.go15
-rw-r--r--test/typeparam/select.dir/main.go28
-rw-r--r--test/typeparam/select.go7
-rw-r--r--test/typeparam/sets.go280
-rw-r--r--test/typeparam/setsimp.dir/a.go128
-rw-r--r--test/typeparam/setsimp.dir/main.go156
-rw-r--r--test/typeparam/setsimp.go7
-rw-r--r--test/typeparam/settable.go123
-rw-r--r--test/typeparam/shape1.go50
-rw-r--r--test/typeparam/shape1.out4
-rw-r--r--test/typeparam/sliceimp.dir/a.go141
-rw-r--r--test/typeparam/sliceimp.dir/main.go179
-rw-r--r--test/typeparam/sliceimp.go7
-rw-r--r--test/typeparam/slices.go318
-rw-r--r--test/typeparam/smallest.go42
-rw-r--r--test/typeparam/smoketest.go56
-rw-r--r--test/typeparam/stringable.go46
-rw-r--r--test/typeparam/stringer.go88
-rw-r--r--test/typeparam/stringerimp.dir/a.go16
-rw-r--r--test/typeparam/stringerimp.dir/main.go38
-rw-r--r--test/typeparam/stringerimp.go7
-rw-r--r--test/typeparam/struct.go49
-rw-r--r--test/typeparam/structinit.dir/a.go15
-rw-r--r--test/typeparam/structinit.dir/b.go12
-rw-r--r--test/typeparam/structinit.dir/main.go11
-rw-r--r--test/typeparam/structinit.go7
-rw-r--r--test/typeparam/subdict.go43
-rw-r--r--test/typeparam/sum.go50
-rw-r--r--test/typeparam/tparam1.go43
-rw-r--r--test/typeparam/typelist.go138
-rw-r--r--test/typeparam/typeswitch1.go33
-rw-r--r--test/typeparam/typeswitch1.out9
-rw-r--r--test/typeparam/typeswitch2.go35
-rw-r--r--test/typeparam/typeswitch2.out9
-rw-r--r--test/typeparam/typeswitch3.go48
-rw-r--r--test/typeparam/typeswitch3.out9
-rw-r--r--test/typeparam/typeswitch4.go46
-rw-r--r--test/typeparam/typeswitch4.out9
-rw-r--r--test/typeparam/typeswitch5.go28
-rw-r--r--test/typeparam/typeswitch5.out4
-rw-r--r--test/typeparam/typeswitch6.go30
-rw-r--r--test/typeparam/typeswitch6.out5
-rw-r--r--test/typeparam/typeswitch7.go37
-rw-r--r--test/typeparam/typeswitch7.out3
-rw-r--r--test/typeparam/valimp.dir/a.go32
-rw-r--r--test/typeparam/valimp.dir/main.go55
-rw-r--r--test/typeparam/valimp.go7
-rw-r--r--test/typeparam/value.go75
481 files changed, 17640 insertions, 0 deletions
diff --git a/test/typeparam/absdiff.go b/test/typeparam/absdiff.go
new file mode 100644
index 0000000..9c83eff
--- /dev/null
+++ b/test/typeparam/absdiff.go
@@ -0,0 +1,94 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Numeric interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~complex64 | ~complex128
+}
+
+// numericAbs matches numeric types with an Abs method.
+type numericAbs[T any] interface {
+ Numeric
+ Abs() T
+}
+
+// AbsDifference computes the absolute value of the difference of
+// a and b, where the absolute value is determined by the Abs method.
+func absDifference[T numericAbs[T]](a, b T) T {
+ d := a - b
+ return d.Abs()
+}
+
+// orderedNumeric matches numeric types that support the < operator.
+type orderedNumeric interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64
+}
+
+// Complex matches the two complex types, which do not have a < operator.
+type Complex interface {
+ ~complex64 | ~complex128
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // orderedAbs is a helper type that defines an Abs method for
+// // ordered numeric types.
+// type orderedAbs[T orderedNumeric] T
+//
+// func (a orderedAbs[T]) Abs() orderedAbs[T] {
+// if a < 0 {
+// return -a
+// }
+// return a
+// }
+//
+// // complexAbs is a helper type that defines an Abs method for
+// // complex types.
+// type complexAbs[T Complex] T
+//
+// func (a complexAbs[T]) Abs() complexAbs[T] {
+// r := float64(real(a))
+// i := float64(imag(a))
+// d := math.Sqrt(r*r + i*i)
+// return complexAbs[T](complex(d, 0))
+// }
+//
+// // OrderedAbsDifference returns the absolute value of the difference
+// // between a and b, where a and b are of an ordered type.
+// func orderedAbsDifference[T orderedNumeric](a, b T) T {
+// return T(absDifference(orderedAbs[T](a), orderedAbs[T](b)))
+// }
+//
+// // ComplexAbsDifference returns the absolute value of the difference
+// // between a and b, where a and b are of a complex type.
+// func complexAbsDifference[T Complex](a, b T) T {
+// return T(absDifference(complexAbs[T](a), complexAbs[T](b)))
+// }
+
+func main() {
+ // // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+ // if got, want := orderedAbsDifference(1.0, -2.0), 3.0; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+ // if got, want := orderedAbsDifference(-1.0, 2.0), 3.0; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+ // if got, want := orderedAbsDifference(-20, 15), 35; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+ //
+ // if got, want := complexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+ // if got, want := complexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+}
diff --git a/test/typeparam/absdiff2.go b/test/typeparam/absdiff2.go
new file mode 100644
index 0000000..87a1ec6
--- /dev/null
+++ b/test/typeparam/absdiff2.go
@@ -0,0 +1,135 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// absdiff example in which an Abs method is attached to a generic type, which is a
+// structure with a single field that may be a list of possible basic types.
+
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+type Numeric interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~complex64 | ~complex128
+}
+
+// numericAbs matches a struct containing a numeric type that has an Abs method.
+type numericAbs[T Numeric] interface {
+ ~struct{ Value_ T }
+ Abs() T
+ Value() T
+}
+
+// absDifference computes the absolute value of the difference of
+// a and b, where the absolute value is determined by the Abs method.
+func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
+ d := a.Value() - b.Value()
+ dt := U{Value_: d}
+ return dt.Abs()
+}
+
+// orderedNumeric matches numeric types that support the < operator.
+type orderedNumeric interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64
+}
+
+// Complex matches the two complex types, which do not have a < operator.
+type Complex interface {
+ ~complex64 | ~complex128
+}
+
+// orderedAbs is a helper type that defines an Abs method for
+// a struct containing an ordered numeric type.
+type orderedAbs[T orderedNumeric] struct {
+ Value_ T
+}
+
+func (a orderedAbs[T]) Abs() T {
+ if a.Value_ < 0 {
+ return -a.Value_
+ }
+ return a.Value_
+}
+
+// Field accesses through type parameters are disabled
+// until we have a more thorough understanding of the
+// implications on the spec. See issue #51576.
+// Use accessor method instead.
+
+func (a orderedAbs[T]) Value() T {
+ return a.Value_
+}
+
+// complexAbs is a helper type that defines an Abs method for
+// a struct containing a complex type.
+type complexAbs[T Complex] struct {
+ Value_ T
+}
+
+func realimag(x any) (re, im float64) {
+ switch z := x.(type) {
+ case complex64:
+ re = float64(real(z))
+ im = float64(imag(z))
+ case complex128:
+ re = real(z)
+ im = imag(z)
+ default:
+ panic("unknown complex type")
+ }
+ return
+}
+
+func (a complexAbs[T]) Abs() T {
+ // TODO use direct conversion instead of realimag once #50937 is fixed
+ r, i := realimag(a.Value_)
+ // r := float64(real(a.Value))
+ // i := float64(imag(a.Value))
+ d := math.Sqrt(r*r + i*i)
+ return T(complex(d, 0))
+}
+
+func (a complexAbs[T]) Value() T {
+ return a.Value_
+}
+
+// OrderedAbsDifference returns the absolute value of the difference
+// between a and b, where a and b are of an ordered type.
+func OrderedAbsDifference[T orderedNumeric](a, b T) T {
+ return absDifference(orderedAbs[T]{a}, orderedAbs[T]{b})
+}
+
+// ComplexAbsDifference returns the absolute value of the difference
+// between a and b, where a and b are of a complex type.
+func ComplexAbsDifference[T Complex](a, b T) T {
+ return absDifference(complexAbs[T]{a}, complexAbs[T]{b})
+}
+
+func main() {
+ if got, want := OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+ if got, want := OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+ if got, want := OrderedAbsDifference(-20, 15), 35; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+
+ if got, want := ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+ if got, want := ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+}
diff --git a/test/typeparam/absdiff3.go b/test/typeparam/absdiff3.go
new file mode 100644
index 0000000..c85cd1d
--- /dev/null
+++ b/test/typeparam/absdiff3.go
@@ -0,0 +1,98 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// absdiff example using a function argument rather than attaching an
+// Abs method to a structure containing base types.
+
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+type Numeric interface {
+ OrderedNumeric | Complex
+}
+
+// absDifference computes the absolute value of the difference of
+// a and b, where the absolute value is determined by the abs function.
+func absDifference[T Numeric](a, b T, abs func(a T) T) T {
+ return abs(a - b)
+}
+
+// OrderedNumeric matches numeric types that support the < operator.
+type OrderedNumeric interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64
+}
+
+func Abs[T OrderedNumeric](a T) T {
+ if a < 0 {
+ return -a
+ }
+ return a
+}
+
+// Complex matches the two complex types, which do not have a < operator.
+type Complex interface {
+ ~complex64 | ~complex128
+}
+
+func realimag(x any) (re, im float64) {
+ switch z := x.(type) {
+ case complex64:
+ re = float64(real(z))
+ im = float64(imag(z))
+ case complex128:
+ re = real(z)
+ im = imag(z)
+ default:
+ panic("unknown complex type")
+ }
+ return
+}
+
+func ComplexAbs[T Complex](a T) T {
+ // TODO use direct conversion instead of realimag once #50937 is fixed
+ r, i := realimag(a)
+ // r := float64(real(a))
+ // i := float64(imag(a))
+ d := math.Sqrt(r*r + i*i)
+ return T(complex(d, 0))
+}
+
+// OrderedAbsDifference returns the absolute value of the difference
+// between a and b, where a and b are of an ordered type.
+func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
+ return absDifference(a, b, Abs[T])
+}
+
+// ComplexAbsDifference returns the absolute value of the difference
+// between a and b, where a and b are of a complex type.
+func ComplexAbsDifference[T Complex](a, b T) T {
+ return absDifference(a, b, ComplexAbs[T])
+}
+
+func main() {
+ if got, want := OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+ if got, want := OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+ if got, want := OrderedAbsDifference(-20, 15), 35; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+
+ if got, want := ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+ if got, want := ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+}
diff --git a/test/typeparam/absdiffimp.dir/a.go b/test/typeparam/absdiffimp.dir/a.go
new file mode 100644
index 0000000..60822fd
--- /dev/null
+++ b/test/typeparam/absdiffimp.dir/a.go
@@ -0,0 +1,72 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Numeric interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~complex64 | ~complex128
+}
+
+// numericAbs matches numeric types with an Abs method.
+type numericAbs[T any] interface {
+ Numeric
+ Abs() T
+}
+
+// AbsDifference computes the absolute value of the difference of
+// a and b, where the absolute value is determined by the Abs method.
+func absDifference[T numericAbs[T]](a, b T) T {
+ d := a - b
+ return d.Abs()
+}
+
+// orderedNumeric matches numeric types that support the < operator.
+type orderedNumeric interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64
+}
+
+// Complex matches the two complex types, which do not have a < operator.
+type Complex interface {
+ ~complex64 | ~complex128
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // orderedAbs is a helper type that defines an Abs method for
+// // ordered numeric types.
+// type orderedAbs[T orderedNumeric] T
+//
+// func (a orderedAbs[T]) Abs() orderedAbs[T] {
+// if a < 0 {
+// return -a
+// }
+// return a
+// }
+//
+// // complexAbs is a helper type that defines an Abs method for
+// // complex types.
+// type complexAbs[T Complex] T
+//
+// func (a complexAbs[T]) Abs() complexAbs[T] {
+// r := float64(real(a))
+// i := float64(imag(a))
+// d := math.Sqrt(r*r + i*i)
+// return complexAbs[T](complex(d, 0))
+// }
+//
+// // OrderedAbsDifference returns the absolute value of the difference
+// // between a and b, where a and b are of an ordered type.
+// func OrderedAbsDifference[T orderedNumeric](a, b T) T {
+// return T(absDifference(orderedAbs[T](a), orderedAbs[T](b)))
+// }
+//
+// // ComplexAbsDifference returns the absolute value of the difference
+// // between a and b, where a and b are of a complex type.
+// func ComplexAbsDifference[T Complex](a, b T) T {
+// return T(absDifference(complexAbs[T](a), complexAbs[T](b)))
+// }
diff --git a/test/typeparam/absdiffimp.dir/main.go b/test/typeparam/absdiffimp.dir/main.go
new file mode 100644
index 0000000..c648013
--- /dev/null
+++ b/test/typeparam/absdiffimp.dir/main.go
@@ -0,0 +1,25 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+ // if got, want := a.OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+ // if got, want := a.OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+ // if got, want := a.OrderedAbsDifference(-20, 15), 35; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+ //
+ // if got, want := a.ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+ // if got, want := a.ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
+ // panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ // }
+}
diff --git a/test/typeparam/absdiffimp.go b/test/typeparam/absdiffimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/absdiffimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/absdiffimp2.dir/a.go b/test/typeparam/absdiffimp2.dir/a.go
new file mode 100644
index 0000000..dc64f2d
--- /dev/null
+++ b/test/typeparam/absdiffimp2.dir/a.go
@@ -0,0 +1,110 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import (
+ "math"
+)
+
+type Numeric interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~complex64 | ~complex128
+}
+
+// numericAbs matches a struct containing a numeric type that has an Abs method.
+type numericAbs[T Numeric] interface {
+ ~struct{ Value_ T }
+ Abs() T
+ Value() T
+}
+
+// absDifference computes the absolute value of the difference of
+// a and b, where the absolute value is determined by the Abs method.
+func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
+ d := a.Value() - b.Value()
+ dt := U{Value_: d}
+ return dt.Abs()
+}
+
+// orderedNumeric matches numeric types that support the < operator.
+type orderedNumeric interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64
+}
+
+// Complex matches the two complex types, which do not have a < operator.
+type Complex interface {
+ ~complex64 | ~complex128
+}
+
+// orderedAbs is a helper type that defines an Abs method for
+// a struct containing an ordered numeric type.
+type orderedAbs[T orderedNumeric] struct {
+ Value_ T
+}
+
+func (a orderedAbs[T]) Abs() T {
+ if a.Value_ < 0 {
+ return -a.Value_
+ }
+ return a.Value_
+}
+
+// Field accesses through type parameters are disabled
+// until we have a more thorough understanding of the
+// implications on the spec. See issue #51576.
+// Use accessor method instead.
+
+func (a orderedAbs[T]) Value() T {
+ return a.Value_
+}
+
+// complexAbs is a helper type that defines an Abs method for
+// a struct containing a complex type.
+type complexAbs[T Complex] struct {
+ Value_ T
+}
+
+func realimag(x any) (re, im float64) {
+ switch z := x.(type) {
+ case complex64:
+ re = float64(real(z))
+ im = float64(imag(z))
+ case complex128:
+ re = real(z)
+ im = imag(z)
+ default:
+ panic("unknown complex type")
+ }
+ return
+}
+
+func (a complexAbs[T]) Abs() T {
+ // TODO use direct conversion instead of realimag once #50937 is fixed
+ r, i := realimag(a.Value_)
+ // r := float64(real(a.Value))
+ // i := float64(imag(a.Value))
+ d := math.Sqrt(r*r + i*i)
+ return T(complex(d, 0))
+}
+
+func (a complexAbs[T]) Value() T {
+ return a.Value_
+}
+
+// OrderedAbsDifference returns the absolute value of the difference
+// between a and b, where a and b are of an ordered type.
+func OrderedAbsDifference[T orderedNumeric](a, b T) T {
+ return absDifference(orderedAbs[T]{a}, orderedAbs[T]{b})
+}
+
+// ComplexAbsDifference returns the absolute value of the difference
+// between a and b, where a and b are of a complex type.
+func ComplexAbsDifference[T Complex](a, b T) T {
+ return absDifference(complexAbs[T]{a}, complexAbs[T]{b})
+}
diff --git a/test/typeparam/absdiffimp2.dir/main.go b/test/typeparam/absdiffimp2.dir/main.go
new file mode 100644
index 0000000..1519da0
--- /dev/null
+++ b/test/typeparam/absdiffimp2.dir/main.go
@@ -0,0 +1,29 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ if got, want := a.OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+ if got, want := a.OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+ if got, want := a.OrderedAbsDifference(-20, 15), 35; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+
+ if got, want := a.ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+ if got, want := a.ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
+ panic(fmt.Sprintf("got = %v, want = %v", got, want))
+ }
+}
diff --git a/test/typeparam/absdiffimp2.go b/test/typeparam/absdiffimp2.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/absdiffimp2.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/adder.go b/test/typeparam/adder.go
new file mode 100644
index 0000000..fbb4925
--- /dev/null
+++ b/test/typeparam/adder.go
@@ -0,0 +1,29 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type AddType interface {
+ int | int64 | string
+}
+
+// Add can add numbers or strings
+func Add[T AddType](a, b T) T {
+ return a + b
+}
+
+func main() {
+ if got, want := Add(5, 3), 8; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ if got, want := Add("ab", "cd"), "abcd"; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/aliasimp.dir/a.go b/test/typeparam/aliasimp.dir/a.go
new file mode 100644
index 0000000..c64e87c
--- /dev/null
+++ b/test/typeparam/aliasimp.dir/a.go
@@ -0,0 +1,9 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Rimp[T any] struct {
+ F T
+}
diff --git a/test/typeparam/aliasimp.dir/main.go b/test/typeparam/aliasimp.dir/main.go
new file mode 100644
index 0000000..39c29fc
--- /dev/null
+++ b/test/typeparam/aliasimp.dir/main.go
@@ -0,0 +1,41 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+type R[T any] struct {
+ F T
+}
+
+// type S = R // disallowed for now
+
+type Sint = R[int]
+
+// type Simp = a.Rimp // disallowed for now
+
+// type SimpString Simp[string] // disallowed for now
+type SimpString a.Rimp[string]
+
+func main() {
+ // var s S[int] // disallowed for now
+ var s R[int]
+ if s.F != 0 {
+ panic(s.F)
+ }
+ var s2 Sint
+ if s2.F != 0 {
+ panic(s2.F)
+ }
+ // var s3 Simp[string] // disallowed for now
+ var s3 a.Rimp[string]
+ if s3.F != "" {
+ panic(s3.F)
+ }
+ var s4 SimpString
+ if s4.F != "" {
+ panic(s4.F)
+ }
+}
diff --git a/test/typeparam/aliasimp.go b/test/typeparam/aliasimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/aliasimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/append.go b/test/typeparam/append.go
new file mode 100644
index 0000000..6168262
--- /dev/null
+++ b/test/typeparam/append.go
@@ -0,0 +1,31 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Recv <-chan int
+
+type sliceOf[E any] interface {
+ ~[]E
+}
+
+func _Append[S sliceOf[T], T any](s S, t ...T) S {
+ return append(s, t...)
+}
+
+func main() {
+ recv := make(Recv)
+ a := _Append([]Recv{recv}, recv)
+ if len(a) != 2 || a[0] != recv || a[1] != recv {
+ panic(a)
+ }
+
+ recv2 := make(chan<- int)
+ a2 := _Append([]chan<- int{recv2}, recv2)
+ if len(a2) != 2 || a2[0] != recv2 || a2[1] != recv2 {
+ panic(a)
+ }
+}
diff --git a/test/typeparam/boundmethod.go b/test/typeparam/boundmethod.go
new file mode 100644
index 0000000..510519a
--- /dev/null
+++ b/test/typeparam/boundmethod.go
@@ -0,0 +1,108 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test illustrates how a type bound method (String below) can be implemented
+// either by a concrete type (myint below) or a instantiated generic type
+// (StringInt[myint] below).
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+)
+
+type myint int
+
+//go:noinline
+func (m myint) String() string {
+ return strconv.Itoa(int(m))
+}
+
+type Stringer interface {
+ String() string
+}
+
+func stringify[T Stringer](s []T) (ret []string) {
+ for _, v := range s {
+ // Test normal bounds method call on type param
+ x1 := v.String()
+
+ // Test converting type param to its bound interface first
+ v1 := Stringer(v)
+ x2 := v1.String()
+
+ // Test method expression with type param type
+ f1 := T.String
+ x3 := f1(v)
+
+ // Test creating and calling closure equivalent to the method expression
+ f2 := func(v1 T) string {
+ return Stringer(v1).String()
+ }
+ x4 := f2(v)
+
+ if x1 != x2 || x2 != x3 || x3 != x4 {
+ panic(fmt.Sprintf("Mismatched values %v, %v, %v, %v\n", x1, x2, x3, x4))
+ }
+
+ ret = append(ret, v.String())
+ }
+ return ret
+}
+
+type Ints interface {
+ ~int32 | ~int
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type StringInt[T Ints] T
+//
+// //go:noinline
+// func (m StringInt[T]) String() string {
+// return strconv.Itoa(int(m))
+// }
+
+type StringStruct[T Ints] struct {
+ f T
+}
+
+func (m StringStruct[T]) String() string {
+ return strconv.Itoa(int(m.f))
+}
+
+func main() {
+ x := []myint{myint(1), myint(2), myint(3)}
+
+ // stringify on a normal type, whose bound method is associated with the base type.
+ got := stringify(x)
+ want := []string{"1", "2", "3"}
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+ // x2 := []StringInt[myint]{StringInt[myint](5), StringInt[myint](7), StringInt[myint](6)}
+ //
+ // // stringify on an instantiated type, whose bound method is associated with
+ // // the generic type StringInt[T], which maps directly to T.
+ // got2 := stringify(x2)
+ // want2 := []string{"5", "7", "6"}
+ // if !reflect.DeepEqual(got2, want2) {
+ // panic(fmt.Sprintf("got %s, want %s", got2, want2))
+ // }
+
+ // stringify on an instantiated type, whose bound method is associated with
+ // the generic type StringStruct[T], which maps to a struct containing T.
+ x3 := []StringStruct[myint]{StringStruct[myint]{f: 11}, StringStruct[myint]{f: 10}, StringStruct[myint]{f: 9}}
+
+ got3 := stringify(x3)
+ want3 := []string{"11", "10", "9"}
+ if !reflect.DeepEqual(got3, want3) {
+ panic(fmt.Sprintf("got %s, want %s", got3, want3))
+ }
+}
diff --git a/test/typeparam/builtins.go b/test/typeparam/builtins.go
new file mode 100644
index 0000000..763d720
--- /dev/null
+++ b/test/typeparam/builtins.go
@@ -0,0 +1,112 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file tests built-in calls on generic types.
+
+// derived and expanded from cmd/compile/internal/types2/testdata/check/builtins.go2
+
+package builtins
+
+// close
+
+type C0 interface{ int }
+type C1 interface{ chan int }
+type C2 interface{ chan int | <-chan int }
+type C3 interface{ chan int | chan float32 }
+type C4 interface{ chan int | chan<- int }
+type C5[T any] interface{ ~chan T | chan<- T }
+
+func f1[T C1](ch T) {
+ close(ch)
+}
+
+func f2[T C3](ch T) {
+ close(ch)
+}
+
+func f3[T C4](ch T) {
+ close(ch)
+}
+
+func f4[T C5[X], X any](ch T) {
+ close(ch)
+}
+
+// delete
+
+type M0 interface{ int }
+type M1 interface{ map[string]int }
+type M2 interface {
+ map[string]int | map[string]float64
+}
+type M3 interface{ map[string]int | map[rune]int }
+type M4[K comparable, V any] interface{ map[K]V | map[rune]V }
+
+func g1[T M1](m T) {
+ delete(m, "foo")
+}
+
+func g2[T M2](m T) {
+ delete(m, "foo")
+}
+
+func g3[T M4[rune, V], V any](m T) {
+ delete(m, 'k')
+}
+
+// make
+
+func m1[
+ S1 interface{ []int },
+ S2 interface{ []int | chan int },
+
+ M1 interface{ map[string]int },
+ M2 interface{ map[string]int | chan int },
+
+ C1 interface{ chan int },
+ C2 interface{ chan int | chan string },
+]() {
+ _ = make([]int, 10)
+ _ = make(m1S0, 10)
+ _ = make(S1, 10)
+ _ = make(S1, 10, 20)
+
+ _ = make(map[string]int)
+ _ = make(m1M0)
+ _ = make(M1)
+ _ = make(M1, 10)
+
+ _ = make(chan int)
+ _ = make(m1C0)
+ _ = make(C1)
+ _ = make(C1, 10)
+}
+// TODO: put these type declarations back inside m1 when issue 47631 is fixed.
+type m1S0 []int
+type m1M0 map[string]int
+type m1C0 chan int
+
+// len/cap
+
+type Slice[T any] interface {
+ []T
+}
+
+func c1[T any, S Slice[T]]() {
+ x := make(S, 5, 10)
+ _ = len(x)
+ _ = cap(x)
+}
+
+// append
+
+func a1[T any, S Slice[T]]() {
+ x := make(S, 5)
+ y := make(S, 2)
+ var z T
+ _ = append(x, y...)
+ _ = append(x, z)
+}
diff --git a/test/typeparam/chans.go b/test/typeparam/chans.go
new file mode 100644
index 0000000..d73ce6e
--- /dev/null
+++ b/test/typeparam/chans.go
@@ -0,0 +1,413 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package chans provides utility functions for working with channels.
+package main
+
+import (
+ "context"
+ "fmt"
+ "runtime"
+ "sort"
+ "sync"
+ "time"
+)
+
+// _Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func _SliceEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// _ReadAll reads from c until the channel is closed or the context is
+// canceled, returning all the values read.
+func _ReadAll[Elem any](ctx context.Context, c <-chan Elem) []Elem {
+ var r []Elem
+ for {
+ select {
+ case <-ctx.Done():
+ return r
+ case v, ok := <-c:
+ if !ok {
+ return r
+ }
+ r = append(r, v)
+ }
+ }
+}
+
+// _Merge merges two channels into a single channel.
+// This will leave a goroutine running until either both channels are closed
+// or the context is canceled, at which point the returned channel is closed.
+func _Merge[Elem any](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {
+ r := make(chan Elem)
+ go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) {
+ defer close(r)
+ for c1 != nil || c2 != nil {
+ select {
+ case <-ctx.Done():
+ return
+ case v1, ok := <-c1:
+ if ok {
+ r <- v1
+ } else {
+ c1 = nil
+ }
+ case v2, ok := <-c2:
+ if ok {
+ r <- v2
+ } else {
+ c2 = nil
+ }
+ }
+ }
+ }(ctx, c1, c2, r)
+ return r
+}
+
+// _Filter calls f on each value read from c. If f returns true the value
+// is sent on the returned channel. This will leave a goroutine running
+// until c is closed or the context is canceled, at which point the
+// returned channel is closed.
+func _Filter[Elem any](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem {
+ r := make(chan Elem)
+ go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) {
+ defer close(r)
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case v, ok := <-c:
+ if !ok {
+ return
+ }
+ if f(v) {
+ r <- v
+ }
+ }
+ }
+ }(ctx, c, f, r)
+ return r
+}
+
+// _Sink returns a channel that discards all values sent to it.
+// This will leave a goroutine running until the context is canceled
+// or the returned channel is closed.
+func _Sink[Elem any](ctx context.Context) chan<- Elem {
+ r := make(chan Elem)
+ go func(ctx context.Context, r <-chan Elem) {
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case _, ok := <-r:
+ if !ok {
+ return
+ }
+ }
+ }
+ }(ctx, r)
+ return r
+}
+
+// An Exclusive is a value that may only be used by a single goroutine
+// at a time. This is implemented using channels rather than a mutex.
+type _Exclusive[Val any] struct {
+ c chan Val
+}
+
+// _MakeExclusive makes an initialized exclusive value.
+func _MakeExclusive[Val any](initial Val) *_Exclusive[Val] {
+ r := &_Exclusive[Val]{
+ c: make(chan Val, 1),
+ }
+ r.c <- initial
+ return r
+}
+
+// _Acquire acquires the exclusive value for private use.
+// It must be released using the Release method.
+func (e *_Exclusive[Val]) Acquire() Val {
+ return <-e.c
+}
+
+// TryAcquire attempts to acquire the value. The ok result reports whether
+// the value was acquired. If the value is acquired, it must be released
+// using the Release method.
+func (e *_Exclusive[Val]) TryAcquire() (v Val, ok bool) {
+ select {
+ case r := <-e.c:
+ return r, true
+ default:
+ return v, false
+ }
+}
+
+// Release updates and releases the value.
+// This method panics if the value has not been acquired.
+func (e *_Exclusive[Val]) Release(v Val) {
+ select {
+ case e.c <- v:
+ default:
+ panic("_Exclusive Release without Acquire")
+ }
+}
+
+// Ranger returns a Sender and a Receiver. The Receiver provides a
+// Next method to retrieve values. The Sender provides a Send method
+// to send values and a Close method to stop sending values. The Next
+// method indicates when the Sender has been closed, and the Send
+// method indicates when the Receiver has been freed.
+//
+// This is a convenient way to exit a goroutine sending values when
+// the receiver stops reading them.
+func _Ranger[Elem any]() (*_Sender[Elem], *_Receiver[Elem]) {
+ c := make(chan Elem)
+ d := make(chan struct{})
+ s := &_Sender[Elem]{
+ values: c,
+ done: d,
+ }
+ r := &_Receiver[Elem]{
+ values: c,
+ done: d,
+ }
+ runtime.SetFinalizer(r, (*_Receiver[Elem]).finalize)
+ return s, r
+}
+
+// A _Sender is used to send values to a Receiver.
+type _Sender[Elem any] struct {
+ values chan<- Elem
+ done <-chan struct{}
+}
+
+// Send sends a value to the receiver. It reports whether the value was sent.
+// The value will not be sent if the context is closed or the receiver
+// is freed.
+func (s *_Sender[Elem]) Send(ctx context.Context, v Elem) bool {
+ select {
+ case <-ctx.Done():
+ return false
+ case s.values <- v:
+ return true
+ case <-s.done:
+ return false
+ }
+}
+
+// Close tells the receiver that no more values will arrive.
+// After Close is called, the _Sender may no longer be used.
+func (s *_Sender[Elem]) Close() {
+ close(s.values)
+}
+
+// A _Receiver receives values from a _Sender.
+type _Receiver[Elem any] struct {
+ values <-chan Elem
+ done chan<- struct{}
+}
+
+// Next returns the next value from the channel. The bool result indicates
+// whether the value is valid.
+func (r *_Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) {
+ select {
+ case <-ctx.Done():
+ case v, ok = <-r.values:
+ }
+ return v, ok
+}
+
+// finalize is a finalizer for the receiver.
+func (r *_Receiver[Elem]) finalize() {
+ close(r.done)
+}
+
+func TestReadAll() {
+ c := make(chan int)
+ go func() {
+ c <- 4
+ c <- 2
+ c <- 5
+ close(c)
+ }()
+ got := _ReadAll(context.Background(), c)
+ want := []int{4, 2, 5}
+ if !_SliceEqual(got, want) {
+ panic(fmt.Sprintf("_ReadAll returned %v, want %v", got, want))
+ }
+}
+
+func TestMerge() {
+ c1 := make(chan int)
+ c2 := make(chan int)
+ go func() {
+ c1 <- 1
+ c1 <- 3
+ c1 <- 5
+ close(c1)
+ }()
+ go func() {
+ c2 <- 2
+ c2 <- 4
+ c2 <- 6
+ close(c2)
+ }()
+ ctx := context.Background()
+ got := _ReadAll(ctx, _Merge(ctx, c1, c2))
+ sort.Ints(got)
+ want := []int{1, 2, 3, 4, 5, 6}
+ if !_SliceEqual(got, want) {
+ panic(fmt.Sprintf("_Merge returned %v, want %v", got, want))
+ }
+}
+
+func TestFilter() {
+ c := make(chan int)
+ go func() {
+ c <- 1
+ c <- 2
+ c <- 3
+ close(c)
+ }()
+ even := func(i int) bool { return i%2 == 0 }
+ ctx := context.Background()
+ got := _ReadAll(ctx, _Filter(ctx, c, even))
+ want := []int{2}
+ if !_SliceEqual(got, want) {
+ panic(fmt.Sprintf("_Filter returned %v, want %v", got, want))
+ }
+}
+
+func TestSink() {
+ c := _Sink[int](context.Background())
+ after := time.NewTimer(time.Minute)
+ defer after.Stop()
+ send := func(v int) {
+ select {
+ case c <- v:
+ case <-after.C:
+ panic("timed out sending to _Sink")
+ }
+ }
+ send(1)
+ send(2)
+ send(3)
+ close(c)
+}
+
+func TestExclusive() {
+ val := 0
+ ex := _MakeExclusive(&val)
+
+ var wg sync.WaitGroup
+ f := func() {
+ defer wg.Done()
+ for i := 0; i < 10; i++ {
+ p := ex.Acquire()
+ (*p)++
+ ex.Release(p)
+ }
+ }
+
+ wg.Add(2)
+ go f()
+ go f()
+
+ wg.Wait()
+ if val != 20 {
+ panic(fmt.Sprintf("after Acquire/Release loop got %d, want 20", val))
+ }
+}
+
+func TestExclusiveTry() {
+ s := ""
+ ex := _MakeExclusive(&s)
+ p, ok := ex.TryAcquire()
+ if !ok {
+ panic("TryAcquire failed")
+ }
+ *p = "a"
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ _, ok := ex.TryAcquire()
+ if ok {
+ panic(fmt.Sprintf("TryAcquire succeeded unexpectedly"))
+ }
+ }()
+ wg.Wait()
+
+ ex.Release(p)
+
+ p, ok = ex.TryAcquire()
+ if !ok {
+ panic(fmt.Sprintf("TryAcquire failed"))
+ }
+}
+
+func TestRanger() {
+ s, r := _Ranger[int]()
+
+ ctx := context.Background()
+ go func() {
+ // Receive one value then exit.
+ v, ok := r.Next(ctx)
+ if !ok {
+ panic(fmt.Sprintf("did not receive any values"))
+ } else if v != 1 {
+ panic(fmt.Sprintf("received %d, want 1", v))
+ }
+ }()
+
+ c1 := make(chan bool)
+ c2 := make(chan bool)
+ go func() {
+ defer close(c2)
+ if !s.Send(ctx, 1) {
+ panic(fmt.Sprintf("Send failed unexpectedly"))
+ }
+ close(c1)
+ if s.Send(ctx, 2) {
+ panic(fmt.Sprintf("Send succeeded unexpectedly"))
+ }
+ }()
+
+ <-c1
+
+ // Force a garbage collection to try to get the finalizers to run.
+ runtime.GC()
+
+ select {
+ case <-c2:
+ case <-time.After(time.Minute):
+ panic("_Ranger Send should have failed, but timed out")
+ }
+}
+
+func main() {
+ TestReadAll()
+ TestMerge()
+ TestFilter()
+ TestSink()
+ TestExclusive()
+ TestExclusiveTry()
+ TestRanger()
+}
diff --git a/test/typeparam/chansimp.dir/a.go b/test/typeparam/chansimp.dir/a.go
new file mode 100644
index 0000000..7321992
--- /dev/null
+++ b/test/typeparam/chansimp.dir/a.go
@@ -0,0 +1,232 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import (
+ "context"
+ "runtime"
+)
+
+// Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func SliceEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// ReadAll reads from c until the channel is closed or the context is
+// canceled, returning all the values read.
+func ReadAll[Elem any](ctx context.Context, c <-chan Elem) []Elem {
+ var r []Elem
+ for {
+ select {
+ case <-ctx.Done():
+ return r
+ case v, ok := <-c:
+ if !ok {
+ return r
+ }
+ r = append(r, v)
+ }
+ }
+}
+
+// Merge merges two channels into a single channel.
+// This will leave a goroutine running until either both channels are closed
+// or the context is canceled, at which point the returned channel is closed.
+func Merge[Elem any](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {
+ r := make(chan Elem)
+ go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) {
+ defer close(r)
+ for c1 != nil || c2 != nil {
+ select {
+ case <-ctx.Done():
+ return
+ case v1, ok := <-c1:
+ if ok {
+ r <- v1
+ } else {
+ c1 = nil
+ }
+ case v2, ok := <-c2:
+ if ok {
+ r <- v2
+ } else {
+ c2 = nil
+ }
+ }
+ }
+ }(ctx, c1, c2, r)
+ return r
+}
+
+// Filter calls f on each value read from c. If f returns true the value
+// is sent on the returned channel. This will leave a goroutine running
+// until c is closed or the context is canceled, at which point the
+// returned channel is closed.
+func Filter[Elem any](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem {
+ r := make(chan Elem)
+ go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) {
+ defer close(r)
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case v, ok := <-c:
+ if !ok {
+ return
+ }
+ if f(v) {
+ r <- v
+ }
+ }
+ }
+ }(ctx, c, f, r)
+ return r
+}
+
+// Sink returns a channel that discards all values sent to it.
+// This will leave a goroutine running until the context is canceled
+// or the returned channel is closed.
+func Sink[Elem any](ctx context.Context) chan<- Elem {
+ r := make(chan Elem)
+ go func(ctx context.Context, r <-chan Elem) {
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case _, ok := <-r:
+ if !ok {
+ return
+ }
+ }
+ }
+ }(ctx, r)
+ return r
+}
+
+// An Exclusive is a value that may only be used by a single goroutine
+// at a time. This is implemented using channels rather than a mutex.
+type Exclusive[Val any] struct {
+ c chan Val
+}
+
+// MakeExclusive makes an initialized exclusive value.
+func MakeExclusive[Val any](initial Val) *Exclusive[Val] {
+ r := &Exclusive[Val]{
+ c: make(chan Val, 1),
+ }
+ r.c <- initial
+ return r
+}
+
+// Acquire acquires the exclusive value for private use.
+// It must be released using the Release method.
+func (e *Exclusive[Val]) Acquire() Val {
+ return <-e.c
+}
+
+// TryAcquire attempts to acquire the value. The ok result reports whether
+// the value was acquired. If the value is acquired, it must be released
+// using the Release method.
+func (e *Exclusive[Val]) TryAcquire() (v Val, ok bool) {
+ select {
+ case r := <-e.c:
+ return r, true
+ default:
+ return v, false
+ }
+}
+
+// Release updates and releases the value.
+// This method panics if the value has not been acquired.
+func (e *Exclusive[Val]) Release(v Val) {
+ select {
+ case e.c <- v:
+ default:
+ panic("Exclusive Release without Acquire")
+ }
+}
+
+// Ranger returns a Sender and a Receiver. The Receiver provides a
+// Next method to retrieve values. The Sender provides a Send method
+// to send values and a Close method to stop sending values. The Next
+// method indicates when the Sender has been closed, and the Send
+// method indicates when the Receiver has been freed.
+//
+// This is a convenient way to exit a goroutine sending values when
+// the receiver stops reading them.
+func Ranger[Elem any]() (*Sender[Elem], *Receiver[Elem]) {
+ c := make(chan Elem)
+ d := make(chan struct{})
+ s := &Sender[Elem]{
+ values: c,
+ done: d,
+ }
+ r := &Receiver[Elem]{
+ values: c,
+ done: d,
+ }
+ runtime.SetFinalizer(r, (*Receiver[Elem]).finalize)
+ return s, r
+}
+
+// A Sender is used to send values to a Receiver.
+type Sender[Elem any] struct {
+ values chan<- Elem
+ done <-chan struct{}
+}
+
+// Send sends a value to the receiver. It reports whether the value was sent.
+// The value will not be sent if the context is closed or the receiver
+// is freed.
+func (s *Sender[Elem]) Send(ctx context.Context, v Elem) bool {
+ select {
+ case <-ctx.Done():
+ return false
+ case s.values <- v:
+ return true
+ case <-s.done:
+ return false
+ }
+}
+
+// Close tells the receiver that no more values will arrive.
+// After Close is called, the Sender may no longer be used.
+func (s *Sender[Elem]) Close() {
+ close(s.values)
+}
+
+// A Receiver receives values from a Sender.
+type Receiver[Elem any] struct {
+ values <-chan Elem
+ done chan<- struct{}
+}
+
+// Next returns the next value from the channel. The bool result indicates
+// whether the value is valid.
+func (r *Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) {
+ select {
+ case <-ctx.Done():
+ case v, ok = <-r.values:
+ }
+ return v, ok
+}
+
+// finalize is a finalizer for the receiver.
+func (r *Receiver[Elem]) finalize() {
+ close(r.done)
+}
diff --git a/test/typeparam/chansimp.dir/main.go b/test/typeparam/chansimp.dir/main.go
new file mode 100644
index 0000000..a380a3c
--- /dev/null
+++ b/test/typeparam/chansimp.dir/main.go
@@ -0,0 +1,189 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "context"
+ "fmt"
+ "runtime"
+ "sort"
+ "sync"
+ "time"
+)
+
+func TestReadAll() {
+ c := make(chan int)
+ go func() {
+ c <- 4
+ c <- 2
+ c <- 5
+ close(c)
+ }()
+ got := a.ReadAll(context.Background(), c)
+ want := []int{4, 2, 5}
+ if !a.SliceEqual(got, want) {
+ panic(fmt.Sprintf("ReadAll returned %v, want %v", got, want))
+ }
+}
+
+func TestMerge() {
+ c1 := make(chan int)
+ c2 := make(chan int)
+ go func() {
+ c1 <- 1
+ c1 <- 3
+ c1 <- 5
+ close(c1)
+ }()
+ go func() {
+ c2 <- 2
+ c2 <- 4
+ c2 <- 6
+ close(c2)
+ }()
+ ctx := context.Background()
+ got := a.ReadAll(ctx, a.Merge(ctx, c1, c2))
+ sort.Ints(got)
+ want := []int{1, 2, 3, 4, 5, 6}
+ if !a.SliceEqual(got, want) {
+ panic(fmt.Sprintf("Merge returned %v, want %v", got, want))
+ }
+}
+
+func TestFilter() {
+ c := make(chan int)
+ go func() {
+ c <- 1
+ c <- 2
+ c <- 3
+ close(c)
+ }()
+ even := func(i int) bool { return i%2 == 0 }
+ ctx := context.Background()
+ got := a.ReadAll(ctx, a.Filter(ctx, c, even))
+ want := []int{2}
+ if !a.SliceEqual(got, want) {
+ panic(fmt.Sprintf("Filter returned %v, want %v", got, want))
+ }
+}
+
+func TestSink() {
+ c := a.Sink[int](context.Background())
+ after := time.NewTimer(time.Minute)
+ defer after.Stop()
+ send := func(v int) {
+ select {
+ case c <- v:
+ case <-after.C:
+ panic("timed out sending to Sink")
+ }
+ }
+ send(1)
+ send(2)
+ send(3)
+ close(c)
+}
+
+func TestExclusive() {
+ val := 0
+ ex := a.MakeExclusive(&val)
+
+ var wg sync.WaitGroup
+ f := func() {
+ defer wg.Done()
+ for i := 0; i < 10; i++ {
+ p := ex.Acquire()
+ (*p)++
+ ex.Release(p)
+ }
+ }
+
+ wg.Add(2)
+ go f()
+ go f()
+
+ wg.Wait()
+ if val != 20 {
+ panic(fmt.Sprintf("after Acquire/Release loop got %d, want 20", val))
+ }
+}
+
+func TestExclusiveTry() {
+ s := ""
+ ex := a.MakeExclusive(&s)
+ p, ok := ex.TryAcquire()
+ if !ok {
+ panic("TryAcquire failed")
+ }
+ *p = "a"
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ _, ok := ex.TryAcquire()
+ if ok {
+ panic(fmt.Sprintf("TryAcquire succeeded unexpectedly"))
+ }
+ }()
+ wg.Wait()
+
+ ex.Release(p)
+
+ p, ok = ex.TryAcquire()
+ if !ok {
+ panic(fmt.Sprintf("TryAcquire failed"))
+ }
+}
+
+func TestRanger() {
+ s, r := a.Ranger[int]()
+
+ ctx := context.Background()
+ go func() {
+ // Receive one value then exit.
+ v, ok := r.Next(ctx)
+ if !ok {
+ panic(fmt.Sprintf("did not receive any values"))
+ } else if v != 1 {
+ panic(fmt.Sprintf("received %d, want 1", v))
+ }
+ }()
+
+ c1 := make(chan bool)
+ c2 := make(chan bool)
+ go func() {
+ defer close(c2)
+ if !s.Send(ctx, 1) {
+ panic(fmt.Sprintf("Send failed unexpectedly"))
+ }
+ close(c1)
+ if s.Send(ctx, 2) {
+ panic(fmt.Sprintf("Send succeeded unexpectedly"))
+ }
+ }()
+
+ <-c1
+
+ // Force a garbage collection to try to get the finalizers to run.
+ runtime.GC()
+
+ select {
+ case <-c2:
+ case <-time.After(time.Minute):
+ panic("Ranger Send should have failed, but timed out")
+ }
+}
+
+func main() {
+ TestReadAll()
+ TestMerge()
+ TestFilter()
+ TestSink()
+ TestExclusive()
+ TestExclusiveTry()
+ TestRanger()
+}
diff --git a/test/typeparam/chansimp.go b/test/typeparam/chansimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/chansimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/combine.go b/test/typeparam/combine.go
new file mode 100644
index 0000000..361708f
--- /dev/null
+++ b/test/typeparam/combine.go
@@ -0,0 +1,65 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type Gen[A any] func() (A, bool)
+
+func Combine[T1, T2, T any](g1 Gen[T1], g2 Gen[T2], join func(T1, T2) T) Gen[T] {
+ return func() (T, bool) {
+ var t T
+ t1, ok := g1()
+ if !ok {
+ return t, false
+ }
+ t2, ok := g2()
+ if !ok {
+ return t, false
+ }
+ return join(t1, t2), true
+ }
+}
+
+type Pair[A, B any] struct {
+ A A
+ B B
+}
+
+func _NewPair[A, B any](a A, b B) Pair[A, B] {
+ return Pair[A, B]{a, b}
+}
+
+func Combine2[A, B any](ga Gen[A], gb Gen[B]) Gen[Pair[A, B]] {
+ return Combine(ga, gb, _NewPair[A, B])
+}
+
+func main() {
+ var g1 Gen[int] = func() (int, bool) { return 3, true }
+ var g2 Gen[string] = func() (string, bool) { return "x", false }
+ var g3 Gen[string] = func() (string, bool) { return "y", true }
+
+ gc := Combine(g1, g2, _NewPair[int, string])
+ if got, ok := gc(); ok {
+ panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok))
+ }
+ gc2 := Combine2(g1, g2)
+ if got, ok := gc2(); ok {
+ panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok))
+ }
+
+ gc3 := Combine(g1, g3, _NewPair[int, string])
+ if got, ok := gc3(); !ok || got.A != 3 || got.B != "y" {
+ panic(fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok))
+ }
+ gc4 := Combine2(g1, g3)
+ if got, ok := gc4(); !ok || got.A != 3 || got.B != "y" {
+ panic(fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok))
+ }
+}
diff --git a/test/typeparam/cons.go b/test/typeparam/cons.go
new file mode 100644
index 0000000..733e579
--- /dev/null
+++ b/test/typeparam/cons.go
@@ -0,0 +1,100 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+// Overriding the predeclare "any", so it can be used as a type constraint or a type
+// argument
+type any interface{}
+
+type Function[a, b any] interface {
+ Apply(x a) b
+}
+
+type incr struct{ n int }
+
+func (this incr) Apply(x int) int {
+ return x + this.n
+}
+
+type pos struct{}
+
+func (this pos) Apply(x int) bool {
+ return x > 0
+}
+
+type compose[a, b, c any] struct {
+ f Function[a, b]
+ g Function[b, c]
+}
+
+func (this compose[a, b, c]) Apply(x a) c {
+ return this.g.Apply(this.f.Apply(x))
+}
+
+type _Eq[a any] interface {
+ Equal(a) bool
+}
+
+type Int int
+
+func (this Int) Equal(that int) bool {
+ return int(this) == that
+}
+
+type List[a any] interface {
+ Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any
+}
+
+type Nil[a any] struct {
+}
+
+func (xs Nil[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any {
+ return casenil.Apply(xs)
+}
+
+type Cons[a any] struct {
+ Head a
+ Tail List[a]
+}
+
+func (xs Cons[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any {
+ return casecons.Apply(xs)
+}
+
+type mapNil[a, b any] struct {
+}
+
+func (m mapNil[a, b]) Apply(_ Nil[a]) any {
+ return Nil[b]{}
+}
+
+type mapCons[a, b any] struct {
+ f Function[a, b]
+}
+
+func (m mapCons[a, b]) Apply(xs Cons[a]) any {
+ return Cons[b]{m.f.Apply(xs.Head), Map[a, b](m.f, xs.Tail)}
+}
+
+func Map[a, b any](f Function[a, b], xs List[a]) List[b] {
+ return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(List[b])
+}
+
+func main() {
+ var xs List[int] = Cons[int]{3, Cons[int]{6, Nil[int]{}}}
+ var ys List[int] = Map[int, int](incr{-5}, xs)
+ var xz List[bool] = Map[int, bool](pos{}, ys)
+ cs1 := xz.(Cons[bool])
+ cs2 := cs1.Tail.(Cons[bool])
+ _, ok := cs2.Tail.(Nil[bool])
+ if cs1.Head != false || cs2.Head != true || !ok {
+ panic(fmt.Sprintf("got %v, %v, %v, expected false, true, true",
+ cs1.Head, cs2.Head, ok))
+ }
+}
diff --git a/test/typeparam/dedup.dir/a.go b/test/typeparam/dedup.dir/a.go
new file mode 100644
index 0000000..f5cb6dc
--- /dev/null
+++ b/test/typeparam/dedup.dir/a.go
@@ -0,0 +1,10 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+//go:noinline
+func F[T comparable](a, b T) bool {
+ return a == b
+}
diff --git a/test/typeparam/dedup.dir/b.go b/test/typeparam/dedup.dir/b.go
new file mode 100644
index 0000000..8507c64
--- /dev/null
+++ b/test/typeparam/dedup.dir/b.go
@@ -0,0 +1,14 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func B() {
+ var x int64
+ println(a.F(&x, &x))
+ var y int32
+ println(a.F(&y, &y))
+}
diff --git a/test/typeparam/dedup.dir/c.go b/test/typeparam/dedup.dir/c.go
new file mode 100644
index 0000000..a1c950f
--- /dev/null
+++ b/test/typeparam/dedup.dir/c.go
@@ -0,0 +1,14 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package c
+
+import "./a"
+
+func C() {
+ var x int64
+ println(a.F(&x, &x))
+ var y int32
+ println(a.F(&y, &y))
+}
diff --git a/test/typeparam/dedup.dir/main.go b/test/typeparam/dedup.dir/main.go
new file mode 100644
index 0000000..920591b
--- /dev/null
+++ b/test/typeparam/dedup.dir/main.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./b"
+ "./c"
+)
+
+func main() {
+ b.B()
+ c.C()
+}
diff --git a/test/typeparam/dedup.go b/test/typeparam/dedup.go
new file mode 100644
index 0000000..3b98e03
--- /dev/null
+++ b/test/typeparam/dedup.go
@@ -0,0 +1,12 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Note: this doesn't really test the deduplication of
+// instantiations. It just provides an easy mechanism to build a
+// binary that you can then check with objdump manually to make sure
+// deduplication is happening. TODO: automate this somehow?
+
+package ignored
diff --git a/test/typeparam/dedup.out b/test/typeparam/dedup.out
new file mode 100644
index 0000000..1140ff5
--- /dev/null
+++ b/test/typeparam/dedup.out
@@ -0,0 +1,4 @@
+true
+true
+true
+true
diff --git a/test/typeparam/devirtualize1.go b/test/typeparam/devirtualize1.go
new file mode 100644
index 0000000..fb26225
--- /dev/null
+++ b/test/typeparam/devirtualize1.go
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S struct {
+ x int
+}
+
+func (t *S) M1() {
+}
+
+func F[T any](x T) any {
+ return x
+}
+
+func main() {
+ F(&S{}).(interface{ M1() }).M1()
+}
diff --git a/test/typeparam/devirtualize2.go b/test/typeparam/devirtualize2.go
new file mode 100644
index 0000000..ca6dc8f
--- /dev/null
+++ b/test/typeparam/devirtualize2.go
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S struct {
+ x int
+}
+
+func (t *S) M1() {
+}
+func (t *S) M2() {
+}
+
+type I interface {
+ M1()
+}
+
+func F[T I](x T) I {
+ return x
+}
+
+func main() {
+ F(&S{}).(interface{ M2() }).M2()
+}
diff --git a/test/typeparam/dictionaryCapture-noinline.go b/test/typeparam/dictionaryCapture-noinline.go
new file mode 100644
index 0000000..4c5e7ec
--- /dev/null
+++ b/test/typeparam/dictionaryCapture-noinline.go
@@ -0,0 +1,126 @@
+// run -gcflags="-l"
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test situations where functions/methods are not
+// immediately called and we need to capture the dictionary
+// required for later invocation.
+
+package main
+
+func main() {
+ functions()
+ methodExpressions()
+ methodValues()
+ interfaceMethods()
+ globals()
+}
+
+func g0[T any](x T) {
+}
+func g1[T any](x T) T {
+ return x
+}
+func g2[T any](x T) (T, T) {
+ return x, x
+}
+
+func functions() {
+ f0 := g0[int]
+ f0(7)
+ f1 := g1[int]
+ is7(f1(7))
+ f2 := g2[int]
+ is77(f2(7))
+}
+
+func is7(x int) {
+ if x != 7 {
+ println(x)
+ panic("assertion failed")
+ }
+}
+func is77(x, y int) {
+ if x != 7 || y != 7 {
+ println(x, y)
+ panic("assertion failed")
+ }
+}
+
+type s[T any] struct {
+ a T
+}
+
+func (x s[T]) g0() {
+}
+func (x s[T]) g1() T {
+ return x.a
+}
+func (x s[T]) g2() (T, T) {
+ return x.a, x.a
+}
+
+func methodExpressions() {
+ x := s[int]{a: 7}
+ f0 := s[int].g0
+ f0(x)
+ f1 := s[int].g1
+ is7(f1(x))
+ f2 := s[int].g2
+ is77(f2(x))
+}
+
+func methodValues() {
+ x := s[int]{a: 7}
+ f0 := x.g0
+ f0()
+ f1 := x.g1
+ is7(f1())
+ f2 := x.g2
+ is77(f2())
+}
+
+var x interface {
+ g0()
+ g1() int
+ g2() (int, int)
+} = s[int]{a: 7}
+var y interface{} = s[int]{a: 7}
+
+func interfaceMethods() {
+ x.g0()
+ is7(x.g1())
+ is77(x.g2())
+ y.(interface{ g0() }).g0()
+ is7(y.(interface{ g1() int }).g1())
+ is77(y.(interface{ g2() (int, int) }).g2())
+}
+
+// Also check for instantiations outside functions.
+var gg0 = g0[int]
+var gg1 = g1[int]
+var gg2 = g2[int]
+
+var hh0 = s[int].g0
+var hh1 = s[int].g1
+var hh2 = s[int].g2
+
+var xtop = s[int]{a: 7}
+var ii0 = x.g0
+var ii1 = x.g1
+var ii2 = x.g2
+
+func globals() {
+ gg0(7)
+ is7(gg1(7))
+ is77(gg2(7))
+ x := s[int]{a: 7}
+ hh0(x)
+ is7(hh1(x))
+ is77(hh2(x))
+ ii0()
+ is7(ii1())
+ is77(ii2())
+}
diff --git a/test/typeparam/dictionaryCapture.go b/test/typeparam/dictionaryCapture.go
new file mode 100644
index 0000000..b503abb
--- /dev/null
+++ b/test/typeparam/dictionaryCapture.go
@@ -0,0 +1,203 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test situations where functions/methods are not
+// immediately called and we need to capture the dictionary
+// required for later invocation.
+
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ functions()
+ methodExpressions()
+ genMethodExpressions[int](7)
+ methodValues()
+ genMethodValues[int](7)
+ interfaceMethods()
+ globals()
+ recursive()
+}
+
+func g0[T any](x T) {
+}
+func g1[T any](x T) T {
+ return x
+}
+func g2[T any](x T) (T, T) {
+ return x, x
+}
+
+func functions() {
+ f0 := g0[int]
+ f0(7)
+ f1 := g1[int]
+ is7(f1(7))
+ f2 := g2[int]
+ is77(f2(7))
+}
+
+func is7(x int) {
+ if x != 7 {
+ println(x)
+ panic("assertion failed")
+ }
+}
+func is77(x, y int) {
+ if x != 7 || y != 7 {
+ println(x, y)
+ panic("assertion failed")
+ }
+}
+
+type s[T any] struct {
+ a T
+}
+
+func (x s[T]) g0() {
+}
+func (x s[T]) g1() T {
+ return x.a
+}
+func (x s[T]) g2() (T, T) {
+ return x.a, x.a
+}
+
+func methodExpressions() {
+ x := s[int]{a: 7}
+ f0 := s[int].g0
+ f0(x)
+ f0p := (*s[int]).g0
+ f0p(&x)
+ f1 := s[int].g1
+ is7(f1(x))
+ f1p := (*s[int]).g1
+ is7(f1p(&x))
+ f2 := s[int].g2
+ is77(f2(x))
+ f2p := (*s[int]).g2
+ is77(f2p(&x))
+}
+
+func genMethodExpressions[T comparable](want T) {
+ x := s[T]{a: want}
+ f0 := s[T].g0
+ f0(x)
+ f0p := (*s[T]).g0
+ f0p(&x)
+ f1 := s[T].g1
+ if got := f1(x); got != want {
+ panic(fmt.Sprintf("f1(x) == %d, want %d", got, want))
+ }
+ f1p := (*s[T]).g1
+ if got := f1p(&x); got != want {
+ panic(fmt.Sprintf("f1p(&x) == %d, want %d", got, want))
+ }
+ f2 := s[T].g2
+ if got1, got2 := f2(x); got1 != want || got2 != want {
+ panic(fmt.Sprintf("f2(x) == %d, %d, want %d, %d", got1, got2, want, want))
+ }
+}
+
+func methodValues() {
+ x := s[int]{a: 7}
+ f0 := x.g0
+ f0()
+ f1 := x.g1
+ is7(f1())
+ f2 := x.g2
+ is77(f2())
+}
+
+func genMethodValues[T comparable](want T) {
+ x := s[T]{a: want}
+ f0 := x.g0
+ f0()
+ f1 := x.g1
+ if got := f1(); got != want {
+ panic(fmt.Sprintf("f1() == %d, want %d", got, want))
+ }
+ f2 := x.g2
+ if got1, got2 := f2(); got1 != want || got2 != want {
+ panic(fmt.Sprintf("f2() == %d, %d, want %d, %d", got1, got2, want, want))
+ }
+}
+
+var x interface {
+ g0()
+ g1() int
+ g2() (int, int)
+} = s[int]{a: 7}
+var y interface{} = s[int]{a: 7}
+
+func interfaceMethods() {
+ x.g0()
+ is7(x.g1())
+ is77(x.g2())
+ y.(interface{ g0() }).g0()
+ is7(y.(interface{ g1() int }).g1())
+ is77(y.(interface{ g2() (int, int) }).g2())
+}
+
+// Also check for instantiations outside functions.
+var gg0 = g0[int]
+var gg1 = g1[int]
+var gg2 = g2[int]
+
+var hh0 = s[int].g0
+var hh1 = s[int].g1
+var hh2 = s[int].g2
+
+var xtop = s[int]{a: 7}
+var ii0 = x.g0
+var ii1 = x.g1
+var ii2 = x.g2
+
+func globals() {
+ gg0(7)
+ is7(gg1(7))
+ is77(gg2(7))
+ x := s[int]{a: 7}
+ hh0(x)
+ is7(hh1(x))
+ is77(hh2(x))
+ ii0()
+ is7(ii1())
+ is77(ii2())
+}
+
+func recursive() {
+ if got, want := recur1[int](5), 110; got != want {
+ panic(fmt.Sprintf("recur1[int](5) = %d, want = %d", got, want))
+ }
+}
+
+type Integer interface {
+ int | int32 | int64
+}
+
+func recur1[T Integer](n T) T {
+ if n == 0 || n == 1 {
+ return T(1)
+ } else {
+ return n * recur2(n-1)
+ }
+}
+
+func recur2[T Integer](n T) T {
+ list := make([]T, n)
+ for i, _ := range list {
+ list[i] = T(i + 1)
+ }
+ var sum T
+ for _, elt := range list {
+ sum += elt
+ }
+ return sum + recur1(n-1)
+}
diff --git a/test/typeparam/dottype.go b/test/typeparam/dottype.go
new file mode 100644
index 0000000..9f1630d
--- /dev/null
+++ b/test/typeparam/dottype.go
@@ -0,0 +1,86 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[T any](x interface{}) T {
+ return x.(T)
+}
+func f2[T any](x interface{}) (T, bool) {
+ t, ok := x.(T)
+ return t, ok
+}
+
+type I interface {
+ foo()
+}
+
+type myint int
+
+func (myint) foo() {
+}
+
+type myfloat float64
+
+func (myfloat) foo() {
+}
+
+func g[T I](x I) T {
+ return x.(T)
+}
+func g2[T I](x I) (T, bool) {
+ t, ok := x.(T)
+ return t, ok
+}
+
+func h[T any](x interface{}) struct{ a, b T } {
+ return x.(struct{ a, b T })
+}
+
+func k[T any](x interface{}) interface{ bar() T } {
+ return x.(interface{ bar() T })
+}
+
+type mybar int
+
+func (x mybar) bar() int {
+ return int(x)
+}
+
+func main() {
+ var i interface{} = int(3)
+ var j I = myint(3)
+ var x interface{} = float64(3)
+ var y I = myfloat(3)
+
+ println(f[int](i))
+ shouldpanic(func() { f[int](x) })
+ println(f2[int](i))
+ println(f2[int](x))
+
+ println(g[myint](j))
+ shouldpanic(func() { g[myint](y) })
+ println(g2[myint](j))
+ println(g2[myint](y))
+
+ println(h[int](struct{ a, b int }{3, 5}).a)
+
+ println(k[int](mybar(3)).bar())
+
+ type large struct {a,b,c,d,e,f int}
+ println(f[large](large{}).a)
+ l2, ok := f2[large](large{})
+ println(l2.a, ok)
+}
+func shouldpanic(x func()) {
+ defer func() {
+ e := recover()
+ if e == nil {
+ panic("didn't panic")
+ }
+ }()
+ x()
+}
diff --git a/test/typeparam/dottype.out b/test/typeparam/dottype.out
new file mode 100644
index 0000000..8e6a3c2
--- /dev/null
+++ b/test/typeparam/dottype.out
@@ -0,0 +1,10 @@
+3
+3 true
+0 false
+3
+3 true
+0 false
+3
+3
+0
+0 true
diff --git a/test/typeparam/double.go b/test/typeparam/double.go
new file mode 100644
index 0000000..fbbe602
--- /dev/null
+++ b/test/typeparam/double.go
@@ -0,0 +1,72 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type Number interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64
+}
+
+type MySlice []int
+type MyFloatSlice []float64
+
+type _SliceOf[E any] interface {
+ ~[]E
+}
+
+func _DoubleElems[S _SliceOf[E], E Number](s S) S {
+ r := make(S, len(s))
+ for i, v := range s {
+ r[i] = v + v
+ }
+ return r
+}
+
+// Test use of untyped constant in an expression with a generically-typed parameter
+func _DoubleElems2[S _SliceOf[E], E Number](s S) S {
+ r := make(S, len(s))
+ for i, v := range s {
+ r[i] = v * 2
+ }
+ return r
+}
+
+func main() {
+ arg := MySlice{1, 2, 3}
+ want := MySlice{2, 4, 6}
+ got := _DoubleElems[MySlice, int](arg)
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ // constraint type inference
+ got = _DoubleElems[MySlice](arg)
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ got = _DoubleElems(arg)
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ farg := MyFloatSlice{1.2, 2.0, 3.5}
+ fwant := MyFloatSlice{2.4, 4.0, 7.0}
+ fgot := _DoubleElems(farg)
+ if !reflect.DeepEqual(fgot, fwant) {
+ panic(fmt.Sprintf("got %s, want %s", fgot, fwant))
+ }
+
+ fgot = _DoubleElems2(farg)
+ if !reflect.DeepEqual(fgot, fwant) {
+ panic(fmt.Sprintf("got %s, want %s", fgot, fwant))
+ }
+}
diff --git a/test/typeparam/eface.go b/test/typeparam/eface.go
new file mode 100644
index 0000000..05d5503
--- /dev/null
+++ b/test/typeparam/eface.go
@@ -0,0 +1,67 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Make sure we handle instantiated empty interfaces.
+
+package main
+
+type E[T any] interface {
+}
+
+//go:noinline
+func f[T any](x E[T]) interface{} {
+ return x
+}
+
+//go:noinline
+func g[T any](x interface{}) E[T] {
+ return x
+}
+
+type I[T any] interface {
+ foo()
+}
+
+type myint int
+
+func (x myint) foo() {}
+
+//go:noinline
+func h[T any](x I[T]) interface{ foo() } {
+ return x
+}
+
+//go:noinline
+func i[T any](x interface{ foo() }) I[T] {
+ return x
+}
+
+func main() {
+ if f[int](1) != 1 {
+ println("test 1 failed")
+ }
+ if f[int](2) != (interface{})(2) {
+ println("test 2 failed")
+ }
+ if g[int](3) != 3 {
+ println("test 3 failed")
+ }
+ if g[int](4) != (E[int])(4) {
+ println("test 4 failed")
+ }
+ if h[int](myint(5)) != myint(5) {
+ println("test 5 failed")
+ }
+ if h[int](myint(6)) != interface{ foo() }(myint(6)) {
+ println("test 6 failed")
+ }
+ if i[int](myint(7)) != myint(7) {
+ println("test 7 failed")
+ }
+ if i[int](myint(8)) != I[int](myint(8)) {
+ println("test 8 failed")
+ }
+}
diff --git a/test/typeparam/equal.go b/test/typeparam/equal.go
new file mode 100644
index 0000000..21e2103
--- /dev/null
+++ b/test/typeparam/equal.go
@@ -0,0 +1,69 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// comparisons of type parameters to interfaces
+
+package main
+
+func f[T comparable](t, u T) bool {
+ // Comparing two type parameters directly.
+ // (Not really testing comparisons to interfaces, but just 'cause we're here.)
+ return t == u
+}
+
+func g[T comparable](t T, i interface{}) bool {
+ // Compare type parameter value to empty interface.
+ return t == i
+}
+
+type I interface {
+ foo()
+}
+
+type C interface {
+ comparable
+ I
+}
+
+func h[T C](t T, i I) bool {
+ // Compare type parameter value to nonempty interface.
+ return t == i
+}
+
+type myint int
+
+func (x myint) foo() {
+}
+
+func k[T comparable](t T, i interface{}) bool {
+ // Compare derived type value to interface.
+ return struct{ a, b T }{t, t} == i
+}
+
+func main() {
+ assert(f(3, 3))
+ assert(!f(3, 5))
+ assert(g(3, 3))
+ assert(!g(3, 5))
+ assert(h(myint(3), myint(3)))
+ assert(!h(myint(3), myint(5)))
+
+ type S struct{ a, b float64 }
+
+ assert(f(S{3, 5}, S{3, 5}))
+ assert(!f(S{3, 5}, S{4, 6}))
+ assert(g(S{3, 5}, S{3, 5}))
+ assert(!g(S{3, 5}, S{4, 6}))
+
+ assert(k(3, struct{ a, b int }{3, 3}))
+ assert(!k(3, struct{ a, b int }{3, 4}))
+}
+
+func assert(b bool) {
+ if !b {
+ panic("assertion failed")
+ }
+}
diff --git a/test/typeparam/fact.go b/test/typeparam/fact.go
new file mode 100644
index 0000000..3c9a13a
--- /dev/null
+++ b/test/typeparam/fact.go
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func fact[T interface{ ~int | ~int64 | ~float64 }](n T) T {
+ if n == 1 {
+ return 1
+ }
+ return n * fact(n-1)
+}
+
+func main() {
+ const want = 120
+
+ if got := fact(5); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := fact[int64](5); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := fact(5.0); got != want {
+ panic(fmt.Sprintf("got %f, want %f", got, want))
+ }
+}
diff --git a/test/typeparam/factimp.dir/a.go b/test/typeparam/factimp.dir/a.go
new file mode 100644
index 0000000..0bd73a8
--- /dev/null
+++ b/test/typeparam/factimp.dir/a.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func Fact[T interface{ int | int64 | float64 }](n T) T {
+ if n == 1 {
+ return 1
+ }
+ return n * Fact(n-1)
+}
diff --git a/test/typeparam/factimp.dir/main.go b/test/typeparam/factimp.dir/main.go
new file mode 100644
index 0000000..75e08da
--- /dev/null
+++ b/test/typeparam/factimp.dir/main.go
@@ -0,0 +1,26 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ const want = 120
+
+ if got := a.Fact(5); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := a.Fact[int64](5); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := a.Fact(5.0); got != want {
+ panic(fmt.Sprintf("got %f, want %f", got, want))
+ }
+}
diff --git a/test/typeparam/factimp.go b/test/typeparam/factimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/factimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/gencrawler.dir/a.go b/test/typeparam/gencrawler.dir/a.go
new file mode 100644
index 0000000..50d6b4a
--- /dev/null
+++ b/test/typeparam/gencrawler.dir/a.go
@@ -0,0 +1,27 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+var V val[int]
+
+type val[T any] struct {
+ valx T
+}
+
+func (v *val[T]) Print() {
+ v.print1()
+}
+
+func (v *val[T]) print1() {
+ println(v.valx)
+}
+
+func (v *val[T]) fnprint1() {
+ println(v.valx)
+}
+
+func FnPrint[T any](v *val[T]) {
+ v.fnprint1()
+}
diff --git a/test/typeparam/gencrawler.dir/main.go b/test/typeparam/gencrawler.dir/main.go
new file mode 100644
index 0000000..198d117
--- /dev/null
+++ b/test/typeparam/gencrawler.dir/main.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ a.V.Print()
+ a.FnPrint(&a.V)
+}
diff --git a/test/typeparam/gencrawler.go b/test/typeparam/gencrawler.go
new file mode 100644
index 0000000..66b5f43
--- /dev/null
+++ b/test/typeparam/gencrawler.go
@@ -0,0 +1,10 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Testing that all methods of a private generic type are exported, if a variable
+// with that type is exported.
+
+package ignored
diff --git a/test/typeparam/gencrawler.out b/test/typeparam/gencrawler.out
new file mode 100644
index 0000000..aa47d0d
--- /dev/null
+++ b/test/typeparam/gencrawler.out
@@ -0,0 +1,2 @@
+0
+0
diff --git a/test/typeparam/genembed.go b/test/typeparam/genembed.go
new file mode 100644
index 0000000..6a11be1
--- /dev/null
+++ b/test/typeparam/genembed.go
@@ -0,0 +1,52 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test wrappers/interfaces for generic type embedding another generic type.
+
+package main
+
+import "fmt"
+
+type A[T any] struct {
+ B[T]
+}
+
+type B[T any] struct {
+ val T
+}
+
+func (b *B[T]) get() T {
+ return b.val
+}
+
+type getter[T any] interface {
+ get() T
+}
+
+//go:noinline
+func doGet[T any](i getter[T]) T {
+ return i.get()
+}
+
+//go:noline
+func doGet2[T any](i interface{}) T {
+ i2 := i.(getter[T])
+ return i2.get()
+}
+
+func main() {
+ a := A[int]{B: B[int]{3}}
+ var i getter[int] = &a
+
+ if got, want := doGet(i), 3; got != want {
+ panic(fmt.Sprintf("got %v, want %v", got, want))
+ }
+
+ as := A[string]{B: B[string]{"abc"}}
+ if got, want := doGet2[string](&as), "abc"; got != want {
+ panic(fmt.Sprintf("got %v, want %v", got, want))
+ }
+}
diff --git a/test/typeparam/genembed2.go b/test/typeparam/genembed2.go
new file mode 100644
index 0000000..f75731f
--- /dev/null
+++ b/test/typeparam/genembed2.go
@@ -0,0 +1,46 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test for declaration and use of a parameterized embedded field.
+
+package main
+
+import (
+ "fmt"
+ "sync"
+)
+
+type MyStruct[T any] struct {
+ val T
+}
+
+type Lockable[T any] struct {
+ MyStruct[T]
+ mu sync.Mutex
+}
+
+// Get returns the value stored in a Lockable.
+func (l *Lockable[T]) Get() T {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ return l.MyStruct.val
+}
+
+// Set sets the value in a Lockable.
+func (l *Lockable[T]) Set(v T) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ l.MyStruct = MyStruct[T]{v}
+}
+
+func main() {
+ var li Lockable[int]
+
+ li.Set(5)
+ if got, want := li.Get(), 5; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/geninline.dir/a.go b/test/typeparam/geninline.dir/a.go
new file mode 100644
index 0000000..fe5ba22
--- /dev/null
+++ b/test/typeparam/geninline.dir/a.go
@@ -0,0 +1,56 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type IVal[T comparable] interface {
+ check(want T)
+}
+
+type Val[T comparable] struct {
+ val T
+}
+
+//go:noinline
+func (l *Val[T]) check(want T) {
+ if l.val != want {
+ panic("hi")
+ }
+}
+
+func Test1() {
+ var l Val[int]
+ if l.val != 0 {
+ panic("hi")
+ }
+ _ = IVal[int](&l)
+}
+
+func Test2() {
+ var l Val[float64]
+ l.val = 3.0
+ l.check(float64(3))
+ _ = IVal[float64](&l)
+}
+
+type privateVal[T comparable] struct {
+ val T
+}
+
+//go:noinline
+func (l *privateVal[T]) check(want T) {
+ if l.val != want {
+ panic("hi")
+ }
+}
+
+type Outer struct {
+ val privateVal[string]
+}
+
+func Test3() {
+ var o Outer
+ o.val.check("")
+ _ = IVal[string](&o.val)
+}
diff --git a/test/typeparam/geninline.dir/main.go b/test/typeparam/geninline.dir/main.go
new file mode 100644
index 0000000..cfc4885
--- /dev/null
+++ b/test/typeparam/geninline.dir/main.go
@@ -0,0 +1,16 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+// Testing inlining of functions that refer to instantiated exported and non-exported
+// generic types.
+
+func main() {
+ a.Test1()
+ a.Test2()
+ a.Test3()
+}
diff --git a/test/typeparam/geninline.go b/test/typeparam/geninline.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/geninline.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/graph.go b/test/typeparam/graph.go
new file mode 100644
index 0000000..5cd1faa
--- /dev/null
+++ b/test/typeparam/graph.go
@@ -0,0 +1,230 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "errors"
+ "fmt"
+)
+
+// _Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func _SliceEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// A Graph is a collection of nodes. A node may have an arbitrary number
+// of edges. An edge connects two nodes. Both nodes and edges must be
+// comparable. This is an undirected simple graph.
+type _Graph[_Node _NodeC[_Edge], _Edge _EdgeC[_Node]] struct {
+ nodes []_Node
+}
+
+// _NodeC is the constraints on a node in a graph, given the _Edge type.
+type _NodeC[_Edge any] interface {
+ comparable
+ Edges() []_Edge
+}
+
+// Edgec is the constraints on an edge in a graph, given the _Node type.
+type _EdgeC[_Node any] interface {
+ comparable
+ Nodes() (a, b _Node)
+}
+
+// _New creates a new _Graph from a collection of Nodes.
+func _New[_Node _NodeC[_Edge], _Edge _EdgeC[_Node]](nodes []_Node) *_Graph[_Node, _Edge] {
+ return &_Graph[_Node, _Edge]{nodes: nodes}
+}
+
+// nodePath holds the path to a node during ShortestPath.
+// This should ideally be a type defined inside ShortestPath,
+// but the translator tool doesn't support that.
+type nodePath[_Node _NodeC[_Edge], _Edge _EdgeC[_Node]] struct {
+ node _Node
+ path []_Edge
+}
+
+// ShortestPath returns the shortest path between two nodes,
+// as an ordered list of edges. If there are multiple shortest paths,
+// which one is returned is unpredictable.
+func (g *_Graph[_Node, _Edge]) ShortestPath(from, to _Node) ([]_Edge, error) {
+ visited := make(map[_Node]bool)
+ visited[from] = true
+ workqueue := []nodePath[_Node, _Edge]{nodePath[_Node, _Edge]{from, nil}}
+ for len(workqueue) > 0 {
+ current := workqueue
+ workqueue = nil
+ for _, np := range current {
+ edges := np.node.Edges()
+ for _, edge := range edges {
+ a, b := edge.Nodes()
+ if a == np.node {
+ a = b
+ }
+ if !visited[a] {
+ ve := append([]_Edge(nil), np.path...)
+ ve = append(ve, edge)
+ if a == to {
+ return ve, nil
+ }
+ workqueue = append(workqueue, nodePath[_Node, _Edge]{a, ve})
+ visited[a] = true
+ }
+ }
+ }
+ }
+ return nil, errors.New("no path")
+}
+
+type direction int
+
+const (
+ north direction = iota
+ ne
+ east
+ se
+ south
+ sw
+ west
+ nw
+ up
+ down
+)
+
+func (dir direction) String() string {
+ strs := map[direction]string{
+ north: "north",
+ ne: "ne",
+ east: "east",
+ se: "se",
+ south: "south",
+ sw: "sw",
+ west: "west",
+ nw: "nw",
+ up: "up",
+ down: "down",
+ }
+ if str, ok := strs[dir]; ok {
+ return str
+ }
+ return fmt.Sprintf("direction %d", dir)
+}
+
+type mazeRoom struct {
+ index int
+ exits [10]int
+}
+
+type mazeEdge struct {
+ from, to int
+ dir direction
+}
+
+// Edges returns the exits from the room.
+func (m mazeRoom) Edges() []mazeEdge {
+ var r []mazeEdge
+ for i, exit := range m.exits {
+ if exit != 0 {
+ r = append(r, mazeEdge{
+ from: m.index,
+ to: exit,
+ dir: direction(i),
+ })
+ }
+ }
+ return r
+}
+
+// Nodes returns the rooms connected by an edge.
+//go:noinline
+func (e mazeEdge) Nodes() (mazeRoom, mazeRoom) {
+ m1, ok := zork[e.from]
+ if !ok {
+ panic("bad edge")
+ }
+ m2, ok := zork[e.to]
+ if !ok {
+ panic("bad edge")
+ }
+ return m1, m2
+}
+
+// The first maze in Zork. Room indexes based on original Fortran data file.
+// You are in a maze of twisty little passages, all alike.
+var zork = map[int]mazeRoom{
+ 11: {exits: [10]int{north: 11, south: 12, east: 14}}, // west to Troll Room
+ 12: {exits: [10]int{south: 11, north: 14, east: 13}},
+ 13: {exits: [10]int{west: 12, north: 14, up: 16}},
+ 14: {exits: [10]int{west: 13, north: 11, east: 15}},
+ 15: {exits: [10]int{south: 14}}, // Dead End
+ 16: {exits: [10]int{east: 17, north: 13, sw: 18}}, // skeleton, etc.
+ 17: {exits: [10]int{west: 16}}, // Dead End
+ 18: {exits: [10]int{down: 16, east: 19, west: 18, up: 22}},
+ 19: {exits: [10]int{up: 29, west: 18, ne: 15, east: 20, south: 30}},
+ 20: {exits: [10]int{ne: 19, west: 20, se: 21}},
+ 21: {exits: [10]int{north: 20}}, // Dead End
+ 22: {exits: [10]int{north: 18, east: 24, down: 23, south: 28, west: 26, nw: 22}},
+ 23: {exits: [10]int{east: 22, west: 28, up: 24}},
+ 24: {exits: [10]int{ne: 25, down: 23, nw: 28, sw: 26}},
+ 25: {exits: [10]int{sw: 24}}, // Grating room (up to Clearing)
+ 26: {exits: [10]int{west: 16, sw: 24, east: 28, up: 22, north: 27}},
+ 27: {exits: [10]int{south: 26}}, // Dead End
+ 28: {exits: [10]int{east: 22, down: 26, south: 23, west: 24}},
+ 29: {exits: [10]int{west: 30, nw: 29, ne: 19, south: 19}},
+ 30: {exits: [10]int{west: 29, south: 19}}, // ne to Cyclops Room
+}
+
+func TestShortestPath() {
+ // The Zork maze is not a proper undirected simple graph,
+ // as there are some one way paths (e.g., 19 -> 15),
+ // but for this test that doesn't matter.
+
+ // Set the index field in the map. Simpler than doing it in the
+ // composite literal.
+ for k := range zork {
+ r := zork[k]
+ r.index = k
+ zork[k] = r
+ }
+
+ var nodes []mazeRoom
+ for idx, room := range zork {
+ mridx := room
+ mridx.index = idx
+ nodes = append(nodes, mridx)
+ }
+ g := _New[mazeRoom, mazeEdge](nodes)
+ path, err := g.ShortestPath(zork[11], zork[30])
+ if err != nil {
+ panic(fmt.Sprintf("%v", err))
+ }
+ var steps []direction
+ for _, edge := range path {
+ steps = append(steps, edge.dir)
+ }
+ want := []direction{east, west, up, sw, east, south}
+ if !_SliceEqual(steps, want) {
+ panic(fmt.Sprintf("ShortestPath returned %v, want %v", steps, want))
+ }
+}
+
+func main() {
+ TestShortestPath()
+}
diff --git a/test/typeparam/ifaceconv.go b/test/typeparam/ifaceconv.go
new file mode 100644
index 0000000..4dfc68f
--- /dev/null
+++ b/test/typeparam/ifaceconv.go
@@ -0,0 +1,83 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that we can convert type parameters to both empty
+// and nonempty interfaces, and named and nonnamed versions
+// thereof.
+
+package main
+
+import "fmt"
+
+type E interface{}
+
+func f[T any](x T) interface{} {
+ var i interface{} = x
+ return i
+}
+
+func fs[T any](x T) interface{} {
+ y := []T{x}
+ var i interface{} = y
+ return i
+}
+
+func g[T any](x T) E {
+ var i E = x
+ return i
+}
+
+type C interface {
+ foo() int
+}
+
+type myInt int
+
+func (x myInt) foo() int {
+ return int(x + 1)
+}
+
+func h[T C](x T) interface{ foo() int } {
+ var i interface{ foo() int } = x
+ return i
+}
+func i[T C](x T) C {
+ var i C = x // conversion in assignment
+ return i
+}
+
+func j[T C](t T) C {
+ return C(t) // explicit conversion
+}
+
+func js[T any](x T) interface{} {
+ y := []T{x}
+ return interface{}(y)
+}
+
+func main() {
+ if got, want := f[int](7), 7; got != want {
+ panic(fmt.Sprintf("got %d want %d", got, want))
+ }
+ if got, want := fs[int](7), []int{7}; got.([]int)[0] != want[0] {
+ panic(fmt.Sprintf("got %d want %d", got, want))
+ }
+ if got, want := g[int](7), 7; got != want {
+ panic(fmt.Sprintf("got %d want %d", got, want))
+ }
+ if got, want := h[myInt](7).foo(), 8; got != want {
+ panic(fmt.Sprintf("got %d want %d", got, want))
+ }
+ if got, want := i[myInt](7).foo(), 8; got != want {
+ panic(fmt.Sprintf("got %d want %d", got, want))
+ }
+ if got, want := j[myInt](7).foo(), 8; got != want {
+ panic(fmt.Sprintf("got %d want %d", got, want))
+ }
+ if got, want := js[int](7), []int{7}; got.([]int)[0] != want[0] {
+ panic(fmt.Sprintf("got %d want %d", got, want))
+ }
+}
diff --git a/test/typeparam/importtest.go b/test/typeparam/importtest.go
new file mode 100644
index 0000000..a49dcd9
--- /dev/null
+++ b/test/typeparam/importtest.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file checks that basic importing works in -G mode.
+
+package p
+
+import "fmt"
+import "math"
+
+func f(x float64) {
+ fmt.Println(math.Sin(x))
+}
diff --git a/test/typeparam/index.go b/test/typeparam/index.go
new file mode 100644
index 0000000..064d33c
--- /dev/null
+++ b/test/typeparam/index.go
@@ -0,0 +1,81 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+// Index returns the index of x in s, or -1 if not found.
+func Index[T comparable](s []T, x T) int {
+ for i, v := range s {
+ // v and x are type T, which has the comparable
+ // constraint, so we can use == here.
+ if v == x {
+ return i
+ }
+ }
+ return -1
+}
+
+type obj struct {
+ x int
+}
+
+type obj2 struct {
+ x int8
+ y float64
+}
+
+type obj3 struct {
+ x int64
+ y int8
+}
+
+type inner struct {
+ y int64
+ z int32
+}
+
+type obj4 struct {
+ x int32
+ s inner
+}
+
+func main() {
+ want := 2
+
+ vec1 := []string{"ab", "cd", "ef"}
+ if got := Index(vec1, "ef"); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ vec2 := []byte{'c', '6', '@'}
+ if got := Index(vec2, '@'); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ vec3 := []*obj{&obj{2}, &obj{42}, &obj{1}}
+ if got := Index(vec3, vec3[2]); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ vec4 := []obj2{obj2{2, 3.0}, obj2{3, 4.0}, obj2{4, 5.0}}
+ if got := Index(vec4, vec4[2]); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ vec5 := []obj3{obj3{2, 3}, obj3{3, 4}, obj3{4, 5}}
+ if got := Index(vec5, vec5[2]); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ vec6 := []obj4{obj4{2, inner{3, 4}}, obj4{3, inner{4, 5}}, obj4{4, inner{5, 6}}}
+ if got := Index(vec6, vec6[2]); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/index2.go b/test/typeparam/index2.go
new file mode 100644
index 0000000..ae1b44a
--- /dev/null
+++ b/test/typeparam/index2.go
@@ -0,0 +1,67 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Testing various generic uses of indexing, both for reads and writes.
+
+package main
+
+import "fmt"
+
+// Can index an argument (read/write) constrained to be a slice or an array.
+func Index1[T interface{ []int64 | [5]int64 }](x T) int64 {
+ x[2] = 5
+ return x[3]
+}
+
+// Can index an argument (read) constrained to be a byte array or a string.
+func Index2[T interface{ []byte | string }](x T) byte {
+ return x[3]
+}
+
+// Can index an argument (write) constrained to be a byte array, but not a string.
+func Index2a[T interface{ []byte }](x T) byte {
+ x[2] = 'b'
+ return x[3]
+}
+
+// Can index an argument (read/write) constrained to be a map. Maps can't
+// be combined with any other type for indexing purposes.
+func Index3[T interface{ map[int]int64 }](x T) int64 {
+ x[2] = 43
+ return x[3]
+}
+
+// But the type of the map keys or values can be parameterized.
+func Index4[T any](x map[int]T) T {
+ var zero T
+ x[2] = zero
+ return x[3]
+}
+
+func test[T comparable](got, want T) {
+ if got != want {
+ panic(fmt.Sprintf("got %v, want %v", got, want))
+ }
+}
+
+func main() {
+ x := make([]int64, 4)
+ x[3] = 2
+ y := [5]int64{1, 2, 3, 4, 5}
+ z := "abcd"
+ w := make([]byte, 4)
+ w[3] = 5
+ v := make(map[int]int64)
+ v[3] = 18
+
+ test(Index1(x), int64(2))
+ test(Index1(y), int64(4))
+ test(Index2(z), byte(100))
+ test(Index2(w), byte(5))
+ test(Index2a(w), byte(5))
+ test(Index3(v), int64(18))
+ test(Index4(v), int64(18))
+}
diff --git a/test/typeparam/interfacearg.go b/test/typeparam/interfacearg.go
new file mode 100644
index 0000000..0e1fd00
--- /dev/null
+++ b/test/typeparam/interfacearg.go
@@ -0,0 +1,46 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface{}
+
+type _S[T any] struct {
+ x *T
+}
+
+// F is a non-generic function, but has a type _S[I] which is instantiated from a
+// generic type. Test that _S[I] is successfully exported.
+func F() {
+ v := _S[I]{}
+ if v.x != nil {
+ panic(v)
+ }
+}
+
+// Testing the various combinations of method expressions.
+type S1 struct{}
+
+func (*S1) M() {}
+
+type S2 struct{}
+
+func (S2) M() {}
+
+func _F1[T interface{ M() }](t T) {
+ _ = T.M
+}
+
+func F2() {
+ _F1(&S1{})
+ _F1(S2{})
+ _F1(&S2{})
+}
+
+func main() {
+ F()
+ F2()
+}
diff --git a/test/typeparam/issue23536.go b/test/typeparam/issue23536.go
new file mode 100644
index 0000000..1d6d79b
--- /dev/null
+++ b/test/typeparam/issue23536.go
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case where a slice of a user-defined byte type (not uint8 or byte) is
+// converted to a string. Same for slice of runes.
+
+package main
+
+type MyByte byte
+
+type MyRune rune
+
+func f[T []MyByte](x T) string {
+ return string(x)
+}
+
+func g[T []MyRune](x T) string {
+ return string(x)
+}
+
+func main() {
+ var y []MyByte
+ _ = f(y)
+ _ = string(y)
+
+ var z []MyRune
+ _ = g(z)
+ _ = string(z)
+}
diff --git a/test/typeparam/issue376214.go b/test/typeparam/issue376214.go
new file mode 100644
index 0000000..269b684
--- /dev/null
+++ b/test/typeparam/issue376214.go
@@ -0,0 +1,20 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func add[S ~string | ~[]byte](buf *[]byte, s S) {
+ *buf = append(*buf, s...)
+}
+
+func main() {
+ var buf []byte
+ add(&buf, "foo")
+ add(&buf, []byte("bar"))
+ if string(buf) != "foobar" {
+ panic("got " + string(buf))
+ }
+}
diff --git a/test/typeparam/issue39755.go b/test/typeparam/issue39755.go
new file mode 100644
index 0000000..52c7e7c
--- /dev/null
+++ b/test/typeparam/issue39755.go
@@ -0,0 +1,27 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// copied from cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go
+
+package p
+
+func _[T interface{ ~map[string]int }](x T) {
+ _ = x == nil
+}
+
+// simplified test case from issue
+
+type PathParamsConstraint interface {
+ ~map[string]string | ~[]struct{ key, value string }
+}
+
+type PathParams[T PathParamsConstraint] struct {
+ t T
+}
+
+func (pp *PathParams[T]) IsNil() bool {
+ return pp.t == nil // this must succeed
+}
diff --git a/test/typeparam/issue42758.go b/test/typeparam/issue42758.go
new file mode 100644
index 0000000..25fb85f
--- /dev/null
+++ b/test/typeparam/issue42758.go
@@ -0,0 +1,19 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func F[T, U int]() interface{} {
+ switch interface{}(nil) {
+ case int(0), T(0), U(0):
+ }
+
+ return map[interface{}]int{int(0): 0, T(0): 0, U(0): 0}
+}
+
+func main() {
+ F[int, int]()
+}
diff --git a/test/typeparam/issue44688.go b/test/typeparam/issue44688.go
new file mode 100644
index 0000000..48160e0
--- /dev/null
+++ b/test/typeparam/issue44688.go
@@ -0,0 +1,149 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// derived & expanded from cmd/compile/internal/types2/testdata/fixedbugs/issue44688.go2
+
+package main
+
+type A1[T any] struct {
+ val T
+}
+
+func (p *A1[T]) m1(val T) {
+ p.val = val
+}
+
+type A2[T any] interface {
+ m2(T)
+}
+
+type B1[T any] struct {
+ filler int
+ *A1[T]
+ A2[T]
+}
+
+type B2[T any] interface {
+ A2[T]
+}
+
+type ImpA2[T any] struct {
+ f T
+}
+
+func (a2 *ImpA2[T]) m2(s T) {
+ a2.f = s
+}
+
+type C[T any] struct {
+ filler1 int
+ filler2 int
+ B1[T]
+}
+
+type D[T any] struct {
+ filler1 int
+ filler2 int
+ filler3 int
+ C[T]
+}
+
+func test1[T any](arg T) {
+ // calling embedded methods
+ var b1 B1[T]
+ b1.A1 = &A1[T]{}
+ b1.A2 = &ImpA2[T]{}
+
+ b1.A1.m1(arg)
+ b1.m1(arg)
+
+ b1.A2.m2(arg)
+ b1.m2(arg)
+
+ var b2 B2[T]
+ b2 = &ImpA2[T]{}
+ b2.m2(arg)
+
+ // a deeper nesting
+ var d D[T]
+ d.C.B1.A1 = &A1[T]{}
+ d.C.B1.A2 = &ImpA2[T]{}
+ d.m1(arg)
+ d.m2(arg)
+
+ // calling method expressions
+ m1x := B1[T].m1
+ m1x(b1, arg)
+ // TODO(khr): reenable these.
+ //m2x := B2[T].m2
+ //m2x(b2, arg)
+
+ // calling method values
+ m1v := b1.m1
+ m1v(arg)
+ m2v := b1.m2
+ m2v(arg)
+ b2v := b2.m2
+ b2v(arg)
+}
+
+func test2() {
+ // calling embedded methods
+ var b1 B1[string]
+ b1.A1 = &A1[string]{}
+ b1.A2 = &ImpA2[string]{}
+
+ b1.A1.m1("")
+ b1.m1("")
+
+ b1.A2.m2("")
+ b1.m2("")
+
+ var b2 B2[string]
+ b2 = &ImpA2[string]{}
+ b2.m2("")
+
+ // a deeper nesting
+ var d D[string]
+ d.C.B1.A1 = &A1[string]{}
+ d.C.B1.A2 = &ImpA2[string]{}
+ d.m1("")
+ d.m2("")
+
+ // calling method expressions
+ m1x := B1[string].m1
+ m1x(b1, "")
+ m2x := B2[string].m2
+ m2x(b2, "")
+
+ // calling method values
+ m1v := b1.m1
+ m1v("")
+ m2v := b1.m2
+ m2v("")
+ b2v := b2.m2
+ b2v("")
+}
+
+// actual test case from issue
+
+type A[T any] struct{}
+
+func (*A[T]) f(T) {}
+
+type B[T any] struct{ A[T] }
+
+func test3() {
+ var b B[string]
+ b.A.f("")
+ b.f("")
+}
+
+func main() {
+ test1[string]("")
+ test2()
+ test3()
+}
diff --git a/test/typeparam/issue45547.go b/test/typeparam/issue45547.go
new file mode 100644
index 0000000..0024f36
--- /dev/null
+++ b/test/typeparam/issue45547.go
@@ -0,0 +1,20 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f[T any]() (f, g T) { return f, g }
+
+// Tests for generic function instantiation on the right hande side of multi-value
+// assignments.
+
+func g() {
+ // Multi-value assignment within a function
+ var _, _ = f[int]()
+}
+
+// Multi-value assignment outside a function.
+var _, _ = f[int]()
diff --git a/test/typeparam/issue45722.go b/test/typeparam/issue45722.go
new file mode 100644
index 0000000..52a3c63
--- /dev/null
+++ b/test/typeparam/issue45722.go
@@ -0,0 +1,34 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "log"
+)
+
+func try[T any](v T, err error) T {
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+func handle(handle func(error)) {
+ if issue := recover(); issue != nil {
+ if e, ok := issue.(error); ok && e != nil {
+ handle(e)
+ } else {
+ handle(fmt.Errorf("%v", e))
+ }
+ }
+}
+
+func main() {
+ defer handle(func(e error) { log.Fatalln(e) })
+ _ = try(fmt.Print(""))
+}
diff --git a/test/typeparam/issue45738.go b/test/typeparam/issue45738.go
new file mode 100644
index 0000000..89b3b11
--- /dev/null
+++ b/test/typeparam/issue45738.go
@@ -0,0 +1,18 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+//go:noinline
+func f[T any]() {
+ x := 5
+ g := func() int { return x }
+ g()
+}
+
+func main() {
+ f[int]()
+}
diff --git a/test/typeparam/issue45817.go b/test/typeparam/issue45817.go
new file mode 100644
index 0000000..78e472f
--- /dev/null
+++ b/test/typeparam/issue45817.go
@@ -0,0 +1,26 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type s[T any] struct {
+ a T
+}
+
+func (x s[T]) f() T {
+ return x.a
+}
+func main() {
+ x := s[int]{a: 7}
+ f := x.f
+ if got, want := f(), 7; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/issue46461.go b/test/typeparam/issue46461.go
new file mode 100644
index 0000000..363a87c
--- /dev/null
+++ b/test/typeparam/issue46461.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T[U interface{ M() T[U] }] int // ERROR "invalid recursive type: T refers to itself"
+
+type X int
+
+func (X) M() T[X] { return 0 }
diff --git a/test/typeparam/issue46461b.dir/a.go b/test/typeparam/issue46461b.dir/a.go
new file mode 100644
index 0000000..fcb4142
--- /dev/null
+++ b/test/typeparam/issue46461b.dir/a.go
@@ -0,0 +1,7 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type T[U interface{ M() int }] int
diff --git a/test/typeparam/issue46461b.dir/b.go b/test/typeparam/issue46461b.dir/b.go
new file mode 100644
index 0000000..a458325
--- /dev/null
+++ b/test/typeparam/issue46461b.dir/b.go
@@ -0,0 +1,13 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+type X int
+
+func (X) M() int { return 0 }
+
+type _ a.T[X]
diff --git a/test/typeparam/issue46461b.go b/test/typeparam/issue46461b.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue46461b.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue46472.go b/test/typeparam/issue46472.go
new file mode 100644
index 0000000..027a8aa
--- /dev/null
+++ b/test/typeparam/issue46472.go
@@ -0,0 +1,20 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func foo[T any](d T) {
+ switch v := interface{}(d).(type) {
+ case string:
+ if v != "x" {
+ panic("unexpected v: " + v)
+ }
+ }
+
+}
+func main() {
+ foo("x")
+}
diff --git a/test/typeparam/issue46591.go b/test/typeparam/issue46591.go
new file mode 100644
index 0000000..9e2c31d
--- /dev/null
+++ b/test/typeparam/issue46591.go
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T[_ any] struct{}
+
+var m = map[interface{}]int{
+ T[struct{ int }]{}: 0,
+ T[struct {
+ int "x"
+ }]{}: 0,
+}
+
+func main() {
+ if len(m) != 2 {
+ panic(len(m))
+ }
+}
diff --git a/test/typeparam/issue47258.go b/test/typeparam/issue47258.go
new file mode 100644
index 0000000..7b202c9
--- /dev/null
+++ b/test/typeparam/issue47258.go
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type Numeric interface {
+ int32 | int64 | float64 | complex64
+}
+
+//go:noline
+func inc[T Numeric](x T) T {
+ x++
+ return x
+}
+func main() {
+ if got, want := inc(int32(5)), int32(6); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ if got, want := inc(float64(5)), float64(6.0); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ if got, want := inc(complex64(5)), complex64(6.0); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/issue47272.go b/test/typeparam/issue47272.go
new file mode 100644
index 0000000..79748ad
--- /dev/null
+++ b/test/typeparam/issue47272.go
@@ -0,0 +1,55 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "errors"
+ "fmt"
+)
+
+type Option[T any] struct {
+ ok bool
+ val T
+}
+
+func (o Option[T]) String() string {
+ if o.ok {
+ return fmt.Sprintf("Some(%v)", o.val)
+ }
+ return "None"
+}
+
+func Some[T any](val T) Option[T] { return Option[T]{ok: true, val: val} }
+func None[T any]() Option[T] { return Option[T]{ok: false} }
+
+type Result[T, E any] struct {
+ ok bool
+ val T
+ err E
+}
+
+func (r Result[T, E]) String() string {
+ if r.ok {
+ return fmt.Sprintf("Ok(%v)", r.val)
+ }
+ return fmt.Sprintf("Err(%v)", r.err)
+}
+
+func Ok[T, E any](val T) Result[T, E] { return Result[T, E]{ok: true, val: val} }
+func Err[T, E any](err E) Result[T, E] { return Result[T, E]{ok: false, err: err} }
+
+func main() {
+ a := Some[int](1)
+ b := None[int]()
+ fmt.Println(a, b)
+
+ x := Ok[int, error](1)
+ y := Err[int, error](errors.New("test"))
+ fmt.Println(x, y)
+ // fmt.Println(x)
+ _, _, _, _ = a, b, x, y
+}
diff --git a/test/typeparam/issue47272.out b/test/typeparam/issue47272.out
new file mode 100644
index 0000000..9c433fa
--- /dev/null
+++ b/test/typeparam/issue47272.out
@@ -0,0 +1,2 @@
+Some(1) None
+Ok(1) Err(test)
diff --git a/test/typeparam/issue47514.go b/test/typeparam/issue47514.go
new file mode 100644
index 0000000..1fc054e
--- /dev/null
+++ b/test/typeparam/issue47514.go
@@ -0,0 +1,20 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that closures inside a generic function are not exported,
+// even though not themselves generic.
+
+package main
+
+func Do[T any]() {
+ _ = func() string {
+ return ""
+ }
+}
+
+func main() {
+ Do[int]()
+}
diff --git a/test/typeparam/issue47514b.go b/test/typeparam/issue47514b.go
new file mode 100644
index 0000000..0609296
--- /dev/null
+++ b/test/typeparam/issue47514b.go
@@ -0,0 +1,19 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func Do[T any](do func() (T, string)) {
+ _ = func() (T, string) {
+ return do()
+ }
+}
+
+func main() {
+ Do[int](func() (int, string) {
+ return 3, "3"
+ })
+}
diff --git a/test/typeparam/issue47514c.dir/a.go b/test/typeparam/issue47514c.dir/a.go
new file mode 100644
index 0000000..782b1d2
--- /dev/null
+++ b/test/typeparam/issue47514c.dir/a.go
@@ -0,0 +1,5 @@
+package a
+
+type Doer[T any] interface {
+ Do() T
+}
diff --git a/test/typeparam/issue47514c.dir/main.go b/test/typeparam/issue47514c.dir/main.go
new file mode 100644
index 0000000..0ef423f
--- /dev/null
+++ b/test/typeparam/issue47514c.dir/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "./a"
+
+func Do[T any](doer a.Doer[T]) {
+ doer.Do()
+}
+
+func main() {
+}
diff --git a/test/typeparam/issue47514c.go b/test/typeparam/issue47514c.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue47514c.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue47631.go b/test/typeparam/issue47631.go
new file mode 100644
index 0000000..32fd837
--- /dev/null
+++ b/test/typeparam/issue47631.go
@@ -0,0 +1,31 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func g[T any]() {
+ type U []T
+ type V []int
+}
+
+type S[T any] struct {
+}
+
+func (s S[T]) m() {
+ type U []T
+ type V []int
+}
+
+func f() {
+ type U []int
+}
+
+type X struct {
+}
+
+func (x X) m() {
+ type U []int
+}
diff --git a/test/typeparam/issue47676.go b/test/typeparam/issue47676.go
new file mode 100644
index 0000000..8569378
--- /dev/null
+++ b/test/typeparam/issue47676.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ d := diff([]int{}, func(int) string {
+ return "foo"
+ })
+ d()
+}
+
+func diff[T any](previous []T, uniqueKey func(T) string) func() {
+ return func() {
+ newJSON := map[string]T{}
+ for _, prev := range previous {
+ delete(newJSON, uniqueKey(prev))
+ }
+ }
+}
diff --git a/test/typeparam/issue47684.go b/test/typeparam/issue47684.go
new file mode 100644
index 0000000..f0e4ed0
--- /dev/null
+++ b/test/typeparam/issue47684.go
@@ -0,0 +1,19 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[G any]() int {
+ return func() int {
+ return func() int {
+ return 0
+ }()
+ }()
+}
+
+func main() {
+ f[int]()
+}
diff --git a/test/typeparam/issue47684b.go b/test/typeparam/issue47684b.go
new file mode 100644
index 0000000..3e9fa93
--- /dev/null
+++ b/test/typeparam/issue47684b.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[G any]() interface{} {
+ return func() interface{} {
+ return func() interface{} {
+ var x G
+ return x
+ }()
+ }()
+}
+
+func main() {
+ x := f[int]()
+ if v, ok := x.(int); !ok || v != 0 {
+ panic("bad")
+ }
+}
diff --git a/test/typeparam/issue47684c.go b/test/typeparam/issue47684c.go
new file mode 100644
index 0000000..b1d4520
--- /dev/null
+++ b/test/typeparam/issue47684c.go
@@ -0,0 +1,19 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[G any]() func()func()int {
+ return func() func()int {
+ return func() int {
+ return 0
+ }
+ }
+}
+
+func main() {
+ f[int]()()()
+}
diff --git a/test/typeparam/issue47708.go b/test/typeparam/issue47708.go
new file mode 100644
index 0000000..d6140f3
--- /dev/null
+++ b/test/typeparam/issue47708.go
@@ -0,0 +1,37 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type FooType[T any] interface {
+ Foo(BarType[T]) string
+}
+type BarType[T any] interface {
+ Bar(FooType[T]) string
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type Baz[T any] T
+// func (l Baz[T]) Foo(v BarType[T]) string {
+// return v.Bar(l)
+// }
+// type Bob[T any] T
+// func (l Bob[T]) Bar(v FooType[T]) string {
+// if v,ok := v.(Baz[T]);ok{
+// return fmt.Sprintf("%v%v",v,l)
+// }
+// return ""
+// }
+
+func main() {
+ // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+ // var baz Baz[int] = 123
+ // var bob Bob[int] = 456
+ //
+ // if got, want := baz.Foo(bob), "123456"; got != want {
+ // panic(fmt.Sprintf("got %s want %s", got, want))
+ // }
+}
diff --git a/test/typeparam/issue47710.go b/test/typeparam/issue47710.go
new file mode 100644
index 0000000..2263c8b
--- /dev/null
+++ b/test/typeparam/issue47710.go
@@ -0,0 +1,19 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type FooType[t any] interface {
+ Foo(BarType[t])
+}
+type BarType[t any] interface {
+ Int(IntType[t]) FooType[int]
+}
+
+type IntType[t any] int
+
+func (n IntType[t]) Foo(BarType[t]) {}
+func (n IntType[_]) String() {}
diff --git a/test/typeparam/issue47713.go b/test/typeparam/issue47713.go
new file mode 100644
index 0000000..7e3b5a5
--- /dev/null
+++ b/test/typeparam/issue47713.go
@@ -0,0 +1,52 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "encoding"
+ "fmt"
+)
+
+type Seralizable interface {
+ encoding.BinaryMarshaler
+ encoding.BinaryUnmarshaler
+}
+
+type SerDeString string
+
+func (s *SerDeString) UnmarshalBinary(in []byte) error {
+ *s = SerDeString(in)
+ return nil
+}
+
+func (s SerDeString) MarshalBinary() ([]byte, error) {
+ return []byte(s), nil
+}
+
+
+type GenericSerializable[T Seralizable] struct {
+ Key string
+ Value T
+}
+
+func (g GenericSerializable[T]) Send() {
+ out, err := g.Value.MarshalBinary()
+ if err != nil {
+ panic("bad")
+ }
+ var newval SerDeString
+ newval.UnmarshalBinary(out)
+ fmt.Printf("Sent %s\n", newval)
+}
+
+func main() {
+ val := SerDeString("asdf")
+ x := GenericSerializable[*SerDeString]{
+ Value: &val,
+ }
+ x.Send()
+}
diff --git a/test/typeparam/issue47713.out b/test/typeparam/issue47713.out
new file mode 100644
index 0000000..a6e7719
--- /dev/null
+++ b/test/typeparam/issue47713.out
@@ -0,0 +1 @@
+Sent asdf
diff --git a/test/typeparam/issue47716.go b/test/typeparam/issue47716.go
new file mode 100644
index 0000000..5024ac9
--- /dev/null
+++ b/test/typeparam/issue47716.go
@@ -0,0 +1,68 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "unsafe"
+)
+
+// size returns the size of type T
+func size[T any](x T) uintptr {
+ return unsafe.Sizeof(x)
+}
+
+// size returns the alignment of type T
+func align[T any](x T) uintptr {
+ return unsafe.Alignof(x)
+}
+
+type Tstruct[T any] struct {
+ f1 T
+ f2 int
+}
+
+// offset returns the offset of field f2 in the generic type Tstruct
+func (r *Tstruct[T]) offset() uintptr {
+ return unsafe.Offsetof(r.f2)
+}
+
+func main() {
+ v1 := int(5)
+ if got, want := size(v1), unsafe.Sizeof(v1); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ if got, want := align(v1), unsafe.Alignof(v1); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ v2 := "abc"
+ if got, want := size(v2), unsafe.Sizeof(v2); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ if got, want := align(v2), unsafe.Alignof(v2); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ var v3 Tstruct[int]
+ if got, want := unsafe.Offsetof(v3.f2), unsafe.Sizeof(v1); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ var v4 Tstruct[interface{}]
+ var v5 interface{}
+ if got, want := unsafe.Offsetof(v4.f2), unsafe.Sizeof(v5); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got, want := v3.offset(), unsafe.Offsetof(v3.f2); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ if got, want := v4.offset(), unsafe.Offsetof(v4.f2); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/issue47723.go b/test/typeparam/issue47723.go
new file mode 100644
index 0000000..44c55b6
--- /dev/null
+++ b/test/typeparam/issue47723.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[_ any]() int {
+ var a [1]int
+ _ = func() int {
+ return func() int {
+ return 0
+ }()
+ }()
+ return a[func() int {
+ return 0
+ }()]
+}
+
+func main() {
+ f[int]()
+}
diff --git a/test/typeparam/issue47740.go b/test/typeparam/issue47740.go
new file mode 100644
index 0000000..f34394c
--- /dev/null
+++ b/test/typeparam/issue47740.go
@@ -0,0 +1,40 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type Exp[Ty any] interface {
+ Eval() Ty
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type Lit[Ty any] Ty
+//
+// func (lit Lit[Ty]) Eval() Ty { return Ty(lit) }
+// func (lit Lit[Ty]) String() string { return fmt.Sprintf("(lit %v)", Ty(lit)) }
+
+type Eq[Ty any] struct {
+ a Exp[Ty]
+ b Exp[Ty]
+}
+
+func (e Eq[Ty]) String() string {
+ return fmt.Sprintf("(eq %v %v)", e.a, e.b)
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// var (
+// e0 = Eq[int]{Lit[int](128), Lit[int](64)}
+// e1 = Eq[bool]{Lit[bool](true), Lit[bool](true)}
+// )
+
+func main() {
+ // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+ // fmt.Printf("%v\n", e0)
+ // fmt.Printf("%v\n", e1)
+}
diff --git a/test/typeparam/issue47740.out b/test/typeparam/issue47740.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/typeparam/issue47740.out
diff --git a/test/typeparam/issue47740b.go b/test/typeparam/issue47740b.go
new file mode 100644
index 0000000..d46d058
--- /dev/null
+++ b/test/typeparam/issue47740b.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "reflect"
+
+type S[T any] struct {
+ a interface{}
+}
+
+func (e S[T]) M() {
+ v := reflect.ValueOf(e.a)
+ _, _ = v.Interface().(int)
+}
+
+func main() {
+ e := S[int]{0}
+ e.M()
+}
diff --git a/test/typeparam/issue47775.dir/b.go b/test/typeparam/issue47775.dir/b.go
new file mode 100644
index 0000000..b6d7ba9
--- /dev/null
+++ b/test/typeparam/issue47775.dir/b.go
@@ -0,0 +1,19 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+type C[T any] struct {
+}
+
+func (c *C[T]) reset() {
+}
+
+func New[T any]() {
+ c := &C[T]{}
+ z(c.reset)
+}
+
+func z(interface{}) {
+}
diff --git a/test/typeparam/issue47775.dir/main.go b/test/typeparam/issue47775.dir/main.go
new file mode 100644
index 0000000..5ec85a4
--- /dev/null
+++ b/test/typeparam/issue47775.dir/main.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./b"
+
+func main() {
+ b.New[int]()
+}
diff --git a/test/typeparam/issue47775.go b/test/typeparam/issue47775.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue47775.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue47775b.go b/test/typeparam/issue47775b.go
new file mode 100644
index 0000000..e084e03
--- /dev/null
+++ b/test/typeparam/issue47775b.go
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type C[T any] struct {
+}
+
+func (c *C[T]) reset() {
+}
+
+func New[T any]() {
+ c := &C[T]{}
+ i = c.reset
+ z(c.reset)
+}
+
+var i interface{}
+
+func z(interface{}) {
+}
+
+func main() {
+ New[int]()
+}
diff --git a/test/typeparam/issue47797.go b/test/typeparam/issue47797.go
new file mode 100644
index 0000000..ad89bcc
--- /dev/null
+++ b/test/typeparam/issue47797.go
@@ -0,0 +1,22 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type Foo[T any] struct {
+ Val T
+}
+
+func (f Foo[T]) Bat() {}
+
+type Bar struct {
+ Foo[int]
+}
+
+func foo() {
+ var b Bar
+ b.Bat()
+}
diff --git a/test/typeparam/issue47877.go b/test/typeparam/issue47877.go
new file mode 100644
index 0000000..be5c5c0
--- /dev/null
+++ b/test/typeparam/issue47877.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Map[K comparable, V any] struct {
+ m map[K]V
+}
+
+func NewMap[K comparable, V any]() Map[K, V] {
+ return Map[K, V]{m: map[K]V{}}
+}
+
+func (m Map[K, V]) Get(key K) V {
+ return m.m[key]
+}
+
+func main() {
+ _ = NewMap[int, struct{}]()
+}
diff --git a/test/typeparam/issue47878.go b/test/typeparam/issue47878.go
new file mode 100644
index 0000000..25758cb
--- /dev/null
+++ b/test/typeparam/issue47878.go
@@ -0,0 +1,56 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Src1[T any] func() Src1[T]
+
+func (s *Src1[T]) Next() {
+ *s = (*s)()
+}
+
+type Src2[T any] []func() Src2[T]
+
+func (s Src2[T]) Next() {
+ _ = s[0]()
+}
+
+type Src3[T comparable] map[T]func() Src3[T]
+
+func (s Src3[T]) Next() {
+ var a T
+ _ = s[a]()
+}
+
+type Src4[T any] chan func() T
+
+func (s Src4[T]) Next() {
+ _ = (<-s)()
+}
+
+type Src5[T any] func() Src5[T]
+
+func (s Src5[T]) Next() {
+ var x interface{} = s
+ _ = (x.(Src5[T]))()
+}
+
+func main() {
+ var src1 Src1[int]
+ src1.Next()
+
+ var src2 Src2[int]
+ src2.Next()
+
+ var src3 Src3[string]
+ src3.Next()
+
+ var src4 Src4[int]
+ src4.Next()
+
+ var src5 Src5[int]
+ src5.Next()
+}
diff --git a/test/typeparam/issue47892.dir/a.go b/test/typeparam/issue47892.dir/a.go
new file mode 100644
index 0000000..b63d604
--- /dev/null
+++ b/test/typeparam/issue47892.dir/a.go
@@ -0,0 +1,17 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Index[T any] interface {
+ G() T
+}
+
+type I1[T any] struct {
+ a T
+}
+
+func (i *I1[T]) G() T {
+ return i.a
+}
diff --git a/test/typeparam/issue47892.dir/main.go b/test/typeparam/issue47892.dir/main.go
new file mode 100644
index 0000000..348e38b
--- /dev/null
+++ b/test/typeparam/issue47892.dir/main.go
@@ -0,0 +1,21 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+type Model[T any] struct {
+ index a.Index[T]
+}
+
+func NewModel[T any](index a.Index[T]) Model[T] {
+ return Model[T]{
+ index: index,
+ }
+}
+
+func main() {
+ _ = NewModel[int]((*a.I1[int])(nil))
+}
diff --git a/test/typeparam/issue47892.go b/test/typeparam/issue47892.go
new file mode 100644
index 0000000..5bb6a74
--- /dev/null
+++ b/test/typeparam/issue47892.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored \ No newline at end of file
diff --git a/test/typeparam/issue47892b.dir/a.go b/test/typeparam/issue47892b.dir/a.go
new file mode 100644
index 0000000..5adb492
--- /dev/null
+++ b/test/typeparam/issue47892b.dir/a.go
@@ -0,0 +1,29 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type T struct{ p *int64 }
+
+type i struct{}
+
+func G() *T { return &T{nil} }
+
+func (j i) F(a, b *T) *T {
+ n := *a.p + *b.p
+ return &T{&n}
+}
+
+func (j i) G() *T {
+ return &T{}
+}
+
+type I[Idx any] interface {
+ G() Idx
+ F(a, b Idx) Idx
+}
+
+func Gen() I[*T] {
+ return i{}
+}
diff --git a/test/typeparam/issue47892b.dir/main.go b/test/typeparam/issue47892b.dir/main.go
new file mode 100644
index 0000000..3cd658f
--- /dev/null
+++ b/test/typeparam/issue47892b.dir/main.go
@@ -0,0 +1,17 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+type S[Idx any] struct {
+ A string
+ B Idx
+}
+
+type O[Idx any] struct {
+ A int
+ B a.I[Idx]
+}
diff --git a/test/typeparam/issue47892b.go b/test/typeparam/issue47892b.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue47892b.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue47896.go b/test/typeparam/issue47896.go
new file mode 100644
index 0000000..616e907
--- /dev/null
+++ b/test/typeparam/issue47896.go
@@ -0,0 +1,74 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "database/sql"
+)
+
+// Collection generic interface which things can be added to.
+type Collection[T any] interface {
+ Add(T)
+}
+
+// Slice generic slice implementation of a Collection
+type Slice[T any] []*T
+
+func (s *Slice[T]) Add(t *T) {
+ *s = append(*s, t)
+}
+
+type Scanner interface {
+ Scan(...interface{}) error
+}
+
+type Mapper[T any] func(s Scanner, t T) error
+
+type Repository[T any] struct {
+ db *sql.DB
+}
+
+func (r *Repository[T]) scan(rows *sql.Rows, m Mapper[*T], c Collection[*T]) error {
+ for rows.Next() {
+ t := new(T)
+ if err := m(rows, t); err != nil {
+ return err
+ }
+ c.Add(t)
+ }
+ return rows.Err()
+}
+
+func (r *Repository[T]) query(query string, m Mapper[*T], c Collection[*T]) error {
+ rows, err := r.db.Query(query)
+ if err != nil {
+ return err
+ }
+ if err := r.scan(rows, m, c); err != nil {
+ rows.Close()
+ return err
+ }
+ return rows.Close()
+}
+
+type Actor struct {
+ ActorID uint16
+ FirstName string
+ LastName string
+}
+
+type ActorRepository struct {
+ r Repository[Actor]
+}
+
+func (ActorRepository) scan(s Scanner, a *Actor) error {
+ return s.Scan(&a.ActorID, &a.FirstName, &a.LastName)
+}
+
+func (r *ActorRepository) SelectAll(c Collection[*Actor]) error {
+ return r.r.query("SELECT `actor_id`, `first_name`, `last_name` FROM `actor` LIMIT 10", r.scan, c)
+}
diff --git a/test/typeparam/issue47901.go b/test/typeparam/issue47901.go
new file mode 100644
index 0000000..e005135
--- /dev/null
+++ b/test/typeparam/issue47901.go
@@ -0,0 +1,21 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Chan[T any] chan Chan[T]
+
+func (ch Chan[T]) recv() Chan[T] {
+ return <-ch
+}
+
+func main() {
+ ch := Chan[int](make(chan Chan[int]))
+ go func() {
+ ch <- make(Chan[int])
+ }()
+ ch.recv()
+}
diff --git a/test/typeparam/issue47924.go b/test/typeparam/issue47924.go
new file mode 100644
index 0000000..eea7acb
--- /dev/null
+++ b/test/typeparam/issue47924.go
@@ -0,0 +1,15 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type Cache[K any] struct{}
+
+func (c Cache[K]) foo(x interface{}, f func(K) bool) {
+ f(x.(K))
+}
+
+var _ Cache[int]
diff --git a/test/typeparam/issue47925.go b/test/typeparam/issue47925.go
new file mode 100644
index 0000000..c595e14
--- /dev/null
+++ b/test/typeparam/issue47925.go
@@ -0,0 +1,20 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type myifacer[T any] interface{ do(T) error }
+
+type stuff[T any] struct{}
+
+func (s stuff[T]) run() interface{} {
+ var i myifacer[T]
+ return i
+}
+
+func main() {
+ stuff[int]{}.run()
+}
diff --git a/test/typeparam/issue47925b.go b/test/typeparam/issue47925b.go
new file mode 100644
index 0000000..bffbe4e
--- /dev/null
+++ b/test/typeparam/issue47925b.go
@@ -0,0 +1,33 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I[T any] interface {
+ foo()
+}
+
+type E[T any] interface {
+}
+
+//go:noinline
+func f[T I[T]](x T) E[T] {
+ // contains a cast from nonempty to empty interface
+ return E[T](I[T](x))
+}
+
+type S struct {
+ x int
+}
+
+func (s *S) foo() {}
+
+func main() {
+ i := f(&S{x: 7})
+ if i.(*S).x != 7 {
+ panic("bad")
+ }
+}
diff --git a/test/typeparam/issue47925c.go b/test/typeparam/issue47925c.go
new file mode 100644
index 0000000..9636b9d
--- /dev/null
+++ b/test/typeparam/issue47925c.go
@@ -0,0 +1,36 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I[T any] interface {
+ foo()
+}
+
+type J[T any] interface {
+ foo()
+ bar()
+}
+
+//go:noinline
+func f[T J[T]](x T) I[T] {
+ // contains a cast between two nonempty interfaces
+ return I[T](J[T](x))
+}
+
+type S struct {
+ x int
+}
+
+func (s *S) foo() {}
+func (s *S) bar() {}
+
+func main() {
+ i := f(&S{x: 7})
+ if i.(*S).x != 7 {
+ panic("bad")
+ }
+}
diff --git a/test/typeparam/issue47925d.go b/test/typeparam/issue47925d.go
new file mode 100644
index 0000000..c5647f9
--- /dev/null
+++ b/test/typeparam/issue47925d.go
@@ -0,0 +1,47 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I[T any] interface {
+ foo()
+}
+
+type J[T any] interface {
+ foo()
+ bar()
+}
+
+//go:noinline
+func f[T J[T]](x T, g func(T) T) I[T] {
+ // contains a cast between two nonempty interfaces
+ // Also make sure we don't evaluate g(x) twice.
+ return I[T](J[T](g(x)))
+}
+
+type S struct {
+ x int
+}
+
+func (s *S) foo() {}
+func (s *S) bar() {}
+
+var cnt int
+
+func inc(s *S) *S {
+ cnt++
+ return s
+}
+
+func main() {
+ i := f(&S{x: 7}, inc)
+ if i.(*S).x != 7 {
+ panic("bad")
+ }
+ if cnt != 1 {
+ panic("multiple calls")
+ }
+}
diff --git a/test/typeparam/issue47929.go b/test/typeparam/issue47929.go
new file mode 100644
index 0000000..1aa6885
--- /dev/null
+++ b/test/typeparam/issue47929.go
@@ -0,0 +1,29 @@
+// compile -p=p
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package v4
+
+var sink interface{}
+
+//go:noinline
+func Do(result, body interface{}) {
+ sink = &result
+}
+
+func DataAction(result DataActionResponse, body DataActionRequest) {
+ Do(&result, body)
+}
+
+type DataActionRequest struct {
+ Action *interface{}
+}
+
+type DataActionResponse struct {
+ ValidationErrors *ValidationError
+}
+
+type ValidationError struct {
+}
diff --git a/test/typeparam/issue47948.go b/test/typeparam/issue47948.go
new file mode 100644
index 0000000..deab0ef
--- /dev/null
+++ b/test/typeparam/issue47948.go
@@ -0,0 +1,18 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type fun func()
+
+func F[T any]() {
+ _ = fun(func() {
+
+ })
+}
+func main() {
+ F[int]()
+}
diff --git a/test/typeparam/issue47966.go b/test/typeparam/issue47966.go
new file mode 100644
index 0000000..ec66478
--- /dev/null
+++ b/test/typeparam/issue47966.go
@@ -0,0 +1,9 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type C comparable
diff --git a/test/typeparam/issue48013.go b/test/typeparam/issue48013.go
new file mode 100644
index 0000000..3fbf249
--- /dev/null
+++ b/test/typeparam/issue48013.go
@@ -0,0 +1,39 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "unsafe"
+)
+
+type S[T any] struct {
+ val T
+}
+
+// Test type substitution where base type is unsafe.Pointer
+type U[T any] unsafe.Pointer
+
+func test[T any]() T {
+ var q U[T]
+ var v struct {
+ // Test derived type that contains an unsafe.Pointer
+ p unsafe.Pointer
+ val T
+ }
+ _ = q
+ return v.val
+}
+
+func main() {
+ want := 0
+ got := test[int]()
+ if got != want {
+ panic(fmt.Sprintf("got %f, want %f", got, want))
+ }
+
+}
diff --git a/test/typeparam/issue48016.go b/test/typeparam/issue48016.go
new file mode 100644
index 0000000..dbc87ec
--- /dev/null
+++ b/test/typeparam/issue48016.go
@@ -0,0 +1,35 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "strconv"
+)
+
+func test1[T any](fn func(T) int, v T) int {
+ fn1 := func() int {
+ var i interface{} = v
+ val := fn(i.(T))
+ return val
+ }
+ return fn1()
+}
+
+func main() {
+ want := 123
+ got := test1(func(s string) int {
+ r, err := strconv.Atoi(s)
+ if err != nil {
+ return 0
+ }
+ return r
+ }, "123")
+ if got != want {
+ panic(fmt.Sprintf("got %f, want %f", got, want))
+ }
+}
diff --git a/test/typeparam/issue48030.go b/test/typeparam/issue48030.go
new file mode 100644
index 0000000..23494f9
--- /dev/null
+++ b/test/typeparam/issue48030.go
@@ -0,0 +1,26 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Src[T any] func() Src[T]
+
+func Seq[T any]() Src[T] {
+ return nil
+}
+
+func Seq2[T1 any, T2 any](v1 T1, v2 T2) Src[T2] {
+ return nil
+}
+
+func main() {
+ // Type args fully supplied
+ Seq[int]()
+ // Partial inference of type args
+ Seq2[int](5, "abc")
+ // Full inference of type args
+ Seq2(5, "abc")
+}
diff --git a/test/typeparam/issue48042.go b/test/typeparam/issue48042.go
new file mode 100644
index 0000000..1cfbfbe
--- /dev/null
+++ b/test/typeparam/issue48042.go
@@ -0,0 +1,77 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type G[T any] interface {
+ g() func()(*T)
+}
+type Foo[T any] struct {
+
+}
+// OCALL
+func (l *Foo[T]) f1() (*T) {
+ return g[T]()()
+}
+// OCALLFUNC
+func (l *Foo[T]) f2() (*T) {
+ var f = g[T]
+ return f()()
+}
+// OCALLMETH
+func (l *Foo[T]) f3() (*T) {
+ return l.g()()
+}
+// OCALLINTER
+func (l *Foo[T]) f4() (*T) {
+ var g G[T] = l
+ return g.g()()
+}
+// ODYNAMICDOTTYPE
+func (l *Foo[T]) f5() (*T) {
+ var x interface{}
+ x = g[T]
+ return x.(func()func()(*T))()()
+}
+func (l *Foo[T]) g() func() (*T) {
+ return func() (*T) {
+ t := new(T)
+ reflect.ValueOf(t).Elem().SetInt(100)
+ return t
+ }
+}
+func g[T any]() func() (*T) {
+ return func() (*T) {
+ t := new(T)
+ reflect.ValueOf(t).Elem().SetInt(100)
+ return t
+ }
+}
+
+func main() {
+ foo := Foo[int]{}
+ // Make sure the function conversion is correct
+ if n := *(foo.f1()) ; n != 100{
+ panic(fmt.Sprintf("%v",n))
+ }
+ if n := *(foo.f2()) ; n != 100{
+ panic(fmt.Sprintf("%v",n))
+ }
+ if n := *(foo.f3()) ; n != 100{
+ panic(fmt.Sprintf("%v",n))
+ }
+ if n := *(foo.f4()) ; n != 100{
+ panic(fmt.Sprintf("%v",n))
+ }
+ if n := *(foo.f5()) ; n != 100{
+ panic(fmt.Sprintf("%v",n))
+ }
+} \ No newline at end of file
diff --git a/test/typeparam/issue48047.go b/test/typeparam/issue48047.go
new file mode 100644
index 0000000..06a2ebd
--- /dev/null
+++ b/test/typeparam/issue48047.go
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type A[T any] struct {
+ field B[T]
+}
+
+type B[T any] interface {
+ Work(T)
+}
+
+func (a *A[T]) Work(t T) {
+ a.field.Work(t)
+}
+
+type BImpl struct{}
+
+func (b BImpl) Work(s string) {}
+
+func main() {
+ a := &A[string]{
+ field: BImpl{},
+ }
+ a.Work("")
+}
diff --git a/test/typeparam/issue48049.go b/test/typeparam/issue48049.go
new file mode 100644
index 0000000..3e87b38
--- /dev/null
+++ b/test/typeparam/issue48049.go
@@ -0,0 +1,33 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ Gooer2[byte]()
+}
+
+type Fooer[T any] interface {
+ Foo(p T)
+}
+
+type fooer1[T any] struct{}
+
+func (fooer1[T]) Foo(T) {}
+
+type fooer2[T any] struct {
+ r []Fooer[T]
+}
+
+//go:noinline
+func (mr fooer2[T]) Foo(p T) {
+ mr.r[0] = fooer1[T]{}
+ return
+}
+
+func Gooer2[T any]() Fooer[T] {
+ return fooer2[T]{}
+}
diff --git a/test/typeparam/issue48056.go b/test/typeparam/issue48056.go
new file mode 100644
index 0000000..e91d689
--- /dev/null
+++ b/test/typeparam/issue48056.go
@@ -0,0 +1,27 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type B[T any] interface {
+ Work()
+}
+type BImpl[T any] struct{}
+
+func (b *BImpl[T]) Work() {
+}
+
+type A[T any] struct {
+ B[T]
+}
+
+func f[T any]() {
+ s := &A[T]{
+ &BImpl[T]{},
+ }
+ // golang.org/issue/48056
+ s.Work()
+}
diff --git a/test/typeparam/issue48094.dir/a.go b/test/typeparam/issue48094.dir/a.go
new file mode 100644
index 0000000..dd8c16f
--- /dev/null
+++ b/test/typeparam/issue48094.dir/a.go
@@ -0,0 +1,26 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import "unsafe"
+
+func F[T any]() uintptr {
+ var t T
+ return unsafe.Sizeof(t)
+}
+
+func G[T any]() uintptr {
+ var t T
+ return unsafe.Alignof(t)
+}
+
+//func H[T any]() uintptr {
+// type S struct {
+// a T
+// b T
+// }
+// var s S
+// return unsafe.Offsetof(s.b)
+//}
diff --git a/test/typeparam/issue48094.dir/main.go b/test/typeparam/issue48094.dir/main.go
new file mode 100644
index 0000000..78337da
--- /dev/null
+++ b/test/typeparam/issue48094.dir/main.go
@@ -0,0 +1,20 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ if a.F[int64]() != 8 {
+ panic("bad")
+ }
+ if a.G[int8]() != 1 {
+ panic("bad")
+ }
+ // TODO: enable once 47631 is fixed.
+ //if a.H[int64]() != 8 {
+ // panic("bad")
+ //}
+}
diff --git a/test/typeparam/issue48094.go b/test/typeparam/issue48094.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48094.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48094b.dir/a.go b/test/typeparam/issue48094b.dir/a.go
new file mode 100644
index 0000000..a113a22
--- /dev/null
+++ b/test/typeparam/issue48094b.dir/a.go
@@ -0,0 +1,8 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F() { G(0) }
+func G[T any](t T) {}
diff --git a/test/typeparam/issue48094b.dir/b.go b/test/typeparam/issue48094b.dir/b.go
new file mode 100644
index 0000000..242b34a
--- /dev/null
+++ b/test/typeparam/issue48094b.dir/b.go
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func H() { a.F() }
diff --git a/test/typeparam/issue48094b.go b/test/typeparam/issue48094b.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue48094b.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48137.go b/test/typeparam/issue48137.go
new file mode 100644
index 0000000..84a0f6d
--- /dev/null
+++ b/test/typeparam/issue48137.go
@@ -0,0 +1,25 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Constraint[T any] interface {
+ ~func() T
+}
+
+func Foo[T Constraint[T]]() T {
+ var t T
+
+ t = func() T {
+ return t
+ }
+ return t
+}
+
+func main() {
+ type Bar func() Bar
+ Foo[Bar]()
+}
diff --git a/test/typeparam/issue48185a.dir/p.go b/test/typeparam/issue48185a.dir/p.go
new file mode 100644
index 0000000..176c7f4
--- /dev/null
+++ b/test/typeparam/issue48185a.dir/p.go
@@ -0,0 +1,19 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type MarshalOptions struct {
+ Marshalers *Marshalers
+}
+
+type Encoder struct {}
+
+type Marshalers = marshalers[MarshalOptions, Encoder]
+
+type marshalers[Options, Coder any] struct{}
+
+func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers {
+ return &Marshalers{}
+}
diff --git a/test/typeparam/issue48185a.dir/p_test.go b/test/typeparam/issue48185a.dir/p_test.go
new file mode 100644
index 0000000..a89d697
--- /dev/null
+++ b/test/typeparam/issue48185a.dir/p_test.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./p"
+
+func main() {
+ _ = p.MarshalFuncV1[int](func(int) ([]byte, error) { return nil, nil })
+}
diff --git a/test/typeparam/issue48185a.go b/test/typeparam/issue48185a.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48185a.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48185b.dir/a.go b/test/typeparam/issue48185b.dir/a.go
new file mode 100644
index 0000000..9aed60c
--- /dev/null
+++ b/test/typeparam/issue48185b.dir/a.go
@@ -0,0 +1,37 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import (
+ "reflect"
+ "sync"
+)
+
+type addressableValue struct{ reflect.Value }
+
+type arshalers[Options, Coder any] struct {
+ fncVals []typedArshaler[Options, Coder]
+ fncCache sync.Map // map[reflect.Type]unmarshaler
+}
+type typedArshaler[Options, Coder any] struct {
+ typ reflect.Type
+ fnc func(Options, *Coder, addressableValue) error
+}
+
+type UnmarshalOptions1 struct {
+ // Unmarshalers is a list of type-specific unmarshalers to use.
+ Unmarshalers *arshalers[UnmarshalOptions1, Decoder1]
+}
+
+type Decoder1 struct {
+}
+
+func (a *arshalers[Options, Coder]) lookup(fnc func(Options, *Coder, addressableValue) error, t reflect.Type) func(Options, *Coder, addressableValue) error {
+ return fnc
+}
+
+func UnmarshalFuncV2[T any](fn func(UnmarshalOptions1, *Decoder1, T) error) *arshalers[UnmarshalOptions1, Decoder1] {
+ return &arshalers[UnmarshalOptions1, Decoder1]{}
+}
diff --git a/test/typeparam/issue48185b.dir/main.go b/test/typeparam/issue48185b.dir/main.go
new file mode 100644
index 0000000..ea157f7
--- /dev/null
+++ b/test/typeparam/issue48185b.dir/main.go
@@ -0,0 +1,18 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ _ = a.UnmarshalOptions1{
+ Unmarshalers: a.UnmarshalFuncV2(func(opts a.UnmarshalOptions1, dec *a.Decoder1, val *interface{}) (err error) {
+ return fmt.Errorf("error")
+ }),
+ }
+}
diff --git a/test/typeparam/issue48185b.go b/test/typeparam/issue48185b.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48185b.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48191.go b/test/typeparam/issue48191.go
new file mode 100644
index 0000000..9c3218b
--- /dev/null
+++ b/test/typeparam/issue48191.go
@@ -0,0 +1,269 @@
+// compile -c=2
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I1 interface {
+ int8 | int16 | int32 | int64 | int | uint
+}
+type I2 interface{ float32 | float64 }
+type I3 interface{ string }
+
+func F[G1 I1, G2 I2, G3 I3]() {
+ var m0 map[G2]rune
+ var ch0, ch1 chan bool
+ var ast0, ast1 []struct{ s0 G3 }
+ var ai64_2 []int64
+ var m1, m2, m3 map[bool]map[int]struct {
+ m0 map[G2]byte
+ s1 G3
+ }
+ var i8_0, i8_1 G1
+ var i16_0 int16
+ var am3, am4 []map[float64]map[G2]*func(*byte, map[uint]int64, G3, struct{}) G2
+ var pi64_0, pi64_1 *int64
+ var i, i1, i2 int
+ var as5, as6, as7 []G3
+ var ch2, ch3, ch4 chan uint
+ var m4, m5, m6 map[G1]chan bool
+
+ if func(G2, int32) byte {
+ return m1[false][30].m0[G2(28.6)] * m3[func(bool, uint) bool {
+ return false
+ }(false, uint(94))][31].m0[G2(185.0)] * m1[(true || true) && (false && false)][51-i2].m0[G2(278.6)]
+ }(G2(672.5), int32(35)) < m3[<-m5[func(int64, int64) G1 {
+ return i8_1
+ }(*pi64_0, int64(50))]][15&i1^i2^i2].m0[G2(895.3)] || (func(int64, uint) uint {
+ return uint(94)
+ }(int64(30), uint(95))&^<-ch2^<-ch4)&<-ch2^<-ch4 == <-ch2 {
+ var f0 float64
+ var pf2 *float64
+ var ch5, ch6 chan int16
+ var fnc0 func(*int64, G2, struct {
+ i8_0 G1
+ m1 map[float64]bool
+ i64_2 int64
+ }, map[byte]func(G2, float64, *uint, float64) struct{}) complex128 = func(p0 *int64, p1 G2, p2 struct {
+ i8_0 G1
+ m1 map[float64]bool
+ i64_2 int64
+ }, p3 map[byte]func(G2, float64, *uint, float64) struct{}) complex128 {
+ p0 = pi64_1
+ m5 = map[G1]chan bool{(p2.i8_0 + i8_1 + i8_1 ^ i8_1) * p2.i8_0 / p2.i8_0: m4[p2.i8_0>><-ch2]}
+ return (2.65i - 31.18i) * func(byte, byte) complex128 {
+ return 13.12i - 32.90i + (44.15i - 70.53i - (87.16i*92.67i + (24.18i - 9.13i))) + (func(G1, int16) complex128 {
+ return 55.80i
+ }(G1(30), int16(80)) + 8.48i*79.18i + (37.30i*73.81i + (21.01i - 76.30i)) + func(G3, G2) complex128 {
+ return 35.58i
+ }(G3("2JYizeFiEMvXLkUR"), p1)*(81.59i-21.76i))
+ }(m1[<-m5[G1(37)*i8_1<<i8_1%p2.i8_0]][i2].m0[p1], m1[<-ch0][55&i2/i2^i].m0[func(G3, float64) G2 {
+ return G2(619.2)
+ }(G3(""), 954.0)])
+ }
+ var m7 map[G2]int64
+ var ch7 chan byte
+ var fnc1 func(bool, func(chan G2, struct {
+ h0 G2
+ }, int64) **rune, int) map[complex128]int32 = func(p0 bool, p1 func(chan G2, struct {
+ h0 G2
+ }, int64) **rune, p2 int) map[complex128]int32 {
+ pf2 = pf2
+ as7 = as7
+ return map[complex128]int32{(94.02i - 22.19i) * (fnc0(pi64_0, G2(554.1)*G2(i1), struct {
+ i8_0 G1
+ m1 map[float64]bool
+ i64_2 int64
+ }{G1(68)*i8_0 ^ i8_0, map[float64]bool{f0: <-m6[G1(33)]}, (int64(40) ^ ai64_2[77]) % *pi64_1}, map[byte]func(G2, float64, *uint, float64) struct {
+ }{func(float64, float64) byte {
+ return byte(32)
+ }(878.2, 984.4) + m3[true][12].m0[G2(594.0)]: nil}) - (fnc0(pi64_0, G2(241.1)+G2(i2), struct {
+ i8_0 G1
+ m1 map[float64]bool
+ i64_2 int64
+ }{i8_0, map[float64]bool{904.1: false}, int64(83) + m7[G2(357.7)]}, map[byte]func(G2, float64, *uint, float64) struct {
+ }{byte(85) | m1[true][99].m0[G2(372.7)]: nil}) - (fnc0(pi64_0, G2(239.9), struct {
+ i8_0 G1
+ m1 map[float64]bool
+ i64_2 int64
+ }{G1(68), map[float64]bool{555.6: false}, int64(0)}, map[byte]func(G2, float64, *uint, float64) struct {
+ }{byte(18) & <-ch7: nil}) + (88.17i - 0.55i)))): int32(73) % int32(i)}
+ }
+ as5[54] = as6[(len(func(bool, G2) G3 {
+ return G3("")
+ }(false, G2(190.8)))|i1^i1)%i1-i1] + m2[68 != i || 'M'&'\xf4'|'H'&'\u1311' >= '4'&'\uab3e'>>uint(83) && (<-m6[G1(24)%i8_0] && <-ch1)][i].s1
+ i = len([]G3{ast1[2].s0})
+ i16_0 = <-ch6 / i16_0 & <-ch6
+ i = (i1^i|i2|i2)/i + i
+ m6 = m4
+ am3 = am3
+ m1[G2(869.6) == G2(i2)] = m2[func(float64, rune) byte {
+ return func(G3, byte) byte {
+ return byte(42)
+ }(G3("8iDnlygG194xl"), byte(89))
+ }(*pf2, '\u9cf4')/m1[func(G3, float64) bool {
+ return false
+ }(G3("6MbwBSHYzr9t0zD"), 774.4)][76].m0[G2(508.0)]/m2[<-m4[i8_0]][92&^i2].m0[G2(807.0)] > m3[(int32(39)|int32(i2))&^int32(i2) < int32(i2)][89*i1&i2].m0[G2(327.5)]]
+ m2[<-m4[func(G1, complex128) G1 {
+ return i8_1
+ }(i8_0, 35.01i)] && <-m4[func(int, G1) G1 {
+ return G1(0)
+ }(10, G1(70))*i8_1&i8_1>><-ch2] || fnc0(pi64_0, G2(689.5), struct {
+ i8_0 G1
+ m1 map[float64]bool
+ i64_2 int64
+ }{(G1(78)*i8_1 - i8_1) / i8_1, map[float64]bool{499.2: <-m6[G1(88)^i8_0]}, int64(83) &^ ai64_2[33] & *pi64_1 * ai64_2[i1]}, map[byte]func(G2, float64, *uint, float64) struct {
+ }{m1[len(G3("bNIJZq")+G3("Fri5pn1MsZzYtsaV7b")) >= i][i^i1].m0[G2(691.7)]: nil}) != 71.77i-34.84i] = map[int]struct {
+ m0 map[G2]byte
+ s1 G3
+ }{((18+i2)&^i2%i2 ^ i) / i: m3[(G2(267.1)*G2(i1) > G2(i2) || (false || true || (true || false))) && func(int32, int64) bool {
+ return <-ch0
+ }(int32(63), ai64_2[61&^i1&i2])][i|i^i1]}
+ i2 = 90 - i1
+ _, _, _, _, _, _, _, _ = f0, pf2, ch5, ch6, fnc0, m7, ch7, fnc1
+ } else {
+ var m7 map[G1]chan uint
+ var ch5, ch6, ch7 chan G3
+ var i32_0, i32_1 int32
+ var m8, m9, m10 map[bool]struct {
+ }
+ pi64_1 = pi64_0
+ m6[func(G3, G2) G1 {
+ return (G1(35) | i8_0) << i8_1 / i8_1 &^ i8_1 / i8_1
+ }(G3("YBiKg"), G2(122.6))] = make(chan bool)
+ ast0 = ast0
+ i8_1 = (((G1(10)+i8_1)&i8_0+i8_0)&i8_0&i8_1 ^ i8_1) & i8_1
+ am4 = am3
+ i32_1 = int32(10) &^ i32_0
+ m8[func(float64, G3) bool {
+ return func(rune, int16) bool {
+ return (G2(267.0)*G2(i2) == G2(i) || func(G2, G3) bool {
+ return <-ch0
+ }(G2(53.3), <-ch5)) && func(G2, G1) int32 {
+ return int32(63)
+ }(G2(804.8), G1(2))-i32_0 < i32_1
+ }('\xbd', i16_0)
+ }(370.9, ast0[len([]complex128{})+i-i2].s0) && (G2(245.0)-G2(i1) == G2(i1) || byte(17)&m2[false][26].m0[G2(628.5)] > m3[false][55].m0[G2(608.8)] || func(G1, G1) bool {
+ return true
+ }(G1(24), G1(2)) || (<-m5[G1(38)] || <-ch1) && func(int32, int) bool {
+ return false && true
+ }(int32(6), i1) && '\x26'&'\x27'|func(G2, G3) rune {
+ return '\x13'
+ }(G2(229.6), G3("ys1msVeg61uSImCDkRG3C")) <= 'V'>>uint(88)-('\xbe'+'\uafd4')) == (53.04i == 37.22i)] = m8[func(byte, int64) bool {
+ return <-ch1
+ }(m3[false && false][96].m0[G2(147.6)], *pi64_0) && 643.5 > float64(i1) && (<-ch0 && <-ch1)]
+ i8_1 = func(byte, uint) G1 {
+ return G1(68)
+ }(m2[<-ch1 || <-m5[G1(96)+i8_0] || func(bool, int32) bool {
+ return func(int, byte) bool {
+ return m1[true][89].s1 <= G3("2ZMnHGOMQnyHSbJ")
+ }(i2, m2[<-m6[G1(47)]][94].m0[G2(981.3)])
+ }(<-m4[G1(0)&^i8_0&i8_0], i32_0)][i2%i&^i].m0[func(complex128, rune) G2 {
+ return G2(93.1) * G2(i2)
+ }(4.63i, m0[G2(975.8)])], uint(21))
+ _, _, _, _, _, _, _, _, _ = m7, ch5, ch6, ch7, i32_0, i32_1, m8, m9, m10
+ }
+
+ if *pi64_0>><-ch3 <= *pi64_0 || func(bool, int32) int32 {
+ return (int32(69)&^int32(i2) + int32(i2)) * int32(i2)
+ }(true, int32(49))^int32(i2) >= int32(i) {
+ var ai8_8, ai8_9 []G1
+ var pi2, pi3, pi4 *int
+ var pi8_5, pi8_6 *G1
+ var i64_0, i64_1 int64
+ m1[754.8*float64(i2) != float64(i) && 6.26i == 69.99i] = map[int]struct {
+ m0 map[G2]byte
+ s1 G3
+ }{len([]G2{G2(935.9) / G2(i2), func(int64, G2) G2 {
+ return G2(720.5)
+ }(int64(36), G2(349.7))})&*pi2 + i2 - i1: m1[(uint(29) >= <-ch4 || int64(45)+ai64_2[18] >= *pi64_1) == (func(G2, G2) bool {
+ return <-m5[G1(25)]
+ }(G2(447.2), G2(946.6)) || func(int, int16) bool {
+ return true
+ }(40, int16(41)) && byte(51) >= m2[true][13].m0[G2(6.6)])][*pi3]}
+ am4 = []map[float64]map[G2]*func(*byte, map[uint]int64, G3, struct {
+ }) G2{am4[i2%*pi3]}
+ pi2 = &i2
+ pi64_0 = pi64_1
+ ai8_8[*pi3] = *pi8_5&ai8_9[(*pi4+*pi3)%*pi3] ^ ai8_8[90+i2|*pi4]
+ ai64_2 = []int64{}
+ m4 = m4
+ pi2 = &i1
+ pi3 = &i2
+ _, _, _, _, _, _, _, _, _ = ai8_8, ai8_9, pi2, pi3, pi4, pi8_5, pi8_6, i64_0, i64_1
+ }
+
+ if (true || false || int32(68) > int32(i1) || <-m5[G1(11)-i8_0] && true) && func(int, float64) bool {
+ return <-m5[(G1(83)-i8_1)&^i8_1]
+ }(i1, 886.6) || func(byte, int) bool {
+ return 401.0/float64(i1)/float64(i1)-float64(i) == float64(i2)
+ }(m1[(G1(85)^i8_1)&^i8_1 <= i8_1][72].m0[G2(617.4)], i1) || (<-m6[(G1(3)|i8_0)>><-ch2%i8_0|i8_0] || <-ch0) {
+ var ch5 chan map[byte]complex128
+ var fnc0 func(int32, *map[rune]complex128) complex128
+ var c0 complex128
+ var st0, st1, st2 struct {
+ }
+ var au8 []uint
+ var st3, st4, st5 struct {
+ ph0 *G2
+ st1 struct {
+ m0 map[rune]complex128
+ pch1 *chan int64
+ m2 map[bool]byte
+ st3 struct {
+ ch0 chan func(map[G1]*struct {
+ pm0 *map[bool]int64
+ h1 G2
+ }, struct {
+ u0 uint
+ }, uint, float64) *struct {
+ ch0 chan map[int16]G2
+ }
+ i1 int
+ ch2 chan complex128
+ }
+ }
+ pm2 *map[int64]struct {
+ s0 G3
+ pi1 *int
+ st2 struct {
+ m0 map[int]map[rune]int64
+ r1 rune
+ }
+ }
+ }
+ var am9, am10, am11 []map[uint]int64
+ m1[G3("E")+(*st4.pm2)[*pi64_0+<-*st3.st1.pch1].s0 < (*st4.pm2)[int64(46)].s0+(G3("4Jsp3pv0x")+G3("MTKt98c")+(G3("E6Nxqpl70")+G3("eXhhxb")))+(G3("siISQNeBXoQIHwGB")+G3("CzocwLRWIUD")+(G3("cDWy3E3qpeJOmw1wP9wZ")+G3("S3ZRONdtB7K1LBC"))+func(G1, uint) G3 {
+ return m2[false][74].s1
+ }(G1(9), uint(26)))+func(G2, int) G3 {
+ return G3("WzncXvaqK4zPn")
+ }(G2(291.6), i)+(ast1[(40^i1+i1)&^st4.st1.st3.i1].s0+func(byte, int64) G3 {
+ return m2[207.7 == float64(i2) && (false || false)][i2].s1
+ }(byte(34), am11[25][func(int32, float64) uint {
+ return uint(77)
+ }(int32(29), 403.1)]))] = map[int]struct {
+ m0 map[G2]byte
+ s1 G3
+ }{st3.st1.st3.i1: m2[<-m4[i8_1]][st5.st1.st3.i1-st3.st1.st3.i1-i2]}
+ st1 = struct {
+ }{}
+ pi64_0 = pi64_1
+ m4 = m6
+ as7 = as7
+ m6[(i8_0+i8_0)&^i8_1&^i8_1] = m5[G1(96)^i8_1]
+ st2 = struct {
+ }{}
+ st1 = struct {
+ }{}
+ am10 = []map[uint]int64{am9[len((*st4.pm2)[int64(65)].s0)+i], am11[st4.st1.st3.i1%st4.st1.st3.i1^i1]}
+ i2 = st5.st1.st3.i1*i - st5.st1.st3.i1
+ _, _, _, _, _, _, _, _, _, _, _, _, _ = ch5, fnc0, c0, st0, st1, st2, au8, st3, st4, st5, am9, am10, am11
+ }
+
+}
+
+func main() {
+ F[int16, float32, string]()
+}
diff --git a/test/typeparam/issue48198.go b/test/typeparam/issue48198.go
new file mode 100644
index 0000000..1ed29b8
--- /dev/null
+++ b/test/typeparam/issue48198.go
@@ -0,0 +1,22 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package p
+
+type Foo[T any] struct {
+}
+
+func (foo Foo[T]) Get() {
+}
+
+var(
+ _ = Foo[byte]{}
+ _ = Foo[[]byte]{}
+ _ = Foo[map[byte]rune]{}
+
+ _ = Foo[rune]{}
+ _ = Foo[[]rune]{}
+ _ = Foo[map[rune]byte]{}
+)
diff --git a/test/typeparam/issue48225.go b/test/typeparam/issue48225.go
new file mode 100644
index 0000000..702bc07
--- /dev/null
+++ b/test/typeparam/issue48225.go
@@ -0,0 +1,37 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "reflect"
+
+type Foo[T any] struct {
+ val int
+}
+
+func (foo Foo[T]) Get() *T {
+ if foo.val != 1 {
+ panic("bad val field in Foo receiver")
+ }
+ return new(T)
+}
+
+var (
+ newInt = Foo[int]{val: 1}.Get
+ newString = Foo[string]{val: 1}.Get
+)
+
+func main() {
+ i := newInt()
+ s := newString()
+
+ if t := reflect.TypeOf(i).String(); t != "*int" {
+ panic(t)
+ }
+ if t := reflect.TypeOf(s).String(); t != "*string" {
+ panic(t)
+ }
+}
diff --git a/test/typeparam/issue48253.go b/test/typeparam/issue48253.go
new file mode 100644
index 0000000..20d5db6
--- /dev/null
+++ b/test/typeparam/issue48253.go
@@ -0,0 +1,34 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "reflect"
+)
+
+type A[T any] struct {
+ B[int]
+}
+
+type B[T any] struct {
+}
+
+func (b B[T]) Bat() {
+ t := new(T)
+ if tt := reflect.TypeOf(t); tt.Kind() != reflect.Pointer || tt.Elem().Kind() != reflect.Int {
+ panic("unexpected type, want: *int, got: "+tt.String())
+ }
+}
+
+type Foo struct {
+ A[string]
+}
+func main() {
+ Foo{}.A.Bat()
+ Foo{}.A.B.Bat()
+ Foo{}.Bat()
+}
diff --git a/test/typeparam/issue48276a.go b/test/typeparam/issue48276a.go
new file mode 100644
index 0000000..2a79268
--- /dev/null
+++ b/test/typeparam/issue48276a.go
@@ -0,0 +1,19 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func main() {
+ IsZero[int](0)
+}
+
+func IsZero[T comparable](val T) bool {
+ var zero T
+ fmt.Printf("%v:%v\n", zero, val)
+ return val != zero
+}
diff --git a/test/typeparam/issue48276a.out b/test/typeparam/issue48276a.out
new file mode 100644
index 0000000..8f38db9
--- /dev/null
+++ b/test/typeparam/issue48276a.out
@@ -0,0 +1 @@
+0:0
diff --git a/test/typeparam/issue48276b.go b/test/typeparam/issue48276b.go
new file mode 100644
index 0000000..774898d
--- /dev/null
+++ b/test/typeparam/issue48276b.go
@@ -0,0 +1,15 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ f[interface{}](nil)
+}
+
+func f[T any](x T) {
+ var _ interface{} = x
+}
diff --git a/test/typeparam/issue48280.dir/a.go b/test/typeparam/issue48280.dir/a.go
new file mode 100644
index 0000000..f66fd30
--- /dev/null
+++ b/test/typeparam/issue48280.dir/a.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type I[T any] interface {
+ F() T
+}
+
+type S struct{}
diff --git a/test/typeparam/issue48280.dir/main.go b/test/typeparam/issue48280.dir/main.go
new file mode 100644
index 0000000..2c8387d
--- /dev/null
+++ b/test/typeparam/issue48280.dir/main.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ _ = a.S{}
+}
diff --git a/test/typeparam/issue48280.go b/test/typeparam/issue48280.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48280.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48306.dir/a.go b/test/typeparam/issue48306.dir/a.go
new file mode 100644
index 0000000..fdfd86c
--- /dev/null
+++ b/test/typeparam/issue48306.dir/a.go
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type I[T any] interface {
+ F() T
+}
diff --git a/test/typeparam/issue48306.dir/main.go b/test/typeparam/issue48306.dir/main.go
new file mode 100644
index 0000000..260c3c8
--- /dev/null
+++ b/test/typeparam/issue48306.dir/main.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+type S struct{}
+
+func (*S) F() *S { return nil }
+
+func main() {
+ var _ a.I[*S] = &S{}
+}
diff --git a/test/typeparam/issue48306.go b/test/typeparam/issue48306.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48306.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48317.go b/test/typeparam/issue48317.go
new file mode 100644
index 0000000..0220360
--- /dev/null
+++ b/test/typeparam/issue48317.go
@@ -0,0 +1,38 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "encoding/json"
+)
+
+type A[T any] struct {
+ F1 string `json:"t1"`
+ F2 T `json:"t2"`
+ B B `json:"t3"`
+}
+
+type B struct {
+ F4 int `json:"t4"`
+}
+
+func a[T any]() {
+ data := `{"t1":"1","t2":2,"t3":{"t4":4}}`
+ a1 := A[T]{}
+ if err := json.Unmarshal([]byte(data), &a1); err != nil {
+ panic(err)
+ }
+ if bytes, err := json.Marshal(&a1); err != nil {
+ panic(err)
+ } else if string(bytes) != data {
+ panic(string(bytes))
+ }
+}
+
+func main() {
+ a[int]()
+}
diff --git a/test/typeparam/issue48318.go b/test/typeparam/issue48318.go
new file mode 100644
index 0000000..b75c520
--- /dev/null
+++ b/test/typeparam/issue48318.go
@@ -0,0 +1,33 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "encoding/xml"
+ "fmt"
+)
+
+type A[T, U any] struct {
+ Name T `xml:"name"`
+ Data U `xml:"data"`
+}
+
+func main() {
+ src := &A[string, int]{Name: "name", Data: 1}
+ data, err := xml.Marshal(src)
+ if err != nil {
+ panic(err)
+ }
+ dst := &A[string, int]{}
+ err = xml.Unmarshal(data, dst)
+ if err != nil {
+ panic(err)
+ }
+ if *src != *dst {
+ panic(fmt.Sprintf("wanted %#v got %#v", src, dst))
+ }
+}
diff --git a/test/typeparam/issue48337a.dir/a.go b/test/typeparam/issue48337a.dir/a.go
new file mode 100644
index 0000000..6f1b128
--- /dev/null
+++ b/test/typeparam/issue48337a.dir/a.go
@@ -0,0 +1,32 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import (
+ "fmt"
+ "sync"
+)
+
+type WrapperWithLock[T any] interface {
+ PrintWithLock()
+}
+
+func NewWrapperWithLock[T any](value T) WrapperWithLock[T] {
+ return &wrapperWithLock[T]{
+ Object: value,
+ }
+}
+
+type wrapperWithLock[T any] struct {
+ Lock sync.Mutex
+ Object T
+}
+
+func (w *wrapperWithLock[T]) PrintWithLock() {
+ w.Lock.Lock()
+ defer w.Lock.Unlock()
+
+ fmt.Println(w.Object)
+}
diff --git a/test/typeparam/issue48337a.dir/main.go b/test/typeparam/issue48337a.dir/main.go
new file mode 100644
index 0000000..ddf6724
--- /dev/null
+++ b/test/typeparam/issue48337a.dir/main.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ obj := a.NewWrapperWithLock("this file does import sync")
+ obj.PrintWithLock()
+}
diff --git a/test/typeparam/issue48337a.go b/test/typeparam/issue48337a.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48337a.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48337a.out b/test/typeparam/issue48337a.out
new file mode 100644
index 0000000..fa8d3ee
--- /dev/null
+++ b/test/typeparam/issue48337a.out
@@ -0,0 +1 @@
+this file does import sync
diff --git a/test/typeparam/issue48337b.dir/a.go b/test/typeparam/issue48337b.dir/a.go
new file mode 100644
index 0000000..a3c2e88
--- /dev/null
+++ b/test/typeparam/issue48337b.dir/a.go
@@ -0,0 +1,25 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Container[T any] struct {
+ X T
+}
+
+func NewContainer[T any](x T) *Container[T] {
+ return &Container[T]{x}
+}
+
+type MetaContainer struct {
+ C *Container[Value]
+}
+
+type Value struct{}
+
+func NewMetaContainer() *MetaContainer {
+ c := NewContainer(Value{})
+ // c := &Container[Value]{Value{}} // <-- this works
+ return &MetaContainer{c}
+}
diff --git a/test/typeparam/issue48337b.dir/main.go b/test/typeparam/issue48337b.dir/main.go
new file mode 100644
index 0000000..0318b67
--- /dev/null
+++ b/test/typeparam/issue48337b.dir/main.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ a.NewMetaContainer()
+}
diff --git a/test/typeparam/issue48337b.go b/test/typeparam/issue48337b.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48337b.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48344.go b/test/typeparam/issue48344.go
new file mode 100644
index 0000000..220bce9
--- /dev/null
+++ b/test/typeparam/issue48344.go
@@ -0,0 +1,26 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type G[T any] interface {
+ g()
+}
+
+type Foo[T any] struct {
+}
+
+func (foo *Foo[T]) g() {
+
+}
+
+func f[T any]() {
+ v := []G[T]{}
+ v = append(v, &Foo[T]{})
+}
+func main() {
+ f[int]()
+}
diff --git a/test/typeparam/issue48424.go b/test/typeparam/issue48424.go
new file mode 100644
index 0000000..c5e5d4b
--- /dev/null
+++ b/test/typeparam/issue48424.go
@@ -0,0 +1,54 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Smoke test for constraint literals with elided interface
+// per issue #48424.
+
+package main
+
+func identity[T int](x T) T {
+ return x
+}
+
+func min[T int | string](x, y T) T {
+ if x < y {
+ return x
+ }
+ return y
+}
+
+func max[T ~int | ~float64](x, y T) T {
+ if x > y {
+ return x
+ }
+ return y
+}
+
+func main() {
+ if identity(1) != 1 {
+ panic("identity(1) failed")
+ }
+
+ if min(2, 3) != 2 {
+ panic("min(2, 3) failed")
+ }
+
+ if min("foo", "bar") != "bar" {
+ panic(`min("foo", "bar") failed`)
+ }
+
+ if max(2, 3) != 3 {
+ panic("max(2, 3) failed")
+ }
+}
+
+// Some random type parameter lists with elided interfaces.
+
+type (
+ _[T struct{}] struct{}
+ _[M map[K]V, K comparable, V any] struct{}
+ _[_ interface{} | int] struct{}
+)
diff --git a/test/typeparam/issue48453.go b/test/typeparam/issue48453.go
new file mode 100644
index 0000000..ef8c7f7
--- /dev/null
+++ b/test/typeparam/issue48453.go
@@ -0,0 +1,21 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+//go:noinline
+func CopyMap[M interface{ ~map[K]V }, K comparable, V any](m M) M {
+ out := make(M, len(m))
+ for k, v := range m {
+ out[k] = v
+ }
+ return out
+}
+
+func main() {
+ var m map[*string]int
+ CopyMap(m)
+}
diff --git a/test/typeparam/issue48454.dir/a.go b/test/typeparam/issue48454.dir/a.go
new file mode 100644
index 0000000..9613916
--- /dev/null
+++ b/test/typeparam/issue48454.dir/a.go
@@ -0,0 +1,16 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import "sync"
+
+type Val[T any] struct {
+ mu sync.RWMutex
+ val T
+}
+
+func (v *Val[T]) Has() {
+ v.mu.RLock()
+}
diff --git a/test/typeparam/issue48454.dir/b.go b/test/typeparam/issue48454.dir/b.go
new file mode 100644
index 0000000..deb59d2
--- /dev/null
+++ b/test/typeparam/issue48454.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+type Session struct {
+ privateField a.Val[string]
+}
diff --git a/test/typeparam/issue48454.dir/main.go b/test/typeparam/issue48454.dir/main.go
new file mode 100644
index 0000000..ad9d290
--- /dev/null
+++ b/test/typeparam/issue48454.dir/main.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./b"
+
+func main() {
+ var _ b.Session
+}
diff --git a/test/typeparam/issue48454.go b/test/typeparam/issue48454.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48454.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48462.dir/a.go b/test/typeparam/issue48462.dir/a.go
new file mode 100644
index 0000000..26c704d
--- /dev/null
+++ b/test/typeparam/issue48462.dir/a.go
@@ -0,0 +1,22 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func Unique[T comparable](set []T) []T {
+ nset := make([]T, 0, 8)
+
+loop:
+ for _, s := range set {
+ for _, e := range nset {
+ if s == e {
+ continue loop
+ }
+ }
+
+ nset = append(nset, s)
+ }
+
+ return nset
+}
diff --git a/test/typeparam/issue48462.dir/main.go b/test/typeparam/issue48462.dir/main.go
new file mode 100644
index 0000000..e615367
--- /dev/null
+++ b/test/typeparam/issue48462.dir/main.go
@@ -0,0 +1,23 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+
+ "./a"
+)
+
+func main() {
+ e := []int{1, 2, 2, 3, 1, 6}
+
+ got := a.Unique(e)
+ want := []int{1, 2, 3, 6}
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+}
diff --git a/test/typeparam/issue48462.go b/test/typeparam/issue48462.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48462.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48537.go b/test/typeparam/issue48537.go
new file mode 100644
index 0000000..3ae85c7
--- /dev/null
+++ b/test/typeparam/issue48537.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+}
+
+type C interface {
+ map[int]string
+}
+
+func f[A C]() A {
+ return A{
+ 1: "a",
+ 2: "b",
+ }
+}
diff --git a/test/typeparam/issue48538.go b/test/typeparam/issue48538.go
new file mode 100644
index 0000000..985f84e
--- /dev/null
+++ b/test/typeparam/issue48538.go
@@ -0,0 +1,60 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Testing composite literal for a type param constrained to be a struct or a map.
+
+package p
+
+type C interface {
+ ~struct{ b1, b2 string }
+}
+
+func f[T C]() T {
+ return T{
+ b1: "a",
+ b2: "b",
+ }
+}
+
+func f2[T ~struct{ b1, b2 string }]() T {
+ return T{
+ b1: "a",
+ b2: "b",
+ }
+}
+
+type D interface {
+ map[string]string | S
+}
+
+type S map[string]string
+
+func g[T D]() T {
+ b1 := "foo"
+ b2 := "bar"
+ return T{
+ b1: "a",
+ b2: "b",
+ }
+}
+
+func g2[T map[string]string]() T {
+ b1 := "foo"
+ b2 := "bar"
+ return T{
+ b1: "a",
+ b2: "b",
+ }
+}
+
+func g3[T S]() T {
+ b1 := "foo"
+ b2 := "bar"
+ return T{
+ b1: "a",
+ b2: "b",
+ }
+}
diff --git a/test/typeparam/issue48598.go b/test/typeparam/issue48598.go
new file mode 100644
index 0000000..945b332
--- /dev/null
+++ b/test/typeparam/issue48598.go
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Iterator[T any] interface {
+ Iterate()
+}
+
+type IteratorFunc[T any] func(fn func(T) bool)
+
+func (f IteratorFunc[T]) Iterate() {
+}
+
+func FromIterator[T any](it Iterator[T]) {
+ it.Iterate()
+}
+
+func Foo[T, R any]() {
+ FromIterator[R](IteratorFunc[R](nil))
+}
+
+func main() {
+ Foo[int, int]()
+}
diff --git a/test/typeparam/issue48602.go b/test/typeparam/issue48602.go
new file mode 100644
index 0000000..c544697
--- /dev/null
+++ b/test/typeparam/issue48602.go
@@ -0,0 +1,25 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Iterator[T any] interface {
+ Iterate(fn T)
+}
+
+type IteratorFunc[T any] func(fn T)
+
+func (f IteratorFunc[T]) Iterate(fn T) {
+ f(fn)
+}
+
+func Foo[R any]() {
+ var _ Iterator[R] = IteratorFunc[R](nil)
+}
+
+func main() {
+ Foo[int]()
+}
diff --git a/test/typeparam/issue48604.go b/test/typeparam/issue48604.go
new file mode 100644
index 0000000..348abf7
--- /dev/null
+++ b/test/typeparam/issue48604.go
@@ -0,0 +1,25 @@
+// build
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Foo[T any] interface {
+ CreateBar() Bar[T]
+}
+
+type Bar[T any] func() Bar[T]
+
+func (f Bar[T]) CreateBar() Bar[T] {
+ return f
+}
+
+func abc[R any]() {
+ var _ Foo[R] = Bar[R](nil)()
+}
+
+func main() {
+ abc[int]()
+} \ No newline at end of file
diff --git a/test/typeparam/issue48609.go b/test/typeparam/issue48609.go
new file mode 100644
index 0000000..53144d2
--- /dev/null
+++ b/test/typeparam/issue48609.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f[T ~chan E, E any](e E) T {
+ ch := make(T)
+ go func() {
+ defer close(ch)
+ ch <- e
+ }()
+ return ch
+}
diff --git a/test/typeparam/issue48617.go b/test/typeparam/issue48617.go
new file mode 100644
index 0000000..96978d4
--- /dev/null
+++ b/test/typeparam/issue48617.go
@@ -0,0 +1,29 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Foo[T any] interface {
+ CreateBar() Bar[T]
+}
+
+type Bar[T any] func() Bar[T]
+
+func (f Bar[T]) CreateBar() Bar[T] {
+ return f
+}
+
+func abc[T any]() {
+ var b Bar[T] = func() Bar[T] {
+ var b Bar[T]
+ return b
+ }
+ var _ Foo[T] = b()
+}
+
+func main() {
+ abc[int]()
+}
diff --git a/test/typeparam/issue48645a.go b/test/typeparam/issue48645a.go
new file mode 100644
index 0000000..39267a9
--- /dev/null
+++ b/test/typeparam/issue48645a.go
@@ -0,0 +1,31 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type Stream[T any] struct {
+}
+
+func (s Stream[T]) DropWhile() Stream[T] {
+ return Pipe[T, T](s)
+}
+
+func Pipe[T, R any](s Stream[T]) Stream[R] {
+ it := func(fn func(R) bool) {
+ }
+ fmt.Println(reflect.TypeOf(it).String())
+ return Stream[R]{}
+}
+
+func main() {
+ s := Stream[int]{}
+ s = s.DropWhile()
+}
diff --git a/test/typeparam/issue48645a.out b/test/typeparam/issue48645a.out
new file mode 100644
index 0000000..5093d0f
--- /dev/null
+++ b/test/typeparam/issue48645a.out
@@ -0,0 +1 @@
+func(func(int) bool)
diff --git a/test/typeparam/issue48645b.go b/test/typeparam/issue48645b.go
new file mode 100644
index 0000000..619e7ee
--- /dev/null
+++ b/test/typeparam/issue48645b.go
@@ -0,0 +1,81 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Iterator[T any] interface {
+ Iterate(fn func(T) bool)
+}
+
+type IteratorFunc[T any] func(fn func(T) bool)
+
+func (f IteratorFunc[T]) Iterate(fn func(T) bool) {
+ f(fn)
+}
+
+type Stream[T any] struct {
+ it Iterator[T]
+}
+
+func (s Stream[T]) Iterate(fn func(T) bool) {
+ if s.it == nil {
+ return
+ }
+ s.it.Iterate(fn)
+}
+
+func FromIterator[T any](it Iterator[T]) Stream[T] {
+ return Stream[T]{it: it}
+}
+
+func (s Stream[T]) DropWhile(fn func(T) bool) Stream[T] {
+ return Pipe[T, T](s, func(t T) (T, bool) {
+ return t, true
+ })
+}
+
+func Pipe[T, R any](s Stream[T], op func(d T) (R, bool)) Stream[R] {
+ it := func(fn func(R) bool) {
+ // XXX Not getting the closure right when converting to interface.
+ // s.it.Iterate(func(t T) bool {
+ // r, ok := op(t)
+ // if !ok {
+ // return true
+ // }
+
+ // return fn(r)
+ // })
+ }
+
+ return FromIterator[R](IteratorFunc[R](it))
+}
+
+func Reduce[T, U any](s Stream[T], identity U, acc func(U, T) U) (r U) {
+ r = identity
+ s.Iterate(func(t T) bool {
+ r = acc(r, t)
+ return true
+ })
+
+ return r
+}
+
+type myIterator struct {
+}
+
+func (myIterator) Iterate(fn func(int) bool) {
+}
+
+func main() {
+ s := Stream[int]{}
+ s.it = myIterator{}
+ s = s.DropWhile(func(i int) bool {
+ return false
+ })
+ Reduce(s, nil, func(acc []int, e int) []int {
+ return append(acc, e)
+ })
+}
diff --git a/test/typeparam/issue48711.go b/test/typeparam/issue48711.go
new file mode 100644
index 0000000..477a5d5
--- /dev/null
+++ b/test/typeparam/issue48711.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[T interface{ ~[]P }, P any](t T) { // ERROR "instantiation cycle"
+ if t == nil {
+ return
+ }
+ f[[]T, T]([]T{t})
+}
+
+func main() {
+ f[[]int](nil)
+}
diff --git a/test/typeparam/issue48716.dir/a.go b/test/typeparam/issue48716.dir/a.go
new file mode 100644
index 0000000..63e599d
--- /dev/null
+++ b/test/typeparam/issue48716.dir/a.go
@@ -0,0 +1,51 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Pair[L, R any] struct {
+ L L
+ R R
+}
+
+func Two[L, R any](l L, r R) Pair[L, R] {
+ return Pair[L, R]{L: l, R: r}
+}
+
+type Map[K, V any] interface {
+ Put(K, V)
+ Len() int
+ Iterate(func(Pair[K, V]) bool)
+}
+
+type HashMap[K comparable, V any] struct {
+ m map[K]V
+}
+
+func NewHashMap[K comparable, V any](capacity int) HashMap[K, V] {
+ var m map[K]V
+ if capacity >= 1 {
+ m = make(map[K]V, capacity)
+ } else {
+ m = map[K]V{}
+ }
+
+ return HashMap[K, V]{m: m}
+}
+
+func (m HashMap[K, V]) Put(k K, v V) {
+ m.m[k] = v
+}
+
+func (m HashMap[K, V]) Len() int {
+ return len(m.m)
+}
+
+func (m HashMap[K, V]) Iterate(cb func(Pair[K, V]) bool) {
+ for k, v := range m.m {
+ if !cb(Two(k, v)) {
+ return
+ }
+ }
+}
diff --git a/test/typeparam/issue48716.dir/main.go b/test/typeparam/issue48716.dir/main.go
new file mode 100644
index 0000000..13a126e
--- /dev/null
+++ b/test/typeparam/issue48716.dir/main.go
@@ -0,0 +1,58 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+)
+
+// Creates copy of set
+func Copy[T comparable](src MapSet[T]) (dst MapSet[T]) {
+ dst = HashSet[T](src.Len())
+ Fill(src, dst)
+ return
+}
+
+// Fill src from dst
+func Fill[T any](src, dst MapSet[T]) {
+ src.Iterate(func(t T) bool {
+ dst.Add(t)
+ return true
+ })
+ return
+}
+
+type MapSet[T any] struct {
+ m a.Map[T, struct{}]
+}
+
+func HashSet[T comparable](capacity int) MapSet[T] {
+ return FromMap[T](a.NewHashMap[T, struct{}](capacity))
+}
+
+func FromMap[T any](m a.Map[T, struct{}]) MapSet[T] {
+ return MapSet[T]{
+ m: m,
+ }
+}
+
+func (s MapSet[T]) Add(t T) {
+ s.m.Put(t, struct{}{})
+}
+
+func (s MapSet[T]) Len() int {
+ return s.m.Len()
+}
+
+func (s MapSet[T]) Iterate(cb func(T) bool) {
+ s.m.Iterate(func(p a.Pair[T, struct{}]) bool {
+ return cb(p.L)
+ })
+}
+
+func main() {
+ x := FromMap[int](a.NewHashMap[int, struct{}](1))
+ Copy[int](x)
+}
diff --git a/test/typeparam/issue48716.go b/test/typeparam/issue48716.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue48716.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue48838.go b/test/typeparam/issue48838.go
new file mode 100644
index 0000000..1711d04
--- /dev/null
+++ b/test/typeparam/issue48838.go
@@ -0,0 +1,31 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ check[string]()
+}
+
+func check[T any]() {
+ var result setter[T]
+ switch result.(type) {
+ case fooA[T]:
+ case fooB[T]:
+ }
+}
+
+type setter[T any] interface {
+ Set(T)
+}
+
+type fooA[T any] struct{}
+
+func (fooA[T]) Set(T) {}
+
+type fooB[T any] struct{}
+
+func (fooB[T]) Set(T) {}
diff --git a/test/typeparam/issue48962.dir/a.go b/test/typeparam/issue48962.dir/a.go
new file mode 100644
index 0000000..a6d2734
--- /dev/null
+++ b/test/typeparam/issue48962.dir/a.go
@@ -0,0 +1,12 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type (
+ A[P any] [10]P
+ S[P any] struct{ f P }
+ P[P any] *P
+ M[K comparable, V any] map[K]V
+)
diff --git a/test/typeparam/issue48962.dir/b.go b/test/typeparam/issue48962.dir/b.go
new file mode 100644
index 0000000..e4eaa06
--- /dev/null
+++ b/test/typeparam/issue48962.dir/b.go
@@ -0,0 +1,51 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+type (
+ lA[P any] [10]P
+ lS[P any] struct{ f P }
+ lP[P any] *P
+ lM[K comparable, V any] map[K]V
+)
+
+// local cycles
+type (
+ A lA[A] // ERROR "invalid recursive type"
+ S lS[S] // ERROR "invalid recursive type"
+ P lP[P] // ok (indirection through lP)
+ M1 lM[int, M1] // ok (indirection through lM)
+ M2 lM[lA[byte], M2] // ok (indirection through lM)
+
+ A2 lA[lS[lP[A2]]] // ok (indirection through lP)
+ A3 lA[lS[lS[A3]]] // ERROR "invalid recursive type"
+)
+
+// cycles through imported types
+type (
+ Ai a.A[Ai] // ERROR "invalid recursive type"
+ Si a.S[Si] // ERROR "invalid recursive type"
+ Pi a.P[Pi] // ok (indirection through a.P)
+ M1i a.M[int, M1i] // ok (indirection through a.M)
+ M2i a.M[a.A[byte], M2i] // ok (indirection through a.M)
+
+ A2i a.A[a.S[a.P[A2i]]] // ok (indirection through a.P)
+ A3i a.A[a.S[a.S[A3i]]] // ERROR "invalid recursive type"
+
+ T2 a.S[T0[T2]] // ERROR "invalid recursive type"
+ T3 T0[Ai] // no follow-on error here
+)
+
+// test case from issue
+
+type T0[P any] struct {
+ f P
+}
+
+type T1 struct { // ERROR "invalid recursive type"
+ _ T0[T1]
+}
diff --git a/test/typeparam/issue48962.go b/test/typeparam/issue48962.go
new file mode 100644
index 0000000..24d0eb0
--- /dev/null
+++ b/test/typeparam/issue48962.go
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue49027.dir/a.go b/test/typeparam/issue49027.dir/a.go
new file mode 100644
index 0000000..da88297
--- /dev/null
+++ b/test/typeparam/issue49027.dir/a.go
@@ -0,0 +1,55 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func Conv(v interface{}) string {
+ return conv[string](v)
+}
+
+func conv[T any](v interface{}) T {
+ return v.(T)
+}
+
+func Conv2(v interface{}) (string, bool) {
+ return conv2[string](v)
+}
+
+func conv2[T any](v interface{}) (T, bool) {
+ x, ok := v.(T)
+ return x, ok
+}
+
+func Conv3(v interface{}) string {
+ return conv3[string](v)
+}
+
+func conv3[T any](v interface{}) T {
+ switch v := v.(type) {
+ case T:
+ return v
+ default:
+ var z T
+ return z
+ }
+}
+
+type Mystring string
+
+func (Mystring) Foo() {
+}
+
+func Conv4(v interface{Foo()}) Mystring {
+ return conv4[Mystring](v)
+}
+
+func conv4[T interface{Foo()}](v interface{Foo()}) T {
+ switch v := v.(type) {
+ case T:
+ return v
+ default:
+ var z T
+ return z
+ }
+}
diff --git a/test/typeparam/issue49027.dir/main.go b/test/typeparam/issue49027.dir/main.go
new file mode 100644
index 0000000..d998c5b
--- /dev/null
+++ b/test/typeparam/issue49027.dir/main.go
@@ -0,0 +1,33 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ s := "foo"
+ x := a.Conv(s)
+ if x != s {
+ panic(fmt.Sprintf("got %s wanted %s", x, s))
+ }
+ y, ok := a.Conv2(s)
+ if !ok {
+ panic("conversion failed")
+ }
+ if y != s {
+ panic(fmt.Sprintf("got %s wanted %s", y, s))
+ }
+ z := a.Conv3(s)
+ if z != s {
+ panic(fmt.Sprintf("got %s wanted %s", z, s))
+ }
+ w := a.Conv4(a.Mystring(s))
+ if w != a.Mystring(s) {
+ panic(fmt.Sprintf("got %s wanted %s", w, s))
+ }
+}
diff --git a/test/typeparam/issue49027.go b/test/typeparam/issue49027.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue49027.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue49049.go b/test/typeparam/issue49049.go
new file mode 100644
index 0000000..b4b3bae
--- /dev/null
+++ b/test/typeparam/issue49049.go
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type A[T any] interface {
+ m()
+}
+
+type Z struct {
+ a,b int
+}
+
+func (z *Z) m() {
+}
+
+func test[T any]() {
+ var a A[T] = &Z{}
+ f := a.m
+ f()
+}
+func main() {
+ test[string]()
+}
diff --git a/test/typeparam/issue49241.dir/a.go b/test/typeparam/issue49241.dir/a.go
new file mode 100644
index 0000000..34c9965
--- /dev/null
+++ b/test/typeparam/issue49241.dir/a.go
@@ -0,0 +1,13 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type T[P any] struct {
+ x P
+}
+
+type U struct {
+ a,b int
+}
diff --git a/test/typeparam/issue49241.dir/b.go b/test/typeparam/issue49241.dir/b.go
new file mode 100644
index 0000000..e5f1e12
--- /dev/null
+++ b/test/typeparam/issue49241.dir/b.go
@@ -0,0 +1,17 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+//go:noinline
+func F() interface{} {
+ return a.T[int]{}
+}
+
+//go:noinline
+func G() interface{} {
+ return struct{ X, Y a.U }{}
+}
diff --git a/test/typeparam/issue49241.dir/c.go b/test/typeparam/issue49241.dir/c.go
new file mode 100644
index 0000000..34ea7c3
--- /dev/null
+++ b/test/typeparam/issue49241.dir/c.go
@@ -0,0 +1,17 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package c
+
+import "./a"
+
+//go:noinline
+func F() interface{} {
+ return a.T[int]{}
+}
+
+//go:noinline
+func G() interface{} {
+ return struct{ X, Y a.U }{}
+}
diff --git a/test/typeparam/issue49241.dir/main.go b/test/typeparam/issue49241.dir/main.go
new file mode 100644
index 0000000..58bb8a0
--- /dev/null
+++ b/test/typeparam/issue49241.dir/main.go
@@ -0,0 +1,21 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./b"
+ "./c"
+)
+
+func main() {
+ if b.G() != c.G() {
+ println(b.G(), c.G())
+ panic("bad")
+ }
+ if b.F() != c.F() {
+ println(b.F(), c.F())
+ panic("bad")
+ }
+}
diff --git a/test/typeparam/issue49241.go b/test/typeparam/issue49241.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue49241.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue49246.dir/a.go b/test/typeparam/issue49246.dir/a.go
new file mode 100644
index 0000000..97459ee
--- /dev/null
+++ b/test/typeparam/issue49246.dir/a.go
@@ -0,0 +1,20 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type R[T any] struct{ v T }
+
+func (r R[T]) Self() R[T] { return R[T]{} }
+
+type Fn[T any] func() R[T]
+
+func X() (r R[int]) { return r.Self() }
+
+func Y[T any](a Fn[T]) Fn[int] {
+ return func() (r R[int]) {
+ // No crash: return R[int]{}
+ return r.Self()
+ }
+}
diff --git a/test/typeparam/issue49246.dir/b.go b/test/typeparam/issue49246.dir/b.go
new file mode 100644
index 0000000..5141b72
--- /dev/null
+++ b/test/typeparam/issue49246.dir/b.go
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func Crash() { a.Y(a.X)() }
diff --git a/test/typeparam/issue49246.go b/test/typeparam/issue49246.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue49246.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue49295.go b/test/typeparam/issue49295.go
new file mode 100644
index 0000000..f96c896
--- /dev/null
+++ b/test/typeparam/issue49295.go
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "io"
+
+type Reader struct {
+ buf []byte
+}
+type Token *[16]byte
+
+func Read[T interface{ ~*[16]byte }](r *Reader) (t T, err error) {
+ if n := len(t); len(r.buf) >= n {
+ t = T(r.buf[:n])
+ r.buf = r.buf[n:]
+ return
+ }
+ err = io.EOF
+ return
+}
+
+func main() {
+ r := &Reader{buf: []byte("0123456789abcdef")}
+ token, err := Read[Token](r)
+ _, _ = token, err
+}
diff --git a/test/typeparam/issue49309.go b/test/typeparam/issue49309.go
new file mode 100644
index 0000000..16c97cd
--- /dev/null
+++ b/test/typeparam/issue49309.go
@@ -0,0 +1,26 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func genfunc[T any](f func(c T)) {
+ var r T
+
+ f(r)
+}
+
+func myfunc(c string) {
+ test2(c)
+}
+
+//go:noinline
+func test2(a interface{}) {
+ _ = a.(string)
+}
+
+func main() {
+ genfunc(myfunc)
+}
diff --git a/test/typeparam/issue49421.go b/test/typeparam/issue49421.go
new file mode 100644
index 0000000..65c32af
--- /dev/null
+++ b/test/typeparam/issue49421.go
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ var a, b foo
+ bar(a, b)
+}
+
+type foo int
+
+func (a foo) less(b foo) bool {
+ return a < b
+}
+
+type lesser[T any] interface {
+ less(T) bool
+ comparable
+}
+
+func bar[T lesser[T]](a, b T) {
+ a.less(b)
+}
diff --git a/test/typeparam/issue49432.go b/test/typeparam/issue49432.go
new file mode 100644
index 0000000..d522b22
--- /dev/null
+++ b/test/typeparam/issue49432.go
@@ -0,0 +1,22 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Handler func(in ...interface{})
+
+type Foo[T any] struct{}
+
+func (b *Foo[T]) Bar(in ...interface{}) {}
+
+func (b *Foo[T]) Init() {
+ _ = Handler(b.Bar)
+}
+
+func main() {
+ c := &Foo[int]{}
+ c.Init()
+}
diff --git a/test/typeparam/issue49497.dir/a.go b/test/typeparam/issue49497.dir/a.go
new file mode 100644
index 0000000..86062d4
--- /dev/null
+++ b/test/typeparam/issue49497.dir/a.go
@@ -0,0 +1,26 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F[T any]() A[T] {
+ var x A[T]
+ return x
+}
+
+type A[T any] struct {
+ b B[T]
+}
+
+func (a A[T]) M() C[T] {
+ return C[T]{
+ B: a.b,
+ }
+}
+
+type B[T any] struct{}
+
+type C[T any] struct {
+ B B[T]
+}
diff --git a/test/typeparam/issue49497.dir/main.go b/test/typeparam/issue49497.dir/main.go
new file mode 100644
index 0000000..e74dae0
--- /dev/null
+++ b/test/typeparam/issue49497.dir/main.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ a.F[string]()
+}
diff --git a/test/typeparam/issue49497.go b/test/typeparam/issue49497.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue49497.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue49516.go b/test/typeparam/issue49516.go
new file mode 100644
index 0000000..11b460d
--- /dev/null
+++ b/test/typeparam/issue49516.go
@@ -0,0 +1,26 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type Q[T any] struct {
+ s []T
+}
+
+func (q *Q[T]) Push(v ...T) {
+ q.s = append(q.s, v...)
+}
+
+func pushN(push func(*Q[int], ...int), n int) {
+ var q Q[int]
+ for i := 0; i < n; i++ {
+ push(&q, i)
+ }
+}
+
+func f() {
+ pushN((*Q[int]).Push, 100)
+}
diff --git a/test/typeparam/issue49524.dir/a.go b/test/typeparam/issue49524.dir/a.go
new file mode 100644
index 0000000..f40075e
--- /dev/null
+++ b/test/typeparam/issue49524.dir/a.go
@@ -0,0 +1,8 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F[T any]() {
+}
diff --git a/test/typeparam/issue49524.dir/main.go b/test/typeparam/issue49524.dir/main.go
new file mode 100644
index 0000000..8787e7e
--- /dev/null
+++ b/test/typeparam/issue49524.dir/main.go
@@ -0,0 +1,11 @@
+package main
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import "./a"
+
+func main() {
+ a.F[int]()
+}
diff --git a/test/typeparam/issue49524.go b/test/typeparam/issue49524.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue49524.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue49536.dir/a.go b/test/typeparam/issue49536.dir/a.go
new file mode 100644
index 0000000..a95ad60
--- /dev/null
+++ b/test/typeparam/issue49536.dir/a.go
@@ -0,0 +1,12 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F() interface{} { return new(T[int]) }
+
+type T[P any] int
+
+func (x *T[P]) One() int { return x.Two() }
+func (x *T[P]) Two() int { return 0 }
diff --git a/test/typeparam/issue49536.dir/b.go b/test/typeparam/issue49536.dir/b.go
new file mode 100644
index 0000000..b08a77b
--- /dev/null
+++ b/test/typeparam/issue49536.dir/b.go
@@ -0,0 +1,9 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+var _ = a.F()
diff --git a/test/typeparam/issue49536.go b/test/typeparam/issue49536.go
new file mode 100644
index 0000000..8bb5c3e
--- /dev/null
+++ b/test/typeparam/issue49536.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue49538.go b/test/typeparam/issue49538.go
new file mode 100644
index 0000000..cb22a06
--- /dev/null
+++ b/test/typeparam/issue49538.go
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type I interface {
+ M(interface{})
+}
+
+type a[T any] struct{}
+
+func (a[T]) M(interface{}) {}
+
+func f[T I](t *T) {
+ (*t).M(t)
+}
+
+func g() {
+ f(&a[int]{})
+}
diff --git a/test/typeparam/issue49547.go b/test/typeparam/issue49547.go
new file mode 100644
index 0000000..6d359ba
--- /dev/null
+++ b/test/typeparam/issue49547.go
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type foo int
+
+func main() {
+ want := "main.F[main.foo]"
+ got := fmt.Sprintf("%T", F[foo]{})
+ if got != want {
+ fmt.Printf("want: %s, got: %s\n", want, got)
+ }
+}
+
+type F[T any] struct {
+}
diff --git a/test/typeparam/issue49611.go b/test/typeparam/issue49611.go
new file mode 100644
index 0000000..879e4d2
--- /dev/null
+++ b/test/typeparam/issue49611.go
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f[T any]() {
+ var ()
+}
diff --git a/test/typeparam/issue49659.dir/a.go b/test/typeparam/issue49659.dir/a.go
new file mode 100644
index 0000000..718bc0c
--- /dev/null
+++ b/test/typeparam/issue49659.dir/a.go
@@ -0,0 +1,13 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type A[T any] struct {
+ a int
+}
+
+func (a A[T]) F() {
+ _ = &a.a
+}
diff --git a/test/typeparam/issue49659.dir/b.go b/test/typeparam/issue49659.dir/b.go
new file mode 100644
index 0000000..4818a42
--- /dev/null
+++ b/test/typeparam/issue49659.dir/b.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+type B[T any] struct {
+ v a.A[T]
+}
+
+func (b B[T]) F() {
+ b.v.F()
+}
diff --git a/test/typeparam/issue49659.go b/test/typeparam/issue49659.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue49659.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue49659b.go b/test/typeparam/issue49659b.go
new file mode 100644
index 0000000..7e1535e
--- /dev/null
+++ b/test/typeparam/issue49659b.go
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Testing that AddrTaken logic doesn't cause problems for function instantiations
+
+package main
+
+type A[T interface{ []int | [5]int }] struct {
+ val T
+}
+
+//go:noinline
+func (a A[T]) F() {
+ _ = &a.val[2]
+}
+
+func main() {
+ var x A[[]int]
+ x.val = make([]int, 4)
+ _ = &x.val[3]
+ x.F()
+ var y A[[5]int]
+ _ = &y.val[3]
+ y.F()
+}
diff --git a/test/typeparam/issue49667.dir/a.go b/test/typeparam/issue49667.dir/a.go
new file mode 100644
index 0000000..3b1889f
--- /dev/null
+++ b/test/typeparam/issue49667.dir/a.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type A[T any] struct {
+}
+
+func (a A[T]) F() {
+ _ = a
+}
diff --git a/test/typeparam/issue49667.dir/b.go b/test/typeparam/issue49667.dir/b.go
new file mode 100644
index 0000000..81cdb80
--- /dev/null
+++ b/test/typeparam/issue49667.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+type B[T any] struct {
+ _ a.A[T]
+}
diff --git a/test/typeparam/issue49667.dir/main.go b/test/typeparam/issue49667.dir/main.go
new file mode 100644
index 0000000..f9fa60f
--- /dev/null
+++ b/test/typeparam/issue49667.dir/main.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./b"
+
+func main() {
+ var _ b.B[int]
+}
diff --git a/test/typeparam/issue49667.go b/test/typeparam/issue49667.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue49667.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue49875.go b/test/typeparam/issue49875.go
new file mode 100644
index 0000000..3fbe48c
--- /dev/null
+++ b/test/typeparam/issue49875.go
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f(args ...interface{}) {}
+
+func g() {
+ var args []any
+ f(args...)
+}
diff --git a/test/typeparam/issue49893.dir/a.go b/test/typeparam/issue49893.dir/a.go
new file mode 100644
index 0000000..bc810cd
--- /dev/null
+++ b/test/typeparam/issue49893.dir/a.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Option[T any] interface {
+ ToSeq() Seq[T]
+}
+
+type Seq[T any] []T
+
+func (r Seq[T]) Find(p func(v T) bool) Option[T] {
+ panic("")
+}
diff --git a/test/typeparam/issue49893.dir/b.go b/test/typeparam/issue49893.dir/b.go
new file mode 100644
index 0000000..b86b536
--- /dev/null
+++ b/test/typeparam/issue49893.dir/b.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+type Ap1[A, B any] struct {
+ opt a.Option[A]
+}
+
+type Ap2[A, B any] struct {
+ opt a.Option[A]
+}
diff --git a/test/typeparam/issue49893.dir/main.go b/test/typeparam/issue49893.dir/main.go
new file mode 100644
index 0000000..447212d
--- /dev/null
+++ b/test/typeparam/issue49893.dir/main.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./b"
+ "fmt"
+)
+
+func main() {
+ opt := b.Ap1[string, string]{}
+ fmt.Println(opt)
+}
diff --git a/test/typeparam/issue49893.go b/test/typeparam/issue49893.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue49893.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50002.go b/test/typeparam/issue50002.go
new file mode 100644
index 0000000..42d97f5
--- /dev/null
+++ b/test/typeparam/issue50002.go
@@ -0,0 +1,64 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test for cases where certain instantiations of a generic function (F in this
+// example) will always fail on a type assertion or mismatch on a type case.
+
+package main
+
+import "fmt"
+
+type S struct{}
+
+func (S) M() byte {
+ return 0
+}
+
+type I[T any] interface {
+ M() T
+}
+
+func F[T, A any](x I[T], shouldMatch bool) {
+ switch x.(type) {
+ case A:
+ if !shouldMatch {
+ fmt.Printf("wanted mis-match, got match")
+ }
+ default:
+ if shouldMatch {
+ fmt.Printf("wanted match, got mismatch")
+ }
+ }
+
+ _, ok := x.(A)
+ if ok != shouldMatch {
+ fmt.Printf("ok: got %v, wanted %v", ok, shouldMatch)
+ }
+
+ if !shouldMatch {
+ defer func() {
+ if shouldMatch {
+ fmt.Printf("Shouldn't have panicked")
+ }
+ recover()
+ }()
+ }
+ _ = x.(A)
+ if !shouldMatch {
+ fmt.Printf("Should have panicked")
+ }
+}
+
+func main() {
+ // Test instantiation where the type switch/type asserts can't possibly succeed
+ // (since string does not implement I[byte]).
+ F[byte, string](S{}, false)
+
+ // Test instantiation where the type switch/type asserts should succeed
+ // (since S does implement I[byte])
+ F[byte, S](S{}, true)
+ F[byte, S](I[byte](S{}), true)
+}
diff --git a/test/typeparam/issue50109.go b/test/typeparam/issue50109.go
new file mode 100644
index 0000000..30aebb2
--- /dev/null
+++ b/test/typeparam/issue50109.go
@@ -0,0 +1,105 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type AnyCacher[T any] interface {
+ // Get an item from the cache. Returns the item or nil, and a bool indicating
+ // whether the key was found.
+ Get(k string) (T, bool)
+ // Add an item to the cache, replacing any existing item.
+ Set(k string, x T)
+}
+
+// Item ...
+type Item[T any] struct {
+ Object T
+}
+
+// AnyCache implements AnyCacher
+type AnyCache[T any] struct {
+ *anyCache[T]
+}
+
+type anyCache[T any] struct {
+ items map[string]Item[T]
+ janitor *janitor[T] // Needed for the failure in the issue
+}
+
+// Set adds an item to the cache, replacing any existing item.
+func (c *anyCache[T]) Set(k string, x T) {
+ c.items[k] = Item[T]{
+ Object: x,
+ }
+}
+
+// Get gets an item from the cache. Returns the item or nil, and a bool indicating
+// whether the key was found.
+func (c *anyCache[T]) Get(k string) (T, bool) {
+ // "Inlining" of get and Expired
+ item, found := c.items[k]
+ if !found {
+ var ret T
+ return ret, false
+ }
+
+ return item.Object, true
+}
+
+type janitor[T any] struct {
+ stop chan bool
+}
+
+func newAnyCache[T any](m map[string]Item[T]) *anyCache[T] {
+ c := &anyCache[T]{
+ items: m,
+ }
+ return c
+}
+
+// NewAny[T any](...) returns a new AnyCache[T].
+func NewAny[T any]() *AnyCache[T] {
+ items := make(map[string]Item[T])
+ return &AnyCache[T]{newAnyCache(items)}
+}
+
+// NewAnyCacher[T any](...) returns an AnyCacher[T] interface.
+func NewAnyCacher[T any]() AnyCacher[T] {
+ return NewAny[T]()
+}
+
+type MyStruct struct {
+ Name string
+}
+
+func main() {
+ // Create a generic cache.
+ // All items are cached as interface{} so they need to be cast back to their
+ // original type when retrieved.
+ // Failure in issue doesn't happen with 'any' replaced by 'interface{}'
+ c := NewAnyCacher[any]()
+
+ myStruct := &MyStruct{"MySuperStruct"}
+
+ c.Set("MySuperStruct", myStruct)
+
+ myRawCachedStruct, found := c.Get("MySuperStruct")
+
+ if found {
+ // Casting the retrieved object back to its original type
+ myCachedStruct := myRawCachedStruct.(*MyStruct)
+ fmt.Printf("%s", myCachedStruct.Name)
+ } else {
+ fmt.Printf("Error: MySuperStruct not found in cache")
+ }
+
+ // Output:
+ // MySuperStruct
+}
diff --git a/test/typeparam/issue50109.out b/test/typeparam/issue50109.out
new file mode 100644
index 0000000..7d6ecc0
--- /dev/null
+++ b/test/typeparam/issue50109.out
@@ -0,0 +1 @@
+MySuperStruct \ No newline at end of file
diff --git a/test/typeparam/issue50109b.go b/test/typeparam/issue50109b.go
new file mode 100644
index 0000000..ee49441
--- /dev/null
+++ b/test/typeparam/issue50109b.go
@@ -0,0 +1,29 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ F[any]()
+}
+
+func F[T any]() I[T] {
+ return (*S1[T])(nil)
+}
+
+type I[T any] interface{}
+
+type S1[T any] struct {
+ *S2[T]
+}
+
+type S2[T any] struct {
+ S3 *S3[T]
+}
+
+type S3[T any] struct {
+ x int
+}
diff --git a/test/typeparam/issue50121.dir/a.go b/test/typeparam/issue50121.dir/a.go
new file mode 100644
index 0000000..ca11b6b
--- /dev/null
+++ b/test/typeparam/issue50121.dir/a.go
@@ -0,0 +1,26 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import (
+ "math/rand"
+)
+
+type Integer interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+type Builder[T Integer] struct{}
+
+func (r Builder[T]) New() T {
+ return T(rand.Int())
+}
+
+var IntBuilder = Builder[int]{}
+
+func BuildInt() int {
+ return IntBuilder.New()
+}
diff --git a/test/typeparam/issue50121.dir/main.go b/test/typeparam/issue50121.dir/main.go
new file mode 100644
index 0000000..3978ef4
--- /dev/null
+++ b/test/typeparam/issue50121.dir/main.go
@@ -0,0 +1,18 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+)
+
+//go:noinline
+func BuildInt() int {
+ return a.BuildInt()
+}
+
+func main() {
+ BuildInt()
+}
diff --git a/test/typeparam/issue50121.go b/test/typeparam/issue50121.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue50121.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50121b.dir/a.go b/test/typeparam/issue50121b.dir/a.go
new file mode 100644
index 0000000..4ddbb6e
--- /dev/null
+++ b/test/typeparam/issue50121b.dir/a.go
@@ -0,0 +1,16 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Integer interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+type Builder[T Integer] struct{}
+
+func (r Builder[T]) New() T {
+ return T(42)
+}
diff --git a/test/typeparam/issue50121b.dir/b.go b/test/typeparam/issue50121b.dir/b.go
new file mode 100644
index 0000000..efa6cbb
--- /dev/null
+++ b/test/typeparam/issue50121b.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import (
+ "./a"
+)
+
+var IntBuilder = a.Builder[int]{}
diff --git a/test/typeparam/issue50121b.dir/c.go b/test/typeparam/issue50121b.dir/c.go
new file mode 100644
index 0000000..1691356
--- /dev/null
+++ b/test/typeparam/issue50121b.dir/c.go
@@ -0,0 +1,13 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package c
+
+import (
+ "./b"
+)
+
+func BuildInt() int {
+ return b.IntBuilder.New()
+}
diff --git a/test/typeparam/issue50121b.dir/d.go b/test/typeparam/issue50121b.dir/d.go
new file mode 100644
index 0000000..93b40c9
--- /dev/null
+++ b/test/typeparam/issue50121b.dir/d.go
@@ -0,0 +1,13 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package d
+
+import (
+ "./c"
+)
+
+func BuildInt() int {
+ return c.BuildInt()
+}
diff --git a/test/typeparam/issue50121b.dir/main.go b/test/typeparam/issue50121b.dir/main.go
new file mode 100644
index 0000000..3398601
--- /dev/null
+++ b/test/typeparam/issue50121b.dir/main.go
@@ -0,0 +1,12 @@
+package main
+
+import (
+ "./d"
+ "fmt"
+)
+
+func main() {
+ if got, want := d.BuildInt(), 42; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/issue50121b.go b/test/typeparam/issue50121b.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/issue50121b.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50147.go b/test/typeparam/issue50147.go
new file mode 100644
index 0000000..f97bace
--- /dev/null
+++ b/test/typeparam/issue50147.go
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func Foo[T any, U interface{ *T }](x T) {
+ var _ U = &x
+}
diff --git a/test/typeparam/issue50177.go b/test/typeparam/issue50177.go
new file mode 100644
index 0000000..c4858fc
--- /dev/null
+++ b/test/typeparam/issue50177.go
@@ -0,0 +1,101 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type Fn[T any] func(T)
+type FnErr[T any] func(T) error
+
+// Test that local generic types across functions don't conflict, and they also don't
+// conflict with local non-generic types and local variables.
+func caller0() {
+ type X[T any] struct {
+ fn Fn[int]
+ }
+
+ x := X[int]{func(v int) { fmt.Println(v) }}
+ x.fn(0)
+}
+
+func caller1(val int) {
+ type X[T any] struct {
+ fn FnErr[int]
+ }
+
+ x := X[int]{func(v int) error { fmt.Println(v); return nil }}
+ x.fn(0)
+}
+
+func caller1a(val int) {
+ type X struct {
+ fn func(float64) error
+ }
+
+ x := X{func(v float64) error { fmt.Println(v); return nil }}
+ x.fn(float64(3.2))
+}
+
+func caller1b(val int) {
+ type Y struct {
+ fn func(float64) error
+ }
+
+ X := Y{func(v float64) error { fmt.Println(v); return nil }}
+ X.fn(float64(3.2))
+}
+
+// Test that local generic types within different if clauses don't conflict.
+func caller2(val int) {
+ if val > 2 {
+ type X[T any] struct {
+ fn func(v int) float64
+ }
+
+ x := X[int]{func(v int) float64 { fmt.Println(v); return 1.5 }}
+ x.fn(0)
+ } else {
+ type X[T any] struct {
+ fn func(v int) int
+ }
+ x := X[int]{func(v int) int { fmt.Println(v); return 5 }}
+ x.fn(0)
+ }
+}
+
+// Test that local generic types within different cases don't conflict with each
+// other or with local non-generic types or local variables.
+func caller3(val int) {
+ switch val {
+ case 0:
+ type X[T any] struct {
+ fn func(v int) float64
+ }
+
+ x := X[int]{func(v int) float64 { fmt.Println(v); return 1.5 }}
+ x.fn(0)
+ case 1:
+ type X[T any] struct {
+ fn func(v int) int
+ }
+ x := X[int]{func(v int) int { fmt.Println(v); return 5 }}
+ x.fn(0)
+ case 2:
+ type X struct {
+ fn func(v int) bool
+ }
+ x := X{func(v int) bool { fmt.Println(v); return false }}
+ x.fn(0)
+ case 3:
+ type Y struct {
+ fn func(v int) bool
+ }
+ X := Y{func(v int) bool { fmt.Println(v); return false }}
+ X.fn(0)
+
+ }
+}
diff --git a/test/typeparam/issue50193.go b/test/typeparam/issue50193.go
new file mode 100644
index 0000000..8b4b841
--- /dev/null
+++ b/test/typeparam/issue50193.go
@@ -0,0 +1,35 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type Complex interface {
+ ~complex64 | ~complex128
+}
+
+func zero[T Complex]() T {
+ return T(0)
+}
+func pi[T Complex]() T {
+ return T(3.14)
+}
+func sqrtN1[T Complex]() T {
+ return T(-1i)
+}
+
+func main() {
+ fmt.Println(zero[complex128]())
+ fmt.Println(pi[complex128]())
+ fmt.Println(sqrtN1[complex128]())
+ fmt.Println(zero[complex64]())
+ fmt.Println(pi[complex64]())
+ fmt.Println(sqrtN1[complex64]())
+}
+
diff --git a/test/typeparam/issue50193.out b/test/typeparam/issue50193.out
new file mode 100644
index 0000000..6818622
--- /dev/null
+++ b/test/typeparam/issue50193.out
@@ -0,0 +1,6 @@
+(0+0i)
+(3.14+0i)
+(0-1i)
+(0+0i)
+(3.14+0i)
+(0-1i)
diff --git a/test/typeparam/issue50259.go b/test/typeparam/issue50259.go
new file mode 100644
index 0000000..50edf8f
--- /dev/null
+++ b/test/typeparam/issue50259.go
@@ -0,0 +1,13 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+var x T[B]
+
+type T[_ any] struct{}
+type A T[B]
+type B = T[A]
diff --git a/test/typeparam/issue50264.go b/test/typeparam/issue50264.go
new file mode 100644
index 0000000..1acab87
--- /dev/null
+++ b/test/typeparam/issue50264.go
@@ -0,0 +1,45 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type hello struct{}
+
+func main() {
+ _ = Some(hello{})
+ res := Applicative2(func(a int, b int) int {
+ return 0
+ })
+ _ = res
+}
+
+type NoneType[T any] struct{}
+
+func (r NoneType[T]) Recover() any {
+ return nil
+}
+
+type Func2[A1, A2, R any] func(a1 A1, a2 A2) R
+
+func Some[T any](v T) any {
+ _ = Some2[T](v)
+ return NoneType[T]{}.Recover()
+}
+
+//go:noinline
+func Some2[T any](v T) any {
+ return v
+}
+
+type Nil struct{}
+
+type ApplicativeFunctor2[H, HT, A1, A2, R any] struct {
+ h any
+}
+
+func Applicative2[A1, A2, R any](fn Func2[A1, A2, R]) ApplicativeFunctor2[Nil, Nil, A1, A2, R] {
+ return ApplicativeFunctor2[Nil, Nil, A1, A2, R]{Some(Nil{})}
+}
diff --git a/test/typeparam/issue50317.go b/test/typeparam/issue50317.go
new file mode 100644
index 0000000..c33c4f0
--- /dev/null
+++ b/test/typeparam/issue50317.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type S struct{}
+
+func (S) _[_ any]() {} // ERROR "method must have no type parameters"
+
+type _ interface {
+ m[_ any]() // ERROR "method must have no type parameters"
+}
diff --git a/test/typeparam/issue50417.go b/test/typeparam/issue50417.go
new file mode 100644
index 0000000..b32e270
--- /dev/null
+++ b/test/typeparam/issue50417.go
@@ -0,0 +1,146 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {}
+
+// Field accesses through type parameters are disabled
+// until we have a more thorough understanding of the
+// implications on the spec. See issue #51576.
+
+/*
+type Sf struct {
+ f int
+}
+
+func f0[P Sf](p P) {
+ _ = p.f
+ p.f = 0
+}
+
+func f0t[P ~struct{ f int }](p P) {
+ _ = p.f
+ p.f = 0
+}
+
+var _ = f0[Sf]
+var _ = f0t[Sf]
+
+func f1[P interface {
+ ~struct{ f int }
+ m()
+}](p P) {
+ _ = p.f
+ p.f = 0
+ p.m()
+}
+
+var _ = f1[Sfm]
+
+type Sm struct{}
+
+func (Sm) m() {}
+
+type Sfm struct {
+ f int
+}
+
+func (Sfm) m() {}
+
+func f2[P interface {
+ Sfm
+ m()
+}](p P) {
+ _ = p.f
+ p.f = 0
+ p.m()
+}
+
+var _ = f2[Sfm]
+
+// special case: core type is a named pointer type
+
+type PSfm *Sfm
+
+func f3[P interface{ PSfm }](p P) {
+ _ = p.f
+ p.f = 0
+}
+
+var _ = f3[PSfm]
+
+// special case: core type is an unnamed pointer type
+
+func f4[P interface{ *Sfm }](p P) {
+ _ = p.f
+ p.f = 0
+}
+
+var _ = f4[*Sfm]
+
+type A int
+type B int
+type C float64
+
+type Int interface {
+ *Sf | A
+ *Sf | B
+}
+
+func f5[P Int](p P) {
+ _ = p.f
+ p.f = 0
+}
+
+var _ = f5[*Sf]
+
+type Int2 interface {
+ *Sf | A
+ any
+ *Sf | C
+}
+
+func f6[P Int2](p P) {
+ _ = p.f
+ p.f = 0
+}
+
+var _ = f6[*Sf]
+
+type Int3 interface {
+ Sf
+ ~struct{ f int }
+}
+
+func f7[P Int3](p P) {
+ _ = p.f
+ p.f = 0
+}
+
+var _ = f7[Sf]
+
+type Em1 interface {
+ *Sf | A
+}
+
+type Em2 interface {
+ *Sf | B
+}
+
+type Int4 interface {
+ Em1
+ Em2
+ any
+}
+
+func f8[P Int4](p P) {
+ _ = p.f
+ p.f = 0
+}
+
+var _ = f8[*Sf]
+*/
diff --git a/test/typeparam/issue50417b.go b/test/typeparam/issue50417b.go
new file mode 100644
index 0000000..1c803b0
--- /dev/null
+++ b/test/typeparam/issue50417b.go
@@ -0,0 +1,58 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {}
+
+// Field accesses through type parameters are disabled
+// until we have a more thorough understanding of the
+// implications on the spec. See issue #51576.
+
+/*
+import "fmt"
+
+type MyStruct struct {
+ b1, b2 string
+ E
+}
+
+type E struct {
+ val int
+}
+
+type C interface {
+ ~struct {
+ b1, b2 string
+ E
+ }
+}
+
+func f[T C]() T {
+ var x T = T{
+ b1: "a",
+ b2: "b",
+ }
+
+ if got, want := x.b2, "b"; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ x.b1 = "y"
+ x.val = 5
+
+ return x
+}
+
+func main() {
+ x := f[MyStruct]()
+ if got, want := x.b1, "y"; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ if got, want := x.val, 5; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
+*/
diff --git a/test/typeparam/issue50419.go b/test/typeparam/issue50419.go
new file mode 100644
index 0000000..dfe55f9
--- /dev/null
+++ b/test/typeparam/issue50419.go
@@ -0,0 +1,33 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that type substitution works correctly even for a method of a generic type
+// that has multiple blank type params.
+
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ foo := &Foo[string, int]{
+ valueA: "i am a string",
+ valueB: 123,
+ }
+ if got, want := fmt.Sprintln(foo), "i am a string 123\n"; got != want {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+}
+
+type Foo[T1 any, T2 any] struct {
+ valueA T1
+ valueB T2
+}
+
+func (f *Foo[_, _]) String() string {
+ return fmt.Sprintf("%v %v", f.valueA, f.valueB)
+}
diff --git a/test/typeparam/issue50437.dir/a.go b/test/typeparam/issue50437.dir/a.go
new file mode 100644
index 0000000..4a136b5
--- /dev/null
+++ b/test/typeparam/issue50437.dir/a.go
@@ -0,0 +1,43 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type MarshalOptions struct {
+ *typedArshalers[MarshalOptions]
+}
+
+func Marshal(in interface{}) (out []byte, err error) {
+ return MarshalOptions{}.Marshal(in)
+}
+
+func (mo MarshalOptions) Marshal(in interface{}) (out []byte, err error) {
+ err = mo.MarshalNext(in)
+ return nil, err
+}
+
+func (mo MarshalOptions) MarshalNext(in interface{}) error {
+ a := new(arshaler)
+ a.marshal = func(MarshalOptions) error { return nil }
+ return a.marshal(mo)
+}
+
+type arshaler struct {
+ marshal func(MarshalOptions) error
+}
+
+type typedArshalers[Options any] struct {
+ m M
+}
+
+func (a *typedArshalers[Options]) lookup(fnc func(Options) error) (func(Options) error, bool) {
+ a.m.Load(nil)
+ return fnc, false
+}
+
+type M struct {}
+
+func (m *M) Load(key any) (value any, ok bool) {
+ return
+}
diff --git a/test/typeparam/issue50437.dir/b.go b/test/typeparam/issue50437.dir/b.go
new file mode 100644
index 0000000..afddc3f
--- /dev/null
+++ b/test/typeparam/issue50437.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func f() {
+ a.Marshal(map[int]int{})
+}
diff --git a/test/typeparam/issue50437.go b/test/typeparam/issue50437.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue50437.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50481b.dir/b.go b/test/typeparam/issue50481b.dir/b.go
new file mode 100644
index 0000000..d458357
--- /dev/null
+++ b/test/typeparam/issue50481b.dir/b.go
@@ -0,0 +1,16 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "fmt"
+
+type Foo[T1 ~string, T2 ~int] struct {
+ ValueA T1
+ ValueB T2
+}
+
+func (f *Foo[_, _]) String() string {
+ return fmt.Sprintf("%v %v", f.ValueA, f.ValueB)
+}
diff --git a/test/typeparam/issue50481b.dir/main.go b/test/typeparam/issue50481b.dir/main.go
new file mode 100644
index 0000000..6a5067c
--- /dev/null
+++ b/test/typeparam/issue50481b.dir/main.go
@@ -0,0 +1,23 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that type substitution and export/import works correctly even for a method of
+// a generic type that has multiple blank type params.
+
+package main
+
+import (
+ "./b"
+ "fmt"
+)
+
+func main() {
+ foo := &b.Foo[string, int]{
+ ValueA: "i am a string",
+ ValueB: 123,
+ }
+ if got, want := fmt.Sprintln(foo), "i am a string 123\n"; got != want {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+}
diff --git a/test/typeparam/issue50481b.go b/test/typeparam/issue50481b.go
new file mode 100644
index 0000000..aefbe67
--- /dev/null
+++ b/test/typeparam/issue50481b.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50481c.dir/a.go b/test/typeparam/issue50481c.dir/a.go
new file mode 100644
index 0000000..384ba23
--- /dev/null
+++ b/test/typeparam/issue50481c.dir/a.go
@@ -0,0 +1,30 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type A interface {
+ int | int64
+}
+
+type B interface {
+ string
+}
+
+type C interface {
+ String() string
+}
+
+type Myint int
+
+func (i Myint) String() string {
+ return "aa"
+}
+
+type T[P A, _ C, _ B] int
+
+func (v T[P, Q, R]) test() {
+ var r Q
+ r.String()
+}
diff --git a/test/typeparam/issue50481c.dir/main.go b/test/typeparam/issue50481c.dir/main.go
new file mode 100644
index 0000000..178542b
--- /dev/null
+++ b/test/typeparam/issue50481c.dir/main.go
@@ -0,0 +1,18 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that type substitution works and export/import works correctly even for a
+// generic type that has multiple blank type params.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ var x a.T[int, a.Myint, string]
+ fmt.Printf("%v\n", x)
+}
diff --git a/test/typeparam/issue50481c.go b/test/typeparam/issue50481c.go
new file mode 100644
index 0000000..aefbe67
--- /dev/null
+++ b/test/typeparam/issue50481c.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50481c.out b/test/typeparam/issue50481c.out
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/typeparam/issue50481c.out
@@ -0,0 +1 @@
+0
diff --git a/test/typeparam/issue50485.dir/a.go b/test/typeparam/issue50485.dir/a.go
new file mode 100644
index 0000000..3a7c71a
--- /dev/null
+++ b/test/typeparam/issue50485.dir/a.go
@@ -0,0 +1,239 @@
+package a
+
+import "fmt"
+
+type ImplicitOrd interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+func LessGiven[T ImplicitOrd]() Ord[T] {
+ return LessFunc[T](func(a, b T) bool {
+ return a < b
+ })
+}
+
+type Eq[T any] interface {
+ Eqv(a T, b T) bool
+}
+
+type Ord[T any] interface {
+ Eq[T]
+ Less(a T, b T) bool
+}
+
+type LessFunc[T any] func(a, b T) bool
+
+func (r LessFunc[T]) Eqv(a, b T) bool {
+ return r(a, b) == false && r(b, a) == false
+}
+
+func (r LessFunc[T]) Less(a, b T) bool {
+ return r(a, b)
+}
+
+type Option[T any] struct {
+ v *T
+}
+
+func (r Option[T]) IsDefined() bool {
+ return r.v != nil
+}
+
+func (r Option[T]) IsEmpty() bool {
+ return !r.IsDefined()
+}
+
+func (r Option[T]) Get() T {
+ return *r.v
+}
+
+func (r Option[T]) String() string {
+ if r.IsDefined() {
+ return fmt.Sprintf("Some(%v)", r.v)
+ } else {
+ return "None"
+ }
+}
+
+func (r Option[T]) OrElse(t T) T {
+ if r.IsDefined() {
+ return *r.v
+ }
+ return t
+}
+
+func (r Option[T]) Recover(f func() T) Option[T] {
+ if r.IsDefined() {
+ return r
+ }
+ t := f()
+ return Option[T]{&t}
+}
+
+type Func1[A1, R any] func(a1 A1) R
+
+type Func2[A1, A2, R any] func(a1 A1, a2 A2) R
+
+func (r Func2[A1, A2, R]) Curried() Func1[A1, Func1[A2, R]] {
+ return func(a1 A1) Func1[A2, R] {
+ return Func1[A2, R](func(a2 A2) R {
+ return r(a1, a2)
+ })
+ }
+}
+
+type HList interface {
+ sealed()
+}
+
+// Header is constrains interface type, enforce Head type of Cons is HT
+type Header[HT any] interface {
+ HList
+ Head() HT
+}
+
+// Cons means H :: T
+// zero value of Cons[H,T] is not allowed.
+// so Cons defined as interface type
+type Cons[H any, T HList] interface {
+ HList
+ Head() H
+ Tail() T
+}
+
+type Nil struct {
+}
+
+func (r Nil) Head() Nil {
+ return r
+}
+
+func (r Nil) Tail() Nil {
+ return r
+}
+
+func (r Nil) String() string {
+ return "Nil"
+}
+
+func (r Nil) sealed() {
+
+}
+
+type hlistImpl[H any, T HList] struct {
+ head H
+ tail T
+}
+
+func (r hlistImpl[H, T]) Head() H {
+ return r.head
+}
+
+func (r hlistImpl[H, T]) Tail() T {
+ return r.tail
+}
+
+func (r hlistImpl[H, T]) String() string {
+ return fmt.Sprintf("%v :: %v", r.head, r.tail)
+}
+
+func (r hlistImpl[H, T]) sealed() {
+
+}
+
+func hlist[H any, T HList](h H, t T) Cons[H, T] {
+ return hlistImpl[H, T]{h, t}
+}
+
+func Concat[H any, T HList](h H, t T) Cons[H, T] {
+ return hlist(h, t)
+}
+
+func Empty() Nil {
+ return Nil{}
+}
+func Some[T any](v T) Option[T] {
+ return Option[T]{}.Recover(func() T {
+ return v
+ })
+}
+
+func None[T any]() Option[T] {
+ return Option[T]{}
+}
+
+func Ap[T, U any](t Option[Func1[T, U]], a Option[T]) Option[U] {
+ return FlatMap(t, func(f Func1[T, U]) Option[U] {
+ return Map(a, f)
+ })
+}
+
+func Map[T, U any](opt Option[T], f func(v T) U) Option[U] {
+ return FlatMap(opt, func(v T) Option[U] {
+ return Some(f(v))
+ })
+}
+
+func FlatMap[T, U any](opt Option[T], fn func(v T) Option[U]) Option[U] {
+ if opt.IsDefined() {
+ return fn(opt.Get())
+ }
+ return None[U]()
+}
+
+type ApplicativeFunctor1[H Header[HT], HT, A, R any] struct {
+ h Option[H]
+ fn Option[Func1[A, R]]
+}
+
+func (r ApplicativeFunctor1[H, HT, A, R]) ApOption(a Option[A]) Option[R] {
+ return Ap(r.fn, a)
+}
+
+func (r ApplicativeFunctor1[H, HT, A, R]) Ap(a A) Option[R] {
+ return r.ApOption(Some(a))
+}
+
+func Applicative1[A, R any](fn Func1[A, R]) ApplicativeFunctor1[Nil, Nil, A, R] {
+ return ApplicativeFunctor1[Nil, Nil, A, R]{Some(Empty()), Some(fn)}
+}
+
+type ApplicativeFunctor2[H Header[HT], HT, A1, A2, R any] struct {
+ h Option[H]
+ fn Option[Func1[A1, Func1[A2, R]]]
+}
+
+func (r ApplicativeFunctor2[H, HT, A1, A2, R]) ApOption(a Option[A1]) ApplicativeFunctor1[Cons[A1, H], A1, A2, R] {
+
+ nh := FlatMap(r.h, func(hv H) Option[Cons[A1, H]] {
+ return Map(a, func(av A1) Cons[A1, H] {
+ return Concat(av, hv)
+ })
+ })
+
+ return ApplicativeFunctor1[Cons[A1, H], A1, A2, R]{nh, Ap(r.fn, a)}
+}
+func (r ApplicativeFunctor2[H, HT, A1, A2, R]) Ap(a A1) ApplicativeFunctor1[Cons[A1, H], A1, A2, R] {
+
+ return r.ApOption(Some(a))
+
+}
+
+func Applicative2[A1, A2, R any](fn Func2[A1, A2, R]) ApplicativeFunctor2[Nil, Nil, A1, A2, R] {
+ return ApplicativeFunctor2[Nil, Nil, A1, A2, R]{Some(Empty()), Some(fn.Curried())}
+}
+func OrdOption[T any](m Ord[T]) Ord[Option[T]] {
+ return LessFunc[Option[T]](func(t1 Option[T], t2 Option[T]) bool {
+ if !t1.IsDefined() && !t2.IsDefined() {
+ return false
+ }
+ return Applicative2(m.Less).ApOption(t1).ApOption(t2).OrElse(!t1.IsDefined())
+ })
+}
+
+func Given[T ImplicitOrd]() Ord[T] {
+ return LessGiven[T]()
+}
diff --git a/test/typeparam/issue50485.dir/main.go b/test/typeparam/issue50485.dir/main.go
new file mode 100644
index 0000000..7181b93
--- /dev/null
+++ b/test/typeparam/issue50485.dir/main.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+ "./a"
+)
+
+func main() {
+ _ = a.OrdOption(a.Given[int]())
+}
diff --git a/test/typeparam/issue50485.go b/test/typeparam/issue50485.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue50485.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50486.dir/goerror_fp.go b/test/typeparam/issue50486.dir/goerror_fp.go
new file mode 100644
index 0000000..fec9095
--- /dev/null
+++ b/test/typeparam/issue50486.dir/goerror_fp.go
@@ -0,0 +1,75 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package goerror_fp
+
+type Seq[T any] []T
+
+func (r Seq[T]) Size() int {
+ return len(r)
+}
+
+func (r Seq[T]) Append(items ...T) Seq[T] {
+ tail := Seq[T](items)
+ ret := make(Seq[T], r.Size()+tail.Size())
+
+ for i := range r {
+ ret[i] = r[i]
+ }
+
+ for i := range tail {
+ ret[i+r.Size()] = tail[i]
+ }
+
+ return ret
+}
+
+func (r Seq[T]) Iterator() Iterator[T] {
+ idx := 0
+
+ return Iterator[T]{
+ IsHasNext: func() bool {
+ return idx < r.Size()
+ },
+ GetNext: func() T {
+ ret := r[idx]
+ idx++
+ return ret
+ },
+ }
+}
+
+type Iterator[T any] struct {
+ IsHasNext func() bool
+ GetNext func() T
+}
+
+func (r Iterator[T]) ToSeq() Seq[T] {
+ ret := Seq[T]{}
+ for r.HasNext() {
+ ret = append(ret, r.Next())
+ }
+ return ret
+}
+
+func (r Iterator[T]) Map(f func(T) any) Iterator[any] {
+ return MakeIterator(r.HasNext, func() any {
+ return f(r.Next())
+ })
+}
+
+func (r Iterator[T]) HasNext() bool {
+ return r.IsHasNext()
+}
+
+func (r Iterator[T]) Next() T {
+ return r.GetNext()
+}
+
+func MakeIterator[T any](has func() bool, next func() T) Iterator[T] {
+ return Iterator[T]{
+ IsHasNext: has,
+ GetNext: next,
+ }
+}
diff --git a/test/typeparam/issue50486.dir/main.go b/test/typeparam/issue50486.dir/main.go
new file mode 100644
index 0000000..c2c8eea
--- /dev/null
+++ b/test/typeparam/issue50486.dir/main.go
@@ -0,0 +1,16 @@
+package main
+
+import fp "./goerror_fp"
+
+func Fold[A, B any](zero B, a A, f func(B, A) B) B {
+ return f(zero, a)
+}
+
+func main() {
+
+ var v any = "hello"
+ Fold(fp.Seq[any]{}, v, func(seq fp.Seq[any], v any) fp.Seq[any] {
+ return seq.Append(v)
+ })
+
+}
diff --git a/test/typeparam/issue50486.go b/test/typeparam/issue50486.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue50486.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50552.dir/a.go b/test/typeparam/issue50552.dir/a.go
new file mode 100644
index 0000000..89b9bcb
--- /dev/null
+++ b/test/typeparam/issue50552.dir/a.go
@@ -0,0 +1,16 @@
+package a
+
+type Builder[T any] struct{}
+
+func (r Builder[T]) New() T {
+ var v T
+ return v
+}
+
+func (r Builder[T]) New2() T {
+ return r.New()
+}
+
+func BuildInt() int {
+ return Builder[int]{}.New()
+}
diff --git a/test/typeparam/issue50552.dir/main.go b/test/typeparam/issue50552.dir/main.go
new file mode 100644
index 0000000..0ff2ed3
--- /dev/null
+++ b/test/typeparam/issue50552.dir/main.go
@@ -0,0 +1,20 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func BuildInt() int {
+ return a.BuildInt()
+}
+
+func main() {
+ if got, want := BuildInt(), 0; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/issue50552.go b/test/typeparam/issue50552.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/issue50552.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50561.dir/diameter.go b/test/typeparam/issue50561.dir/diameter.go
new file mode 100644
index 0000000..2bfe924
--- /dev/null
+++ b/test/typeparam/issue50561.dir/diameter.go
@@ -0,0 +1,86 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package diameter
+
+type Runnable interface {
+ Run()
+}
+
+// RunnableFunc is converter which converts function to Runnable interface
+type RunnableFunc func()
+
+// Run is Runnable.Run
+func (r RunnableFunc) Run() {
+ r()
+}
+
+type Executor interface {
+ ExecuteUnsafe(runnable Runnable)
+}
+
+type Promise[T any] interface {
+ Future() Future[T]
+ Success(value T) bool
+ Failure(err error) bool
+ IsCompleted() bool
+ Complete(result Try[T]) bool
+}
+
+type Future[T any] interface {
+ OnFailure(cb func(err error), ctx ...Executor)
+ OnSuccess(cb func(success T), ctx ...Executor)
+ Foreach(f func(v T), ctx ...Executor)
+ OnComplete(cb func(try Try[T]), ctx ...Executor)
+ IsCompleted() bool
+ // Value() Option[Try[T]]
+ Failed() Future[error]
+ Recover(f func(err error) T, ctx ...Executor) Future[T]
+ RecoverWith(f func(err error) Future[T], ctx ...Executor) Future[T]
+}
+
+type Try[T any] struct {
+ v *T
+ err error
+}
+
+func (r Try[T]) IsSuccess() bool {
+ return r.v != nil
+}
+
+type ByteBuffer struct {
+ pos int
+ buf []byte
+ underflow error
+}
+
+// InboundHandler is extends of uclient.NetInboundHandler
+type InboundHandler interface {
+ OriginHost() string
+ OriginRealm() string
+}
+
+type transactionID struct {
+ hopID uint32
+ endID uint32
+}
+
+type roundTripper struct {
+ promise map[transactionID]Promise[*ByteBuffer]
+ host string
+ realm string
+}
+
+func (r *roundTripper) OriginHost() string {
+ return r.host
+}
+func (r *roundTripper) OriginRealm() string {
+ return r.realm
+}
+
+func NewInboundHandler(host string, realm string, productName string) InboundHandler {
+ ret := &roundTripper{promise: make(map[transactionID]Promise[*ByteBuffer]), host: host, realm: realm}
+
+ return ret
+}
diff --git a/test/typeparam/issue50561.dir/main.go b/test/typeparam/issue50561.dir/main.go
new file mode 100644
index 0000000..3e656bd
--- /dev/null
+++ b/test/typeparam/issue50561.dir/main.go
@@ -0,0 +1,13 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./diameter"
+)
+
+func main() {
+ diameter.NewInboundHandler("hello", "world", "hi")
+}
diff --git a/test/typeparam/issue50561.go b/test/typeparam/issue50561.go
new file mode 100644
index 0000000..8bb5c3e
--- /dev/null
+++ b/test/typeparam/issue50561.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50598.dir/a0.go b/test/typeparam/issue50598.dir/a0.go
new file mode 100644
index 0000000..61d353e
--- /dev/null
+++ b/test/typeparam/issue50598.dir/a0.go
@@ -0,0 +1,23 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a0
+
+type Builder[T any] struct{}
+
+func (r Builder[T]) New1() T {
+ var v T
+ return v
+}
+
+func (r Builder[T]) New2() T {
+ var v T
+ return v
+}
+
+type IntBuilder struct{}
+
+func (b IntBuilder) New() int {
+ return Builder[int]{}.New2()
+}
diff --git a/test/typeparam/issue50598.dir/a1.go b/test/typeparam/issue50598.dir/a1.go
new file mode 100644
index 0000000..36624b4
--- /dev/null
+++ b/test/typeparam/issue50598.dir/a1.go
@@ -0,0 +1,11 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a1
+
+import "./a0"
+
+func New() int {
+ return a0.IntBuilder{}.New()
+}
diff --git a/test/typeparam/issue50598.dir/a2.go b/test/typeparam/issue50598.dir/a2.go
new file mode 100644
index 0000000..c28be66
--- /dev/null
+++ b/test/typeparam/issue50598.dir/a2.go
@@ -0,0 +1,11 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a2
+
+import "./a0"
+
+func New() int {
+ return a0.Builder[int]{}.New1()
+}
diff --git a/test/typeparam/issue50598.dir/main.go b/test/typeparam/issue50598.dir/main.go
new file mode 100644
index 0000000..b0b6844
--- /dev/null
+++ b/test/typeparam/issue50598.dir/main.go
@@ -0,0 +1,22 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+
+ "./a1"
+ "./a2"
+)
+
+func New() int {
+ return a1.New() + a2.New()
+}
+
+func main() {
+ if got, want := New(), 0; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/issue50598.go b/test/typeparam/issue50598.go
new file mode 100644
index 0000000..aefbe67
--- /dev/null
+++ b/test/typeparam/issue50598.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50642.go b/test/typeparam/issue50642.go
new file mode 100644
index 0000000..d2d4a66
--- /dev/null
+++ b/test/typeparam/issue50642.go
@@ -0,0 +1,63 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type Temp[T any] struct {
+}
+
+var temp, temp1 any
+var ch any
+
+func (it Temp[T]) HasNext() bool {
+ var ok bool
+ temp1 = <-ch.(chan T)
+ // test conversion of T to interface{} during an OAS2RECV
+ temp, ok = <-ch.(chan T)
+ return ok
+}
+
+type MyInt int
+
+func (i MyInt) String() string {
+ return "a"
+}
+
+type Stringer interface {
+ String() string
+}
+
+type Temp2[T Stringer] struct {
+}
+
+var temp2 Stringer
+
+func (it Temp2[T]) HasNext() string {
+ var x map[int]T
+
+ var ok bool
+ // test conversion of T to Stringer during an OAS2MAPR
+ temp2, ok = x[43]
+ _ = ok
+ return temp2.String()
+}
+
+func main() {
+ ch1 := make(chan int, 2)
+ ch1 <- 5
+ ch1 <- 6
+ ch = ch1
+ iter := Temp[int]{}
+ iter.HasNext()
+
+ iter2 := Temp2[MyInt]{}
+ if got, want := iter2.HasNext(), "a"; got != want {
+ panic(fmt.Sprintf("got %v, want %v", got, want))
+ }
+
+}
diff --git a/test/typeparam/issue50690a.go b/test/typeparam/issue50690a.go
new file mode 100644
index 0000000..6691af0
--- /dev/null
+++ b/test/typeparam/issue50690a.go
@@ -0,0 +1,75 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+// Numeric expresses a type constraint satisfied by any numeric type.
+type Numeric interface {
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~float32 | ~float64 |
+ ~complex64 | ~complex128
+}
+
+// Sum returns the sum of the provided arguments.
+func Sum[T Numeric](args ...T) T {
+ var sum T
+ for i := 0; i < len(args); i++ {
+ sum += args[i]
+ }
+ return sum
+}
+
+// Ledger is an identifiable, financial record.
+type Ledger[T ~string, K Numeric] struct {
+ // ID identifies the ledger.
+ ID_ T
+
+ // Amounts is a list of monies associated with this ledger.
+ Amounts_ []K
+
+ // SumFn is a function that can be used to sum the amounts
+ // in this ledger.
+ SumFn_ func(...K) K
+}
+
+// Field accesses through type parameters are disabled
+// until we have a more thorough understanding of the
+// implications on the spec. See issue #51576.
+// Use accessor methods instead.
+
+func (l Ledger[T, _]) ID() T { return l.ID_ }
+func (l Ledger[_, K]) Amounts() []K { return l.Amounts_ }
+func (l Ledger[_, K]) SumFn() func(...K) K { return l.SumFn_ }
+
+func PrintLedger[
+ T ~string,
+ K Numeric,
+ L interface {
+ ~struct {
+ ID_ T
+ Amounts_ []K
+ SumFn_ func(...K) K
+ }
+ ID() T
+ Amounts() []K
+ SumFn() func(...K) K
+ },
+](l L) {
+ fmt.Printf("%s has a sum of %v\n", l.ID(), l.SumFn()(l.Amounts()...))
+}
+
+func main() {
+ PrintLedger(Ledger[string, int]{
+ ID_: "fake",
+ Amounts_: []int{1, 2, 3},
+ SumFn_: Sum[int],
+ })
+}
diff --git a/test/typeparam/issue50690a.out b/test/typeparam/issue50690a.out
new file mode 100644
index 0000000..2932767
--- /dev/null
+++ b/test/typeparam/issue50690a.out
@@ -0,0 +1 @@
+fake has a sum of 6
diff --git a/test/typeparam/issue50690b.go b/test/typeparam/issue50690b.go
new file mode 100644
index 0000000..09c84e0
--- /dev/null
+++ b/test/typeparam/issue50690b.go
@@ -0,0 +1,51 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type Printer[T ~string] struct {
+ PrintFn func(T)
+}
+
+func Print[T ~string](s T) {
+ fmt.Println(s)
+}
+
+func PrintWithPrinter[T ~string, S interface {
+ ~struct {
+ ID T
+ PrintFn_ func(T)
+ }
+ PrintFn() func(T)
+}](message T, obj S) {
+ obj.PrintFn()(message)
+}
+
+type PrintShop[T ~string] struct {
+ ID T
+ PrintFn_ func(T)
+}
+
+// Field accesses through type parameters are disabled
+// until we have a more thorough understanding of the
+// implications on the spec. See issue #51576.
+// Use accessor method instead.
+
+func (s PrintShop[T]) PrintFn() func(T) { return s.PrintFn_ }
+
+func main() {
+ PrintWithPrinter(
+ "Hello, world.",
+ PrintShop[string]{
+ ID: "fake",
+ PrintFn_: Print[string],
+ },
+ )
+}
diff --git a/test/typeparam/issue50690b.out b/test/typeparam/issue50690b.out
new file mode 100644
index 0000000..f75ba05
--- /dev/null
+++ b/test/typeparam/issue50690b.out
@@ -0,0 +1 @@
+Hello, world.
diff --git a/test/typeparam/issue50690c.go b/test/typeparam/issue50690c.go
new file mode 100644
index 0000000..2db1487
--- /dev/null
+++ b/test/typeparam/issue50690c.go
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type Printer[T ~string] struct {
+ PrintFn func(T)
+}
+
+func Print[T ~string](s T) {
+ fmt.Println(s)
+}
+
+func PrintWithPrinter[T ~string, S interface {
+ ~struct {
+ ID T
+ PrintFn_ func(T)
+ }
+ PrintFn() func(T)
+}](message T, obj S) {
+ obj.PrintFn()(message)
+}
+
+func main() {
+ PrintWithPrinter(
+ "Hello, world.",
+ StructWithPrinter{ID: "fake", PrintFn_: Print[string]},
+ )
+}
+
+type StructWithPrinter struct {
+ ID string
+ PrintFn_ func(string)
+}
+
+// Field accesses through type parameters are disabled
+// until we have a more thorough understanding of the
+// implications on the spec. See issue #51576.
+// Use accessor method instead.
+
+func (s StructWithPrinter) PrintFn() func(string) {
+ return s.PrintFn_
+}
diff --git a/test/typeparam/issue50690c.out b/test/typeparam/issue50690c.out
new file mode 100644
index 0000000..f75ba05
--- /dev/null
+++ b/test/typeparam/issue50690c.out
@@ -0,0 +1 @@
+Hello, world.
diff --git a/test/typeparam/issue50833.go b/test/typeparam/issue50833.go
new file mode 100644
index 0000000..fe729b1
--- /dev/null
+++ b/test/typeparam/issue50833.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type (
+ S struct{ f int }
+ PS *S
+)
+
+func a() []*S { return []*S{{f: 1}} }
+func b() []PS { return []PS{{f: 1}} }
+
+func c[P *S]() []P { return []P{{f: 1}} }
+func d[P PS]() []P { return []P{{f: 1}} }
+
+func main() {
+ c[*S]()
+ d[PS]()
+}
diff --git a/test/typeparam/issue50841.dir/a.go b/test/typeparam/issue50841.dir/a.go
new file mode 100644
index 0000000..37e0233
--- /dev/null
+++ b/test/typeparam/issue50841.dir/a.go
@@ -0,0 +1,22 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func Marshal[foobar any]() {
+ _ = NewEncoder[foobar]()
+}
+
+func NewEncoder[foobar any]() *Encoder[foobar] {
+ return nil
+}
+
+type Encoder[foobar any] struct {
+}
+
+func (e *Encoder[foobar]) EncodeToken(t Token[foobar]) {
+
+}
+
+type Token[foobar any] any
diff --git a/test/typeparam/issue50841.dir/b.go b/test/typeparam/issue50841.dir/b.go
new file mode 100644
index 0000000..38e3de3
--- /dev/null
+++ b/test/typeparam/issue50841.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func F() {
+ a.Marshal[int]()
+}
diff --git a/test/typeparam/issue50841.go b/test/typeparam/issue50841.go
new file mode 100644
index 0000000..8bb5c3e
--- /dev/null
+++ b/test/typeparam/issue50841.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue50993.go b/test/typeparam/issue50993.go
new file mode 100644
index 0000000..4d459fd
--- /dev/null
+++ b/test/typeparam/issue50993.go
@@ -0,0 +1,35 @@
+// compile -d=checkptr
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "sync/atomic"
+ "unsafe"
+)
+
+type Node[T any] struct {
+ Next *Node[T]
+ // Prev *Node[T]
+}
+
+func LoadPointer[T any](addr **T) (val *T) {
+ return (*T)(
+ atomic.LoadPointer(
+ (*unsafe.Pointer)(unsafe.Pointer(addr)),
+ ))
+}
+
+func (q *Node[T]) Pop() {
+ var tail, head *Node[T]
+ if head == LoadPointer(&tail) {
+ }
+}
+
+func main() {
+ ch := Node[uint64]{}
+ ch.Pop()
+}
diff --git a/test/typeparam/issue51219.dir/a.go b/test/typeparam/issue51219.dir/a.go
new file mode 100644
index 0000000..29670df
--- /dev/null
+++ b/test/typeparam/issue51219.dir/a.go
@@ -0,0 +1,20 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+// Type I is the first basic test for the issue, which relates to a type that is recursive
+// via a type constraint. (In this test, I -> IConstraint -> MyStruct -> I.)
+type JsonRaw []byte
+
+type MyStruct struct {
+ x *I[JsonRaw]
+}
+
+type IConstraint interface {
+ JsonRaw | MyStruct
+}
+
+type I[T IConstraint] struct {
+}
diff --git a/test/typeparam/issue51219.dir/main.go b/test/typeparam/issue51219.dir/main.go
new file mode 100644
index 0000000..14c6d17
--- /dev/null
+++ b/test/typeparam/issue51219.dir/main.go
@@ -0,0 +1,16 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ var x a.I[a.JsonRaw]
+
+ fmt.Printf("%v\n", x)
+}
diff --git a/test/typeparam/issue51219.go b/test/typeparam/issue51219.go
new file mode 100644
index 0000000..aefbe67
--- /dev/null
+++ b/test/typeparam/issue51219.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue51219.out b/test/typeparam/issue51219.out
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/test/typeparam/issue51219.out
@@ -0,0 +1 @@
+{}
diff --git a/test/typeparam/issue51219b.dir/a.go b/test/typeparam/issue51219b.dir/a.go
new file mode 100644
index 0000000..1904940
--- /dev/null
+++ b/test/typeparam/issue51219b.dir/a.go
@@ -0,0 +1,37 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Interaction[DataT InteractionDataConstraint] struct {
+}
+
+type InteractionDataConstraint interface {
+ []byte |
+ UserCommandInteractionData
+}
+
+type UserCommandInteractionData struct {
+ resolvedInteractionWithOptions
+}
+
+type resolvedInteractionWithOptions struct {
+ Resolved Resolved `json:"resolved,omitempty"`
+}
+
+type Resolved struct {
+ Users ResolvedData[User] `json:"users,omitempty"`
+}
+
+type ResolvedData[T ResolvedDataConstraint] map[uint64]T
+
+type ResolvedDataConstraint interface {
+ User | Message
+}
+
+type User struct{}
+
+type Message struct {
+ Interaction *Interaction[[]byte] `json:"interaction,omitempty"`
+}
diff --git a/test/typeparam/issue51219b.dir/b.go b/test/typeparam/issue51219b.dir/b.go
new file mode 100644
index 0000000..8413d66
--- /dev/null
+++ b/test/typeparam/issue51219b.dir/b.go
@@ -0,0 +1,14 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import (
+ "./a"
+)
+
+// InteractionRequest is an incoming request Interaction
+type InteractionRequest[T a.InteractionDataConstraint] struct {
+ a.Interaction[T]
+}
diff --git a/test/typeparam/issue51219b.dir/p.go b/test/typeparam/issue51219b.dir/p.go
new file mode 100644
index 0000000..9f8b840
--- /dev/null
+++ b/test/typeparam/issue51219b.dir/p.go
@@ -0,0 +1,14 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import (
+ "./b"
+)
+
+// ResponseWriterMock mocks corde's ResponseWriter interface
+type ResponseWriterMock struct {
+ x b.InteractionRequest[[]byte]
+}
diff --git a/test/typeparam/issue51219b.go b/test/typeparam/issue51219b.go
new file mode 100644
index 0000000..8bb5c3e
--- /dev/null
+++ b/test/typeparam/issue51219b.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue51232.go b/test/typeparam/issue51232.go
new file mode 100644
index 0000000..0d25e18
--- /dev/null
+++ b/test/typeparam/issue51232.go
@@ -0,0 +1,31 @@
+// errorcheck
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type RC[RG any] interface {
+ ~[]RG
+}
+
+type Fn[RCT RC[RG], RG any] func(RCT)
+
+type F[RCT RC[RG], RG any] interface {
+ Fn() Fn[RCT] // ERROR "got 1 arguments"
+}
+
+type concreteF[RCT RC[RG], RG any] struct {
+ makeFn func() Fn[RCT] // ERROR "got 1 arguments"
+}
+
+func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { // ERROR "got 1 arguments"
+ return c.makeFn()
+}
+
+func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] { // ERROR "got 1 arguments"
+ return &concreteF[RCT]{ // ERROR "cannot use" "got 1 arguments"
+ makeFn: nil,
+ }
+}
diff --git a/test/typeparam/issue51233.go b/test/typeparam/issue51233.go
new file mode 100644
index 0000000..96a25dd
--- /dev/null
+++ b/test/typeparam/issue51233.go
@@ -0,0 +1,28 @@
+// errorcheck
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package p
+
+// As of issue #51527, type-type inference has been disabled.
+
+type RC[RG any] interface {
+ ~[]RG
+}
+
+type Fn[RCT RC[RG], RG any] func(RCT)
+
+type FFn[RCT RC[RG], RG any] func() Fn[RCT] // ERROR "got 1 arguments"
+
+type F[RCT RC[RG], RG any] interface {
+ Fn() Fn[RCT] // ERROR "got 1 arguments"
+}
+
+type concreteF[RCT RC[RG], RG any] struct {
+ makeFn FFn[RCT] // ERROR "got 1 arguments"
+}
+
+func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { // ERROR "got 1 arguments"
+ return c.makeFn()
+}
diff --git a/test/typeparam/issue51236.go b/test/typeparam/issue51236.go
new file mode 100644
index 0000000..51fde1e
--- /dev/null
+++ b/test/typeparam/issue51236.go
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface {
+ []byte
+}
+
+func F[T I]() {
+ var t T
+ explodes(t)
+}
+
+func explodes(b []byte) {}
+
+func main() {
+
+}
diff --git a/test/typeparam/issue51245.go b/test/typeparam/issue51245.go
new file mode 100644
index 0000000..425d517
--- /dev/null
+++ b/test/typeparam/issue51245.go
@@ -0,0 +1,16 @@
+// build
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T[P any] int
+const C T[int] = 3
+
+type T2 int
+const C2 T2 = 9
+
+func main() {
+}
diff --git a/test/typeparam/issue51250a.dir/a.go b/test/typeparam/issue51250a.dir/a.go
new file mode 100644
index 0000000..12dd60a
--- /dev/null
+++ b/test/typeparam/issue51250a.dir/a.go
@@ -0,0 +1,9 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type G[T any] struct {
+ x T
+}
diff --git a/test/typeparam/issue51250a.dir/b.go b/test/typeparam/issue51250a.dir/b.go
new file mode 100644
index 0000000..114c9f8
--- /dev/null
+++ b/test/typeparam/issue51250a.dir/b.go
@@ -0,0 +1,24 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+type T struct { a int }
+
+var I interface{} = a.G[T]{}
+
+//go:noinline
+func F(x interface{}) {
+ switch x.(type) {
+ case a.G[T]:
+ case int:
+ panic("bad")
+ case float64:
+ panic("bad")
+ default:
+ panic("bad")
+ }
+}
diff --git a/test/typeparam/issue51250a.dir/main.go b/test/typeparam/issue51250a.dir/main.go
new file mode 100644
index 0000000..45288be
--- /dev/null
+++ b/test/typeparam/issue51250a.dir/main.go
@@ -0,0 +1,24 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "./b"
+)
+
+func main() {
+ switch b.I.(type) {
+ case a.G[b.T]:
+ case int:
+ panic("bad")
+ case float64:
+ panic("bad")
+ default:
+ panic("bad")
+ }
+
+ b.F(a.G[b.T]{})
+}
diff --git a/test/typeparam/issue51250a.go b/test/typeparam/issue51250a.go
new file mode 100644
index 0000000..aefbe67
--- /dev/null
+++ b/test/typeparam/issue51250a.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue51303.go b/test/typeparam/issue51303.go
new file mode 100644
index 0000000..a3a7849
--- /dev/null
+++ b/test/typeparam/issue51303.go
@@ -0,0 +1,65 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ x := [][]int{{1}}
+ y := [][]int{{2, 3}}
+ IntersectSS(x, y)
+}
+
+type list[E any] interface {
+ ~[]E
+ Equal(x, y E) bool
+}
+
+// ss is a set of sets
+type ss[E comparable, T []E] []T
+
+func (ss[E, T]) Equal(a, b T) bool {
+ return SetEq(a, b)
+}
+
+func IntersectSS[E comparable](x, y [][]E) [][]E {
+ return IntersectT[[]E, ss[E, []E]](ss[E, []E](x), ss[E, []E](y))
+}
+
+func IntersectT[E any, L list[E]](x, y L) L {
+ var z L
+outer:
+ for _, xe := range x {
+ fmt.Println("xe", xe)
+ for _, ye := range y {
+ fmt.Println("ye", ye)
+ fmt.Println("x", x)
+ if x.Equal(xe, ye) {
+ fmt.Println("appending")
+ z = append(z, xe)
+ continue outer
+ }
+ }
+ }
+ return z
+}
+
+func SetEq[S []E, E comparable](x, y S) bool {
+ fmt.Println("SetEq", x, y)
+outer:
+ for _, xe := range x {
+ for _, ye := range y {
+ if xe == ye {
+ continue outer
+ }
+ }
+ return false // xs wasn't found in y
+ }
+ return true
+}
diff --git a/test/typeparam/issue51303.out b/test/typeparam/issue51303.out
new file mode 100644
index 0000000..34b3be3
--- /dev/null
+++ b/test/typeparam/issue51303.out
@@ -0,0 +1,4 @@
+xe [1]
+ye [2 3]
+x [[1]]
+SetEq [1] [2 3]
diff --git a/test/typeparam/issue51355.go b/test/typeparam/issue51355.go
new file mode 100644
index 0000000..321d5ff
--- /dev/null
+++ b/test/typeparam/issue51355.go
@@ -0,0 +1,31 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Cache[E comparable] struct {
+ adder func(...E)
+}
+
+func New[E comparable]() *Cache[E] {
+ c := &Cache[E]{}
+
+ c.adder = func(elements ...E) {
+ for _, value := range elements {
+ value := value
+ go func() {
+ println(value)
+ }()
+ }
+ }
+
+ return c
+}
+
+func main() {
+ c := New[string]()
+ c.adder("test")
+}
diff --git a/test/typeparam/issue51367.dir/a.go b/test/typeparam/issue51367.dir/a.go
new file mode 100644
index 0000000..be0c3b0
--- /dev/null
+++ b/test/typeparam/issue51367.dir/a.go
@@ -0,0 +1,14 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type A[T any] struct{}
+
+func (_ A[T]) Method() {}
+
+func DoSomething[P any]() {
+ a := A[*byte]{}
+ a.Method()
+}
diff --git a/test/typeparam/issue51367.dir/main.go b/test/typeparam/issue51367.dir/main.go
new file mode 100644
index 0000000..1de8793
--- /dev/null
+++ b/test/typeparam/issue51367.dir/main.go
@@ -0,0 +1,13 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+)
+
+func main() {
+ a.DoSomething[byte]()
+}
diff --git a/test/typeparam/issue51367.go b/test/typeparam/issue51367.go
new file mode 100644
index 0000000..aefbe67
--- /dev/null
+++ b/test/typeparam/issue51367.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue51423.dir/a.go b/test/typeparam/issue51423.dir/a.go
new file mode 100644
index 0000000..e824d0e
--- /dev/null
+++ b/test/typeparam/issue51423.dir/a.go
@@ -0,0 +1,17 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Comparator[T any] func(v1, v2 T) int
+
+func CompareInt[T ~int](a, b T) int {
+ if a < b {
+ return -1
+ }
+ if a == b {
+ return 0
+ }
+ return 1
+}
diff --git a/test/typeparam/issue51423.dir/b.go b/test/typeparam/issue51423.dir/b.go
new file mode 100644
index 0000000..2bad19f
--- /dev/null
+++ b/test/typeparam/issue51423.dir/b.go
@@ -0,0 +1,11 @@
+package b
+
+import "./a"
+
+func C() a.Comparator[int] {
+ return a.CompareInt[int]
+}
+
+func main() {
+ _ = C()(1, 2)
+}
diff --git a/test/typeparam/issue51423.go b/test/typeparam/issue51423.go
new file mode 100644
index 0000000..8bb5c3e
--- /dev/null
+++ b/test/typeparam/issue51423.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue51521.go b/test/typeparam/issue51521.go
new file mode 100644
index 0000000..5eb4e35
--- /dev/null
+++ b/test/typeparam/issue51521.go
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "strings"
+)
+
+type I interface{ M() }
+
+func F[P I](p P) { defer catch(); p.M() }
+func G[T any]() { defer catch(); interface{ M() T }.M(nil) }
+
+func main() {
+ F[I](nil)
+ G[int]()
+}
+
+func catch() {
+ err := recover()
+ if err, ok := err.(error); ok && strings.Contains(err.Error(), "nil pointer dereference") {
+ return
+ }
+ fmt.Println("FAIL", err)
+}
diff --git a/test/typeparam/issue51522a.go b/test/typeparam/issue51522a.go
new file mode 100644
index 0000000..3f85408
--- /dev/null
+++ b/test/typeparam/issue51522a.go
@@ -0,0 +1,42 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package main
+
+
+func f[T comparable](i any) {
+ var t T
+
+ if i != t {
+ println("FAIL: if i != t")
+ }
+}
+
+type myint int
+
+func (m myint) foo() {
+}
+
+type fooer interface {
+ foo()
+}
+
+type comparableFoo interface {
+ comparable
+ foo()
+}
+
+func g[T comparableFoo](i fooer) {
+ var t T
+
+ if i != t {
+ println("FAIL: if i != t")
+ }
+}
+
+func main() {
+ f[int](int(0))
+ g[myint](myint(0))
+}
diff --git a/test/typeparam/issue51522b.go b/test/typeparam/issue51522b.go
new file mode 100644
index 0000000..115b6b9
--- /dev/null
+++ b/test/typeparam/issue51522b.go
@@ -0,0 +1,62 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[T comparable](i any) {
+ var t T
+
+ switch i {
+ case t:
+ // ok
+ default:
+ println("FAIL: switch i")
+ }
+
+ switch t {
+ case i:
+ // ok
+ default:
+ println("FAIL: switch t")
+ }
+}
+
+type myint int
+
+func (m myint) foo() {
+}
+
+type fooer interface {
+ foo()
+}
+
+type comparableFoo interface {
+ comparable
+ foo()
+}
+
+func g[T comparableFoo](i fooer) {
+ var t T
+
+ switch i {
+ case t:
+ // ok
+ default:
+ println("FAIL: switch i")
+ }
+
+ switch t {
+ case i:
+ // ok
+ default:
+ println("FAIL: switch t")
+ }
+}
+
+func main() {
+ f[int](0)
+ g[myint](myint(0))
+}
diff --git a/test/typeparam/issue51700.go b/test/typeparam/issue51700.go
new file mode 100644
index 0000000..bf8a1f6
--- /dev/null
+++ b/test/typeparam/issue51700.go
@@ -0,0 +1,26 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[B any](b B) {
+ if b1, ok := any(b).(interface{ m1() }); ok {
+ panic(1)
+ _ = b1.(B)
+ }
+ if b2, ok := any(b).(interface{ m2() }); ok {
+ panic(2)
+ _ = b2.(B)
+ }
+}
+
+type S struct{}
+
+func (S) m3() {}
+
+func main() {
+ f(S{})
+}
diff --git a/test/typeparam/issue51765.go b/test/typeparam/issue51765.go
new file mode 100644
index 0000000..683cb0f
--- /dev/null
+++ b/test/typeparam/issue51765.go
@@ -0,0 +1,15 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type empty[T any] struct{}
+
+func (this *empty[T]) Next() (empty T, _ error) {
+ return empty, nil
+}
+
+var _ = &empty[string]{}
diff --git a/test/typeparam/issue51832.go b/test/typeparam/issue51832.go
new file mode 100644
index 0000000..c325ae6
--- /dev/null
+++ b/test/typeparam/issue51832.go
@@ -0,0 +1,25 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type F func() F
+
+func do[T any]() F {
+ return nil
+}
+
+type G[T any] func() G[T]
+
+//go:noinline
+func dog[T any]() G[T] {
+ return nil
+}
+
+func main() {
+ do[int]()
+ dog[int]()
+}
diff --git a/test/typeparam/issue51836.dir/a.go b/test/typeparam/issue51836.dir/a.go
new file mode 100644
index 0000000..e9223c9
--- /dev/null
+++ b/test/typeparam/issue51836.dir/a.go
@@ -0,0 +1,8 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type T[K any] struct {
+}
diff --git a/test/typeparam/issue51836.dir/aa.go b/test/typeparam/issue51836.dir/aa.go
new file mode 100644
index 0000000..d774be2
--- /dev/null
+++ b/test/typeparam/issue51836.dir/aa.go
@@ -0,0 +1,13 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import (
+ "./a"
+)
+
+type T[K any] struct {
+ t a.T[K]
+}
diff --git a/test/typeparam/issue51836.dir/p.go b/test/typeparam/issue51836.dir/p.go
new file mode 100644
index 0000000..98197ae
--- /dev/null
+++ b/test/typeparam/issue51836.dir/p.go
@@ -0,0 +1,11 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import (
+ a "./aa"
+)
+
+var Foo a.T[int]
diff --git a/test/typeparam/issue51836.go b/test/typeparam/issue51836.go
new file mode 100644
index 0000000..c755e74
--- /dev/null
+++ b/test/typeparam/issue51836.go
@@ -0,0 +1,7 @@
+// compiledir -s
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue51840.go b/test/typeparam/issue51840.go
new file mode 100644
index 0000000..19fa3e4
--- /dev/null
+++ b/test/typeparam/issue51840.go
@@ -0,0 +1,36 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Addr struct {
+ hi uint64
+ lo uint64
+ z *byte
+}
+
+func EqualMap[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool {
+ for k, v1 := range m1 {
+ if v2, ok := m2[k]; !ok || v1 != v2 {
+ return false
+ }
+ }
+ return true
+}
+
+type Set[T comparable] map[T]struct{}
+
+func NewSet[T comparable](items ...T) Set[T] {
+ return nil
+}
+
+func (s Set[T]) Equals(other Set[T]) bool {
+ return EqualMap(s, other)
+}
+
+func main() {
+ NewSet[Addr](Addr{0, 0, nil})
+}
diff --git a/test/typeparam/issue51909.go b/test/typeparam/issue51909.go
new file mode 100644
index 0000000..5fe39ca
--- /dev/null
+++ b/test/typeparam/issue51909.go
@@ -0,0 +1,30 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type None struct{}
+
+type Response interface {
+ send(ctx *struct{})
+}
+
+type HandlerFunc[Input any] func(Input) Response
+
+func Operation[Input any](method, path string, h HandlerFunc[Input]) {
+ var input Input
+ h(input)
+}
+
+func Get[Body any](path string, h HandlerFunc[struct{ Body Body }]) {
+ Operation("GET", path, h)
+}
+
+func main() {
+ Get("/", func(req struct{ Body None }) Response {
+ return nil
+ })
+}
diff --git a/test/typeparam/issue51925.go b/test/typeparam/issue51925.go
new file mode 100644
index 0000000..0a385ac
--- /dev/null
+++ b/test/typeparam/issue51925.go
@@ -0,0 +1,52 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type IntLike interface {
+ ~int | ~int64 | ~int32 | ~int16 | ~int8
+}
+
+func Reduce[T any, U any, Uslice ~[]U](function func(T, U) T, sequence Uslice, initial T) T {
+ result := initial
+ for _, x := range sequence {
+ result = function(result, x)
+ }
+ return result
+}
+
+func min[T IntLike](x, y T) T {
+ if x < y {
+ return x
+ }
+ return y
+
+}
+
+// Min returns the minimum element of `nums`.
+func Min[T IntLike, NumSlice ~[]T](nums NumSlice) T {
+ if len(nums) == 0 {
+ return T(0)
+ }
+ return Reduce(min[T], nums, nums[0])
+}
+
+// VarMin is the variadic version of Min.
+func VarMin[T IntLike](nums ...T) T {
+ return Min(nums)
+}
+
+type myInt int
+
+func main() {
+ fmt.Println(VarMin(myInt(1), myInt(2)))
+
+ seq := []myInt{1, 2}
+ fmt.Println(Min(seq))
+ fmt.Println(VarMin(seq...))
+}
diff --git a/test/typeparam/issue52026.go b/test/typeparam/issue52026.go
new file mode 100644
index 0000000..db8999a
--- /dev/null
+++ b/test/typeparam/issue52026.go
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func returnOption[T any](n int) Option[T] {
+ if n == 1 {
+ return Some[T]{}
+ } else {
+ return None{}
+ }
+}
+
+type Option[T any] interface {
+ sealedOption()
+}
+
+type Some[T any] struct {
+ val T
+}
+
+func (s Some[T]) Value() T {
+ return s.val
+}
+
+func (s Some[T]) sealedOption() {}
+
+type None struct{}
+
+func (s None) sealedOption() {}
+
+func main() {
+ s := returnOption[int](1)
+ _ = s.(Some[int])
+
+ s = returnOption[int](0)
+ _ = s.(None)
+
+ switch (any)(s).(type) {
+ case Some[int]:
+ panic("s is a Some[int]")
+ case None:
+ // ok
+ default:
+ panic("oops")
+ }
+}
diff --git a/test/typeparam/issue52117.dir/a.go b/test/typeparam/issue52117.dir/a.go
new file mode 100644
index 0000000..e571ea9
--- /dev/null
+++ b/test/typeparam/issue52117.dir/a.go
@@ -0,0 +1,15 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func Compare[T int | uint](a, b T) int {
+ return 0
+}
+
+type Slice[T int | uint] struct{}
+
+func (l Slice[T]) Comparator() func(v1, v2 T) int {
+ return Compare[T]
+}
diff --git a/test/typeparam/issue52117.dir/b.go b/test/typeparam/issue52117.dir/b.go
new file mode 100644
index 0000000..3d3bf4c
--- /dev/null
+++ b/test/typeparam/issue52117.dir/b.go
@@ -0,0 +1,7 @@
+package b
+
+import "./a"
+
+func Test() {
+ var _ a.Slice[uint]
+}
diff --git a/test/typeparam/issue52117.go b/test/typeparam/issue52117.go
new file mode 100644
index 0000000..8bb5c3e
--- /dev/null
+++ b/test/typeparam/issue52117.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/issue52124.go b/test/typeparam/issue52124.go
new file mode 100644
index 0000000..802d103
--- /dev/null
+++ b/test/typeparam/issue52124.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type Any any
+type IntOrBool interface{ int | bool }
+
+type I interface{ Any | IntOrBool }
+
+var (
+ X I = 42
+ Y I = "xxx"
+ Z I = true
+)
+
+type A interface{ *B | int }
+type B interface{ A | any }
diff --git a/test/typeparam/issue52228.go b/test/typeparam/issue52228.go
new file mode 100644
index 0000000..3fbbde5
--- /dev/null
+++ b/test/typeparam/issue52228.go
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type SomeInterface interface {
+ Whatever()
+}
+
+func X[T any]() T {
+ var m T
+
+ // for this example, this block should never run
+ if _, ok := any(m).(SomeInterface); ok {
+ var dst SomeInterface
+ _, _ = dst.(T)
+ return dst.(T)
+ }
+
+ return m
+}
+
+type holder struct{}
+
+func main() {
+ X[holder]()
+}
diff --git a/test/typeparam/issue52241.go b/test/typeparam/issue52241.go
new file mode 100644
index 0000000..4feb97e
--- /dev/null
+++ b/test/typeparam/issue52241.go
@@ -0,0 +1,22 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Collector[T any] struct {
+}
+
+func (c *Collector[T]) Collect() {
+}
+
+func TestInOrderIntTree() {
+ collector := Collector[int]{}
+ _ = collector.Collect
+}
+
+func main() {
+ TestInOrderIntTree()
+}
diff --git a/test/typeparam/issue53087.go b/test/typeparam/issue53087.go
new file mode 100644
index 0000000..5e19c59
--- /dev/null
+++ b/test/typeparam/issue53087.go
@@ -0,0 +1,56 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type I interface {
+ M()
+}
+
+type S struct {
+ str string
+}
+
+func (s *S) M() {}
+
+var _ I = &S{}
+
+type CloningMap[K comparable, V any] struct {
+ inner map[K]V
+}
+
+func (cm CloningMap[K, V]) With(key K, value V) CloningMap[K, V] {
+ result := CloneBad(cm.inner)
+ result[key] = value
+ return CloningMap[K, V]{result}
+}
+
+func CloneBad[M ~map[K]V, K comparable, V any](m M) M {
+ r := make(M, len(m))
+ for k, v := range m {
+ r[k] = v
+ }
+ return r
+}
+
+func main() {
+ s1 := &S{"one"}
+ s2 := &S{"two"}
+
+ m := CloningMap[string, I]{inner: make(map[string]I)}
+ m = m.With("a", s1)
+ m = m.With("b", s2)
+
+ it, found := m.inner["a"]
+ if !found {
+ panic("a not found")
+ }
+ if _, ok := it.(*S); !ok {
+ panic(fmt.Sprintf("got %T want *main.S", it))
+ }
+}
diff --git a/test/typeparam/issue53254.go b/test/typeparam/issue53254.go
new file mode 100644
index 0000000..afc0f18
--- /dev/null
+++ b/test/typeparam/issue53254.go
@@ -0,0 +1,19 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Interface[T any] interface {
+}
+
+func F[T any]() Interface[T] {
+ var i int
+ return i
+}
+
+func main() {
+ F[int]()
+}
diff --git a/test/typeparam/issue53390.go b/test/typeparam/issue53390.go
new file mode 100644
index 0000000..52098c5
--- /dev/null
+++ b/test/typeparam/issue53390.go
@@ -0,0 +1,20 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import "unsafe"
+
+func F[T any](v T) uintptr {
+ return unsafe.Alignof(func() T {
+ func(any) {}(struct{ _ T }{})
+ return v
+ }())
+}
+
+func f() {
+ F(0)
+}
diff --git a/test/typeparam/issue53406.go b/test/typeparam/issue53406.go
new file mode 100644
index 0000000..90fe78f
--- /dev/null
+++ b/test/typeparam/issue53406.go
@@ -0,0 +1,22 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ f[int]()
+}
+
+func f[T1 any]() {
+ var x Outer[T1, int]
+ x.M()
+}
+
+type Outer[T1, T2 any] struct{ Inner[T2] }
+
+type Inner[_ any] int
+
+func (Inner[_]) M() {}
diff --git a/test/typeparam/issue53419.go b/test/typeparam/issue53419.go
new file mode 100644
index 0000000..62a226f
--- /dev/null
+++ b/test/typeparam/issue53419.go
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T1 struct{}
+type T2 struct{}
+type Both struct {
+ T1
+ T2
+}
+
+func (T1) m() { panic("FAIL") }
+func (T2) m() { panic("FAIL") }
+func (Both) m() {}
+
+func f[T interface{ m() }](c T) {
+ c.m()
+}
+
+func main() {
+ var b Both
+ b.m()
+ f(b)
+}
diff --git a/test/typeparam/issue53477.go b/test/typeparam/issue53477.go
new file mode 100644
index 0000000..d128a7e
--- /dev/null
+++ b/test/typeparam/issue53477.go
@@ -0,0 +1,34 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that generic interface-interface comparisons resulting from
+// value switch statements are handled correctly.
+
+package main
+
+func main() {
+ f[X](0)
+}
+
+type Mer[T any] interface{ M(T) }
+type MNer[T any] interface {
+ Mer[T]
+ N()
+}
+
+type X int
+
+func (X) M(X) {}
+func (X) N() {}
+
+func f[T MNer[T]](t T) {
+ switch Mer[T](t) {
+ case MNer[T](t):
+ // ok
+ default:
+ panic("FAIL")
+ }
+}
diff --git a/test/typeparam/issue53762.go b/test/typeparam/issue53762.go
new file mode 100644
index 0000000..e6d7f0f
--- /dev/null
+++ b/test/typeparam/issue53762.go
@@ -0,0 +1,18 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Value[T any] interface {
+}
+
+func use[T any](v Value[T]) {
+ _, _ = v.(int)
+}
+
+func main() {
+ use[int](Value[int](1))
+}
diff --git a/test/typeparam/issue54135.go b/test/typeparam/issue54135.go
new file mode 100644
index 0000000..b489a51
--- /dev/null
+++ b/test/typeparam/issue54135.go
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Foo struct{}
+
+func (Foo) Blanker() {}
+
+type Bar[T any] interface {
+ Blanker()
+}
+
+type Baz interface {
+ Some()
+}
+
+func check[T comparable](p Bar[T]) {
+ if x, ok := p.(any); !ok || x != p {
+ panic("FAIL")
+ }
+ if _, ok := p.(Baz); ok {
+ panic("FAIL")
+ }
+}
+
+func main() {
+ check[int](Foo{})
+}
diff --git a/test/typeparam/issue54225.go b/test/typeparam/issue54225.go
new file mode 100644
index 0000000..4de3efc
--- /dev/null
+++ b/test/typeparam/issue54225.go
@@ -0,0 +1,33 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ One[TextValue]()
+}
+
+func One[V Value]() { Two[Node[V]]() }
+
+func Two[V interface{ contentLen() int }]() {
+ var v V
+ v.contentLen()
+}
+
+type Value interface {
+ Len() int
+}
+
+type Node[V Value] struct{}
+
+func (Node[V]) contentLen() int {
+ var value V
+ return value.Len()
+}
+
+type TextValue struct{}
+
+func (TextValue) Len() int { return 0 }
diff --git a/test/typeparam/issue54302.dir/a.go b/test/typeparam/issue54302.dir/a.go
new file mode 100644
index 0000000..52875ab
--- /dev/null
+++ b/test/typeparam/issue54302.dir/a.go
@@ -0,0 +1,20 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func A() {
+ B[int](new(G[int]))
+}
+
+func B[T any](iface interface{ M(T) }) {
+ x, ok := iface.(*G[T])
+ if !ok || iface != x {
+ panic("FAIL")
+ }
+}
+
+type G[T any] struct{}
+
+func (*G[T]) M(T) {}
diff --git a/test/typeparam/issue54302.dir/main.go b/test/typeparam/issue54302.dir/main.go
new file mode 100644
index 0000000..b4c6cd1
--- /dev/null
+++ b/test/typeparam/issue54302.dir/main.go
@@ -0,0 +1,11 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ a.A()
+}
diff --git a/test/typeparam/issue54302.go b/test/typeparam/issue54302.go
new file mode 100644
index 0000000..f132421
--- /dev/null
+++ b/test/typeparam/issue54302.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
diff --git a/test/typeparam/issue54456.go b/test/typeparam/issue54456.go
new file mode 100644
index 0000000..8342163
--- /dev/null
+++ b/test/typeparam/issue54456.go
@@ -0,0 +1,37 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The Go 1.18 frontend failed to disambiguate instantiations of
+// different, locally defined generic types with the same name.
+//
+// The unified frontend also exposed the scope-disambiguation mangling
+// to end users in reflect data.
+
+package main
+
+import (
+ "reflect"
+)
+
+func one() any { type T[_ any] int; return T[int](0) }
+func two() any { type T[_ any] int; return T[int](0) }
+
+func main() {
+ p, q := one(), two()
+
+ // p and q have different dynamic types; this comparison should
+ // evaluate false.
+ if p == q {
+ panic("bad type identity")
+ }
+
+ for _, x := range []any{p, q} {
+ // The names here should not contain "·1" or "·2".
+ if name := reflect.TypeOf(x).String(); name != "main.T[int]" {
+ panic(name)
+ }
+ }
+}
diff --git a/test/typeparam/issue54497.go b/test/typeparam/issue54497.go
new file mode 100644
index 0000000..1b24cd9
--- /dev/null
+++ b/test/typeparam/issue54497.go
@@ -0,0 +1,19 @@
+// errorcheck -0 -m
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that inlining works with generic functions.
+
+package testcase
+
+type C interface{ ~uint | ~uint32 | ~uint64 }
+
+func isAligned[T C](x, y T) bool { // ERROR "can inline isAligned\[uint\]" "can inline isAligned\[go\.shape\.uint\]" "inlining call to isAligned\[go\.shape\.uint\]"
+ return x%y == 0
+}
+
+func foo(x uint) bool { // ERROR "can inline foo"
+ return isAligned(x, 64) // ERROR "inlining call to isAligned\[go\.shape\.uint\]"
+}
diff --git a/test/typeparam/issue54535.go b/test/typeparam/issue54535.go
new file mode 100644
index 0000000..574b275
--- /dev/null
+++ b/test/typeparam/issue54535.go
@@ -0,0 +1,37 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type node[T any] struct {
+ items items[T]
+ children items[*node[T]]
+}
+
+func (n *node[T]) f(i int, j int) bool {
+ if len(n.children[i].items) < j {
+ return false
+ }
+ return true
+}
+
+type items[T any] []T
+
+func main() {
+ _ = node[int]{}
+ _ = f[int]
+}
+
+type s[T, U any] struct {
+ a T
+ c U
+}
+
+func f[T any]() {
+ var x s[*struct{ b T }, *struct{ d int }]
+ _ = x.a.b
+ _ = x.c.d
+}
diff --git a/test/typeparam/issue54537.go b/test/typeparam/issue54537.go
new file mode 100644
index 0000000..614ed46
--- /dev/null
+++ b/test/typeparam/issue54537.go
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ _ = F[bool]
+
+ var x string
+ _ = G(x == "foo")
+}
+
+func F[T ~bool](x string) {
+ var _ T = x == "foo"
+}
+
+func G[T any](t T) *T {
+ return &t
+}
diff --git a/test/typeparam/issue54765.go b/test/typeparam/issue54765.go
new file mode 100644
index 0000000..364567d
--- /dev/null
+++ b/test/typeparam/issue54765.go
@@ -0,0 +1,28 @@
+// errorcheck
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that not-in-heap types cannot be used as type
+// arguments. (pointer-to-nih types are okay though.)
+
+//go:build cgo
+// +build cgo
+
+package p
+
+import (
+ "runtime/cgo"
+ "sync/atomic"
+)
+
+var _ atomic.Pointer[cgo.Incomplete] // ERROR "cannot use incomplete \(or unallocatable\) type as a type argument: runtime/cgo\.Incomplete"
+var _ atomic.Pointer[*cgo.Incomplete] // ok
+
+func implicit(ptr *cgo.Incomplete) {
+ g(ptr) // ERROR "cannot use incomplete \(or unallocatable\) type as a type argument: runtime/cgo\.Incomplete"
+ g(&ptr) // ok
+}
+
+func g[T any](_ *T) {}
diff --git a/test/typeparam/issue55101.go b/test/typeparam/issue55101.go
new file mode 100644
index 0000000..2d45c87
--- /dev/null
+++ b/test/typeparam/issue55101.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func F() *Cache[error] { return nil }
+
+type Cache[T any] struct{ l *List[entry[T]] }
+type entry[T any] struct{ value T }
+type List[T any] struct{ len int }
+
+func (c *Cache[V]) Len() int { return c.l.Len() }
+func (l *List[T]) Len() int { return l.len }
diff --git a/test/typeparam/issue58513.go b/test/typeparam/issue58513.go
new file mode 100644
index 0000000..37cb572
--- /dev/null
+++ b/test/typeparam/issue58513.go
@@ -0,0 +1,60 @@
+// run
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Some derived-type expressions require the compiler to synthesize
+// function literals to plumb sub-dictionaries appropriately.
+// However, when these expressions are inlined, we were constructing
+// the function literal bodies with the inline-adjusted positions
+// instead of the original (inline-free) positions, which could lead
+// to infinite loops when unwinding the stack.
+
+package main
+
+import "runtime"
+
+func assert[_ any]() {
+ panic(0)
+}
+
+func Assert[To any]() func() {
+ return assert[To]
+}
+
+type asserter[_ any] struct{}
+
+func (asserter[_]) assert() {
+ panic(0)
+}
+
+func AssertMV[To any]() func() {
+ return asserter[To]{}.assert
+}
+
+func AssertME[To any]() func(asserter[To]) {
+ return asserter[To].assert
+}
+
+var me = AssertME[string]()
+
+var tests = []func(){
+ Assert[int](),
+ AssertMV[int](),
+ func() { me(asserter[string]{}) },
+}
+
+func main() {
+ for _, test := range tests {
+ func() {
+ defer func() {
+ recover()
+
+ // Check that we can unwind the stack without infinite looping.
+ runtime.Caller(1000)
+ }()
+ test()
+ }()
+ }
+}
diff --git a/test/typeparam/list.go b/test/typeparam/list.go
new file mode 100644
index 0000000..34ad71c
--- /dev/null
+++ b/test/typeparam/list.go
@@ -0,0 +1,103 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type Ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+// _List is a linked list of ordered values of type T.
+type _List[T Ordered] struct {
+ next *_List[T]
+ val T
+}
+
+func (l *_List[T]) Largest() T {
+ var max T
+ for p := l; p != nil; p = p.next {
+ if p.val > max {
+ max = p.val
+ }
+ }
+ return max
+}
+
+type OrderedNum interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64
+}
+
+// _ListNum is a linked _List of ordered numeric values of type T.
+type _ListNum[T OrderedNum] struct {
+ next *_ListNum[T]
+ val T
+}
+
+const Clip = 5
+
+// ClippedLargest returns the largest in the list of OrderNums, but a max of 5.
+// Test use of untyped constant in an expression with a generically-typed parameter
+func (l *_ListNum[T]) ClippedLargest() T {
+ var max T
+ for p := l; p != nil; p = p.next {
+ if p.val > max && p.val < Clip {
+ max = p.val
+ }
+ }
+ return max
+}
+
+func main() {
+ i3 := &_List[int]{nil, 1}
+ i2 := &_List[int]{i3, 3}
+ i1 := &_List[int]{i2, 2}
+ if got, want := i1.Largest(), 3; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ b3 := &_List[byte]{nil, byte(1)}
+ b2 := &_List[byte]{b3, byte(3)}
+ b1 := &_List[byte]{b2, byte(2)}
+ if got, want := b1.Largest(), byte(3); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ f3 := &_List[float64]{nil, 13.5}
+ f2 := &_List[float64]{f3, 1.2}
+ f1 := &_List[float64]{f2, 4.5}
+ if got, want := f1.Largest(), 13.5; got != want {
+ panic(fmt.Sprintf("got %f, want %f", got, want))
+ }
+
+ s3 := &_List[string]{nil, "dd"}
+ s2 := &_List[string]{s3, "aa"}
+ s1 := &_List[string]{s2, "bb"}
+ if got, want := s1.Largest(), "dd"; got != want {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ j3 := &_ListNum[int]{nil, 1}
+ j2 := &_ListNum[int]{j3, 32}
+ j1 := &_ListNum[int]{j2, 2}
+ if got, want := j1.ClippedLargest(), 2; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ g3 := &_ListNum[float64]{nil, 13.5}
+ g2 := &_ListNum[float64]{g3, 1.2}
+ g1 := &_ListNum[float64]{g2, 4.5}
+ if got, want := g1.ClippedLargest(), 4.5; got != want {
+ panic(fmt.Sprintf("got %f, want %f", got, want))
+ }
+}
diff --git a/test/typeparam/list2.go b/test/typeparam/list2.go
new file mode 100644
index 0000000..111ac78
--- /dev/null
+++ b/test/typeparam/list2.go
@@ -0,0 +1,608 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package list provides a doubly linked list of some element type
+// (generic form of the "container/list" package).
+
+package main
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Element is an element of a linked list.
+type _Element[T any] struct {
+ // Next and previous pointers in the doubly-linked list of elements.
+ // To simplify the implementation, internally a list l is implemented
+ // as a ring, such that &l.root is both the next element of the last
+ // list element (l.Back()) and the previous element of the first list
+ // element (l.Front()).
+ next, prev *_Element[T]
+
+ // The list to which this element belongs.
+ list *_List[T]
+
+ // The value stored with this element.
+ Value T
+}
+
+// Next returns the next list element or nil.
+func (e *_Element[T]) Next() *_Element[T] {
+ if p := e.next; e.list != nil && p != &e.list.root {
+ return p
+ }
+ return nil
+}
+
+// Prev returns the previous list element or nil.
+func (e *_Element[T]) Prev() *_Element[T] {
+ if p := e.prev; e.list != nil && p != &e.list.root {
+ return p
+ }
+ return nil
+}
+
+// _List represents a doubly linked list.
+// The zero value for _List is an empty list ready to use.
+type _List[T any] struct {
+ root _Element[T] // sentinel list element, only &root, root.prev, and root.next are used
+ len int // current list length excluding (this) sentinel element
+}
+
+// Init initializes or clears list l.
+func (l *_List[T]) Init() *_List[T] {
+ l.root.next = &l.root
+ l.root.prev = &l.root
+ l.len = 0
+ return l
+}
+
+// New returns an initialized list.
+func _New[T any]() *_List[T] { return new(_List[T]).Init() }
+
+// Len returns the number of elements of list l.
+// The complexity is O(1).
+func (l *_List[_]) Len() int { return l.len }
+
+// Front returns the first element of list l or nil if the list is empty.
+func (l *_List[T]) Front() *_Element[T] {
+ if l.len == 0 {
+ return nil
+ }
+ return l.root.next
+}
+
+// Back returns the last element of list l or nil if the list is empty.
+func (l *_List[T]) Back() *_Element[T] {
+ if l.len == 0 {
+ return nil
+ }
+ return l.root.prev
+}
+
+// lazyInit lazily initializes a zero _List value.
+func (l *_List[_]) lazyInit() {
+ if l.root.next == nil {
+ l.Init()
+ }
+}
+
+// insert inserts e after at, increments l.len, and returns e.
+func (l *_List[T]) insert(e, at *_Element[T]) *_Element[T] {
+ e.prev = at
+ e.next = at.next
+ e.prev.next = e
+ e.next.prev = e
+ e.list = l
+ l.len++
+ return e
+}
+
+// insertValue is a convenience wrapper for insert(&_Element[T]{Value: v}, at).
+func (l *_List[T]) insertValue(v T, at *_Element[T]) *_Element[T] {
+ return l.insert(&_Element[T]{Value: v}, at)
+}
+
+// remove removes e from its list, decrements l.len, and returns e.
+func (l *_List[T]) remove(e *_Element[T]) *_Element[T] {
+ e.prev.next = e.next
+ e.next.prev = e.prev
+ e.next = nil // avoid memory leaks
+ e.prev = nil // avoid memory leaks
+ e.list = nil
+ l.len--
+ return e
+}
+
+// move moves e to next to at and returns e.
+func (l *_List[T]) move(e, at *_Element[T]) *_Element[T] {
+ if e == at {
+ return e
+ }
+ e.prev.next = e.next
+ e.next.prev = e.prev
+
+ e.prev = at
+ e.next = at.next
+ e.prev.next = e
+ e.next.prev = e
+
+ return e
+}
+
+// Remove removes e from l if e is an element of list l.
+// It returns the element value e.Value.
+// The element must not be nil.
+func (l *_List[T]) Remove(e *_Element[T]) T {
+ if e.list == l {
+ // if e.list == l, l must have been initialized when e was inserted
+ // in l or l == nil (e is a zero _Element) and l.remove will crash
+ l.remove(e)
+ }
+ return e.Value
+}
+
+// PushFront inserts a new element e with value v at the front of list l and returns e.
+func (l *_List[T]) PushFront(v T) *_Element[T] {
+ l.lazyInit()
+ return l.insertValue(v, &l.root)
+}
+
+// PushBack inserts a new element e with value v at the back of list l and returns e.
+func (l *_List[T]) PushBack(v T) *_Element[T] {
+ l.lazyInit()
+ return l.insertValue(v, l.root.prev)
+}
+
+// InsertBefore inserts a new element e with value v immediately before mark and returns e.
+// If mark is not an element of l, the list is not modified.
+// The mark must not be nil.
+func (l *_List[T]) InsertBefore(v T, mark *_Element[T]) *_Element[T] {
+ if mark.list != l {
+ return nil
+ }
+ // see comment in _List.Remove about initialization of l
+ return l.insertValue(v, mark.prev)
+}
+
+// InsertAfter inserts a new element e with value v immediately after mark and returns e.
+// If mark is not an element of l, the list is not modified.
+// The mark must not be nil.
+func (l *_List[T]) InsertAfter(v T, mark *_Element[T]) *_Element[T] {
+ if mark.list != l {
+ return nil
+ }
+ // see comment in _List.Remove about initialization of l
+ return l.insertValue(v, mark)
+}
+
+// MoveToFront moves element e to the front of list l.
+// If e is not an element of l, the list is not modified.
+// The element must not be nil.
+func (l *_List[T]) MoveToFront(e *_Element[T]) {
+ if e.list != l || l.root.next == e {
+ return
+ }
+ // see comment in _List.Remove about initialization of l
+ l.move(e, &l.root)
+}
+
+// MoveToBack moves element e to the back of list l.
+// If e is not an element of l, the list is not modified.
+// The element must not be nil.
+func (l *_List[T]) MoveToBack(e *_Element[T]) {
+ if e.list != l || l.root.prev == e {
+ return
+ }
+ // see comment in _List.Remove about initialization of l
+ l.move(e, l.root.prev)
+}
+
+// MoveBefore moves element e to its new position before mark.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
+// The element and mark must not be nil.
+func (l *_List[T]) MoveBefore(e, mark *_Element[T]) {
+ if e.list != l || e == mark || mark.list != l {
+ return
+ }
+ l.move(e, mark.prev)
+}
+
+// MoveAfter moves element e to its new position after mark.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
+// The element and mark must not be nil.
+func (l *_List[T]) MoveAfter(e, mark *_Element[T]) {
+ if e.list != l || e == mark || mark.list != l {
+ return
+ }
+ l.move(e, mark)
+}
+
+// PushBackList inserts a copy of an other list at the back of list l.
+// The lists l and other may be the same. They must not be nil.
+func (l *_List[T]) PushBackList(other *_List[T]) {
+ l.lazyInit()
+ for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
+ l.insertValue(e.Value, l.root.prev)
+ }
+}
+
+// PushFrontList inserts a copy of an other list at the front of list l.
+// The lists l and other may be the same. They must not be nil.
+func (l *_List[T]) PushFrontList(other *_List[T]) {
+ l.lazyInit()
+ for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() {
+ l.insertValue(e.Value, &l.root)
+ }
+}
+
+// Transform runs a transform function on a list returning a new list.
+func _Transform[TElem1, TElem2 any](lst *_List[TElem1], f func(TElem1) TElem2) *_List[TElem2] {
+ ret := _New[TElem2]()
+ for p := lst.Front(); p != nil; p = p.Next() {
+ ret.PushBack(f(p.Value))
+ }
+ return ret
+}
+
+func checkListLen[T any](l *_List[T], len int) bool {
+ if n := l.Len(); n != len {
+ panic(fmt.Sprintf("l.Len() = %d, want %d", n, len))
+ return false
+ }
+ return true
+}
+
+func checkListPointers[T any](l *_List[T], es []*_Element[T]) {
+ root := &l.root
+
+ if !checkListLen(l, len(es)) {
+ return
+ }
+
+ // zero length lists must be the zero value or properly initialized (sentinel circle)
+ if len(es) == 0 {
+ if l.root.next != nil && l.root.next != root || l.root.prev != nil && l.root.prev != root {
+ panic(fmt.Sprintf("l.root.next = %p, l.root.prev = %p; both should both be nil or %p", l.root.next, l.root.prev, root))
+ }
+ return
+ }
+ // len(es) > 0
+
+ // check internal and external prev/next connections
+ for i, e := range es {
+ prev := root
+ Prev := (*_Element[T])(nil)
+ if i > 0 {
+ prev = es[i-1]
+ Prev = prev
+ }
+ if p := e.prev; p != prev {
+ panic(fmt.Sprintf("elt[%d](%p).prev = %p, want %p", i, e, p, prev))
+ }
+ if p := e.Prev(); p != Prev {
+ panic(fmt.Sprintf("elt[%d](%p).Prev() = %p, want %p", i, e, p, Prev))
+ }
+
+ next := root
+ Next := (*_Element[T])(nil)
+ if i < len(es)-1 {
+ next = es[i+1]
+ Next = next
+ }
+ if n := e.next; n != next {
+ panic(fmt.Sprintf("elt[%d](%p).next = %p, want %p", i, e, n, next))
+ }
+ if n := e.Next(); n != Next {
+ panic(fmt.Sprintf("elt[%d](%p).Next() = %p, want %p", i, e, n, Next))
+ }
+ }
+}
+
+func TestList() {
+ l := _New[string]()
+ checkListPointers(l, []*(_Element[string]){})
+
+ // Single element list
+ e := l.PushFront("a")
+ checkListPointers(l, []*(_Element[string]){e})
+ l.MoveToFront(e)
+ checkListPointers(l, []*(_Element[string]){e})
+ l.MoveToBack(e)
+ checkListPointers(l, []*(_Element[string]){e})
+ l.Remove(e)
+ checkListPointers(l, []*(_Element[string]){})
+
+ // Bigger list
+ l2 := _New[int]()
+ e2 := l2.PushFront(2)
+ e1 := l2.PushFront(1)
+ e3 := l2.PushBack(3)
+ e4 := l2.PushBack(600)
+ checkListPointers(l2, []*(_Element[int]){e1, e2, e3, e4})
+
+ l2.Remove(e2)
+ checkListPointers(l2, []*(_Element[int]){e1, e3, e4})
+
+ l2.MoveToFront(e3) // move from middle
+ checkListPointers(l2, []*(_Element[int]){e3, e1, e4})
+
+ l2.MoveToFront(e1)
+ l2.MoveToBack(e3) // move from middle
+ checkListPointers(l2, []*(_Element[int]){e1, e4, e3})
+
+ l2.MoveToFront(e3) // move from back
+ checkListPointers(l2, []*(_Element[int]){e3, e1, e4})
+ l2.MoveToFront(e3) // should be no-op
+ checkListPointers(l2, []*(_Element[int]){e3, e1, e4})
+
+ l2.MoveToBack(e3) // move from front
+ checkListPointers(l2, []*(_Element[int]){e1, e4, e3})
+ l2.MoveToBack(e3) // should be no-op
+ checkListPointers(l2, []*(_Element[int]){e1, e4, e3})
+
+ e2 = l2.InsertBefore(2, e1) // insert before front
+ checkListPointers(l2, []*(_Element[int]){e2, e1, e4, e3})
+ l2.Remove(e2)
+ e2 = l2.InsertBefore(2, e4) // insert before middle
+ checkListPointers(l2, []*(_Element[int]){e1, e2, e4, e3})
+ l2.Remove(e2)
+ e2 = l2.InsertBefore(2, e3) // insert before back
+ checkListPointers(l2, []*(_Element[int]){e1, e4, e2, e3})
+ l2.Remove(e2)
+
+ e2 = l2.InsertAfter(2, e1) // insert after front
+ checkListPointers(l2, []*(_Element[int]){e1, e2, e4, e3})
+ l2.Remove(e2)
+ e2 = l2.InsertAfter(2, e4) // insert after middle
+ checkListPointers(l2, []*(_Element[int]){e1, e4, e2, e3})
+ l2.Remove(e2)
+ e2 = l2.InsertAfter(2, e3) // insert after back
+ checkListPointers(l2, []*(_Element[int]){e1, e4, e3, e2})
+ l2.Remove(e2)
+
+ // Check standard iteration.
+ sum := 0
+ for e := l2.Front(); e != nil; e = e.Next() {
+ sum += e.Value
+ }
+ if sum != 604 {
+ panic(fmt.Sprintf("sum over l = %d, want 604", sum))
+ }
+
+ // Clear all elements by iterating
+ var next *_Element[int]
+ for e := l2.Front(); e != nil; e = next {
+ next = e.Next()
+ l2.Remove(e)
+ }
+ checkListPointers(l2, []*(_Element[int]){})
+}
+
+func checkList[T comparable](l *_List[T], es []interface{}) {
+ if !checkListLen(l, len(es)) {
+ return
+ }
+
+ i := 0
+ for e := l.Front(); e != nil; e = e.Next() {
+ le := e.Value
+ // Comparison between a generically-typed variable le and an interface.
+ if le != es[i] {
+ panic(fmt.Sprintf("elt[%d].Value = %v, want %v", i, le, es[i]))
+ }
+ i++
+ }
+}
+
+func TestExtending() {
+ l1 := _New[int]()
+ l2 := _New[int]()
+
+ l1.PushBack(1)
+ l1.PushBack(2)
+ l1.PushBack(3)
+
+ l2.PushBack(4)
+ l2.PushBack(5)
+
+ l3 := _New[int]()
+ l3.PushBackList(l1)
+ checkList(l3, []interface{}{1, 2, 3})
+ l3.PushBackList(l2)
+ checkList(l3, []interface{}{1, 2, 3, 4, 5})
+
+ l3 = _New[int]()
+ l3.PushFrontList(l2)
+ checkList(l3, []interface{}{4, 5})
+ l3.PushFrontList(l1)
+ checkList(l3, []interface{}{1, 2, 3, 4, 5})
+
+ checkList(l1, []interface{}{1, 2, 3})
+ checkList(l2, []interface{}{4, 5})
+
+ l3 = _New[int]()
+ l3.PushBackList(l1)
+ checkList(l3, []interface{}{1, 2, 3})
+ l3.PushBackList(l3)
+ checkList(l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+ l3 = _New[int]()
+ l3.PushFrontList(l1)
+ checkList(l3, []interface{}{1, 2, 3})
+ l3.PushFrontList(l3)
+ checkList(l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+ l3 = _New[int]()
+ l1.PushBackList(l3)
+ checkList(l1, []interface{}{1, 2, 3})
+ l1.PushFrontList(l3)
+ checkList(l1, []interface{}{1, 2, 3})
+}
+
+func TestRemove() {
+ l := _New[int]()
+ e1 := l.PushBack(1)
+ e2 := l.PushBack(2)
+ checkListPointers(l, []*(_Element[int]){e1, e2})
+ e := l.Front()
+ l.Remove(e)
+ checkListPointers(l, []*(_Element[int]){e2})
+ l.Remove(e)
+ checkListPointers(l, []*(_Element[int]){e2})
+}
+
+func TestIssue4103() {
+ l1 := _New[int]()
+ l1.PushBack(1)
+ l1.PushBack(2)
+
+ l2 := _New[int]()
+ l2.PushBack(3)
+ l2.PushBack(4)
+
+ e := l1.Front()
+ l2.Remove(e) // l2 should not change because e is not an element of l2
+ if n := l2.Len(); n != 2 {
+ panic(fmt.Sprintf("l2.Len() = %d, want 2", n))
+ }
+
+ l1.InsertBefore(8, e)
+ if n := l1.Len(); n != 3 {
+ panic(fmt.Sprintf("l1.Len() = %d, want 3", n))
+ }
+}
+
+func TestIssue6349() {
+ l := _New[int]()
+ l.PushBack(1)
+ l.PushBack(2)
+
+ e := l.Front()
+ l.Remove(e)
+ if e.Value != 1 {
+ panic(fmt.Sprintf("e.value = %d, want 1", e.Value))
+ }
+ if e.Next() != nil {
+ panic(fmt.Sprintf("e.Next() != nil"))
+ }
+ if e.Prev() != nil {
+ panic(fmt.Sprintf("e.Prev() != nil"))
+ }
+}
+
+func TestMove() {
+ l := _New[int]()
+ e1 := l.PushBack(1)
+ e2 := l.PushBack(2)
+ e3 := l.PushBack(3)
+ e4 := l.PushBack(4)
+
+ l.MoveAfter(e3, e3)
+ checkListPointers(l, []*(_Element[int]){e1, e2, e3, e4})
+ l.MoveBefore(e2, e2)
+ checkListPointers(l, []*(_Element[int]){e1, e2, e3, e4})
+
+ l.MoveAfter(e3, e2)
+ checkListPointers(l, []*(_Element[int]){e1, e2, e3, e4})
+ l.MoveBefore(e2, e3)
+ checkListPointers(l, []*(_Element[int]){e1, e2, e3, e4})
+
+ l.MoveBefore(e2, e4)
+ checkListPointers(l, []*(_Element[int]){e1, e3, e2, e4})
+ e2, e3 = e3, e2
+
+ l.MoveBefore(e4, e1)
+ checkListPointers(l, []*(_Element[int]){e4, e1, e2, e3})
+ e1, e2, e3, e4 = e4, e1, e2, e3
+
+ l.MoveAfter(e4, e1)
+ checkListPointers(l, []*(_Element[int]){e1, e4, e2, e3})
+ e2, e3, e4 = e4, e2, e3
+
+ l.MoveAfter(e2, e3)
+ checkListPointers(l, []*(_Element[int]){e1, e3, e2, e4})
+ e2, e3 = e3, e2
+}
+
+// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized _List
+func TestZeroList() {
+ var l1 = new(_List[int])
+ l1.PushFront(1)
+ checkList(l1, []interface{}{1})
+
+ var l2 = new(_List[int])
+ l2.PushBack(1)
+ checkList(l2, []interface{}{1})
+
+ var l3 = new(_List[int])
+ l3.PushFrontList(l1)
+ checkList(l3, []interface{}{1})
+
+ var l4 = new(_List[int])
+ l4.PushBackList(l2)
+ checkList(l4, []interface{}{1})
+}
+
+// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.
+func TestInsertBeforeUnknownMark() {
+ var l _List[int]
+ l.PushBack(1)
+ l.PushBack(2)
+ l.PushBack(3)
+ l.InsertBefore(1, new(_Element[int]))
+ checkList(&l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.
+func TestInsertAfterUnknownMark() {
+ var l _List[int]
+ l.PushBack(1)
+ l.PushBack(2)
+ l.PushBack(3)
+ l.InsertAfter(1, new(_Element[int]))
+ checkList(&l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
+func TestMoveUnknownMark() {
+ var l1 _List[int]
+ e1 := l1.PushBack(1)
+
+ var l2 _List[int]
+ e2 := l2.PushBack(2)
+
+ l1.MoveAfter(e1, e2)
+ checkList(&l1, []interface{}{1})
+ checkList(&l2, []interface{}{2})
+
+ l1.MoveBefore(e1, e2)
+ checkList(&l1, []interface{}{1})
+ checkList(&l2, []interface{}{2})
+}
+
+// Test the Transform function.
+func TestTransform() {
+ l1 := _New[int]()
+ l1.PushBack(1)
+ l1.PushBack(2)
+ l2 := _Transform(l1, strconv.Itoa)
+ checkList(l2, []interface{}{"1", "2"})
+}
+
+func main() {
+ TestList()
+ TestExtending()
+ TestRemove()
+ TestIssue4103()
+ TestIssue6349()
+ TestMove()
+ TestZeroList()
+ TestInsertBeforeUnknownMark()
+ TestInsertAfterUnknownMark()
+ TestTransform()
+}
diff --git a/test/typeparam/listimp.dir/a.go b/test/typeparam/listimp.dir/a.go
new file mode 100644
index 0000000..e9c46d6
--- /dev/null
+++ b/test/typeparam/listimp.dir/a.go
@@ -0,0 +1,53 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+// List is a linked list of ordered values of type T.
+type List[T Ordered] struct {
+ Next *List[T]
+ Val T
+}
+
+func (l *List[T]) Largest() T {
+ var max T
+ for p := l; p != nil; p = p.Next {
+ if p.Val > max {
+ max = p.Val
+ }
+ }
+ return max
+}
+
+type OrderedNum interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64
+}
+
+// ListNum is a linked _List of ordered numeric values of type T.
+type ListNum[T OrderedNum] struct {
+ Next *ListNum[T]
+ Val T
+}
+
+const Clip = 5
+
+// ClippedLargest returns the largest in the list of OrderNums, but a max of 5.
+func (l *ListNum[T]) ClippedLargest() T {
+ var max T
+ for p := l; p != nil; p = p.Next {
+ if p.Val > max && p.Val < Clip {
+ max = p.Val
+ }
+ }
+ return max
+}
diff --git a/test/typeparam/listimp.dir/main.go b/test/typeparam/listimp.dir/main.go
new file mode 100644
index 0000000..652a34a
--- /dev/null
+++ b/test/typeparam/listimp.dir/main.go
@@ -0,0 +1,52 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ i3 := &a.List[int]{nil, 1}
+ i2 := &a.List[int]{i3, 3}
+ i1 := &a.List[int]{i2, 2}
+ if got, want := i1.Largest(), 3; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ b3 := &a.List[byte]{nil, byte(1)}
+ b2 := &a.List[byte]{b3, byte(3)}
+ b1 := &a.List[byte]{b2, byte(2)}
+ if got, want := b1.Largest(), byte(3); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ f3 := &a.List[float64]{nil, 13.5}
+ f2 := &a.List[float64]{f3, 1.2}
+ f1 := &a.List[float64]{f2, 4.5}
+ if got, want := f1.Largest(), 13.5; got != want {
+ panic(fmt.Sprintf("got %f, want %f", got, want))
+ }
+
+ s3 := &a.List[string]{nil, "dd"}
+ s2 := &a.List[string]{s3, "aa"}
+ s1 := &a.List[string]{s2, "bb"}
+ if got, want := s1.Largest(), "dd"; got != want {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+ j3 := &a.ListNum[int]{nil, 1}
+ j2 := &a.ListNum[int]{j3, 32}
+ j1 := &a.ListNum[int]{j2, 2}
+ if got, want := j1.ClippedLargest(), 2; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ g3 := &a.ListNum[float64]{nil, 13.5}
+ g2 := &a.ListNum[float64]{g3, 1.2}
+ g1 := &a.ListNum[float64]{g2, 4.5}
+ if got, want := g1.ClippedLargest(), 4.5; got != want {
+ panic(fmt.Sprintf("got %f, want %f", got, want))
+ }
+}
diff --git a/test/typeparam/listimp.go b/test/typeparam/listimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/listimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/listimp2.dir/a.go b/test/typeparam/listimp2.dir/a.go
new file mode 100644
index 0000000..3a7dfc3
--- /dev/null
+++ b/test/typeparam/listimp2.dir/a.go
@@ -0,0 +1,298 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import (
+ "fmt"
+)
+
+// Element is an element of a linked list.
+type Element[T any] struct {
+ // Next and previous pointers in the doubly-linked list of elements.
+ // To simplify the implementation, internally a list l is implemented
+ // as a ring, such that &l.root is both the next element of the last
+ // list element (l.Back()) and the previous element of the first list
+ // element (l.Front()).
+ next, prev *Element[T]
+
+ // The list to which this element belongs.
+ list *List[T]
+
+ // The value stored with this element.
+ Value T
+}
+
+// Next returns the next list element or nil.
+func (e *Element[T]) Next() *Element[T] {
+ if p := e.next; e.list != nil && p != &e.list.root {
+ return p
+ }
+ return nil
+}
+
+// Prev returns the previous list element or nil.
+func (e *Element[T]) Prev() *Element[T] {
+ if p := e.prev; e.list != nil && p != &e.list.root {
+ return p
+ }
+ return nil
+}
+
+// List represents a doubly linked list.
+// The zero value for List is an empty list ready to use.
+type List[T any] struct {
+ root Element[T] // sentinel list element, only &root, root.prev, and root.next are used
+ len int // current list length excluding (this) sentinel element
+}
+
+// Init initializes or clears list l.
+func (l *List[T]) Init() *List[T] {
+ l.root.next = &l.root
+ l.root.prev = &l.root
+ l.len = 0
+ return l
+}
+
+// New returns an initialized list.
+func New[T any]() *List[T] { return new(List[T]).Init() }
+
+// Len returns the number of elements of list l.
+// The complexity is O(1).
+func (l *List[_]) Len() int { return l.len }
+
+// Front returns the first element of list l or nil if the list is empty.
+func (l *List[T]) Front() *Element[T] {
+ if l.len == 0 {
+ return nil
+ }
+ return l.root.next
+}
+
+// Back returns the last element of list l or nil if the list is empty.
+func (l *List[T]) Back() *Element[T] {
+ if l.len == 0 {
+ return nil
+ }
+ return l.root.prev
+}
+
+// lazyInit lazily initializes a zero List value.
+func (l *List[_]) lazyInit() {
+ if l.root.next == nil {
+ l.Init()
+ }
+}
+
+// insert inserts e after at, increments l.len, and returns e.
+func (l *List[T]) insert(e, at *Element[T]) *Element[T] {
+ e.prev = at
+ e.next = at.next
+ e.prev.next = e
+ e.next.prev = e
+ e.list = l
+ l.len++
+ return e
+}
+
+// insertValue is a convenience wrapper for insert(&Element[T]{Value: v}, at).
+func (l *List[T]) insertValue(v T, at *Element[T]) *Element[T] {
+ return l.insert(&Element[T]{Value: v}, at)
+}
+
+// remove removes e from its list, decrements l.len, and returns e.
+func (l *List[T]) remove(e *Element[T]) *Element[T] {
+ e.prev.next = e.next
+ e.next.prev = e.prev
+ e.next = nil // avoid memory leaks
+ e.prev = nil // avoid memory leaks
+ e.list = nil
+ l.len--
+ return e
+}
+
+// move moves e to next to at and returns e.
+func (l *List[T]) move(e, at *Element[T]) *Element[T] {
+ if e == at {
+ return e
+ }
+ e.prev.next = e.next
+ e.next.prev = e.prev
+
+ e.prev = at
+ e.next = at.next
+ e.prev.next = e
+ e.next.prev = e
+
+ return e
+}
+
+// Remove removes e from l if e is an element of list l.
+// It returns the element value e.Value.
+// The element must not be nil.
+func (l *List[T]) Remove(e *Element[T]) T {
+ if e.list == l {
+ // if e.list == l, l must have been initialized when e was inserted
+ // in l or l == nil (e is a zero Element) and l.remove will crash
+ l.remove(e)
+ }
+ return e.Value
+}
+
+// PushFront inserts a new element e with value v at the front of list l and returns e.
+func (l *List[T]) PushFront(v T) *Element[T] {
+ l.lazyInit()
+ return l.insertValue(v, &l.root)
+}
+
+// PushBack inserts a new element e with value v at the back of list l and returns e.
+func (l *List[T]) PushBack(v T) *Element[T] {
+ l.lazyInit()
+ return l.insertValue(v, l.root.prev)
+}
+
+// InsertBefore inserts a new element e with value v immediately before mark and returns e.
+// If mark is not an element of l, the list is not modified.
+// The mark must not be nil.
+func (l *List[T]) InsertBefore(v T, mark *Element[T]) *Element[T] {
+ if mark.list != l {
+ return nil
+ }
+ // see comment in List.Remove about initialization of l
+ return l.insertValue(v, mark.prev)
+}
+
+// InsertAfter inserts a new element e with value v immediately after mark and returns e.
+// If mark is not an element of l, the list is not modified.
+// The mark must not be nil.
+func (l *List[T]) InsertAfter(v T, mark *Element[T]) *Element[T] {
+ if mark.list != l {
+ return nil
+ }
+ // see comment in List.Remove about initialization of l
+ return l.insertValue(v, mark)
+}
+
+// MoveToFront moves element e to the front of list l.
+// If e is not an element of l, the list is not modified.
+// The element must not be nil.
+func (l *List[T]) MoveToFront(e *Element[T]) {
+ if e.list != l || l.root.next == e {
+ return
+ }
+ // see comment in List.Remove about initialization of l
+ l.move(e, &l.root)
+}
+
+// MoveToBack moves element e to the back of list l.
+// If e is not an element of l, the list is not modified.
+// The element must not be nil.
+func (l *List[T]) MoveToBack(e *Element[T]) {
+ if e.list != l || l.root.prev == e {
+ return
+ }
+ // see comment in List.Remove about initialization of l
+ l.move(e, l.root.prev)
+}
+
+// MoveBefore moves element e to its new position before mark.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
+// The element and mark must not be nil.
+func (l *List[T]) MoveBefore(e, mark *Element[T]) {
+ if e.list != l || e == mark || mark.list != l {
+ return
+ }
+ l.move(e, mark.prev)
+}
+
+// MoveAfter moves element e to its new position after mark.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
+// The element and mark must not be nil.
+func (l *List[T]) MoveAfter(e, mark *Element[T]) {
+ if e.list != l || e == mark || mark.list != l {
+ return
+ }
+ l.move(e, mark)
+}
+
+// PushBackList inserts a copy of an other list at the back of list l.
+// The lists l and other may be the same. They must not be nil.
+func (l *List[T]) PushBackList(other *List[T]) {
+ l.lazyInit()
+ for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
+ l.insertValue(e.Value, l.root.prev)
+ }
+}
+
+// PushFrontList inserts a copy of an other list at the front of list l.
+// The lists l and other may be the same. They must not be nil.
+func (l *List[T]) PushFrontList(other *List[T]) {
+ l.lazyInit()
+ for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() {
+ l.insertValue(e.Value, &l.root)
+ }
+}
+
+// Transform runs a transform function on a list returning a new list.
+func Transform[TElem1, TElem2 any](lst *List[TElem1], f func(TElem1) TElem2) *List[TElem2] {
+ ret := New[TElem2]()
+ for p := lst.Front(); p != nil; p = p.Next() {
+ ret.PushBack(f(p.Value))
+ }
+ return ret
+}
+
+func CheckListLen[T any](l *List[T], len int) bool {
+ if n := l.Len(); n != len {
+ panic(fmt.Sprintf("l.Len() = %d, want %d", n, len))
+ return false
+ }
+ return true
+}
+
+func CheckListPointers[T any](l *List[T], es []*Element[T]) {
+ root := &l.root
+
+ if !CheckListLen(l, len(es)) {
+ return
+ }
+
+ // zero length lists must be the zero value or properly initialized (sentinel circle)
+ if len(es) == 0 {
+ if l.root.next != nil && l.root.next != root || l.root.prev != nil && l.root.prev != root {
+ panic(fmt.Sprintf("l.root.next = %p, l.root.prev = %p; both should both be nil or %p", l.root.next, l.root.prev, root))
+ }
+ return
+ }
+ // len(es) > 0
+
+ // check internal and external prev/next connections
+ for i, e := range es {
+ prev := root
+ Prev := (*Element[T])(nil)
+ if i > 0 {
+ prev = es[i-1]
+ Prev = prev
+ }
+ if p := e.prev; p != prev {
+ panic(fmt.Sprintf("elt[%d](%p).prev = %p, want %p", i, e, p, prev))
+ }
+ if p := e.Prev(); p != Prev {
+ panic(fmt.Sprintf("elt[%d](%p).Prev() = %p, want %p", i, e, p, Prev))
+ }
+
+ next := root
+ Next := (*Element[T])(nil)
+ if i < len(es)-1 {
+ next = es[i+1]
+ Next = next
+ }
+ if n := e.next; n != next {
+ panic(fmt.Sprintf("elt[%d](%p).next = %p, want %p", i, e, n, next))
+ }
+ if n := e.Next(); n != Next {
+ panic(fmt.Sprintf("elt[%d](%p).Next() = %p, want %p", i, e, n, Next))
+ }
+ }
+}
diff --git a/test/typeparam/listimp2.dir/main.go b/test/typeparam/listimp2.dir/main.go
new file mode 100644
index 0000000..c3b936e
--- /dev/null
+++ b/test/typeparam/listimp2.dir/main.go
@@ -0,0 +1,315 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+ "strconv"
+)
+
+func TestList() {
+ l := a.New[string]()
+ a.CheckListPointers(l, []*(a.Element[string]){})
+
+ // Single element list
+ e := l.PushFront("a")
+ a.CheckListPointers(l, []*(a.Element[string]){e})
+ l.MoveToFront(e)
+ a.CheckListPointers(l, []*(a.Element[string]){e})
+ l.MoveToBack(e)
+ a.CheckListPointers(l, []*(a.Element[string]){e})
+ l.Remove(e)
+ a.CheckListPointers(l, []*(a.Element[string]){})
+
+ // Bigger list
+ l2 := a.New[int]()
+ e2 := l2.PushFront(2)
+ e1 := l2.PushFront(1)
+ e3 := l2.PushBack(3)
+ e4 := l2.PushBack(600)
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e2, e3, e4})
+
+ l2.Remove(e2)
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e3, e4})
+
+ l2.MoveToFront(e3) // move from middle
+ a.CheckListPointers(l2, []*(a.Element[int]){e3, e1, e4})
+
+ l2.MoveToFront(e1)
+ l2.MoveToBack(e3) // move from middle
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3})
+
+ l2.MoveToFront(e3) // move from back
+ a.CheckListPointers(l2, []*(a.Element[int]){e3, e1, e4})
+ l2.MoveToFront(e3) // should be no-op
+ a.CheckListPointers(l2, []*(a.Element[int]){e3, e1, e4})
+
+ l2.MoveToBack(e3) // move from front
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3})
+ l2.MoveToBack(e3) // should be no-op
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3})
+
+ e2 = l2.InsertBefore(2, e1) // insert before front
+ a.CheckListPointers(l2, []*(a.Element[int]){e2, e1, e4, e3})
+ l2.Remove(e2)
+ e2 = l2.InsertBefore(2, e4) // insert before middle
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e2, e4, e3})
+ l2.Remove(e2)
+ e2 = l2.InsertBefore(2, e3) // insert before back
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e2, e3})
+ l2.Remove(e2)
+
+ e2 = l2.InsertAfter(2, e1) // insert after front
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e2, e4, e3})
+ l2.Remove(e2)
+ e2 = l2.InsertAfter(2, e4) // insert after middle
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e2, e3})
+ l2.Remove(e2)
+ e2 = l2.InsertAfter(2, e3) // insert after back
+ a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3, e2})
+ l2.Remove(e2)
+
+ // Check standard iteration.
+ sum := 0
+ for e := l2.Front(); e != nil; e = e.Next() {
+ sum += e.Value
+ }
+ if sum != 604 {
+ panic(fmt.Sprintf("sum over l = %d, want 604", sum))
+ }
+
+ // Clear all elements by iterating
+ var next *a.Element[int]
+ for e := l2.Front(); e != nil; e = next {
+ next = e.Next()
+ l2.Remove(e)
+ }
+ a.CheckListPointers(l2, []*(a.Element[int]){})
+}
+
+func checkList[T comparable](l *a.List[T], es []interface{}) {
+ if !a.CheckListLen(l, len(es)) {
+ return
+ }
+
+ i := 0
+ for e := l.Front(); e != nil; e = e.Next() {
+ le := e.Value
+ // Comparison between a generically-typed variable le and an interface.
+ if le != es[i] {
+ panic(fmt.Sprintf("elt[%d].Value = %v, want %v", i, le, es[i]))
+ }
+ i++
+ }
+}
+
+func TestExtending() {
+ l1 := a.New[int]()
+ l2 := a.New[int]()
+
+ l1.PushBack(1)
+ l1.PushBack(2)
+ l1.PushBack(3)
+
+ l2.PushBack(4)
+ l2.PushBack(5)
+
+ l3 := a.New[int]()
+ l3.PushBackList(l1)
+ checkList(l3, []interface{}{1, 2, 3})
+ l3.PushBackList(l2)
+ checkList(l3, []interface{}{1, 2, 3, 4, 5})
+
+ l3 = a.New[int]()
+ l3.PushFrontList(l2)
+ checkList(l3, []interface{}{4, 5})
+ l3.PushFrontList(l1)
+ checkList(l3, []interface{}{1, 2, 3, 4, 5})
+
+ checkList(l1, []interface{}{1, 2, 3})
+ checkList(l2, []interface{}{4, 5})
+
+ l3 = a.New[int]()
+ l3.PushBackList(l1)
+ checkList(l3, []interface{}{1, 2, 3})
+ l3.PushBackList(l3)
+ checkList(l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+ l3 = a.New[int]()
+ l3.PushFrontList(l1)
+ checkList(l3, []interface{}{1, 2, 3})
+ l3.PushFrontList(l3)
+ checkList(l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+ l3 = a.New[int]()
+ l1.PushBackList(l3)
+ checkList(l1, []interface{}{1, 2, 3})
+ l1.PushFrontList(l3)
+ checkList(l1, []interface{}{1, 2, 3})
+}
+
+func TestRemove() {
+ l := a.New[int]()
+ e1 := l.PushBack(1)
+ e2 := l.PushBack(2)
+ a.CheckListPointers(l, []*(a.Element[int]){e1, e2})
+ e := l.Front()
+ l.Remove(e)
+ a.CheckListPointers(l, []*(a.Element[int]){e2})
+ l.Remove(e)
+ a.CheckListPointers(l, []*(a.Element[int]){e2})
+}
+
+func TestIssue4103() {
+ l1 := a.New[int]()
+ l1.PushBack(1)
+ l1.PushBack(2)
+
+ l2 := a.New[int]()
+ l2.PushBack(3)
+ l2.PushBack(4)
+
+ e := l1.Front()
+ l2.Remove(e) // l2 should not change because e is not an element of l2
+ if n := l2.Len(); n != 2 {
+ panic(fmt.Sprintf("l2.Len() = %d, want 2", n))
+ }
+
+ l1.InsertBefore(8, e)
+ if n := l1.Len(); n != 3 {
+ panic(fmt.Sprintf("l1.Len() = %d, want 3", n))
+ }
+}
+
+func TestIssue6349() {
+ l := a.New[int]()
+ l.PushBack(1)
+ l.PushBack(2)
+
+ e := l.Front()
+ l.Remove(e)
+ if e.Value != 1 {
+ panic(fmt.Sprintf("e.value = %d, want 1", e.Value))
+ }
+ if e.Next() != nil {
+ panic(fmt.Sprintf("e.Next() != nil"))
+ }
+ if e.Prev() != nil {
+ panic(fmt.Sprintf("e.Prev() != nil"))
+ }
+}
+
+func TestMove() {
+ l := a.New[int]()
+ e1 := l.PushBack(1)
+ e2 := l.PushBack(2)
+ e3 := l.PushBack(3)
+ e4 := l.PushBack(4)
+
+ l.MoveAfter(e3, e3)
+ a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4})
+ l.MoveBefore(e2, e2)
+ a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4})
+
+ l.MoveAfter(e3, e2)
+ a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4})
+ l.MoveBefore(e2, e3)
+ a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4})
+
+ l.MoveBefore(e2, e4)
+ a.CheckListPointers(l, []*(a.Element[int]){e1, e3, e2, e4})
+ e2, e3 = e3, e2
+
+ l.MoveBefore(e4, e1)
+ a.CheckListPointers(l, []*(a.Element[int]){e4, e1, e2, e3})
+ e1, e2, e3, e4 = e4, e1, e2, e3
+
+ l.MoveAfter(e4, e1)
+ a.CheckListPointers(l, []*(a.Element[int]){e1, e4, e2, e3})
+ e2, e3, e4 = e4, e2, e3
+
+ l.MoveAfter(e2, e3)
+ a.CheckListPointers(l, []*(a.Element[int]){e1, e3, e2, e4})
+ e2, e3 = e3, e2
+}
+
+// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized a.List
+func TestZeroList() {
+ var l1 = new(a.List[int])
+ l1.PushFront(1)
+ checkList(l1, []interface{}{1})
+
+ var l2 = new(a.List[int])
+ l2.PushBack(1)
+ checkList(l2, []interface{}{1})
+
+ var l3 = new(a.List[int])
+ l3.PushFrontList(l1)
+ checkList(l3, []interface{}{1})
+
+ var l4 = new(a.List[int])
+ l4.PushBackList(l2)
+ checkList(l4, []interface{}{1})
+}
+
+// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.
+func TestInsertBeforeUnknownMark() {
+ var l a.List[int]
+ l.PushBack(1)
+ l.PushBack(2)
+ l.PushBack(3)
+ l.InsertBefore(1, new(a.Element[int]))
+ checkList(&l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.
+func TestInsertAfterUnknownMark() {
+ var l a.List[int]
+ l.PushBack(1)
+ l.PushBack(2)
+ l.PushBack(3)
+ l.InsertAfter(1, new(a.Element[int]))
+ checkList(&l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
+func TestMoveUnknownMark() {
+ var l1 a.List[int]
+ e1 := l1.PushBack(1)
+
+ var l2 a.List[int]
+ e2 := l2.PushBack(2)
+
+ l1.MoveAfter(e1, e2)
+ checkList(&l1, []interface{}{1})
+ checkList(&l2, []interface{}{2})
+
+ l1.MoveBefore(e1, e2)
+ checkList(&l1, []interface{}{1})
+ checkList(&l2, []interface{}{2})
+}
+
+// Test the Transform function.
+func TestTransform() {
+ l1 := a.New[int]()
+ l1.PushBack(1)
+ l1.PushBack(2)
+ l2 := a.Transform(l1, strconv.Itoa)
+ checkList(l2, []interface{}{"1", "2"})
+}
+
+func main() {
+ TestList()
+ TestExtending()
+ TestRemove()
+ TestIssue4103()
+ TestIssue6349()
+ TestMove()
+ TestZeroList()
+ TestInsertBeforeUnknownMark()
+ TestInsertAfterUnknownMark()
+ TestTransform()
+}
diff --git a/test/typeparam/listimp2.go b/test/typeparam/listimp2.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/listimp2.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/lockable.go b/test/typeparam/lockable.go
new file mode 100644
index 0000000..2b50e2c
--- /dev/null
+++ b/test/typeparam/lockable.go
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "sync"
+
+// A Lockable is a value that may be safely simultaneously accessed
+// from multiple goroutines via the Get and Set methods.
+type Lockable[T any] struct {
+ x T
+ mu sync.Mutex
+}
+
+// Get returns the value stored in a Lockable.
+func (l *Lockable[T]) get() T {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ return l.x
+}
+
+// set sets the value in a Lockable.
+func (l *Lockable[T]) set(v T) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ l.x = v
+}
+
+func main() {
+ sl := Lockable[string]{x: "a"}
+ if got := sl.get(); got != "a" {
+ panic(got)
+ }
+ sl.set("b")
+ if got := sl.get(); got != "b" {
+ panic(got)
+ }
+
+ il := Lockable[int]{x: 1}
+ if got := il.get(); got != 1 {
+ panic(got)
+ }
+ il.set(2)
+ if got := il.get(); got != 2 {
+ panic(got)
+ }
+}
diff --git a/test/typeparam/map.go b/test/typeparam/map.go
new file mode 100644
index 0000000..eb68fe5
--- /dev/null
+++ b/test/typeparam/map.go
@@ -0,0 +1,39 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+)
+
+// Map calls the function f on every element of the slice s,
+// returning a new slice of the results.
+func mapper[F, T any](s []F, f func(F) T) []T {
+ r := make([]T, len(s))
+ for i, v := range s {
+ r[i] = f(v)
+ }
+ return r
+}
+
+func main() {
+ got := mapper([]int{1, 2, 3}, strconv.Itoa)
+ want := []string{"1", "2", "3"}
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ fgot := mapper([]float64{2.5, 2.3, 3.5}, func(f float64) string {
+ return strconv.FormatFloat(f, 'f', -1, 64)
+ })
+ fwant := []string{"2.5", "2.3", "3.5"}
+ if !reflect.DeepEqual(fgot, fwant) {
+ panic(fmt.Sprintf("got %s, want %s", fgot, fwant))
+ }
+}
diff --git a/test/typeparam/mapimp.dir/a.go b/test/typeparam/mapimp.dir/a.go
new file mode 100644
index 0000000..cbfa80a
--- /dev/null
+++ b/test/typeparam/mapimp.dir/a.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+// Map calls the function f on every element of the slice s,
+// returning a new slice of the results.
+func Mapper[F, T any](s []F, f func(F) T) []T {
+ r := make([]T, len(s))
+ for i, v := range s {
+ r[i] = f(v)
+ }
+ return r
+}
diff --git a/test/typeparam/mapimp.dir/main.go b/test/typeparam/mapimp.dir/main.go
new file mode 100644
index 0000000..8a56ce2
--- /dev/null
+++ b/test/typeparam/mapimp.dir/main.go
@@ -0,0 +1,28 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+ "reflect"
+ "strconv"
+)
+
+func main() {
+ got := a.Mapper([]int{1, 2, 3}, strconv.Itoa)
+ want := []string{"1", "2", "3"}
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ fgot := a.Mapper([]float64{2.5, 2.3, 3.5}, func(f float64) string {
+ return strconv.FormatFloat(f, 'f', -1, 64)
+ })
+ fwant := []string{"2.5", "2.3", "3.5"}
+ if !reflect.DeepEqual(fgot, fwant) {
+ panic(fmt.Sprintf("got %s, want %s", fgot, fwant))
+ }
+}
diff --git a/test/typeparam/mapimp.go b/test/typeparam/mapimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/mapimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/maps.go b/test/typeparam/maps.go
new file mode 100644
index 0000000..d4be5dd
--- /dev/null
+++ b/test/typeparam/maps.go
@@ -0,0 +1,260 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "math"
+ "sort"
+)
+
+// _Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func _SliceEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// _Keys returns the keys of the map m.
+// The keys will be an indeterminate order.
+func _Keys[K comparable, V any](m map[K]V) []K {
+ r := make([]K, 0, len(m))
+ for k := range m {
+ r = append(r, k)
+ }
+ return r
+}
+
+// _Values returns the values of the map m.
+// The values will be in an indeterminate order.
+func _Values[K comparable, V any](m map[K]V) []V {
+ r := make([]V, 0, len(m))
+ for _, v := range m {
+ r = append(r, v)
+ }
+ return r
+}
+
+// _Equal reports whether two maps contain the same key/value pairs.
+// _Values are compared using ==.
+func _Equal[K, V comparable](m1, m2 map[K]V) bool {
+ if len(m1) != len(m2) {
+ return false
+ }
+ for k, v1 := range m1 {
+ if v2, ok := m2[k]; !ok || v1 != v2 {
+ return false
+ }
+ }
+ return true
+}
+
+// _Copy returns a copy of m.
+func _Copy[K comparable, V any](m map[K]V) map[K]V {
+ r := make(map[K]V, len(m))
+ for k, v := range m {
+ r[k] = v
+ }
+ return r
+}
+
+// _Add adds all key/value pairs in m2 to m1. _Keys in m2 that are already
+// present in m1 will be overwritten with the value in m2.
+func _Add[K comparable, V any](m1, m2 map[K]V) {
+ for k, v := range m2 {
+ m1[k] = v
+ }
+}
+
+// _Sub removes all keys in m2 from m1. _Keys in m2 that are not present
+// in m1 are ignored. The values in m2 are ignored.
+func _Sub[K comparable, V any](m1, m2 map[K]V) {
+ for k := range m2 {
+ delete(m1, k)
+ }
+}
+
+// _Intersect removes all keys from m1 that are not present in m2.
+// _Keys in m2 that are not in m1 are ignored. The values in m2 are ignored.
+func _Intersect[K comparable, V any](m1, m2 map[K]V) {
+ for k := range m1 {
+ if _, ok := m2[k]; !ok {
+ delete(m1, k)
+ }
+ }
+}
+
+// _Filter deletes any key/value pairs from m for which f returns false.
+func _Filter[K comparable, V any](m map[K]V, f func(K, V) bool) {
+ for k, v := range m {
+ if !f(k, v) {
+ delete(m, k)
+ }
+ }
+}
+
+// _TransformValues applies f to each value in m. The keys remain unchanged.
+func _TransformValues[K comparable, V any](m map[K]V, f func(V) V) {
+ for k, v := range m {
+ m[k] = f(v)
+ }
+}
+
+var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16}
+var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"}
+
+func TestKeys() {
+ want := []int{1, 2, 4, 8}
+
+ got1 := _Keys(m1)
+ sort.Ints(got1)
+ if !_SliceEqual(got1, want) {
+ panic(fmt.Sprintf("_Keys(%v) = %v, want %v", m1, got1, want))
+ }
+
+ got2 := _Keys(m2)
+ sort.Ints(got2)
+ if !_SliceEqual(got2, want) {
+ panic(fmt.Sprintf("_Keys(%v) = %v, want %v", m2, got2, want))
+ }
+}
+
+func TestValues() {
+ got1 := _Values(m1)
+ want1 := []int{2, 4, 8, 16}
+ sort.Ints(got1)
+ if !_SliceEqual(got1, want1) {
+ panic(fmt.Sprintf("_Values(%v) = %v, want %v", m1, got1, want1))
+ }
+
+ got2 := _Values(m2)
+ want2 := []string{"16", "2", "4", "8"}
+ sort.Strings(got2)
+ if !_SliceEqual(got2, want2) {
+ panic(fmt.Sprintf("_Values(%v) = %v, want %v", m2, got2, want2))
+ }
+}
+
+func TestEqual() {
+ if !_Equal(m1, m1) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", m1, m1))
+ }
+ if _Equal(m1, nil) {
+ panic(fmt.Sprintf("_Equal(%v, nil) = true, want false", m1))
+ }
+ if _Equal(nil, m1) {
+ panic(fmt.Sprintf("_Equal(nil, %v) = true, want false", m1))
+ }
+ if !_Equal[int, int](nil, nil) {
+ panic("_Equal(nil, nil) = false, want true")
+ }
+ if ms := map[int]int{1: 2}; _Equal(m1, ms) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", m1, ms))
+ }
+
+ // Comparing NaN for equality is expected to fail.
+ mf := map[int]float64{1: 0, 2: math.NaN()}
+ if _Equal(mf, mf) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", mf, mf))
+ }
+}
+
+func TestCopy() {
+ m2 := _Copy(m1)
+ if !_Equal(m1, m2) {
+ panic(fmt.Sprintf("_Copy(%v) = %v, want %v", m1, m2, m1))
+ }
+ m2[16] = 32
+ if _Equal(m1, m2) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", m1, m2))
+ }
+}
+
+func TestAdd() {
+ mc := _Copy(m1)
+ _Add(mc, mc)
+ if !_Equal(mc, m1) {
+ panic(fmt.Sprintf("_Add(%v, %v) = %v, want %v", m1, m1, mc, m1))
+ }
+ _Add(mc, map[int]int{16: 32})
+ want := map[int]int{1: 2, 2: 4, 4: 8, 8: 16, 16: 32}
+ if !_Equal(mc, want) {
+ panic(fmt.Sprintf("_Add result = %v, want %v", mc, want))
+ }
+}
+
+func TestSub() {
+ mc := _Copy(m1)
+ _Sub(mc, mc)
+ if len(mc) > 0 {
+ panic(fmt.Sprintf("_Sub(%v, %v) = %v, want empty map", m1, m1, mc))
+ }
+ mc = _Copy(m1)
+ _Sub(mc, map[int]int{1: 0})
+ want := map[int]int{2: 4, 4: 8, 8: 16}
+ if !_Equal(mc, want) {
+ panic(fmt.Sprintf("_Sub result = %v, want %v", mc, want))
+ }
+}
+
+func TestIntersect() {
+ mc := _Copy(m1)
+ _Intersect(mc, mc)
+ if !_Equal(mc, m1) {
+ panic(fmt.Sprintf("_Intersect(%v, %v) = %v, want %v", m1, m1, mc, m1))
+ }
+ _Intersect(mc, map[int]int{1: 0, 2: 0})
+ want := map[int]int{1: 2, 2: 4}
+ if !_Equal(mc, want) {
+ panic(fmt.Sprintf("_Intersect result = %v, want %v", mc, want))
+ }
+}
+
+func TestFilter() {
+ mc := _Copy(m1)
+ _Filter(mc, func(int, int) bool { return true })
+ if !_Equal(mc, m1) {
+ panic(fmt.Sprintf("_Filter(%v, true) = %v, want %v", m1, mc, m1))
+ }
+ _Filter(mc, func(k, v int) bool { return k < 3 })
+ want := map[int]int{1: 2, 2: 4}
+ if !_Equal(mc, want) {
+ panic(fmt.Sprintf("_Filter result = %v, want %v", mc, want))
+ }
+}
+
+func TestTransformValues() {
+ mc := _Copy(m1)
+ _TransformValues(mc, func(i int) int { return i / 2 })
+ want := map[int]int{1: 1, 2: 2, 4: 4, 8: 8}
+ if !_Equal(mc, want) {
+ panic(fmt.Sprintf("_TransformValues result = %v, want %v", mc, want))
+ }
+}
+
+func main() {
+ TestKeys()
+ TestValues()
+ TestEqual()
+ TestCopy()
+ TestAdd()
+ TestSub()
+ TestIntersect()
+ TestFilter()
+ TestTransformValues()
+}
diff --git a/test/typeparam/mapsimp.dir/a.go b/test/typeparam/mapsimp.dir/a.go
new file mode 100644
index 0000000..696e2a5
--- /dev/null
+++ b/test/typeparam/mapsimp.dir/a.go
@@ -0,0 +1,108 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+// SliceEqual reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func SliceEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// Keys returns the keys of the map m.
+// The keys will be an indeterminate order.
+func Keys[K comparable, V any](m map[K]V) []K {
+ r := make([]K, 0, len(m))
+ for k := range m {
+ r = append(r, k)
+ }
+ return r
+}
+
+// Values returns the values of the map m.
+// The values will be in an indeterminate order.
+func Values[K comparable, V any](m map[K]V) []V {
+ r := make([]V, 0, len(m))
+ for _, v := range m {
+ r = append(r, v)
+ }
+ return r
+}
+
+// Equal reports whether two maps contain the same key/value pairs.
+// Values are compared using ==.
+func Equal[K, V comparable](m1, m2 map[K]V) bool {
+ if len(m1) != len(m2) {
+ return false
+ }
+ for k, v1 := range m1 {
+ if v2, ok := m2[k]; !ok || v1 != v2 {
+ return false
+ }
+ }
+ return true
+}
+
+// Copy returns a copy of m.
+func Copy[K comparable, V any](m map[K]V) map[K]V {
+ r := make(map[K]V, len(m))
+ for k, v := range m {
+ r[k] = v
+ }
+ return r
+}
+
+// Add adds all key/value pairs in m2 to m1. Keys in m2 that are already
+// present in m1 will be overwritten with the value in m2.
+func Add[K comparable, V any](m1, m2 map[K]V) {
+ for k, v := range m2 {
+ m1[k] = v
+ }
+}
+
+// Sub removes all keys in m2 from m1. Keys in m2 that are not present
+// in m1 are ignored. The values in m2 are ignored.
+func Sub[K comparable, V any](m1, m2 map[K]V) {
+ for k := range m2 {
+ delete(m1, k)
+ }
+}
+
+// Intersect removes all keys from m1 that are not present in m2.
+// Keys in m2 that are not in m1 are ignored. The values in m2 are ignored.
+func Intersect[K comparable, V any](m1, m2 map[K]V) {
+ for k := range m1 {
+ if _, ok := m2[k]; !ok {
+ delete(m1, k)
+ }
+ }
+}
+
+// Filter deletes any key/value pairs from m for which f returns false.
+func Filter[K comparable, V any](m map[K]V, f func(K, V) bool) {
+ for k, v := range m {
+ if !f(k, v) {
+ delete(m, k)
+ }
+ }
+}
+
+// TransformValues applies f to each value in m. The keys remain unchanged.
+func TransformValues[K comparable, V any](m map[K]V, f func(V) V) {
+ for k, v := range m {
+ m[k] = f(v)
+ }
+}
diff --git a/test/typeparam/mapsimp.dir/main.go b/test/typeparam/mapsimp.dir/main.go
new file mode 100644
index 0000000..45f7d39
--- /dev/null
+++ b/test/typeparam/mapsimp.dir/main.go
@@ -0,0 +1,156 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+ "math"
+ "sort"
+)
+
+var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16}
+var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"}
+
+func TestKeys() {
+ want := []int{1, 2, 4, 8}
+
+ got1 := a.Keys(m1)
+ sort.Ints(got1)
+ if !a.SliceEqual(got1, want) {
+ panic(fmt.Sprintf("a.Keys(%v) = %v, want %v", m1, got1, want))
+ }
+
+ got2 := a.Keys(m2)
+ sort.Ints(got2)
+ if !a.SliceEqual(got2, want) {
+ panic(fmt.Sprintf("a.Keys(%v) = %v, want %v", m2, got2, want))
+ }
+}
+
+func TestValues() {
+ got1 := a.Values(m1)
+ want1 := []int{2, 4, 8, 16}
+ sort.Ints(got1)
+ if !a.SliceEqual(got1, want1) {
+ panic(fmt.Sprintf("a.Values(%v) = %v, want %v", m1, got1, want1))
+ }
+
+ got2 := a.Values(m2)
+ want2 := []string{"16", "2", "4", "8"}
+ sort.Strings(got2)
+ if !a.SliceEqual(got2, want2) {
+ panic(fmt.Sprintf("a.Values(%v) = %v, want %v", m2, got2, want2))
+ }
+}
+
+func TestEqual() {
+ if !a.Equal(m1, m1) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", m1, m1))
+ }
+ if a.Equal(m1, nil) {
+ panic(fmt.Sprintf("a.Equal(%v, nil) = true, want false", m1))
+ }
+ if a.Equal(nil, m1) {
+ panic(fmt.Sprintf("a.Equal(nil, %v) = true, want false", m1))
+ }
+ if !a.Equal[int, int](nil, nil) {
+ panic("a.Equal(nil, nil) = false, want true")
+ }
+ if ms := map[int]int{1: 2}; a.Equal(m1, ms) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", m1, ms))
+ }
+
+ // Comparing NaN for equality is expected to fail.
+ mf := map[int]float64{1: 0, 2: math.NaN()}
+ if a.Equal(mf, mf) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", mf, mf))
+ }
+}
+
+func TestCopy() {
+ m2 := a.Copy(m1)
+ if !a.Equal(m1, m2) {
+ panic(fmt.Sprintf("a.Copy(%v) = %v, want %v", m1, m2, m1))
+ }
+ m2[16] = 32
+ if a.Equal(m1, m2) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", m1, m2))
+ }
+}
+
+func TestAdd() {
+ mc := a.Copy(m1)
+ a.Add(mc, mc)
+ if !a.Equal(mc, m1) {
+ panic(fmt.Sprintf("a.Add(%v, %v) = %v, want %v", m1, m1, mc, m1))
+ }
+ a.Add(mc, map[int]int{16: 32})
+ want := map[int]int{1: 2, 2: 4, 4: 8, 8: 16, 16: 32}
+ if !a.Equal(mc, want) {
+ panic(fmt.Sprintf("a.Add result = %v, want %v", mc, want))
+ }
+}
+
+func TestSub() {
+ mc := a.Copy(m1)
+ a.Sub(mc, mc)
+ if len(mc) > 0 {
+ panic(fmt.Sprintf("a.Sub(%v, %v) = %v, want empty map", m1, m1, mc))
+ }
+ mc = a.Copy(m1)
+ a.Sub(mc, map[int]int{1: 0})
+ want := map[int]int{2: 4, 4: 8, 8: 16}
+ if !a.Equal(mc, want) {
+ panic(fmt.Sprintf("a.Sub result = %v, want %v", mc, want))
+ }
+}
+
+func TestIntersect() {
+ mc := a.Copy(m1)
+ a.Intersect(mc, mc)
+ if !a.Equal(mc, m1) {
+ panic(fmt.Sprintf("a.Intersect(%v, %v) = %v, want %v", m1, m1, mc, m1))
+ }
+ a.Intersect(mc, map[int]int{1: 0, 2: 0})
+ want := map[int]int{1: 2, 2: 4}
+ if !a.Equal(mc, want) {
+ panic(fmt.Sprintf("a.Intersect result = %v, want %v", mc, want))
+ }
+}
+
+func TestFilter() {
+ mc := a.Copy(m1)
+ a.Filter(mc, func(int, int) bool { return true })
+ if !a.Equal(mc, m1) {
+ panic(fmt.Sprintf("a.Filter(%v, true) = %v, want %v", m1, mc, m1))
+ }
+ a.Filter(mc, func(k, v int) bool { return k < 3 })
+ want := map[int]int{1: 2, 2: 4}
+ if !a.Equal(mc, want) {
+ panic(fmt.Sprintf("a.Filter result = %v, want %v", mc, want))
+ }
+}
+
+func TestTransformValues() {
+ mc := a.Copy(m1)
+ a.TransformValues(mc, func(i int) int { return i / 2 })
+ want := map[int]int{1: 1, 2: 2, 4: 4, 8: 8}
+ if !a.Equal(mc, want) {
+ panic(fmt.Sprintf("a.TransformValues result = %v, want %v", mc, want))
+ }
+}
+
+func main() {
+ TestKeys()
+ TestValues()
+ TestEqual()
+ TestCopy()
+ TestAdd()
+ TestSub()
+ TestIntersect()
+ TestFilter()
+ TestTransformValues()
+}
diff --git a/test/typeparam/mapsimp.go b/test/typeparam/mapsimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/mapsimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/mdempsky/1.dir/a.go b/test/typeparam/mdempsky/1.dir/a.go
new file mode 100644
index 0000000..a668eb5
--- /dev/null
+++ b/test/typeparam/mdempsky/1.dir/a.go
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type T[_ any] int
+
+func F() { _ = new(T[int]) }
diff --git a/test/typeparam/mdempsky/1.dir/b.go b/test/typeparam/mdempsky/1.dir/b.go
new file mode 100644
index 0000000..af6fef3
--- /dev/null
+++ b/test/typeparam/mdempsky/1.dir/b.go
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() { a.F() }
diff --git a/test/typeparam/mdempsky/1.go b/test/typeparam/mdempsky/1.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/mdempsky/1.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/mdempsky/10.dir/a.go b/test/typeparam/mdempsky/10.dir/a.go
new file mode 100644
index 0000000..95e111d
--- /dev/null
+++ b/test/typeparam/mdempsky/10.dir/a.go
@@ -0,0 +1,7 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type I[T any] interface{ M() T }
diff --git a/test/typeparam/mdempsky/10.dir/b.go b/test/typeparam/mdempsky/10.dir/b.go
new file mode 100644
index 0000000..0ef28fd
--- /dev/null
+++ b/test/typeparam/mdempsky/10.dir/b.go
@@ -0,0 +1,17 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+var m = a.I[int].M
+
+var never bool
+
+func main() {
+ if never {
+ m(nil)
+ }
+}
diff --git a/test/typeparam/mdempsky/10.go b/test/typeparam/mdempsky/10.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/mdempsky/10.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/mdempsky/12.dir/a.go b/test/typeparam/mdempsky/12.dir/a.go
new file mode 100644
index 0000000..ee8be93
--- /dev/null
+++ b/test/typeparam/mdempsky/12.dir/a.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type S[T any] struct {
+ F T
+}
+
+var X = S[int]{}
diff --git a/test/typeparam/mdempsky/12.dir/main.go b/test/typeparam/mdempsky/12.dir/main.go
new file mode 100644
index 0000000..2891322
--- /dev/null
+++ b/test/typeparam/mdempsky/12.dir/main.go
@@ -0,0 +1,13 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+)
+
+func main() {
+ _ = a.X
+}
diff --git a/test/typeparam/mdempsky/12.go b/test/typeparam/mdempsky/12.go
new file mode 100644
index 0000000..0316402
--- /dev/null
+++ b/test/typeparam/mdempsky/12.go
@@ -0,0 +1,9 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Reported by Cuong Manh Le.
+
+package ignored
diff --git a/test/typeparam/mdempsky/13.go b/test/typeparam/mdempsky/13.go
new file mode 100644
index 0000000..8e11352
--- /dev/null
+++ b/test/typeparam/mdempsky/13.go
@@ -0,0 +1,84 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Interface which will be used as a regular interface type and as a type bound.
+type Mer interface{
+ M()
+}
+
+// Interface that is a superset of Mer.
+type Mer2 interface {
+ M()
+ String() string
+}
+
+func F[T Mer](t T) {
+ T.M(t)
+ t.M()
+}
+
+type MyMer int
+
+func (MyMer) M() {}
+func (MyMer) String() string {
+ return "aa"
+}
+
+// Parameterized interface
+type Abs[T any] interface {
+ Abs() T
+}
+
+func G[T Abs[U], U any](t T) {
+ T.Abs(t)
+ t.Abs()
+}
+
+type MyInt int
+func (m MyInt) Abs() MyInt {
+ if m < 0 {
+ return -m
+ }
+ return m
+}
+
+type Abs2 interface {
+ Abs() MyInt
+}
+
+
+func main() {
+ mm := MyMer(3)
+ ms := struct{ Mer }{Mer: mm }
+
+ // Testing F with an interface type arg: Mer and Mer2
+ F[Mer](mm)
+ F[Mer2](mm)
+ F[struct{ Mer }](ms)
+ F[*struct{ Mer }](&ms)
+
+ ms2 := struct { MyMer }{MyMer: mm}
+ ms3 := struct { *MyMer }{MyMer: &mm}
+
+ // Testing F with a concrete type arg
+ F[MyMer](mm)
+ F[*MyMer](&mm)
+ F[struct{ MyMer }](ms2)
+ F[struct{ *MyMer }](ms3)
+ F[*struct{ MyMer }](&ms2)
+ F[*struct{ *MyMer }](&ms3)
+
+ // Testing G with a concrete type args
+ mi := MyInt(-3)
+ G[MyInt,MyInt](mi)
+
+ // Interface Abs[MyInt] holding an mi.
+ intMi := Abs[MyInt](mi)
+ // First type arg here is Abs[MyInt], an interface type.
+ G[Abs[MyInt],MyInt](intMi)
+}
diff --git a/test/typeparam/mdempsky/14.go b/test/typeparam/mdempsky/14.go
new file mode 100644
index 0000000..4af990c
--- /dev/null
+++ b/test/typeparam/mdempsky/14.go
@@ -0,0 +1,40 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Zero returns the zero value of T
+func Zero[T any]() (_ T) {
+ return
+}
+
+type AnyInt[X any] int
+
+func (AnyInt[X]) M() {
+ var have interface{} = Zero[X]()
+ var want interface{} = Zero[MyInt]()
+
+ if have != want {
+ println("FAIL")
+ }
+}
+
+type I interface{ M() }
+
+type MyInt int
+type U = AnyInt[MyInt]
+
+var x = U(0)
+var i I = x
+
+func main() {
+ x.M()
+ U.M(x)
+ (*U).M(&x)
+
+ i.M()
+ I.M(x)
+}
diff --git a/test/typeparam/mdempsky/15.go b/test/typeparam/mdempsky/15.go
new file mode 100644
index 0000000..b03ad6f
--- /dev/null
+++ b/test/typeparam/mdempsky/15.go
@@ -0,0 +1,69 @@
+// run -goexperiment fieldtrack
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that generics, promoted methods, and //go:nointerface
+// interoperate as expected.
+
+package main
+
+import (
+ "reflect"
+)
+
+func TypeString[T any]() string {
+ return reflect.TypeOf(new(T)).Elem().String()
+}
+
+func Test[T, Bad, Good any]() {
+ switch interface{}(new(T)).(type) {
+ case Bad:
+ println("FAIL:", TypeString[T](), "matched", TypeString[Bad]())
+ case Good:
+ // ok
+ default:
+ println("FAIL:", TypeString[T](), "did not match", TypeString[Good]())
+ }
+}
+
+func TestE[T any]() { Test[T, interface{ EBad() }, interface{ EGood() }]() }
+func TestX[T any]() { Test[T, interface{ XBad() }, interface{ XGood() }]() }
+
+type E struct{}
+
+//go:nointerface
+func (E) EBad() {}
+func (E) EGood() {}
+
+type X[T any] struct{ E }
+
+//go:nointerface
+func (X[T]) XBad() {}
+func (X[T]) XGood() {}
+
+type W struct{ X[int] }
+
+func main() {
+ _ = E.EGood
+ _ = E.EBad
+
+ TestE[E]()
+
+ _ = X[int].EGood
+ _ = X[int].EBad
+ _ = X[int].XGood
+ _ = X[int].XBad
+
+ TestE[X[int]]()
+ TestX[X[int]]()
+
+ _ = W.EGood
+ _ = W.EBad
+ _ = W.XGood
+ _ = W.XBad
+
+ TestE[W]()
+ TestX[W]()
+}
diff --git a/test/typeparam/mdempsky/16.go b/test/typeparam/mdempsky/16.go
new file mode 100644
index 0000000..f4f79b9
--- /dev/null
+++ b/test/typeparam/mdempsky/16.go
@@ -0,0 +1,34 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that type assertion panics mention the real interface type,
+// not their shape type.
+
+package main
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+)
+
+func main() {
+ // The exact error message isn't important, but it should mention
+ // `main.T`, not `go.shape.int_0`.
+ if have := F[T](); !strings.Contains(have, "interface { T() main.T }") {
+ fmt.Printf("FAIL: unexpected panic message: %q\n", have)
+ }
+}
+
+type T int
+
+func F[T any]() (res string) {
+ defer func() {
+ res = recover().(runtime.Error).Error()
+ }()
+ _ = interface{ T() T }(nil).(T)
+ return
+}
diff --git a/test/typeparam/mdempsky/17.go b/test/typeparam/mdempsky/17.go
new file mode 100644
index 0000000..12385c3
--- /dev/null
+++ b/test/typeparam/mdempsky/17.go
@@ -0,0 +1,110 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that implicit conversions of derived types to interface type
+// in range loops work correctly.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+)
+
+func main() {
+ test{"int", "V"}.match(RangeArrayAny[V]())
+ test{"int", "V"}.match(RangeArrayIface[V]())
+ test{"V"}.match(RangeChanAny[V]())
+ test{"V"}.match(RangeChanIface[V]())
+ test{"K", "V"}.match(RangeMapAny[K, V]())
+ test{"K", "V"}.match(RangeMapIface[K, V]())
+ test{"int", "V"}.match(RangeSliceAny[V]())
+ test{"int", "V"}.match(RangeSliceIface[V]())
+}
+
+type test []string
+
+func (t test) match(args ...any) {
+ if len(t) != len(args) {
+ fmt.Printf("FAIL: want %v values, have %v\n", len(t), len(args))
+ return
+ }
+ for i, want := range t {
+ if have := reflect.TypeOf(args[i]).Name(); want != have {
+ fmt.Printf("FAIL: %v: want type %v, have %v\n", i, want, have)
+ }
+ }
+}
+
+type iface interface{ M() int }
+
+type K int
+type V int
+
+func (K) M() int { return 0 }
+func (V) M() int { return 0 }
+
+func RangeArrayAny[V any]() (k, v any) {
+ for k, v = range [...]V{zero[V]()} {
+ }
+ return
+}
+
+func RangeArrayIface[V iface]() (k any, v iface) {
+ for k, v = range [...]V{zero[V]()} {
+ }
+ return
+}
+
+func RangeChanAny[V any]() (v any) {
+ for v = range chanOf(zero[V]()) {
+ }
+ return
+}
+
+func RangeChanIface[V iface]() (v iface) {
+ for v = range chanOf(zero[V]()) {
+ }
+ return
+}
+
+func RangeMapAny[K comparable, V any]() (k, v any) {
+ for k, v = range map[K]V{zero[K](): zero[V]()} {
+ }
+ return
+}
+
+func RangeMapIface[K interface {
+ iface
+ comparable
+}, V iface]() (k, v iface) {
+ for k, v = range map[K]V{zero[K](): zero[V]()} {
+ }
+ return
+}
+
+func RangeSliceAny[V any]() (k, v any) {
+ for k, v = range []V{zero[V]()} {
+ }
+ return
+}
+
+func RangeSliceIface[V iface]() (k any, v iface) {
+ for k, v = range []V{zero[V]()} {
+ }
+ return
+}
+
+func chanOf[T any](elems ...T) chan T {
+ c := make(chan T, len(elems))
+ for _, elem := range elems {
+ c <- elem
+ }
+ close(c)
+ return c
+}
+
+func zero[T any]() (_ T) { return }
diff --git a/test/typeparam/mdempsky/18.go b/test/typeparam/mdempsky/18.go
new file mode 100644
index 0000000..f4a4ec7
--- /dev/null
+++ b/test/typeparam/mdempsky/18.go
@@ -0,0 +1,26 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that implicit conversions to interface type in a select/case
+// clause are compiled correctly.
+
+package main
+
+import "fmt"
+
+func main() { f[int]() }
+
+func f[T any]() {
+ ch := make(chan T)
+ close(ch)
+
+ var i, ok any
+ select {
+ case i, ok = <-ch:
+ }
+
+ fmt.Printf("%T %T\n", i, ok)
+}
diff --git a/test/typeparam/mdempsky/18.out b/test/typeparam/mdempsky/18.out
new file mode 100644
index 0000000..19f1c39
--- /dev/null
+++ b/test/typeparam/mdempsky/18.out
@@ -0,0 +1 @@
+int bool
diff --git a/test/typeparam/mdempsky/19.go b/test/typeparam/mdempsky/19.go
new file mode 100644
index 0000000..53d979a
--- /dev/null
+++ b/test/typeparam/mdempsky/19.go
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that type parameter methods are handled correctly, even when
+// the instantiating type argument has additional methods.
+
+package main
+
+func main() {
+ F(X(0))
+}
+
+type I interface{ B() }
+
+func F[T I](t T) {
+ CallMethod(t)
+ MethodExpr[T]()(t)
+ MethodVal(t)()
+}
+
+func CallMethod[T I](t T) { t.B() }
+func MethodExpr[T I]() func(T) { return T.B }
+func MethodVal[T I](t T) func() { return t.B }
+
+type X int
+
+func (X) A() { panic("FAIL") }
+func (X) B() {}
+func (X) C() { panic("FAIL") }
diff --git a/test/typeparam/mdempsky/2.go b/test/typeparam/mdempsky/2.go
new file mode 100644
index 0000000..ad548e6
--- /dev/null
+++ b/test/typeparam/mdempsky/2.go
@@ -0,0 +1,20 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T[A, B, C any] int
+
+func (T[A, B, C]) m(x int) {
+ if x <= 0 {
+ return
+ }
+ T[B, C, A](0).m(x - 1)
+}
+
+func main() {
+ T[int8, int16, int32](0).m(3)
+}
diff --git a/test/typeparam/mdempsky/20.go b/test/typeparam/mdempsky/20.go
new file mode 100644
index 0000000..6b97ca1
--- /dev/null
+++ b/test/typeparam/mdempsky/20.go
@@ -0,0 +1,38 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that method expressions with a derived receiver type and
+// promoted methods work correctly.
+
+package main
+
+func main() {
+ F[int]()
+ F[string]()
+}
+
+func F[X any]() {
+ call(T[X].M, T[X].N)
+}
+
+func call[X any](fns ...func(T[X]) int) {
+ for want, fn := range fns {
+ if have := fn(T[X]{}); have != want {
+ println("FAIL:", have, "!=", want)
+ }
+ }
+}
+
+type T[X any] struct {
+ E1
+ *E2[*X]
+}
+
+type E1 struct{}
+type E2[_ any] struct{}
+
+func (E1) M() int { return 0 }
+func (*E2[_]) N() int { return 1 }
diff --git a/test/typeparam/mdempsky/21.go b/test/typeparam/mdempsky/21.go
new file mode 100644
index 0000000..da10ae3
--- /dev/null
+++ b/test/typeparam/mdempsky/21.go
@@ -0,0 +1,26 @@
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that devirtualization doesn't introduce spurious type
+// assertion failures due to shaped and non-shaped interfaces having
+// distinct itabs.
+
+package main
+
+func main() {
+ F[int]()
+}
+
+func F[T any]() {
+ var i I[T] = X(0)
+ i.M()
+}
+
+type I[T any] interface{ M() }
+
+type X int
+
+func (X) M() {}
diff --git a/test/typeparam/mdempsky/3.dir/a.go b/test/typeparam/mdempsky/3.dir/a.go
new file mode 100644
index 0000000..cf456e8
--- /dev/null
+++ b/test/typeparam/mdempsky/3.dir/a.go
@@ -0,0 +1,7 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F[T interface{ chan int }](c T) {}
diff --git a/test/typeparam/mdempsky/3.dir/b.go b/test/typeparam/mdempsky/3.dir/b.go
new file mode 100644
index 0000000..0cfd142
--- /dev/null
+++ b/test/typeparam/mdempsky/3.dir/b.go
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func g() { a.F(make(chan int)) }
diff --git a/test/typeparam/mdempsky/3.go b/test/typeparam/mdempsky/3.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/mdempsky/3.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/mdempsky/4.dir/a.go b/test/typeparam/mdempsky/4.dir/a.go
new file mode 100644
index 0000000..cb67294
--- /dev/null
+++ b/test/typeparam/mdempsky/4.dir/a.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F[T any](T) {
+Loop:
+ for {
+ break Loop
+ }
+}
diff --git a/test/typeparam/mdempsky/4.dir/b.go b/test/typeparam/mdempsky/4.dir/b.go
new file mode 100644
index 0000000..e1fb0e7
--- /dev/null
+++ b/test/typeparam/mdempsky/4.dir/b.go
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func f() { a.F(0) }
diff --git a/test/typeparam/mdempsky/4.go b/test/typeparam/mdempsky/4.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/mdempsky/4.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/mdempsky/5.go b/test/typeparam/mdempsky/5.go
new file mode 100644
index 0000000..00d3b71
--- /dev/null
+++ b/test/typeparam/mdempsky/5.go
@@ -0,0 +1,15 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type X[T any] int
+
+func (X[T]) F(T) {}
+
+func x() {
+ X[interface{}](0).F(0)
+}
diff --git a/test/typeparam/mdempsky/6.go b/test/typeparam/mdempsky/6.go
new file mode 100644
index 0000000..ed57009
--- /dev/null
+++ b/test/typeparam/mdempsky/6.go
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type I[T any] interface{ M() T }
+
+var _ = I[int].M
diff --git a/test/typeparam/mdempsky/7.dir/a.go b/test/typeparam/mdempsky/7.dir/a.go
new file mode 100644
index 0000000..59c5995
--- /dev/null
+++ b/test/typeparam/mdempsky/7.dir/a.go
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type I[T any] interface{ M() T }
+
+var X I[int]
diff --git a/test/typeparam/mdempsky/7.dir/b.go b/test/typeparam/mdempsky/7.dir/b.go
new file mode 100644
index 0000000..9f70530
--- /dev/null
+++ b/test/typeparam/mdempsky/7.dir/b.go
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+var _ = a.X
diff --git a/test/typeparam/mdempsky/7.go b/test/typeparam/mdempsky/7.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/mdempsky/7.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/mdempsky/8.dir/a.go b/test/typeparam/mdempsky/8.dir/a.go
new file mode 100644
index 0000000..607fe5e
--- /dev/null
+++ b/test/typeparam/mdempsky/8.dir/a.go
@@ -0,0 +1,7 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F[T interface{ comparable }]() {}
diff --git a/test/typeparam/mdempsky/8.dir/b.go b/test/typeparam/mdempsky/8.dir/b.go
new file mode 100644
index 0000000..ef2637b
--- /dev/null
+++ b/test/typeparam/mdempsky/8.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func init() {
+ a.F[func()]() // ERROR "does not satisfy comparable"
+}
diff --git a/test/typeparam/mdempsky/8.go b/test/typeparam/mdempsky/8.go
new file mode 100644
index 0000000..e3a470b
--- /dev/null
+++ b/test/typeparam/mdempsky/8.go
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/mdempsky/9.go b/test/typeparam/mdempsky/9.go
new file mode 100644
index 0000000..948a9e5
--- /dev/null
+++ b/test/typeparam/mdempsky/9.go
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func f[V any]() []V { return []V{0: *new(V)} }
+
+func g() { f[int]() }
diff --git a/test/typeparam/metrics.go b/test/typeparam/metrics.go
new file mode 100644
index 0000000..dcc5737
--- /dev/null
+++ b/test/typeparam/metrics.go
@@ -0,0 +1,196 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package metrics provides tracking arbitrary metrics composed of
+// values of comparable types.
+package main
+
+import (
+ "fmt"
+ "sort"
+ "sync"
+)
+
+// _Metric1 tracks metrics of values of some type.
+type _Metric1[T comparable] struct {
+ mu sync.Mutex
+ m map[T]int
+}
+
+// Add adds another instance of some value.
+func (m *_Metric1[T]) Add(v T) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.m == nil {
+ m.m = make(map[T]int)
+ }
+ m.m[v]++
+}
+
+// Count returns the number of instances we've seen of v.
+func (m *_Metric1[T]) Count(v T) int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.m[v]
+}
+
+// Metrics returns all the values we've seen, in an indeterminate order.
+func (m *_Metric1[T]) Metrics() []T {
+ return _Keys(m.m)
+}
+
+type key2[T1, T2 comparable] struct {
+ f1 T1
+ f2 T2
+}
+
+// _Metric2 tracks metrics of pairs of values.
+type _Metric2[T1, T2 comparable] struct {
+ mu sync.Mutex
+ m map[key2[T1, T2]]int
+}
+
+// Add adds another instance of some pair of values.
+func (m *_Metric2[T1, T2]) Add(v1 T1, v2 T2) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.m == nil {
+ m.m = make(map[key2[T1, T2]]int)
+ }
+ m.m[key2[T1, T2]{v1, v2}]++
+}
+
+// Count returns the number of instances we've seen of v1/v2.
+func (m *_Metric2[T1, T2]) Count(v1 T1, v2 T2) int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.m[key2[T1, T2]{v1, v2}]
+}
+
+// Metrics returns all the values we've seen, in an indeterminate order.
+func (m *_Metric2[T1, T2]) Metrics() (r1 []T1, r2 []T2) {
+ for _, k := range _Keys(m.m) {
+ r1 = append(r1, k.f1)
+ r2 = append(r2, k.f2)
+ }
+ return r1, r2
+}
+
+type key3[T1, T2, T3 comparable] struct {
+ f1 T1
+ f2 T2
+ f3 T3
+}
+
+// _Metric3 tracks metrics of triplets of values.
+type _Metric3[T1, T2, T3 comparable] struct {
+ mu sync.Mutex
+ m map[key3[T1, T2, T3]]int
+}
+
+// Add adds another instance of some triplet of values.
+func (m *_Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.m == nil {
+ m.m = make(map[key3[T1, T2, T3]]int)
+ }
+ m.m[key3[T1, T2, T3]{v1, v2, v3}]++
+}
+
+// Count returns the number of instances we've seen of v1/v2/v3.
+func (m *_Metric3[T1, T2, T3]) Count(v1 T1, v2 T2, v3 T3) int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.m[key3[T1, T2, T3]{v1, v2, v3}]
+}
+
+// Metrics returns all the values we've seen, in an indeterminate order.
+func (m *_Metric3[T1, T2, T3]) Metrics() (r1 []T1, r2 []T2, r3 []T3) {
+ for k := range m.m {
+ r1 = append(r1, k.f1)
+ r2 = append(r2, k.f2)
+ r3 = append(r3, k.f3)
+ }
+ return r1, r2, r3
+}
+
+type S struct{ a, b, c string }
+
+func TestMetrics() {
+ m1 := _Metric1[string]{}
+ if got := m1.Count("a"); got != 0 {
+ panic(fmt.Sprintf("Count(%q) = %d, want 0", "a", got))
+ }
+ m1.Add("a")
+ m1.Add("a")
+ if got := m1.Count("a"); got != 2 {
+ panic(fmt.Sprintf("Count(%q) = %d, want 2", "a", got))
+ }
+ if got, want := m1.Metrics(), []string{"a"}; !_SlicesEqual(got, want) {
+ panic(fmt.Sprintf("Metrics = %v, want %v", got, want))
+ }
+
+ m2 := _Metric2[int, float64]{}
+ m2.Add(1, 1)
+ m2.Add(2, 2)
+ m2.Add(3, 3)
+ m2.Add(3, 3)
+ k1, k2 := m2.Metrics()
+
+ sort.Ints(k1)
+ w1 := []int{1, 2, 3}
+ if !_SlicesEqual(k1, w1) {
+ panic(fmt.Sprintf("_Metric2.Metrics first slice = %v, want %v", k1, w1))
+ }
+
+ sort.Float64s(k2)
+ w2 := []float64{1, 2, 3}
+ if !_SlicesEqual(k2, w2) {
+ panic(fmt.Sprintf("_Metric2.Metrics first slice = %v, want %v", k2, w2))
+ }
+
+ m3 := _Metric3[string, S, S]{}
+ m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
+ m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
+ m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
+ m3.Add("b", S{"d", "e", "f"}, S{"g", "h", "i"})
+ if got := m3.Count("a", S{"d", "e", "f"}, S{"g", "h", "i"}); got != 3 {
+ panic(fmt.Sprintf("Count(%v, %v, %v) = %d, want 3", "a", S{"d", "e", "f"}, S{"g", "h", "i"}, got))
+ }
+}
+
+func main() {
+ TestMetrics()
+}
+
+// _Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func _SlicesEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// _Keys returns the keys of the map m.
+// The keys will be an indeterminate order.
+func _Keys[K comparable, V any](m map[K]V) []K {
+ r := make([]K, 0, len(m))
+ for k := range m {
+ r = append(r, k)
+ }
+ return r
+}
diff --git a/test/typeparam/min.go b/test/typeparam/min.go
new file mode 100644
index 0000000..a922450
--- /dev/null
+++ b/test/typeparam/min.go
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type Ordered interface {
+ ~int | ~int64 | ~float64 | ~string
+}
+
+func min[T Ordered](x, y T) T {
+ if x < y {
+ return x
+ }
+ return y
+}
+
+func main() {
+ const want = 2
+ if got := min[int](2, 3); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := min(2, 3); got != want {
+ panic(fmt.Sprintf("want %d, got %d", want, got))
+ }
+
+ if got := min[float64](3.5, 2.0); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := min(3.5, 2.0); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ const want2 = "ay"
+ if got := min[string]("bb", "ay"); got != want2 {
+ panic(fmt.Sprintf("got %d, want %d", got, want2))
+ }
+
+ if got := min("bb", "ay"); got != want2 {
+ panic(fmt.Sprintf("got %d, want %d", got, want2))
+ }
+}
diff --git a/test/typeparam/mincheck.dir/a.go b/test/typeparam/mincheck.dir/a.go
new file mode 100644
index 0000000..fa0f249
--- /dev/null
+++ b/test/typeparam/mincheck.dir/a.go
@@ -0,0 +1,16 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Ordered interface {
+ int | int64 | float64
+}
+
+func Min[T Ordered](x, y T) T {
+ if x < y {
+ return x
+ }
+ return y
+}
diff --git a/test/typeparam/mincheck.dir/main.go b/test/typeparam/mincheck.dir/main.go
new file mode 100644
index 0000000..6f85f9e
--- /dev/null
+++ b/test/typeparam/mincheck.dir/main.go
@@ -0,0 +1,38 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ const want = 2
+ if got := a.Min[int](2, 3); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := a.Min(2, 3); got != want {
+ panic(fmt.Sprintf("want %d, got %d", want, got))
+ }
+
+ if got := a.Min[float64](3.5, 2.0); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := a.Min(3.5, 2.0); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ const want2 = "ay"
+ if got := a.Min[string]("bb", "ay"); got != want2 { // ERROR "string does not satisfy"
+ panic(fmt.Sprintf("got %d, want %d", got, want2))
+ }
+
+ if got := a.Min("bb", "ay"); got != want2 { // ERROR "string does not satisfy"
+ panic(fmt.Sprintf("got %d, want %d", got, want2))
+ }
+}
diff --git a/test/typeparam/mincheck.go b/test/typeparam/mincheck.go
new file mode 100644
index 0000000..e3a470b
--- /dev/null
+++ b/test/typeparam/mincheck.go
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/minimp.dir/a.go b/test/typeparam/minimp.dir/a.go
new file mode 100644
index 0000000..fabde62
--- /dev/null
+++ b/test/typeparam/minimp.dir/a.go
@@ -0,0 +1,16 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Ordered interface {
+ ~int | ~int64 | ~float64 | ~string
+}
+
+func Min[T Ordered](x, y T) T {
+ if x < y {
+ return x
+ }
+ return y
+}
diff --git a/test/typeparam/minimp.dir/main.go b/test/typeparam/minimp.dir/main.go
new file mode 100644
index 0000000..36bec0f
--- /dev/null
+++ b/test/typeparam/minimp.dir/main.go
@@ -0,0 +1,38 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ const want = 2
+ if got := a.Min[int](2, 3); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := a.Min(2, 3); got != want {
+ panic(fmt.Sprintf("want %d, got %d", want, got))
+ }
+
+ if got := a.Min[float64](3.5, 2.0); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ if got := a.Min(3.5, 2.0); got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ const want2 = "ay"
+ if got := a.Min[string]("bb", "ay"); got != want2 {
+ panic(fmt.Sprintf("got %d, want %d", got, want2))
+ }
+
+ if got := a.Min("bb", "ay"); got != want2 {
+ panic(fmt.Sprintf("got %d, want %d", got, want2))
+ }
+}
diff --git a/test/typeparam/minimp.go b/test/typeparam/minimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/minimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/mutualimp.dir/a.go b/test/typeparam/mutualimp.dir/a.go
new file mode 100644
index 0000000..5b924d3
--- /dev/null
+++ b/test/typeparam/mutualimp.dir/a.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type X int
+
+func (x X) M() X { return x }
+
+func F[T interface{ M() U }, U interface{ M() T }]() {}
+func G() { F[X, X]() }
diff --git a/test/typeparam/mutualimp.dir/b.go b/test/typeparam/mutualimp.dir/b.go
new file mode 100644
index 0000000..83cc3af
--- /dev/null
+++ b/test/typeparam/mutualimp.dir/b.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func H() {
+ a.F[a.X, a.X]()
+ a.G()
+}
diff --git a/test/typeparam/mutualimp.go b/test/typeparam/mutualimp.go
new file mode 100644
index 0000000..b83fbd7
--- /dev/null
+++ b/test/typeparam/mutualimp.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/nested.go b/test/typeparam/nested.go
new file mode 100644
index 0000000..cdb8bfb
--- /dev/null
+++ b/test/typeparam/nested.go
@@ -0,0 +1,134 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test case stress tests a number of subtle cases involving
+// nested type-parameterized declarations. At a high-level, it
+// declares a generic function that contains a generic type
+// declaration:
+//
+// func F[A intish]() {
+// type T[B intish] struct{}
+//
+// // store reflect.Type tuple (A, B, F[A].T[B]) in tests
+// }
+//
+// It then instantiates this function with a variety of type arguments
+// for A and B. Particularly tricky things like shadowed types.
+//
+// From this data it tests two things:
+//
+// 1. Given tuples (A, B, F[A].T[B]) and (A', B', F[A'].T[B']),
+// F[A].T[B] should be identical to F[A'].T[B'] iff (A, B) is
+// identical to (A', B').
+//
+// 2. A few of the instantiations are constructed to be identical, and
+// it tests that exactly these pairs are duplicated (by golden
+// output comparison to nested.out).
+//
+// In both cases, we're effectively using the compiler's existing
+// runtime.Type handling (which is well tested) of type identity of A
+// and B as a way to help bootstrap testing and validate its new
+// runtime.Type handling of F[A].T[B].
+//
+// This isn't perfect, but it smoked out a handful of issues in
+// gotypes2 and unified IR.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type test struct {
+ TArgs [2]reflect.Type
+ Instance reflect.Type
+}
+
+var tests []test
+
+type intish interface{ ~int }
+
+type Int int
+type GlobalInt = Int // allow access to global Int, even when shadowed
+
+func F[A intish]() {
+ add := func(B, T interface{}) {
+ tests = append(tests, test{
+ TArgs: [2]reflect.Type{
+ reflect.TypeOf(A(0)),
+ reflect.TypeOf(B),
+ },
+ Instance: reflect.TypeOf(T),
+ })
+ }
+
+ type Int int
+
+ type T[B intish] struct{}
+
+ add(int(0), T[int]{})
+ add(Int(0), T[Int]{})
+ add(GlobalInt(0), T[GlobalInt]{})
+ add(A(0), T[A]{}) // NOTE: intentionally dups with int and GlobalInt
+
+ type U[_ any] int
+ type V U[int]
+ type W V
+
+ add(U[int](0), T[U[int]]{})
+ add(U[Int](0), T[U[Int]]{})
+ add(U[GlobalInt](0), T[U[GlobalInt]]{})
+ add(U[A](0), T[U[A]]{}) // NOTE: intentionally dups with U[int] and U[GlobalInt]
+ add(V(0), T[V]{})
+ add(W(0), T[W]{})
+}
+
+func main() {
+ type Int int
+
+ F[int]()
+ F[Int]()
+ F[GlobalInt]()
+
+ type U[_ any] int
+ type V U[int]
+ type W V
+
+ F[U[int]]()
+ F[U[Int]]()
+ F[U[GlobalInt]]()
+ F[V]()
+ F[W]()
+
+ type X[A any] U[X[A]]
+
+ F[X[int]]()
+ F[X[Int]]()
+ F[X[GlobalInt]]()
+
+ for j, tj := range tests {
+ for i, ti := range tests[:j+1] {
+ if (ti.TArgs == tj.TArgs) != (ti.Instance == tj.Instance) {
+ fmt.Printf("FAIL: %d,%d: %s, but %s\n", i, j, eq(ti.TArgs, tj.TArgs), eq(ti.Instance, tj.Instance))
+ }
+
+ // The test is constructed so we should see a few identical types.
+ // See "NOTE" comments above.
+ if i != j && ti.Instance == tj.Instance {
+ fmt.Printf("%d,%d: %v\n", i, j, ti.Instance)
+ }
+ }
+ }
+}
+
+func eq(a, b interface{}) string {
+ op := "=="
+ if a != b {
+ op = "!="
+ }
+ return fmt.Sprintf("%v %s %v", a, op, b)
+}
diff --git a/test/typeparam/nested.out b/test/typeparam/nested.out
new file mode 100644
index 0000000..0836d9b
--- /dev/null
+++ b/test/typeparam/nested.out
@@ -0,0 +1,4 @@
+0,3: main.T[int;int]
+4,7: main.T[int;main.U[int;int]·3]
+22,23: main.T[main.Int;main.Int]
+26,27: main.T[main.Int;main.U[main.Int;main.Int]·3]
diff --git a/test/typeparam/ordered.go b/test/typeparam/ordered.go
new file mode 100644
index 0000000..d304298
--- /dev/null
+++ b/test/typeparam/ordered.go
@@ -0,0 +1,95 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "math"
+ "sort"
+)
+
+type Ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+type orderedSlice[Elem Ordered] []Elem
+
+func (s orderedSlice[Elem]) Len() int { return len(s) }
+func (s orderedSlice[Elem]) Less(i, j int) bool {
+ if s[i] < s[j] {
+ return true
+ }
+ isNaN := func(f Elem) bool { return f != f }
+ if isNaN(s[i]) && !isNaN(s[j]) {
+ return true
+ }
+ return false
+}
+func (s orderedSlice[Elem]) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func _OrderedSlice[Elem Ordered](s []Elem) {
+ sort.Sort(orderedSlice[Elem](s))
+}
+
+var ints = []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
+var float64s = []float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8}
+var strings = []string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
+
+func TestSortOrderedInts() bool {
+ return testOrdered("ints", ints, sort.Ints)
+}
+
+func TestSortOrderedFloat64s() bool {
+ return testOrdered("float64s", float64s, sort.Float64s)
+}
+
+func TestSortOrderedStrings() bool {
+ return testOrdered("strings", strings, sort.Strings)
+}
+
+func testOrdered[Elem Ordered](name string, s []Elem, sorter func([]Elem)) bool {
+ s1 := make([]Elem, len(s))
+ copy(s1, s)
+ s2 := make([]Elem, len(s))
+ copy(s2, s)
+ _OrderedSlice(s1)
+ sorter(s2)
+ ok := true
+ if !sliceEq(s1, s2) {
+ fmt.Printf("%s: got %v, want %v", name, s1, s2)
+ ok = false
+ }
+ for i := len(s1) - 1; i > 0; i-- {
+ if s1[i] < s1[i-1] {
+ fmt.Printf("%s: element %d (%v) < element %d (%v)", name, i, s1[i], i-1, s1[i-1])
+ ok = false
+ }
+ }
+ return ok
+}
+
+func sliceEq[Elem Ordered](s1, s2 []Elem) bool {
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func main() {
+ if !TestSortOrderedInts() || !TestSortOrderedFloat64s() || !TestSortOrderedStrings() {
+ panic("failure")
+ }
+}
diff --git a/test/typeparam/orderedmap.go b/test/typeparam/orderedmap.go
new file mode 100644
index 0000000..1245669
--- /dev/null
+++ b/test/typeparam/orderedmap.go
@@ -0,0 +1,286 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package orderedmap provides an ordered map, implemented as a binary tree.
+package main
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "runtime"
+)
+
+type Ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+// _Map is an ordered map.
+type _Map[K, V any] struct {
+ root *node[K, V]
+ compare func(K, K) int
+}
+
+// node is the type of a node in the binary tree.
+type node[K, V any] struct {
+ key K
+ val V
+ left, right *node[K, V]
+}
+
+// _New returns a new map. It takes a comparison function that compares two
+// keys and returns < 0 if the first is less, == 0 if they are equal,
+// > 0 if the first is greater.
+func _New[K, V any](compare func(K, K) int) *_Map[K, V] {
+ return &_Map[K, V]{compare: compare}
+}
+
+// _NewOrdered returns a new map whose key is an ordered type.
+// This is like _New, but does not require providing a compare function.
+// The map compare function uses the obvious key ordering.
+func _NewOrdered[K Ordered, V any]() *_Map[K, V] {
+ return _New[K, V](func(k1, k2 K) int {
+ switch {
+ case k1 < k2:
+ return -1
+ case k1 == k2:
+ return 0
+ default:
+ return 1
+ }
+ })
+}
+
+// find looks up key in the map, returning either a pointer to the slot of the
+// node holding key, or a pointer to the slot where should a node would go.
+func (m *_Map[K, V]) find(key K) **node[K, V] {
+ pn := &m.root
+ for *pn != nil {
+ switch cmp := m.compare(key, (*pn).key); {
+ case cmp < 0:
+ pn = &(*pn).left
+ case cmp > 0:
+ pn = &(*pn).right
+ default:
+ return pn
+ }
+ }
+ return pn
+}
+
+// Insert inserts a new key/value into the map.
+// If the key is already present, the value is replaced.
+// Reports whether this is a new key.
+func (m *_Map[K, V]) Insert(key K, val V) bool {
+ pn := m.find(key)
+ if *pn != nil {
+ (*pn).val = val
+ return false
+ }
+ *pn = &node[K, V]{key: key, val: val}
+ return true
+}
+
+// Find returns the value associated with a key, or the zero value
+// if not present. The found result reports whether the key was found.
+func (m *_Map[K, V]) Find(key K) (V, bool) {
+ pn := m.find(key)
+ if *pn == nil {
+ var zero V
+ return zero, false
+ }
+ return (*pn).val, true
+}
+
+// keyValue is a pair of key and value used while iterating.
+type keyValue[K, V any] struct {
+ key K
+ val V
+}
+
+// iterate returns an iterator that traverses the map.
+func (m *_Map[K, V]) Iterate() *_Iterator[K, V] {
+ sender, receiver := _Ranger[keyValue[K, V]]()
+ var f func(*node[K, V]) bool
+ f = func(n *node[K, V]) bool {
+ if n == nil {
+ return true
+ }
+ // Stop the traversal if Send fails, which means that
+ // nothing is listening to the receiver.
+ return f(n.left) &&
+ sender.Send(context.Background(), keyValue[K, V]{n.key, n.val}) &&
+ f(n.right)
+ }
+ go func() {
+ f(m.root)
+ sender.Close()
+ }()
+ return &_Iterator[K, V]{receiver}
+}
+
+// _Iterator is used to iterate over the map.
+type _Iterator[K, V any] struct {
+ r *_Receiver[keyValue[K, V]]
+}
+
+// Next returns the next key and value pair, and a boolean that reports
+// whether they are valid. If not valid, we have reached the end of the map.
+func (it *_Iterator[K, V]) Next() (K, V, bool) {
+ keyval, ok := it.r.Next(context.Background())
+ if !ok {
+ var zerok K
+ var zerov V
+ return zerok, zerov, false
+ }
+ return keyval.key, keyval.val, true
+}
+
+func TestMap() {
+ m := _New[[]byte, int](bytes.Compare)
+
+ if _, found := m.Find([]byte("a")); found {
+ panic(fmt.Sprintf("unexpectedly found %q in empty map", []byte("a")))
+ }
+ if !m.Insert([]byte("a"), 'a') {
+ panic(fmt.Sprintf("key %q unexpectedly already present", []byte("a")))
+ }
+ if !m.Insert([]byte("c"), 'c') {
+ panic(fmt.Sprintf("key %q unexpectedly already present", []byte("c")))
+ }
+ if !m.Insert([]byte("b"), 'b') {
+ panic(fmt.Sprintf("key %q unexpectedly already present", []byte("b")))
+ }
+ if m.Insert([]byte("c"), 'x') {
+ panic(fmt.Sprintf("key %q unexpectedly not present", []byte("c")))
+ }
+
+ if v, found := m.Find([]byte("a")); !found {
+ panic(fmt.Sprintf("did not find %q", []byte("a")))
+ } else if v != 'a' {
+ panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("a"), v, 'a'))
+ }
+ if v, found := m.Find([]byte("c")); !found {
+ panic(fmt.Sprintf("did not find %q", []byte("c")))
+ } else if v != 'x' {
+ panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("c"), v, 'x'))
+ }
+
+ if _, found := m.Find([]byte("d")); found {
+ panic(fmt.Sprintf("unexpectedly found %q", []byte("d")))
+ }
+
+ gather := func(it *_Iterator[[]byte, int]) []int {
+ var r []int
+ for {
+ _, v, ok := it.Next()
+ if !ok {
+ return r
+ }
+ r = append(r, v)
+ }
+ }
+ got := gather(m.Iterate())
+ want := []int{'a', 'b', 'x'}
+ if !_SliceEqual(got, want) {
+ panic(fmt.Sprintf("Iterate returned %v, want %v", got, want))
+ }
+}
+
+func main() {
+ TestMap()
+}
+
+// _Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func _SliceEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// Ranger returns a Sender and a Receiver. The Receiver provides a
+// Next method to retrieve values. The Sender provides a Send method
+// to send values and a Close method to stop sending values. The Next
+// method indicates when the Sender has been closed, and the Send
+// method indicates when the Receiver has been freed.
+//
+// This is a convenient way to exit a goroutine sending values when
+// the receiver stops reading them.
+func _Ranger[Elem any]() (*_Sender[Elem], *_Receiver[Elem]) {
+ c := make(chan Elem)
+ d := make(chan struct{})
+ s := &_Sender[Elem]{
+ values: c,
+ done: d,
+ }
+ r := &_Receiver[Elem]{
+ values: c,
+ done: d,
+ }
+ runtime.SetFinalizer(r, (*_Receiver[Elem]).finalize)
+ return s, r
+}
+
+// A _Sender is used to send values to a Receiver.
+type _Sender[Elem any] struct {
+ values chan<- Elem
+ done <-chan struct{}
+}
+
+// Send sends a value to the receiver. It reports whether the value was sent.
+// The value will not be sent if the context is closed or the receiver
+// is freed.
+func (s *_Sender[Elem]) Send(ctx context.Context, v Elem) bool {
+ select {
+ case <-ctx.Done():
+ return false
+ case s.values <- v:
+ return true
+ case <-s.done:
+ return false
+ }
+}
+
+// Close tells the receiver that no more values will arrive.
+// After Close is called, the _Sender may no longer be used.
+func (s *_Sender[Elem]) Close() {
+ close(s.values)
+}
+
+// A _Receiver receives values from a _Sender.
+type _Receiver[Elem any] struct {
+ values <-chan Elem
+ done chan<- struct{}
+}
+
+// Next returns the next value from the channel. The bool result indicates
+// whether the value is valid.
+func (r *_Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) {
+ select {
+ case <-ctx.Done():
+ case v, ok = <-r.values:
+ }
+ return v, ok
+}
+
+// finalize is a finalizer for the receiver.
+func (r *_Receiver[Elem]) finalize() {
+ close(r.done)
+}
diff --git a/test/typeparam/orderedmapsimp.dir/a.go b/test/typeparam/orderedmapsimp.dir/a.go
new file mode 100644
index 0000000..d6a2de5
--- /dev/null
+++ b/test/typeparam/orderedmapsimp.dir/a.go
@@ -0,0 +1,226 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import (
+ "context"
+ "runtime"
+)
+
+type Ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+// Map is an ordered map.
+type Map[K, V any] struct {
+ root *node[K, V]
+ compare func(K, K) int
+}
+
+// node is the type of a node in the binary tree.
+type node[K, V any] struct {
+ key K
+ val V
+ left, right *node[K, V]
+}
+
+// New returns a new map. It takes a comparison function that compares two
+// keys and returns < 0 if the first is less, == 0 if they are equal,
+// > 0 if the first is greater.
+func New[K, V any](compare func(K, K) int) *Map[K, V] {
+ return &Map[K, V]{compare: compare}
+}
+
+// NewOrdered returns a new map whose key is an ordered type.
+// This is like New, but does not require providing a compare function.
+// The map compare function uses the obvious key ordering.
+func NewOrdered[K Ordered, V any]() *Map[K, V] {
+ return New[K, V](func(k1, k2 K) int {
+ switch {
+ case k1 < k2:
+ return -1
+ case k1 > k2:
+ return 1
+ default:
+ return 0
+ }
+ })
+}
+
+// find looks up key in the map, returning either a pointer to the slot of the
+// node holding key, or a pointer to the slot where a node would go.
+func (m *Map[K, V]) find(key K) **node[K, V] {
+ pn := &m.root
+ for *pn != nil {
+ switch cmp := m.compare(key, (*pn).key); {
+ case cmp < 0:
+ pn = &(*pn).left
+ case cmp > 0:
+ pn = &(*pn).right
+ default:
+ return pn
+ }
+ }
+ return pn
+}
+
+// Insert inserts a new key/value into the map.
+// If the key is already present, the value is replaced.
+// Reports whether this is a new key.
+func (m *Map[K, V]) Insert(key K, val V) bool {
+ pn := m.find(key)
+ if *pn != nil {
+ (*pn).val = val
+ return false
+ }
+ *pn = &node[K, V]{key: key, val: val}
+ return true
+}
+
+// Find returns the value associated with a key, or the zero value
+// if not present. The second result reports whether the key was found.
+func (m *Map[K, V]) Find(key K) (V, bool) {
+ pn := m.find(key)
+ if *pn == nil {
+ var zero V
+ return zero, false
+ }
+ return (*pn).val, true
+}
+
+// keyValue is a pair of key and value used while iterating.
+type keyValue[K, V any] struct {
+ key K
+ val V
+}
+
+// iterate returns an iterator that traverses the map.
+func (m *Map[K, V]) Iterate() *Iterator[K, V] {
+ sender, receiver := Ranger[keyValue[K, V]]()
+ var f func(*node[K, V]) bool
+ f = func(n *node[K, V]) bool {
+ if n == nil {
+ return true
+ }
+ // Stop the traversal if Send fails, which means that
+ // nothing is listening to the receiver.
+ return f(n.left) &&
+ sender.Send(context.Background(), keyValue[K, V]{n.key, n.val}) &&
+ f(n.right)
+ }
+ go func() {
+ f(m.root)
+ sender.Close()
+ }()
+ return &Iterator[K, V]{receiver}
+}
+
+// Iterator is used to iterate over the map.
+type Iterator[K, V any] struct {
+ r *Receiver[keyValue[K, V]]
+}
+
+// Next returns the next key and value pair, and a boolean that reports
+// whether they are valid. If not valid, we have reached the end of the map.
+func (it *Iterator[K, V]) Next() (K, V, bool) {
+ keyval, ok := it.r.Next(context.Background())
+ if !ok {
+ var zerok K
+ var zerov V
+ return zerok, zerov, false
+ }
+ return keyval.key, keyval.val, true
+}
+
+// Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func SliceEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// Ranger returns a Sender and a Receiver. The Receiver provides a
+// Next method to retrieve values. The Sender provides a Send method
+// to send values and a Close method to stop sending values. The Next
+// method indicates when the Sender has been closed, and the Send
+// method indicates when the Receiver has been freed.
+//
+// This is a convenient way to exit a goroutine sending values when
+// the receiver stops reading them.
+func Ranger[Elem any]() (*Sender[Elem], *Receiver[Elem]) {
+ c := make(chan Elem)
+ d := make(chan struct{})
+ s := &Sender[Elem]{
+ values: c,
+ done: d,
+ }
+ r := &Receiver[Elem]{
+ values: c,
+ done: d,
+ }
+ runtime.SetFinalizer(r, (*Receiver[Elem]).finalize)
+ return s, r
+}
+
+// A Sender is used to send values to a Receiver.
+type Sender[Elem any] struct {
+ values chan<- Elem
+ done <-chan struct{}
+}
+
+// Send sends a value to the receiver. It reports whether the value was sent.
+// The value will not be sent if the context is closed or the receiver
+// is freed.
+func (s *Sender[Elem]) Send(ctx context.Context, v Elem) bool {
+ select {
+ case <-ctx.Done():
+ return false
+ case s.values <- v:
+ return true
+ case <-s.done:
+ return false
+ }
+}
+
+// Close tells the receiver that no more values will arrive.
+// After Close is called, the Sender may no longer be used.
+func (s *Sender[Elem]) Close() {
+ close(s.values)
+}
+
+// A Receiver receives values from a Sender.
+type Receiver[Elem any] struct {
+ values <-chan Elem
+ done chan<- struct{}
+}
+
+// Next returns the next value from the channel. The bool result indicates
+// whether the value is valid.
+func (r *Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) {
+ select {
+ case <-ctx.Done():
+ case v, ok = <-r.values:
+ }
+ return v, ok
+}
+
+// finalize is a finalizer for the receiver.
+func (r *Receiver[Elem]) finalize() {
+ close(r.done)
+}
diff --git a/test/typeparam/orderedmapsimp.dir/main.go b/test/typeparam/orderedmapsimp.dir/main.go
new file mode 100644
index 0000000..7758a75
--- /dev/null
+++ b/test/typeparam/orderedmapsimp.dir/main.go
@@ -0,0 +1,64 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "bytes"
+ "fmt"
+)
+
+func TestMap() {
+ m := a.New[[]byte, int](bytes.Compare)
+
+ if _, found := m.Find([]byte("a")); found {
+ panic(fmt.Sprintf("unexpectedly found %q in empty map", []byte("a")))
+ }
+
+ for _, c := range []int{'a', 'c', 'b'} {
+ if !m.Insert([]byte(string(c)), c) {
+ panic(fmt.Sprintf("key %q unexpectedly already present", []byte(string(c))))
+ }
+ }
+ if m.Insert([]byte("c"), 'x') {
+ panic(fmt.Sprintf("key %q unexpectedly not present", []byte("c")))
+ }
+
+ if v, found := m.Find([]byte("a")); !found {
+ panic(fmt.Sprintf("did not find %q", []byte("a")))
+ } else if v != 'a' {
+ panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("a"), v, 'a'))
+ }
+ if v, found := m.Find([]byte("c")); !found {
+ panic(fmt.Sprintf("did not find %q", []byte("c")))
+ } else if v != 'x' {
+ panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("c"), v, 'x'))
+ }
+
+ if _, found := m.Find([]byte("d")); found {
+ panic(fmt.Sprintf("unexpectedly found %q", []byte("d")))
+ }
+
+ gather := func(it *a.Iterator[[]byte, int]) []int {
+ var r []int
+ for {
+ _, v, ok := it.Next()
+ if !ok {
+ return r
+ }
+ r = append(r, v)
+ }
+ }
+ got := gather(m.Iterate())
+ want := []int{'a', 'b', 'x'}
+ if !a.SliceEqual(got, want) {
+ panic(fmt.Sprintf("Iterate returned %v, want %v", got, want))
+ }
+
+}
+
+func main() {
+ TestMap()
+}
diff --git a/test/typeparam/orderedmapsimp.go b/test/typeparam/orderedmapsimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/orderedmapsimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/pair.go b/test/typeparam/pair.go
new file mode 100644
index 0000000..dd0adb1
--- /dev/null
+++ b/test/typeparam/pair.go
@@ -0,0 +1,36 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "unsafe"
+)
+
+type pair[F1, F2 any] struct {
+ f1 F1
+ f2 F2
+}
+
+func main() {
+ p := pair[int32, int64]{1, 2}
+ if got, want := unsafe.Sizeof(p.f1), uintptr(4); got != want {
+ panic(fmt.Sprintf("unexpected f1 size == %d, want %d", got, want))
+ }
+ if got, want := unsafe.Sizeof(p.f2), uintptr(8); got != want {
+ panic(fmt.Sprintf("unexpected f2 size == %d, want %d", got, want))
+ }
+
+ type mypair struct {
+ f1 int32
+ f2 int64
+ }
+ mp := mypair(p)
+ if mp.f1 != 1 || mp.f2 != 2 {
+ panic(fmt.Sprintf("mp == %#v, want %#v", mp, mypair{1, 2}))
+ }
+}
diff --git a/test/typeparam/pairimp.dir/a.go b/test/typeparam/pairimp.dir/a.go
new file mode 100644
index 0000000..a984fba
--- /dev/null
+++ b/test/typeparam/pairimp.dir/a.go
@@ -0,0 +1,10 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Pair[F1, F2 any] struct {
+ Field1 F1
+ Field2 F2
+}
diff --git a/test/typeparam/pairimp.dir/main.go b/test/typeparam/pairimp.dir/main.go
new file mode 100644
index 0000000..f76da43
--- /dev/null
+++ b/test/typeparam/pairimp.dir/main.go
@@ -0,0 +1,30 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+ "unsafe"
+)
+
+func main() {
+ p := a.Pair[int32, int64]{1, 2}
+ if got, want := unsafe.Sizeof(p.Field1), uintptr(4); got != want {
+ panic(fmt.Sprintf("unexpected f1 size == %d, want %d", got, want))
+ }
+ if got, want := unsafe.Sizeof(p.Field2), uintptr(8); got != want {
+ panic(fmt.Sprintf("unexpected f2 size == %d, want %d", got, want))
+ }
+
+ type mypair struct {
+ Field1 int32
+ Field2 int64
+ }
+ mp := mypair(p)
+ if mp.Field1 != 1 || mp.Field2 != 2 {
+ panic(fmt.Sprintf("mp == %#v, want %#v", mp, mypair{1, 2}))
+ }
+}
diff --git a/test/typeparam/pairimp.go b/test/typeparam/pairimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/pairimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/pragma.go b/test/typeparam/pragma.go
new file mode 100644
index 0000000..59411ab
--- /dev/null
+++ b/test/typeparam/pragma.go
@@ -0,0 +1,19 @@
+// errorcheck -0 -m
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Make sure the go:noinline pragma makes it from a
+// generic function to any of its stenciled instances.
+
+package main
+
+//go:noinline
+func f[T any](x T) T {
+ return x
+}
+
+func main() { // ERROR "can inline main"
+ println(f(5))
+}
diff --git a/test/typeparam/recoverimp.dir/a.go b/test/typeparam/recoverimp.dir/a.go
new file mode 100644
index 0000000..a465fd1
--- /dev/null
+++ b/test/typeparam/recoverimp.dir/a.go
@@ -0,0 +1,16 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import "fmt"
+
+func F[T any](a T) {
+ defer func() {
+ if x := recover(); x != nil {
+ fmt.Printf("panic: %v\n", x)
+ }
+ }()
+ panic(a)
+}
diff --git a/test/typeparam/recoverimp.dir/main.go b/test/typeparam/recoverimp.dir/main.go
new file mode 100644
index 0000000..d8cfa38
--- /dev/null
+++ b/test/typeparam/recoverimp.dir/main.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ a.F(5.3)
+ a.F("hello")
+}
diff --git a/test/typeparam/recoverimp.go b/test/typeparam/recoverimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/recoverimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/recoverimp.out b/test/typeparam/recoverimp.out
new file mode 100644
index 0000000..3c8b38c
--- /dev/null
+++ b/test/typeparam/recoverimp.out
@@ -0,0 +1,2 @@
+panic: 5.3
+panic: hello
diff --git a/test/typeparam/select.dir/a.go b/test/typeparam/select.dir/a.go
new file mode 100644
index 0000000..983e4b1
--- /dev/null
+++ b/test/typeparam/select.dir/a.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F[T any](c, d chan T) T {
+ select {
+ case x := <- c:
+ return x
+ case x := <- d:
+ return x
+ }
+}
+
diff --git a/test/typeparam/select.dir/main.go b/test/typeparam/select.dir/main.go
new file mode 100644
index 0000000..6ea3fe2
--- /dev/null
+++ b/test/typeparam/select.dir/main.go
@@ -0,0 +1,28 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "sort"
+
+ "./a"
+)
+
+func main() {
+ c := make(chan int, 1)
+ d := make(chan int, 1)
+
+ c <- 5
+ d <- 6
+
+ var r [2]int
+ r[0] = a.F(c, d)
+ r[1] = a.F(c, d)
+ sort.Ints(r[:])
+
+ if r != [2]int{5, 6} {
+ panic("incorrect results")
+ }
+}
diff --git a/test/typeparam/select.go b/test/typeparam/select.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/select.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/sets.go b/test/typeparam/sets.go
new file mode 100644
index 0000000..bd08ad7
--- /dev/null
+++ b/test/typeparam/sets.go
@@ -0,0 +1,280 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "sort"
+)
+
+// _Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func _SliceEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// A _Set is a set of elements of some type.
+type _Set[Elem comparable] struct {
+ m map[Elem]struct{}
+}
+
+// _Make makes a new set.
+func _Make[Elem comparable]() _Set[Elem] {
+ return _Set[Elem]{m: make(map[Elem]struct{})}
+}
+
+// Add adds an element to a set.
+func (s _Set[Elem]) Add(v Elem) {
+ s.m[v] = struct{}{}
+}
+
+// Delete removes an element from a set. If the element is not present
+// in the set, this does nothing.
+func (s _Set[Elem]) Delete(v Elem) {
+ delete(s.m, v)
+}
+
+// Contains reports whether v is in the set.
+func (s _Set[Elem]) Contains(v Elem) bool {
+ _, ok := s.m[v]
+ return ok
+}
+
+// Len returns the number of elements in the set.
+func (s _Set[Elem]) Len() int {
+ return len(s.m)
+}
+
+// Values returns the values in the set.
+// The values will be in an indeterminate order.
+func (s _Set[Elem]) Values() []Elem {
+ r := make([]Elem, 0, len(s.m))
+ for v := range s.m {
+ r = append(r, v)
+ }
+ return r
+}
+
+// _Equal reports whether two sets contain the same elements.
+func _Equal[Elem comparable](s1, s2 _Set[Elem]) bool {
+ if len(s1.m) != len(s2.m) {
+ return false
+ }
+ for v1 := range s1.m {
+ if !s2.Contains(v1) {
+ return false
+ }
+ }
+ return true
+}
+
+// Copy returns a copy of s.
+func (s _Set[Elem]) Copy() _Set[Elem] {
+ r := _Set[Elem]{m: make(map[Elem]struct{}, len(s.m))}
+ for v := range s.m {
+ r.m[v] = struct{}{}
+ }
+ return r
+}
+
+// AddSet adds all the elements of s2 to s.
+func (s _Set[Elem]) AddSet(s2 _Set[Elem]) {
+ for v := range s2.m {
+ s.m[v] = struct{}{}
+ }
+}
+
+// SubSet removes all elements in s2 from s.
+// Values in s2 that are not in s are ignored.
+func (s _Set[Elem]) SubSet(s2 _Set[Elem]) {
+ for v := range s2.m {
+ delete(s.m, v)
+ }
+}
+
+// Intersect removes all elements from s that are not present in s2.
+// Values in s2 that are not in s are ignored.
+func (s _Set[Elem]) Intersect(s2 _Set[Elem]) {
+ for v := range s.m {
+ if !s2.Contains(v) {
+ delete(s.m, v)
+ }
+ }
+}
+
+// Iterate calls f on every element in the set.
+func (s _Set[Elem]) Iterate(f func(Elem)) {
+ for v := range s.m {
+ f(v)
+ }
+}
+
+// Filter deletes any elements from s for which f returns false.
+func (s _Set[Elem]) Filter(f func(Elem) bool) {
+ for v := range s.m {
+ if !f(v) {
+ delete(s.m, v)
+ }
+ }
+}
+
+func TestSet() {
+ s1 := _Make[int]()
+ if got := s1.Len(); got != 0 {
+ panic(fmt.Sprintf("Len of empty set = %d, want 0", got))
+ }
+ s1.Add(1)
+ s1.Add(1)
+ s1.Add(1)
+ if got := s1.Len(); got != 1 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got))
+ }
+ s1.Add(2)
+ s1.Add(3)
+ s1.Add(4)
+ if got := s1.Len(); got != 4 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 4", s1, got))
+ }
+ if !s1.Contains(1) {
+ panic(fmt.Sprintf("(%v).Contains(1) == false, want true", s1))
+ }
+ if s1.Contains(5) {
+ panic(fmt.Sprintf("(%v).Contains(5) == true, want false", s1))
+ }
+ vals := s1.Values()
+ sort.Ints(vals)
+ w1 := []int{1, 2, 3, 4}
+ if !_SliceEqual(vals, w1) {
+ panic(fmt.Sprintf("(%v).Values() == %v, want %v", s1, vals, w1))
+ }
+}
+
+func TestEqual() {
+ s1 := _Make[string]()
+ s2 := _Make[string]()
+ if !_Equal(s1, s2) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2))
+ }
+ s1.Add("hello")
+ s1.Add("world")
+ if got := s1.Len(); got != 2 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 2", s1, got))
+ }
+ if _Equal(s1, s2) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", s1, s2))
+ }
+}
+
+func TestCopy() {
+ s1 := _Make[float64]()
+ s1.Add(0)
+ s2 := s1.Copy()
+ if !_Equal(s1, s2) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2))
+ }
+ s1.Add(1)
+ if _Equal(s1, s2) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", s1, s2))
+ }
+}
+
+func TestAddSet() {
+ s1 := _Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s2 := _Make[int]()
+ s2.Add(2)
+ s2.Add(3)
+ s1.AddSet(s2)
+ if got := s1.Len(); got != 3 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 3", s1, got))
+ }
+ s2.Add(1)
+ if !_Equal(s1, s2) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2))
+ }
+}
+
+func TestSubSet() {
+ s1 := _Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s2 := _Make[int]()
+ s2.Add(2)
+ s2.Add(3)
+ s1.SubSet(s2)
+ if got := s1.Len(); got != 1 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got))
+ }
+ if vals, want := s1.Values(), []int{1}; !_SliceEqual(vals, want) {
+ panic(fmt.Sprintf("after SubSet got %v, want %v", vals, want))
+ }
+}
+
+func TestIntersect() {
+ s1 := _Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s2 := _Make[int]()
+ s2.Add(2)
+ s2.Add(3)
+ s1.Intersect(s2)
+ if got := s1.Len(); got != 1 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got))
+ }
+ if vals, want := s1.Values(), []int{2}; !_SliceEqual(vals, want) {
+ panic(fmt.Sprintf("after Intersect got %v, want %v", vals, want))
+ }
+}
+
+func TestIterate() {
+ s1 := _Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s1.Add(3)
+ s1.Add(4)
+ tot := 0
+ s1.Iterate(func(i int) { tot += i })
+ if tot != 10 {
+ panic(fmt.Sprintf("total of %v == %d, want 10", s1, tot))
+ }
+}
+
+func TestFilter() {
+ s1 := _Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s1.Add(3)
+ s1.Filter(func(v int) bool { return v%2 == 0 })
+ if vals, want := s1.Values(), []int{2}; !_SliceEqual(vals, want) {
+ panic(fmt.Sprintf("after Filter got %v, want %v", vals, want))
+ }
+
+}
+
+func main() {
+ TestSet()
+ TestEqual()
+ TestCopy()
+ TestAddSet()
+ TestSubSet()
+ TestIntersect()
+ TestIterate()
+ TestFilter()
+}
diff --git a/test/typeparam/setsimp.dir/a.go b/test/typeparam/setsimp.dir/a.go
new file mode 100644
index 0000000..92449ce
--- /dev/null
+++ b/test/typeparam/setsimp.dir/a.go
@@ -0,0 +1,128 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+// SliceEqual reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func SliceEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// A Set is a set of elements of some type.
+type Set[Elem comparable] struct {
+ m map[Elem]struct{}
+}
+
+// Make makes a new set.
+func Make[Elem comparable]() Set[Elem] {
+ return Set[Elem]{m: make(map[Elem]struct{})}
+}
+
+// Add adds an element to a set.
+func (s Set[Elem]) Add(v Elem) {
+ s.m[v] = struct{}{}
+}
+
+// Delete removes an element from a set. If the element is not present
+// in the set, this does nothing.
+func (s Set[Elem]) Delete(v Elem) {
+ delete(s.m, v)
+}
+
+// Contains reports whether v is in the set.
+func (s Set[Elem]) Contains(v Elem) bool {
+ _, ok := s.m[v]
+ return ok
+}
+
+// Len returns the number of elements in the set.
+func (s Set[Elem]) Len() int {
+ return len(s.m)
+}
+
+// Values returns the values in the set.
+// The values will be in an indeterminate order.
+func (s Set[Elem]) Values() []Elem {
+ r := make([]Elem, 0, len(s.m))
+ for v := range s.m {
+ r = append(r, v)
+ }
+ return r
+}
+
+// Equal reports whether two sets contain the same elements.
+func Equal[Elem comparable](s1, s2 Set[Elem]) bool {
+ if len(s1.m) != len(s2.m) {
+ return false
+ }
+ for v1 := range s1.m {
+ if !s2.Contains(v1) {
+ return false
+ }
+ }
+ return true
+}
+
+// Copy returns a copy of s.
+func (s Set[Elem]) Copy() Set[Elem] {
+ r := Set[Elem]{m: make(map[Elem]struct{}, len(s.m))}
+ for v := range s.m {
+ r.m[v] = struct{}{}
+ }
+ return r
+}
+
+// AddSet adds all the elements of s2 to s.
+func (s Set[Elem]) AddSet(s2 Set[Elem]) {
+ for v := range s2.m {
+ s.m[v] = struct{}{}
+ }
+}
+
+// SubSet removes all elements in s2 from s.
+// Values in s2 that are not in s are ignored.
+func (s Set[Elem]) SubSet(s2 Set[Elem]) {
+ for v := range s2.m {
+ delete(s.m, v)
+ }
+}
+
+// Intersect removes all elements from s that are not present in s2.
+// Values in s2 that are not in s are ignored.
+func (s Set[Elem]) Intersect(s2 Set[Elem]) {
+ for v := range s.m {
+ if !s2.Contains(v) {
+ delete(s.m, v)
+ }
+ }
+}
+
+// Iterate calls f on every element in the set.
+func (s Set[Elem]) Iterate(f func(Elem)) {
+ for v := range s.m {
+ f(v)
+ }
+}
+
+// Filter deletes any elements from s for which f returns false.
+func (s Set[Elem]) Filter(f func(Elem) bool) {
+ for v := range s.m {
+ if !f(v) {
+ delete(s.m, v)
+ }
+ }
+}
diff --git a/test/typeparam/setsimp.dir/main.go b/test/typeparam/setsimp.dir/main.go
new file mode 100644
index 0000000..e1ec86a
--- /dev/null
+++ b/test/typeparam/setsimp.dir/main.go
@@ -0,0 +1,156 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+ "sort"
+)
+
+func TestSet() {
+ s1 := a.Make[int]()
+ if got := s1.Len(); got != 0 {
+ panic(fmt.Sprintf("Len of empty set = %d, want 0", got))
+ }
+ s1.Add(1)
+ s1.Add(1)
+ s1.Add(1)
+ if got := s1.Len(); got != 1 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got))
+ }
+ s1.Add(2)
+ s1.Add(3)
+ s1.Add(4)
+ if got := s1.Len(); got != 4 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 4", s1, got))
+ }
+ if !s1.Contains(1) {
+ panic(fmt.Sprintf("(%v).Contains(1) == false, want true", s1))
+ }
+ if s1.Contains(5) {
+ panic(fmt.Sprintf("(%v).Contains(5) == true, want false", s1))
+ }
+ vals := s1.Values()
+ sort.Ints(vals)
+ w1 := []int{1, 2, 3, 4}
+ if !a.SliceEqual(vals, w1) {
+ panic(fmt.Sprintf("(%v).Values() == %v, want %v", s1, vals, w1))
+ }
+}
+
+func TestEqual() {
+ s1 := a.Make[string]()
+ s2 := a.Make[string]()
+ if !a.Equal(s1, s2) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2))
+ }
+ s1.Add("hello")
+ s1.Add("world")
+ if got := s1.Len(); got != 2 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 2", s1, got))
+ }
+ if a.Equal(s1, s2) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2))
+ }
+}
+
+func TestCopy() {
+ s1 := a.Make[float64]()
+ s1.Add(0)
+ s2 := s1.Copy()
+ if !a.Equal(s1, s2) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2))
+ }
+ s1.Add(1)
+ if a.Equal(s1, s2) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2))
+ }
+}
+
+func TestAddSet() {
+ s1 := a.Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s2 := a.Make[int]()
+ s2.Add(2)
+ s2.Add(3)
+ s1.AddSet(s2)
+ if got := s1.Len(); got != 3 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 3", s1, got))
+ }
+ s2.Add(1)
+ if !a.Equal(s1, s2) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2))
+ }
+}
+
+func TestSubSet() {
+ s1 := a.Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s2 := a.Make[int]()
+ s2.Add(2)
+ s2.Add(3)
+ s1.SubSet(s2)
+ if got := s1.Len(); got != 1 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got))
+ }
+ if vals, want := s1.Values(), []int{1}; !a.SliceEqual(vals, want) {
+ panic(fmt.Sprintf("after SubSet got %v, want %v", vals, want))
+ }
+}
+
+func TestIntersect() {
+ s1 := a.Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s2 := a.Make[int]()
+ s2.Add(2)
+ s2.Add(3)
+ s1.Intersect(s2)
+ if got := s1.Len(); got != 1 {
+ panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got))
+ }
+ if vals, want := s1.Values(), []int{2}; !a.SliceEqual(vals, want) {
+ panic(fmt.Sprintf("after Intersect got %v, want %v", vals, want))
+ }
+}
+
+func TestIterate() {
+ s1 := a.Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s1.Add(3)
+ s1.Add(4)
+ tot := 0
+ s1.Iterate(func(i int) { tot += i })
+ if tot != 10 {
+ panic(fmt.Sprintf("total of %v == %d, want 10", s1, tot))
+ }
+}
+
+func TestFilter() {
+ s1 := a.Make[int]()
+ s1.Add(1)
+ s1.Add(2)
+ s1.Add(3)
+ s1.Filter(func(v int) bool { return v%2 == 0 })
+ if vals, want := s1.Values(), []int{2}; !a.SliceEqual(vals, want) {
+ panic(fmt.Sprintf("after Filter got %v, want %v", vals, want))
+ }
+
+}
+
+func main() {
+ TestSet()
+ TestEqual()
+ TestCopy()
+ TestAddSet()
+ TestSubSet()
+ TestIntersect()
+ TestIterate()
+ TestFilter()
+}
diff --git a/test/typeparam/setsimp.go b/test/typeparam/setsimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/setsimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/settable.go b/test/typeparam/settable.go
new file mode 100644
index 0000000..56cf367
--- /dev/null
+++ b/test/typeparam/settable.go
@@ -0,0 +1,123 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Various implementations of fromStrings().
+
+type Setter[B any] interface {
+ Set(string)
+ *B
+}
+
+// Takes two type parameters where PT = *T
+func fromStrings1[T any, PT Setter[T]](s []string) []T {
+ result := make([]T, len(s))
+ for i, v := range s {
+ // The type of &result[i] is *T which is in the type list
+ // of Setter, so we can convert it to PT.
+ p := PT(&result[i])
+ // PT has a Set method.
+ p.Set(v)
+ }
+ return result
+}
+
+func fromStrings1a[T any, PT Setter[T]](s []string) []PT {
+ result := make([]PT, len(s))
+ for i, v := range s {
+ // The type new(T) is *T which is in the type list
+ // of Setter, so we can convert it to PT.
+ result[i] = PT(new(T))
+ p := result[i]
+ // PT has a Set method.
+ p.Set(v)
+ }
+ return result
+}
+
+// Takes one type parameter and a set function
+func fromStrings2[T any](s []string, set func(*T, string)) []T {
+ results := make([]T, len(s))
+ for i, v := range s {
+ set(&results[i], v)
+ }
+ return results
+}
+
+type Setter2 interface {
+ Set(string)
+}
+
+// Takes only one type parameter, but causes a panic (see below)
+func fromStrings3[T Setter2](s []string) []T {
+ results := make([]T, len(s))
+ for i, v := range s {
+ // Panics if T is a pointer type because receiver is T(nil).
+ results[i].Set(v)
+ }
+ return results
+}
+
+// Two concrete types with the appropriate Set method.
+
+type SettableInt int
+
+func (p *SettableInt) Set(s string) {
+ i, err := strconv.Atoi(s)
+ if err != nil {
+ panic(err)
+ }
+ *p = SettableInt(i)
+}
+
+type SettableString struct {
+ s string
+}
+
+func (x *SettableString) Set(s string) {
+ x.s = s
+}
+
+func main() {
+ s := fromStrings1[SettableInt, *SettableInt]([]string{"1"})
+ if len(s) != 1 || s[0] != 1 {
+ panic(fmt.Sprintf("got %v, want %v", s, []int{1}))
+ }
+
+ s2 := fromStrings1a[SettableInt, *SettableInt]([]string{"1"})
+ if len(s2) != 1 || *s2[0] != 1 {
+ x := 1
+ panic(fmt.Sprintf("got %v, want %v", s2, []*int{&x}))
+ }
+
+ // Test out constraint type inference, which should determine that the second
+ // type param is *SettableString.
+ ps := fromStrings1[SettableString]([]string{"x", "y"})
+ if len(ps) != 2 || ps[0] != (SettableString{"x"}) || ps[1] != (SettableString{"y"}) {
+ panic(s)
+ }
+
+ s = fromStrings2([]string{"1"}, func(p *SettableInt, s string) { p.Set(s) })
+ if len(s) != 1 || s[0] != 1 {
+ panic(fmt.Sprintf("got %v, want %v", s, []int{1}))
+ }
+
+ defer func() {
+ if recover() == nil {
+ panic("did not panic as expected")
+ }
+ }()
+ // This should type check but should panic at run time,
+ // because it will make a slice of *SettableInt and then call
+ // Set on a nil value.
+ fromStrings3[*SettableInt]([]string{"1"})
+}
diff --git a/test/typeparam/shape1.go b/test/typeparam/shape1.go
new file mode 100644
index 0000000..2400f1c
--- /dev/null
+++ b/test/typeparam/shape1.go
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface {
+ foo() int
+}
+
+// There should be one instantiation of f for both squarer and doubler.
+// Similarly, there should be one instantiation of f for both *incrementer and *decrementer.
+func f[T I](x T) int {
+ return x.foo()
+}
+
+type squarer int
+
+func (x squarer) foo() int {
+ return int(x*x)
+}
+
+type doubler int
+
+func (x doubler) foo() int {
+ return int(2*x)
+}
+
+type incrementer int16
+
+func (x *incrementer) foo() int {
+ return int(*x+1)
+}
+
+type decrementer int32
+
+func (x *decrementer) foo() int{
+ return int(*x-1)
+}
+
+func main() {
+ println(f(squarer(5)))
+ println(f(doubler(5)))
+ var i incrementer = 5
+ println(f(&i))
+ var d decrementer = 5
+ println(f(&d))
+}
diff --git a/test/typeparam/shape1.out b/test/typeparam/shape1.out
new file mode 100644
index 0000000..da9a12d
--- /dev/null
+++ b/test/typeparam/shape1.out
@@ -0,0 +1,4 @@
+25
+10
+6
+4
diff --git a/test/typeparam/sliceimp.dir/a.go b/test/typeparam/sliceimp.dir/a.go
new file mode 100644
index 0000000..dbcfae8
--- /dev/null
+++ b/test/typeparam/sliceimp.dir/a.go
@@ -0,0 +1,141 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+// Max returns the maximum of two values of some ordered type.
+func Max[T Ordered](a, b T) T {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+// Min returns the minimum of two values of some ordered type.
+func Min[T Ordered](a, b T) T {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+// Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func Equal[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// EqualFn reports whether two slices are equal using a comparison
+// function on each element.
+func EqualFn[Elem any](s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if !eq(v1, v2) {
+ return false
+ }
+ }
+ return true
+}
+
+// Map turns a []Elem1 to a []Elem2 using a mapping function.
+func Map[Elem1, Elem2 any](s []Elem1, f func(Elem1) Elem2) []Elem2 {
+ r := make([]Elem2, len(s))
+ for i, v := range s {
+ r[i] = f(v)
+ }
+ return r
+}
+
+// Reduce reduces a []Elem1 to a single value of type Elem2 using
+// a reduction function.
+func Reduce[Elem1, Elem2 any](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 {
+ r := initializer
+ for _, v := range s {
+ r = f(r, v)
+ }
+ return r
+}
+
+// Filter filters values from a slice using a filter function.
+func Filter[Elem any](s []Elem, f func(Elem) bool) []Elem {
+ var r []Elem
+ for _, v := range s {
+ if f(v) {
+ r = append(r, v)
+ }
+ }
+ return r
+}
+
+// Max returns the maximum element in a slice of some ordered type.
+// If the slice is empty it returns the zero value of the element type.
+func SliceMax[Elem Ordered](s []Elem) Elem {
+ if len(s) == 0 {
+ var zero Elem
+ return zero
+ }
+ return Reduce(s[1:], s[0], Max[Elem])
+}
+
+// Min returns the minimum element in a slice of some ordered type.
+// If the slice is empty it returns the zero value of the element type.
+func SliceMin[Elem Ordered](s []Elem) Elem {
+ if len(s) == 0 {
+ var zero Elem
+ return zero
+ }
+ return Reduce(s[1:], s[0], Min[Elem])
+}
+
+// Append adds values to the end of a slice, returning a new slice.
+// This is like the predeclared append function; it's an example
+// of how to write it using generics. We used to write code like
+// this before append was added to the language, but we had to write
+// a separate copy for each type.
+func Append[T any](s []T, t ...T) []T {
+ lens := len(s)
+ tot := lens + len(t)
+ if tot <= cap(s) {
+ s = s[:tot]
+ } else {
+ news := make([]T, tot, tot+tot/2)
+ Copy(news, s)
+ s = news
+ }
+ Copy(s[lens:tot], t)
+ return s
+}
+
+// Copy copies values from t to s, stopping when either slice is full,
+// returning the number of values copied. This is like the predeclared
+// copy function; it's an example of how to write it using generics.
+func Copy[T any](s, t []T) int {
+ i := 0
+ for ; i < len(s) && i < len(t); i++ {
+ s[i] = t[i]
+ }
+ return i
+}
diff --git a/test/typeparam/sliceimp.dir/main.go b/test/typeparam/sliceimp.dir/main.go
new file mode 100644
index 0000000..ec13188
--- /dev/null
+++ b/test/typeparam/sliceimp.dir/main.go
@@ -0,0 +1,179 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+ "math"
+ "strings"
+)
+
+type Integer interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+func TestEqual() {
+ s1 := []int{1, 2, 3}
+ if !a.Equal(s1, s1) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s1))
+ }
+ s2 := []int{1, 2, 3}
+ if !a.Equal(s1, s2) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2))
+ }
+ s2 = append(s2, 4)
+ if a.Equal(s1, s2) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2))
+ }
+
+ s3 := []float64{1, 2, math.NaN()}
+ if !a.Equal(s3, s3) {
+ panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s3, s3))
+ }
+
+ if a.Equal(s1, nil) {
+ panic(fmt.Sprintf("a.Equal(%v, nil) = true, want false", s1))
+ }
+ if a.Equal(nil, s1) {
+ panic(fmt.Sprintf("a.Equal(nil, %v) = true, want false", s1))
+ }
+ if !a.Equal(s1[:0], nil) {
+ panic(fmt.Sprintf("a.Equal(%v, nil = false, want true", s1[:0]))
+ }
+}
+
+func offByOne[Elem Integer](a, b Elem) bool {
+ return a == b+1 || a == b-1
+}
+
+func TestEqualFn() {
+ s1 := []int{1, 2, 3}
+ s2 := []int{2, 3, 4}
+ if a.EqualFn(s1, s1, offByOne[int]) {
+ panic(fmt.Sprintf("a.EqualFn(%v, %v, offByOne) = true, want false", s1, s1))
+ }
+ if !a.EqualFn(s1, s2, offByOne[int]) {
+ panic(fmt.Sprintf("a.EqualFn(%v, %v, offByOne) = false, want true", s1, s2))
+ }
+
+ if !a.EqualFn(s1[:0], nil, offByOne[int]) {
+ panic(fmt.Sprintf("a.EqualFn(%v, nil, offByOne) = false, want true", s1[:0]))
+ }
+
+ s3 := []string{"a", "b", "c"}
+ s4 := []string{"A", "B", "C"}
+ if !a.EqualFn(s3, s4, strings.EqualFold) {
+ panic(fmt.Sprintf("a.EqualFn(%v, %v, strings.EqualFold) = false, want true", s3, s4))
+ }
+}
+
+func TestMap() {
+ s1 := []int{1, 2, 3}
+ s2 := a.Map(s1, func(i int) float64 { return float64(i) * 2.5 })
+ if want := []float64{2.5, 5, 7.5}; !a.Equal(s2, want) {
+ panic(fmt.Sprintf("a.Map(%v, ...) = %v, want %v", s1, s2, want))
+ }
+
+ s3 := []string{"Hello", "World"}
+ s4 := a.Map(s3, strings.ToLower)
+ if want := []string{"hello", "world"}; !a.Equal(s4, want) {
+ panic(fmt.Sprintf("a.Map(%v, strings.ToLower) = %v, want %v", s3, s4, want))
+ }
+
+ s5 := a.Map(nil, func(i int) int { return i })
+ if len(s5) != 0 {
+ panic(fmt.Sprintf("a.Map(nil, identity) = %v, want empty slice", s5))
+ }
+}
+
+func TestReduce() {
+ s1 := []int{1, 2, 3}
+ r := a.Reduce(s1, 0, func(f float64, i int) float64 { return float64(i)*2.5 + f })
+ if want := 15.0; r != want {
+ panic(fmt.Sprintf("a.Reduce(%v, 0, ...) = %v, want %v", s1, r, want))
+ }
+
+ if got := a.Reduce(nil, 0, func(i, j int) int { return i + j }); got != 0 {
+ panic(fmt.Sprintf("a.Reduce(nil, 0, add) = %v, want 0", got))
+ }
+}
+
+func TestFilter() {
+ s1 := []int{1, 2, 3}
+ s2 := a.Filter(s1, func(i int) bool { return i%2 == 0 })
+ if want := []int{2}; !a.Equal(s2, want) {
+ panic(fmt.Sprintf("a.Filter(%v, even) = %v, want %v", s1, s2, want))
+ }
+
+ if s3 := a.Filter(s1[:0], func(i int) bool { return true }); len(s3) > 0 {
+ panic(fmt.Sprintf("a.Filter(%v, identity) = %v, want empty slice", s1[:0], s3))
+ }
+}
+
+func TestMax() {
+ s1 := []int{1, 2, 3, -5}
+ if got, want := a.SliceMax(s1), 3; got != want {
+ panic(fmt.Sprintf("a.Max(%v) = %d, want %d", s1, got, want))
+ }
+
+ s2 := []string{"aaa", "a", "aa", "aaaa"}
+ if got, want := a.SliceMax(s2), "aaaa"; got != want {
+ panic(fmt.Sprintf("a.Max(%v) = %q, want %q", s2, got, want))
+ }
+
+ if got, want := a.SliceMax(s2[:0]), ""; got != want {
+ panic(fmt.Sprintf("a.Max(%v) = %q, want %q", s2[:0], got, want))
+ }
+}
+
+func TestMin() {
+ s1 := []int{1, 2, 3, -5}
+ if got, want := a.SliceMin(s1), -5; got != want {
+ panic(fmt.Sprintf("a.Min(%v) = %d, want %d", s1, got, want))
+ }
+
+ s2 := []string{"aaa", "a", "aa", "aaaa"}
+ if got, want := a.SliceMin(s2), "a"; got != want {
+ panic(fmt.Sprintf("a.Min(%v) = %q, want %q", s2, got, want))
+ }
+
+ if got, want := a.SliceMin(s2[:0]), ""; got != want {
+ panic(fmt.Sprintf("a.Min(%v) = %q, want %q", s2[:0], got, want))
+ }
+}
+
+func TestAppend() {
+ s := []int{1, 2, 3}
+ s = a.Append(s, 4, 5, 6)
+ want := []int{1, 2, 3, 4, 5, 6}
+ if !a.Equal(s, want) {
+ panic(fmt.Sprintf("after a.Append got %v, want %v", s, want))
+ }
+}
+
+func TestCopy() {
+ s1 := []int{1, 2, 3}
+ s2 := []int{4, 5}
+ if got := a.Copy(s1, s2); got != 2 {
+ panic(fmt.Sprintf("a.Copy returned %d, want 2", got))
+ }
+ want := []int{4, 5, 3}
+ if !a.Equal(s1, want) {
+ panic(fmt.Sprintf("after a.Copy got %v, want %v", s1, want))
+ }
+}
+func main() {
+ TestEqual()
+ TestEqualFn()
+ TestMap()
+ TestReduce()
+ TestFilter()
+ TestMax()
+ TestMin()
+ TestAppend()
+ TestCopy()
+}
diff --git a/test/typeparam/sliceimp.go b/test/typeparam/sliceimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/sliceimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/slices.go b/test/typeparam/slices.go
new file mode 100644
index 0000000..b24817d
--- /dev/null
+++ b/test/typeparam/slices.go
@@ -0,0 +1,318 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package slices provides functions for basic operations on
+// slices of any element type.
+package main
+
+import (
+ "fmt"
+ "math"
+ "strings"
+)
+
+type Ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+type Integer interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+// Max returns the maximum of two values of some ordered type.
+func _Max[T Ordered](a, b T) T {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+// Min returns the minimum of two values of some ordered type.
+func _Min[T Ordered](a, b T) T {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+// _Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func _Equal[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// _EqualFn reports whether two slices are equal using a comparison
+// function on each element.
+func _EqualFn[Elem any](s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if !eq(v1, v2) {
+ return false
+ }
+ }
+ return true
+}
+
+// _Map turns a []Elem1 to a []Elem2 using a mapping function.
+func _Map[Elem1, Elem2 any](s []Elem1, f func(Elem1) Elem2) []Elem2 {
+ r := make([]Elem2, len(s))
+ for i, v := range s {
+ r[i] = f(v)
+ }
+ return r
+}
+
+// _Reduce reduces a []Elem1 to a single value of type Elem2 using
+// a reduction function.
+func _Reduce[Elem1, Elem2 any](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 {
+ r := initializer
+ for _, v := range s {
+ r = f(r, v)
+ }
+ return r
+}
+
+// _Filter filters values from a slice using a filter function.
+func _Filter[Elem any](s []Elem, f func(Elem) bool) []Elem {
+ var r []Elem
+ for _, v := range s {
+ if f(v) {
+ r = append(r, v)
+ }
+ }
+ return r
+}
+
+// _Max returns the maximum element in a slice of some ordered type.
+// If the slice is empty it returns the zero value of the element type.
+func _SliceMax[Elem Ordered](s []Elem) Elem {
+ if len(s) == 0 {
+ var zero Elem
+ return zero
+ }
+ return _Reduce(s[1:], s[0], _Max[Elem])
+}
+
+// _Min returns the minimum element in a slice of some ordered type.
+// If the slice is empty it returns the zero value of the element type.
+func _SliceMin[Elem Ordered](s []Elem) Elem {
+ if len(s) == 0 {
+ var zero Elem
+ return zero
+ }
+ return _Reduce(s[1:], s[0], _Min[Elem])
+}
+
+// _Append adds values to the end of a slice, returning a new slice.
+// This is like the predeclared append function; it's an example
+// of how to write it using generics. We used to write code like
+// this before append was added to the language, but we had to write
+// a separate copy for each type.
+func _Append[T any](s []T, t ...T) []T {
+ lens := len(s)
+ tot := lens + len(t)
+ if tot <= cap(s) {
+ s = s[:tot]
+ } else {
+ news := make([]T, tot, tot+tot/2)
+ _Copy(news, s)
+ s = news
+ }
+ _Copy(s[lens:tot], t)
+ return s
+}
+
+// _Copy copies values from t to s, stopping when either slice is full,
+// returning the number of values copied. This is like the predeclared
+// copy function; it's an example of how to write it using generics.
+func _Copy[T any](s, t []T) int {
+ i := 0
+ for ; i < len(s) && i < len(t); i++ {
+ s[i] = t[i]
+ }
+ return i
+}
+
+func TestEqual() {
+ s1 := []int{1, 2, 3}
+ if !_Equal(s1, s1) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s1))
+ }
+ s2 := []int{1, 2, 3}
+ if !_Equal(s1, s2) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2))
+ }
+ s2 = append(s2, 4)
+ if _Equal(s1, s2) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", s1, s2))
+ }
+
+ s3 := []float64{1, 2, math.NaN()}
+ if !_Equal(s3, s3) {
+ panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s3, s3))
+ }
+
+ if _Equal(s1, nil) {
+ panic(fmt.Sprintf("_Equal(%v, nil) = true, want false", s1))
+ }
+ if _Equal(nil, s1) {
+ panic(fmt.Sprintf("_Equal(nil, %v) = true, want false", s1))
+ }
+ if !_Equal(s1[:0], nil) {
+ panic(fmt.Sprintf("_Equal(%v, nil = false, want true", s1[:0]))
+ }
+}
+
+func offByOne[Elem Integer](a, b Elem) bool {
+ return a == b+1 || a == b-1
+}
+
+func TestEqualFn() {
+ s1 := []int{1, 2, 3}
+ s2 := []int{2, 3, 4}
+ if _EqualFn(s1, s1, offByOne[int]) {
+ panic(fmt.Sprintf("_EqualFn(%v, %v, offByOne) = true, want false", s1, s1))
+ }
+ if !_EqualFn(s1, s2, offByOne[int]) {
+ panic(fmt.Sprintf("_EqualFn(%v, %v, offByOne) = false, want true", s1, s2))
+ }
+
+ if !_EqualFn(s1[:0], nil, offByOne[int]) {
+ panic(fmt.Sprintf("_EqualFn(%v, nil, offByOne) = false, want true", s1[:0]))
+ }
+
+ s3 := []string{"a", "b", "c"}
+ s4 := []string{"A", "B", "C"}
+ if !_EqualFn(s3, s4, strings.EqualFold) {
+ panic(fmt.Sprintf("_EqualFn(%v, %v, strings.EqualFold) = false, want true", s3, s4))
+ }
+}
+
+func TestMap() {
+ s1 := []int{1, 2, 3}
+ s2 := _Map(s1, func(i int) float64 { return float64(i) * 2.5 })
+ if want := []float64{2.5, 5, 7.5}; !_Equal(s2, want) {
+ panic(fmt.Sprintf("_Map(%v, ...) = %v, want %v", s1, s2, want))
+ }
+
+ s3 := []string{"Hello", "World"}
+ s4 := _Map(s3, strings.ToLower)
+ if want := []string{"hello", "world"}; !_Equal(s4, want) {
+ panic(fmt.Sprintf("_Map(%v, strings.ToLower) = %v, want %v", s3, s4, want))
+ }
+
+ s5 := _Map(nil, func(i int) int { return i })
+ if len(s5) != 0 {
+ panic(fmt.Sprintf("_Map(nil, identity) = %v, want empty slice", s5))
+ }
+}
+
+func TestReduce() {
+ s1 := []int{1, 2, 3}
+ r := _Reduce(s1, 0, func(f float64, i int) float64 { return float64(i)*2.5 + f })
+ if want := 15.0; r != want {
+ panic(fmt.Sprintf("_Reduce(%v, 0, ...) = %v, want %v", s1, r, want))
+ }
+
+ if got := _Reduce(nil, 0, func(i, j int) int { return i + j }); got != 0 {
+ panic(fmt.Sprintf("_Reduce(nil, 0, add) = %v, want 0", got))
+ }
+}
+
+func TestFilter() {
+ s1 := []int{1, 2, 3}
+ s2 := _Filter(s1, func(i int) bool { return i%2 == 0 })
+ if want := []int{2}; !_Equal(s2, want) {
+ panic(fmt.Sprintf("_Filter(%v, even) = %v, want %v", s1, s2, want))
+ }
+
+ if s3 := _Filter(s1[:0], func(i int) bool { return true }); len(s3) > 0 {
+ panic(fmt.Sprintf("_Filter(%v, identity) = %v, want empty slice", s1[:0], s3))
+ }
+}
+
+func TestMax() {
+ s1 := []int{1, 2, 3, -5}
+ if got, want := _SliceMax(s1), 3; got != want {
+ panic(fmt.Sprintf("_Max(%v) = %d, want %d", s1, got, want))
+ }
+
+ s2 := []string{"aaa", "a", "aa", "aaaa"}
+ if got, want := _SliceMax(s2), "aaaa"; got != want {
+ panic(fmt.Sprintf("_Max(%v) = %q, want %q", s2, got, want))
+ }
+
+ if got, want := _SliceMax(s2[:0]), ""; got != want {
+ panic(fmt.Sprintf("_Max(%v) = %q, want %q", s2[:0], got, want))
+ }
+}
+
+func TestMin() {
+ s1 := []int{1, 2, 3, -5}
+ if got, want := _SliceMin(s1), -5; got != want {
+ panic(fmt.Sprintf("_Min(%v) = %d, want %d", s1, got, want))
+ }
+
+ s2 := []string{"aaa", "a", "aa", "aaaa"}
+ if got, want := _SliceMin(s2), "a"; got != want {
+ panic(fmt.Sprintf("_Min(%v) = %q, want %q", s2, got, want))
+ }
+
+ if got, want := _SliceMin(s2[:0]), ""; got != want {
+ panic(fmt.Sprintf("_Min(%v) = %q, want %q", s2[:0], got, want))
+ }
+}
+
+func TestAppend() {
+ s := []int{1, 2, 3}
+ s = _Append(s, 4, 5, 6)
+ want := []int{1, 2, 3, 4, 5, 6}
+ if !_Equal(s, want) {
+ panic(fmt.Sprintf("after _Append got %v, want %v", s, want))
+ }
+}
+
+func TestCopy() {
+ s1 := []int{1, 2, 3}
+ s2 := []int{4, 5}
+ if got := _Copy(s1, s2); got != 2 {
+ panic(fmt.Sprintf("_Copy returned %d, want 2", got))
+ }
+ want := []int{4, 5, 3}
+ if !_Equal(s1, want) {
+ panic(fmt.Sprintf("after _Copy got %v, want %v", s1, want))
+ }
+}
+func main() {
+ TestEqual()
+ TestEqualFn()
+ TestMap()
+ TestReduce()
+ TestFilter()
+ TestMax()
+ TestMin()
+ TestAppend()
+ TestCopy()
+}
diff --git a/test/typeparam/smallest.go b/test/typeparam/smallest.go
new file mode 100644
index 0000000..0ebd10e
--- /dev/null
+++ b/test/typeparam/smallest.go
@@ -0,0 +1,42 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type Ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+func Smallest[T Ordered](s []T) T {
+ r := s[0] // panics if slice is empty
+ for _, v := range s[1:] {
+ if v < r {
+ r = v
+ }
+ }
+ return r
+}
+
+func main() {
+ vec1 := []float64{5.3, 1.2, 32.8}
+ vec2 := []string{"abc", "def", "aaa"}
+
+ want1 := 1.2
+ if got := Smallest(vec1); got != want1 {
+ panic(fmt.Sprintf("got %d, want %d", got, want1))
+ }
+ want2 := "aaa"
+ if got := Smallest(vec2); got != want2 {
+ panic(fmt.Sprintf("got %d, want %d", got, want2))
+ }
+}
diff --git a/test/typeparam/smoketest.go b/test/typeparam/smoketest.go
new file mode 100644
index 0000000..b720e04
--- /dev/null
+++ b/test/typeparam/smoketest.go
@@ -0,0 +1,56 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file checks simple code using type parameters.
+
+package smoketest
+
+// type parameters for functions
+func f1[P any]() {}
+func f2[P1, P2 any, P3 any]() {}
+func f3[P interface{}](x P, y T1[int]) {}
+
+// function instantiations
+var _ = f1[int]
+var _ = f2[int, string, struct{}]
+var _ = f3[bool]
+
+// type parameters for types
+type T1[P any] struct{}
+type T2[P1, P2 any, P3 any] struct{}
+type T3[P interface{}] interface{}
+
+// type instantiations
+type _ T1[int]
+type _ T2[int, string, struct{}]
+type _ T3[bool]
+
+// methods
+func (T1[P]) m1() {}
+func (T1[_]) m2() {}
+func (x T2[P1, P2, P3]) m() {}
+
+// type lists
+type _ interface {
+ m1()
+ m2()
+ int | float32 | string
+ m3()
+}
+
+// embedded instantiated types
+type _ struct {
+ f1, f2 int
+ T1[int]
+ T2[int, string, struct{}]
+ T3[bool]
+}
+
+type _ interface {
+ m1()
+ m2()
+ T3[bool]
+}
diff --git a/test/typeparam/stringable.go b/test/typeparam/stringable.go
new file mode 100644
index 0000000..791b670
--- /dev/null
+++ b/test/typeparam/stringable.go
@@ -0,0 +1,46 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+type Stringer interface {
+ String() string
+}
+
+// StringableList is a slice of some type, where the type
+// must have a String method.
+type StringableList[T Stringer] []T
+
+func (s StringableList[T]) String() string {
+ var sb strings.Builder
+ for i, v := range s {
+ if i > 0 {
+ sb.WriteString(", ")
+ }
+ sb.WriteString(v.String())
+ }
+ return sb.String()
+}
+
+type myint int
+
+func (a myint) String() string {
+ return strconv.Itoa(int(a))
+}
+
+func main() {
+ v := StringableList[myint]{myint(1), myint(2)}
+
+ if got, want := v.String(), "1, 2"; got != want {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+}
diff --git a/test/typeparam/stringer.go b/test/typeparam/stringer.go
new file mode 100644
index 0000000..0892cd8
--- /dev/null
+++ b/test/typeparam/stringer.go
@@ -0,0 +1,88 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test method calls on type parameters
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+)
+
+// Simple constraint
+type Stringer interface {
+ String() string
+}
+
+func stringify[T Stringer](s []T) (ret []string) {
+ for _, v := range s {
+ ret = append(ret, v.String())
+ }
+ return ret
+}
+
+type myint int
+
+func (i myint) String() string {
+ return strconv.Itoa(int(i))
+}
+
+// Constraint with an embedded interface, but still only requires String()
+type Stringer2 interface {
+ CanBeStringer2() int
+ SubStringer2
+}
+
+type SubStringer2 interface {
+ CanBeSubStringer2() int
+ String() string
+}
+
+func stringify2[T Stringer2](s []T) (ret []string) {
+ for _, v := range s {
+ ret = append(ret, v.String())
+ }
+ return ret
+}
+
+func (myint) CanBeStringer2() int {
+ return 0
+}
+
+func (myint) CanBeSubStringer2() int {
+ return 0
+}
+
+// Test use of method values that are not called
+func stringify3[T Stringer](s []T) (ret []string) {
+ for _, v := range s {
+ f := v.String
+ ret = append(ret, f())
+ }
+ return ret
+}
+
+func main() {
+ x := []myint{myint(1), myint(2), myint(3)}
+
+ got := stringify(x)
+ want := []string{"1", "2", "3"}
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ got = stringify2(x)
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ got = stringify3(x)
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+}
diff --git a/test/typeparam/stringerimp.dir/a.go b/test/typeparam/stringerimp.dir/a.go
new file mode 100644
index 0000000..3f70937
--- /dev/null
+++ b/test/typeparam/stringerimp.dir/a.go
@@ -0,0 +1,16 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Stringer interface {
+ String() string
+}
+
+func Stringify[T Stringer](s []T) (ret []string) {
+ for _, v := range s {
+ ret = append(ret, v.String())
+ }
+ return ret
+}
diff --git a/test/typeparam/stringerimp.dir/main.go b/test/typeparam/stringerimp.dir/main.go
new file mode 100644
index 0000000..9b41d3b
--- /dev/null
+++ b/test/typeparam/stringerimp.dir/main.go
@@ -0,0 +1,38 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+ "reflect"
+ "strconv"
+)
+
+type myint int
+
+func (i myint) String() string {
+ return strconv.Itoa(int(i))
+}
+
+func main() {
+ x := []myint{myint(1), myint(2), myint(3)}
+
+ got := a.Stringify(x)
+ want := []string{"1", "2", "3"}
+ if !reflect.DeepEqual(got, want) {
+ panic(fmt.Sprintf("got %s, want %s", got, want))
+ }
+
+ m1 := myint(1)
+ m2 := myint(2)
+ m3 := myint(3)
+ y := []*myint{&m1, &m2, &m3}
+ got2 := a.Stringify(y)
+ want2 := []string{"1", "2", "3"}
+ if !reflect.DeepEqual(got2, want2) {
+ panic(fmt.Sprintf("got %s, want %s", got2, want2))
+ }
+}
diff --git a/test/typeparam/stringerimp.go b/test/typeparam/stringerimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/stringerimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/struct.go b/test/typeparam/struct.go
new file mode 100644
index 0000000..2dad908
--- /dev/null
+++ b/test/typeparam/struct.go
@@ -0,0 +1,49 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type E[T any] struct {
+ v T
+}
+
+type S1 struct {
+ E[int]
+ v string
+}
+
+type Eint = E[int]
+type Ebool = E[bool]
+
+type S2 struct {
+ Eint
+ Ebool
+ v string
+}
+
+type S3 struct {
+ *E[int]
+}
+
+func main() {
+ s1 := S1{Eint{2}, "foo"}
+ if got, want := s1.E.v, 2; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ s2 := S2{Eint{3}, Ebool{true}, "foo"}
+ if got, want := s2.Eint.v, 3; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ var s3 S3
+ s3.E = &Eint{4}
+ if got, want := s3.E.v, 4; got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/structinit.dir/a.go b/test/typeparam/structinit.dir/a.go
new file mode 100644
index 0000000..c76d155
--- /dev/null
+++ b/test/typeparam/structinit.dir/a.go
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type S[T any] struct {
+}
+
+func (b *S[T]) build() *X[T] {
+ return &X[T]{f:0}
+}
+type X[T any] struct {
+ f int
+}
diff --git a/test/typeparam/structinit.dir/b.go b/test/typeparam/structinit.dir/b.go
new file mode 100644
index 0000000..40a929b
--- /dev/null
+++ b/test/typeparam/structinit.dir/b.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+func B() {
+ var x a.S[int]
+ _ = x
+}
diff --git a/test/typeparam/structinit.dir/main.go b/test/typeparam/structinit.dir/main.go
new file mode 100644
index 0000000..c564171
--- /dev/null
+++ b/test/typeparam/structinit.dir/main.go
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./b"
+
+func main() {
+ b.B()
+}
diff --git a/test/typeparam/structinit.go b/test/typeparam/structinit.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/structinit.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/subdict.go b/test/typeparam/subdict.go
new file mode 100644
index 0000000..463c510
--- /dev/null
+++ b/test/typeparam/subdict.go
@@ -0,0 +1,43 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test cases where a main dictionary is needed inside a generic function/method, because
+// we are calling a method on a fully-instantiated type or a fully-instantiated function.
+// (probably not common situations, of course)
+
+package main
+
+import (
+ "fmt"
+)
+
+type C comparable
+
+type value[T C] struct {
+ val T
+}
+
+func (v *value[T]) test(def T) bool {
+ return (v.val == def)
+}
+
+func (v *value[T]) get(def T) T {
+ var c value[int]
+ if c.test(32) {
+ return def
+ } else if v.test(def) {
+ return def
+ } else {
+ return v.val
+ }
+}
+
+func main() {
+ var s value[string]
+ if got, want := s.get("ab"), ""; got != want {
+ panic(fmt.Sprintf("get() == %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/sum.go b/test/typeparam/sum.go
new file mode 100644
index 0000000..25bac18
--- /dev/null
+++ b/test/typeparam/sum.go
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+func Sum[T interface{ int | float64 }](vec []T) T {
+ var sum T
+ for _, elt := range vec {
+ sum = sum + elt
+ }
+ return sum
+}
+
+func Abs(f float64) float64 {
+ if f < 0.0 {
+ return -f
+ }
+ return f
+}
+
+func main() {
+ vec1 := []int{3, 4}
+ vec2 := []float64{5.8, 9.6}
+ got := Sum[int](vec1)
+ want := vec1[0] + vec1[1]
+ if got != want {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+ got = Sum(vec1)
+ if want != got {
+ panic(fmt.Sprintf("got %d, want %d", got, want))
+ }
+
+ fwant := vec2[0] + vec2[1]
+ fgot := Sum[float64](vec2)
+ if Abs(fgot-fwant) > 1e-10 {
+ panic(fmt.Sprintf("got %f, want %f", fgot, fwant))
+ }
+ fgot = Sum(vec2)
+ if Abs(fgot-fwant) > 1e-10 {
+ panic(fmt.Sprintf("got %f, want %f", fgot, fwant))
+ }
+}
diff --git a/test/typeparam/tparam1.go b/test/typeparam/tparam1.go
new file mode 100644
index 0000000..a05f542
--- /dev/null
+++ b/test/typeparam/tparam1.go
@@ -0,0 +1,43 @@
+// errorcheck
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Basic type parameter list type-checking (not syntax) errors.
+
+package tparam1
+
+// The predeclared identifier "any" may be used in place of interface{}.
+var _ any
+
+func _(_ any)
+
+type _[_ any] struct{}
+
+const N = 10
+
+type (
+ _ []struct{} // slice
+ _ [N]struct{} // array
+ _[T any] struct{}
+ _[T, T any] struct{} // ERROR "T redeclared"
+ _[T1, T2 any, T3 any] struct{}
+)
+
+func _[T any]() {}
+func _[T, T any]() {} // ERROR "T redeclared"
+func _[T1, T2 any](x T1) T2 { panic(0) }
+
+// Type parameters are visible from opening [ to end of function.
+type C interface{}
+
+func _[T interface{}]() {}
+func _[T C]() {}
+func _[T struct{}]() {} // ok if #48424 is accepted
+func _[T interface{ m() T }]() {}
+func _[T1 interface{ m() T2 }, T2 interface{ m() T1 }]() {
+ var _ T1
+}
+
+// TODO(gri) expand this
diff --git a/test/typeparam/typelist.go b/test/typeparam/typelist.go
new file mode 100644
index 0000000..7c71321
--- /dev/null
+++ b/test/typeparam/typelist.go
@@ -0,0 +1,138 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file tests type lists & constraints with core types.
+
+// Note: This test has been adjusted to use the new
+// type set notation rather than type lists.
+
+package p
+
+// Assignability of an unnamed pointer type to a type parameter that
+// has a matching underlying type.
+func _[T interface{}, PT interface{ ~*T }](x T) PT {
+ return &x
+}
+
+// Indexing of generic types containing type parameters in their type list:
+func at[T interface{ ~[]E }, E any](x T, i int) E {
+ return x[i]
+}
+
+// A generic type inside a function acts like a named type. Its underlying
+// type is itself, its "operational type" is defined by the type list in
+// the tybe bound, if any.
+func _[T interface{ ~int }](x T) {
+ var _ int = int(x)
+ var _ T = 42
+ var _ T = T(myint(42))
+}
+
+// TODO: put this type declaration back inside the above function when issue 47631 is fixed.
+type myint int
+
+// Indexing a generic type which has a an array as core type.
+func _[T interface{ ~[10]int }](x T) {
+ _ = x[9] // ok
+}
+
+// Dereference of a generic type which has a pointer as core type.
+func _[T interface{ ~*int }](p T) int {
+ return *p
+}
+
+// Channel send and receive on a generic type which has a channel as core type.
+func _[T interface{ ~chan int }](ch T) int {
+ // This would deadlock if executed (but ok for a compile test)
+ ch <- 0
+ return <-ch
+}
+
+// Calling of a generic type which has a function as core type.
+func _[T interface{ ~func() }](f T) {
+ f()
+ go f()
+}
+
+// Same, but function has a parameter and return value.
+func _[T interface{ ~func(string) int }](f T) int {
+ return f("hello")
+}
+
+// Map access of a generic type which has a map as core type.
+func _[V any, T interface{ ~map[string]V }](p T) V {
+ return p["test"]
+}
+
+// Testing partial and full type inference, including the case where the types can
+// be inferred without needing the types of the function arguments.
+
+// Cannot embed stand-alone type parameters. Disabled for now.
+/*
+func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D)
+func f0x() {
+ f := f0[string]
+ f("a", "b", "c", "d")
+ f0("a", "b", "c", "d")
+}
+
+func f1[A any, B interface{type A}](A, B)
+func f1x() {
+ f := f1[int]
+ f(int(0), int(0))
+ f1(int(0), int(0))
+ f(0, 0)
+ f1(0, 0)
+}
+*/
+
+func f2[A any, B interface{ []A }](_ A, _ B) {}
+func f2x() {
+ f := f2[byte]
+ f(byte(0), []byte{})
+ f2(byte(0), []byte{})
+ f(0, []byte{})
+ // f2(0, []byte{}) - this one doesn't work
+}
+
+// Cannot embed stand-alone type parameters. Disabled for now.
+/*
+func f3[A any, B interface{type C}, C interface{type *A}](a A, _ B, c C)
+func f3x() {
+ f := f3[int]
+ var x int
+ f(x, &x, &x)
+ f3(x, &x, &x)
+}
+*/
+
+func f4[A any, B interface{ []C }, C interface{ *A }](_ A, _ B, c C) {}
+func f4x() {
+ f := f4[int]
+ var x int
+ f(x, []*int{}, &x)
+ f4(x, []*int{}, &x)
+}
+
+func f5[A interface {
+ struct {
+ b B
+ c C
+ }
+}, B any, C interface{ *B }](x B) A {
+ panic(0)
+}
+func f5x() {
+ x := f5(1.2)
+ var _ float64 = x.b
+ var _ float64 = *x.c
+}
+
+func f6[A any, B interface{ ~struct{ f []A } }](B) A { panic(0) }
+func f6x() {
+ x := f6(struct{ f []string }{})
+ var _ string = x
+}
diff --git a/test/typeparam/typeswitch1.go b/test/typeparam/typeswitch1.go
new file mode 100644
index 0000000..a0468d3
--- /dev/null
+++ b/test/typeparam/typeswitch1.go
@@ -0,0 +1,33 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[T any](i interface{}) {
+ switch i.(type) {
+ case T:
+ println("T")
+ case int:
+ println("int")
+ case int32, int16:
+ println("int32/int16")
+ case struct{ a, b T }:
+ println("struct{T,T}")
+ default:
+ println("other")
+ }
+}
+func main() {
+ f[float64](float64(6))
+ f[float64](int(7))
+ f[float64](int32(8))
+ f[float64](struct{ a, b float64 }{a: 1, b: 2})
+ f[float64](int8(9))
+ f[int32](int32(7))
+ f[int](int32(7))
+ f[any](int(10))
+ f[interface{ M() }](int(11))
+}
diff --git a/test/typeparam/typeswitch1.out b/test/typeparam/typeswitch1.out
new file mode 100644
index 0000000..6b8a33c
--- /dev/null
+++ b/test/typeparam/typeswitch1.out
@@ -0,0 +1,9 @@
+T
+int
+int32/int16
+struct{T,T}
+other
+T
+int32/int16
+T
+int
diff --git a/test/typeparam/typeswitch2.go b/test/typeparam/typeswitch2.go
new file mode 100644
index 0000000..286002a
--- /dev/null
+++ b/test/typeparam/typeswitch2.go
@@ -0,0 +1,35 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func f[T any](i interface{}) {
+ switch x := i.(type) {
+ case T:
+ fmt.Println("T", x)
+ case int:
+ fmt.Println("int", x)
+ case int32, int16:
+ fmt.Println("int32/int16", x)
+ case struct{ a, b T }:
+ fmt.Println("struct{T,T}", x.a, x.b)
+ default:
+ fmt.Println("other", x)
+ }
+}
+func main() {
+ f[float64](float64(6))
+ f[float64](int(7))
+ f[float64](int32(8))
+ f[float64](struct{ a, b float64 }{a: 1, b: 2})
+ f[float64](int8(9))
+ f[int32](int32(7))
+ f[int](int32(7))
+ f[any](int(10))
+ f[interface{ M() }](int(11))
+}
diff --git a/test/typeparam/typeswitch2.out b/test/typeparam/typeswitch2.out
new file mode 100644
index 0000000..6d4df54
--- /dev/null
+++ b/test/typeparam/typeswitch2.out
@@ -0,0 +1,9 @@
+T 6
+int 7
+int32/int16 8
+struct{T,T} 1 2
+other 9
+T 7
+int32/int16 7
+T 10
+int 11
diff --git a/test/typeparam/typeswitch3.go b/test/typeparam/typeswitch3.go
new file mode 100644
index 0000000..b84fdd0
--- /dev/null
+++ b/test/typeparam/typeswitch3.go
@@ -0,0 +1,48 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface{ foo() int }
+type J interface {
+ I
+ bar()
+}
+
+type myint int
+
+func (x myint) foo() int { return int(x) }
+
+type myfloat float64
+
+func (x myfloat) foo() int { return int(x) }
+
+type myint32 int32
+
+func (x myint32) foo() int { return int(x) }
+func (x myint32) bar() {}
+
+func f[T I](i I) {
+ switch x := i.(type) {
+ case T:
+ println("T", x.foo())
+ case myint:
+ println("myint", x.foo())
+ default:
+ println("other", x.foo())
+ }
+}
+func main() {
+ f[myfloat](myint(6))
+ f[myfloat](myfloat(7))
+ f[myfloat](myint32(8))
+ f[myint32](myint32(8))
+ f[myint32](myfloat(7))
+ f[myint](myint32(9))
+ f[I](myint(10))
+ f[J](myint(11))
+ f[J](myint32(12))
+}
diff --git a/test/typeparam/typeswitch3.out b/test/typeparam/typeswitch3.out
new file mode 100644
index 0000000..05ed533
--- /dev/null
+++ b/test/typeparam/typeswitch3.out
@@ -0,0 +1,9 @@
+myint 6
+T 7
+other 8
+T 8
+other 7
+other 9
+T 10
+myint 11
+T 12
diff --git a/test/typeparam/typeswitch4.go b/test/typeparam/typeswitch4.go
new file mode 100644
index 0000000..3fdf552
--- /dev/null
+++ b/test/typeparam/typeswitch4.go
@@ -0,0 +1,46 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface{ foo() int }
+type J interface {
+ I
+ bar()
+}
+
+type myint int
+
+func (x myint) foo() int { return int(x) }
+
+type myfloat float64
+
+func (x myfloat) foo() int { return int(x) }
+
+type myint32 int32
+
+func (x myint32) foo() int { return int(x) }
+func (x myint32) bar() {}
+
+func f[T I](i I) {
+ switch x := i.(type) {
+ case T, myint32:
+ println("T/myint32", x.foo())
+ default:
+ println("other", x.foo())
+ }
+}
+func main() {
+ f[myfloat](myint(6))
+ f[myfloat](myfloat(7))
+ f[myfloat](myint32(8))
+ f[myint32](myint32(9))
+ f[myint](myint32(10))
+ f[myint](myfloat(42))
+ f[I](myint(10))
+ f[J](myint(11))
+ f[J](myint32(12))
+}
diff --git a/test/typeparam/typeswitch4.out b/test/typeparam/typeswitch4.out
new file mode 100644
index 0000000..b98f074
--- /dev/null
+++ b/test/typeparam/typeswitch4.out
@@ -0,0 +1,9 @@
+other 6
+T/myint32 7
+T/myint32 8
+T/myint32 9
+T/myint32 10
+other 42
+T/myint32 10
+other 11
+T/myint32 12
diff --git a/test/typeparam/typeswitch5.go b/test/typeparam/typeswitch5.go
new file mode 100644
index 0000000..ac52adb
--- /dev/null
+++ b/test/typeparam/typeswitch5.go
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type myint int
+func (x myint) foo() int {return int(x)}
+
+type myfloat float64
+func (x myfloat) foo() float64 {return float64(x) }
+
+func f[T any](i interface{}) {
+ switch x := i.(type) {
+ case interface { foo() T }:
+ println("fooer", x.foo())
+ default:
+ println("other")
+ }
+}
+func main() {
+ f[int](myint(6))
+ f[int](myfloat(7))
+ f[float64](myint(8))
+ f[float64](myfloat(9))
+}
diff --git a/test/typeparam/typeswitch5.out b/test/typeparam/typeswitch5.out
new file mode 100644
index 0000000..6b4cb44
--- /dev/null
+++ b/test/typeparam/typeswitch5.out
@@ -0,0 +1,4 @@
+fooer 6
+other
+other
+fooer +9.000000e+000
diff --git a/test/typeparam/typeswitch6.go b/test/typeparam/typeswitch6.go
new file mode 100644
index 0000000..81d4f20
--- /dev/null
+++ b/test/typeparam/typeswitch6.go
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[T any](i interface{}) {
+ switch i.(type) {
+ case T:
+ println("T")
+ case int:
+ println("int")
+ default:
+ println("other")
+ }
+}
+
+type myint int
+func (myint) foo() {
+}
+
+func main() {
+ f[interface{}](nil)
+ f[interface{}](6)
+ f[interface{foo()}](nil)
+ f[interface{foo()}](7)
+ f[interface{foo()}](myint(8))
+}
diff --git a/test/typeparam/typeswitch6.out b/test/typeparam/typeswitch6.out
new file mode 100644
index 0000000..441add5
--- /dev/null
+++ b/test/typeparam/typeswitch6.out
@@ -0,0 +1,5 @@
+other
+T
+other
+int
+T
diff --git a/test/typeparam/typeswitch7.go b/test/typeparam/typeswitch7.go
new file mode 100644
index 0000000..067bed7
--- /dev/null
+++ b/test/typeparam/typeswitch7.go
@@ -0,0 +1,37 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f[T any](i interface{foo()}) {
+ switch i.(type) {
+ case interface{bar() T}:
+ println("barT")
+ case myint:
+ println("myint")
+ case myfloat:
+ println("myfloat")
+ default:
+ println("other")
+ }
+}
+
+type myint int
+func (myint) foo() {
+}
+func (x myint) bar() int {
+ return int(x)
+}
+
+type myfloat float64
+func (myfloat) foo() {
+}
+
+func main() {
+ f[int](nil)
+ f[int](myint(6))
+ f[int](myfloat(7))
+}
diff --git a/test/typeparam/typeswitch7.out b/test/typeparam/typeswitch7.out
new file mode 100644
index 0000000..d7fcad4
--- /dev/null
+++ b/test/typeparam/typeswitch7.out
@@ -0,0 +1,3 @@
+other
+barT
+myfloat
diff --git a/test/typeparam/valimp.dir/a.go b/test/typeparam/valimp.dir/a.go
new file mode 100644
index 0000000..2ed0063
--- /dev/null
+++ b/test/typeparam/valimp.dir/a.go
@@ -0,0 +1,32 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Value[T any] struct {
+ val T
+}
+
+// The noinline directive should survive across import, and prevent instantiations
+// of these functions from being inlined.
+
+//go:noinline
+func Get[T any](v *Value[T]) T {
+ return v.val
+}
+
+//go:noinline
+func Set[T any](v *Value[T], val T) {
+ v.val = val
+}
+
+//go:noinline
+func (v *Value[T]) Set(val T) {
+ v.val = val
+}
+
+//go:noinline
+func (v *Value[T]) Get() T {
+ return v.val
+}
diff --git a/test/typeparam/valimp.dir/main.go b/test/typeparam/valimp.dir/main.go
new file mode 100644
index 0000000..e357af4
--- /dev/null
+++ b/test/typeparam/valimp.dir/main.go
@@ -0,0 +1,55 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "./a"
+ "fmt"
+)
+
+func main() {
+ var v1 a.Value[int]
+
+ a.Set(&v1, 1)
+ if got, want := a.Get(&v1), 1; got != want {
+ panic(fmt.Sprintf("Get() == %d, want %d", got, want))
+ }
+ v1.Set(2)
+ if got, want := v1.Get(), 2; got != want {
+ panic(fmt.Sprintf("Get() == %d, want %d", got, want))
+ }
+ v1p := new(a.Value[int])
+ a.Set(v1p, 3)
+ if got, want := a.Get(v1p), 3; got != want {
+ panic(fmt.Sprintf("Get() == %d, want %d", got, want))
+ }
+
+ v1p.Set(4)
+ if got, want := v1p.Get(), 4; got != want {
+ panic(fmt.Sprintf("Get() == %d, want %d", got, want))
+ }
+
+ var v2 a.Value[string]
+ a.Set(&v2, "a")
+ if got, want := a.Get(&v2), "a"; got != want {
+ panic(fmt.Sprintf("Get() == %q, want %q", got, want))
+ }
+
+ v2.Set("b")
+ if got, want := a.Get(&v2), "b"; got != want {
+ panic(fmt.Sprintf("Get() == %q, want %q", got, want))
+ }
+
+ v2p := new(a.Value[string])
+ a.Set(v2p, "c")
+ if got, want := a.Get(v2p), "c"; got != want {
+ panic(fmt.Sprintf("Get() == %d, want %d", got, want))
+ }
+
+ v2p.Set("d")
+ if got, want := v2p.Get(), "d"; got != want {
+ panic(fmt.Sprintf("Get() == %d, want %d", got, want))
+ }
+}
diff --git a/test/typeparam/valimp.go b/test/typeparam/valimp.go
new file mode 100644
index 0000000..40df49f
--- /dev/null
+++ b/test/typeparam/valimp.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
diff --git a/test/typeparam/value.go b/test/typeparam/value.go
new file mode 100644
index 0000000..be25dce
--- /dev/null
+++ b/test/typeparam/value.go
@@ -0,0 +1,75 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type value[T any] struct {
+ val T
+}
+
+func get[T any](v *value[T]) T {
+ return v.val
+}
+
+func set[T any](v *value[T], val T) {
+ v.val = val
+}
+
+func (v *value[T]) set(val T) {
+ v.val = val
+}
+
+func (v *value[T]) get() T {
+ return v.val
+}
+
+func main() {
+ var v1 value[int]
+ set(&v1, 1)
+ if got, want := get(&v1), 1; got != want {
+ panic(fmt.Sprintf("get() == %d, want %d", got, want))
+ }
+
+ v1.set(2)
+ if got, want := v1.get(), 2; got != want {
+ panic(fmt.Sprintf("get() == %d, want %d", got, want))
+ }
+
+ v1p := new(value[int])
+ set(v1p, 3)
+ if got, want := get(v1p), 3; got != want {
+ panic(fmt.Sprintf("get() == %d, want %d", got, want))
+ }
+
+ v1p.set(4)
+ if got, want := v1p.get(), 4; got != want {
+ panic(fmt.Sprintf("get() == %d, want %d", got, want))
+ }
+
+ var v2 value[string]
+ set(&v2, "a")
+ if got, want := get(&v2), "a"; got != want {
+ panic(fmt.Sprintf("get() == %q, want %q", got, want))
+ }
+
+ v2.set("b")
+ if got, want := get(&v2), "b"; got != want {
+ panic(fmt.Sprintf("get() == %q, want %q", got, want))
+ }
+
+ v2p := new(value[string])
+ set(v2p, "c")
+ if got, want := get(v2p), "c"; got != want {
+ panic(fmt.Sprintf("get() == %d, want %d", got, want))
+ }
+
+ v2p.set("d")
+ if got, want := v2p.get(), "d"; got != want {
+ panic(fmt.Sprintf("get() == %d, want %d", got, want))
+ }
+}