Skip to content

Commit 4712569

Browse files
committed
more tests
1 parent aee26ec commit 4712569

File tree

1 file changed

+386
-0
lines changed

1 file changed

+386
-0
lines changed

tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs

Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,4 +1639,390 @@ if result3 <> 3 then failwithf $"Expected 3, but got {result3}"
16391639
|> withLangVersionPreview
16401640
|> asExe
16411641
|> compileAndRun
1642+
|> shouldSucceed
1643+
1644+
[<Fact>]
1645+
let ``Version 9.0: and! with record patterns and type annotations requires parentheses`` () =
1646+
FSharp """
1647+
module Test
1648+
1649+
type Person = { Name: string; Age: int }
1650+
type User = { Id: int; Username: string }
1651+
1652+
type ParallelBuilder() =
1653+
member _.Return(x) = async { return x }
1654+
member _.ReturnFrom(computation: Async<'T>) = computation
1655+
member _.Bind(computation: Async<'T>, binder: 'T -> Async<'U>) =
1656+
async {
1657+
let! x = computation
1658+
return! binder x
1659+
}
1660+
member _.Bind2(comp1: Async<'T1>, comp2: Async<'T2>, binder: 'T1 * 'T2 -> Async<'U>) =
1661+
async {
1662+
let! task1 = Async.StartChild comp1
1663+
let! task2 = Async.StartChild comp2
1664+
let! result1 = task1
1665+
let! result2 = task2
1666+
return! binder (result1, result2)
1667+
}
1668+
1669+
member _.Zero() = async.Zero()
1670+
member _.Combine(comp1, comp2) = async.Combine(comp1, comp2)
1671+
member _.Delay(f) = async.Delay(f)
1672+
1673+
let parallelCE = ParallelBuilder()
1674+
1675+
let asyncPerson() = async { return { Name = "John"; Age = 30 } }
1676+
let asyncUser() = async { return { Id = 1; Username = "john_doe" } }
1677+
1678+
let testParallel1() =
1679+
parallelCE {
1680+
let! ({ Name = name; Age = age }: Person) = asyncPerson()
1681+
and! ({ Id = id; Username = username }: User) = asyncUser()
1682+
return (name, age, id, username)
1683+
}
1684+
1685+
let testParallel2() =
1686+
parallelCE {
1687+
let! { Name = name; Age = age }: Person = asyncPerson()
1688+
and! { Id = id; Username = username }: User = asyncUser()
1689+
return (name, age, id, username)
1690+
}
1691+
"""
1692+
|> withLangVersion90
1693+
|> typecheck
1694+
|> shouldFail
1695+
|> withDiagnostics [
1696+
(Error 3350, Line 43, Col 14, Line 43, Col 48, "Feature 'Allow let! and use! type annotations without requiring parentheses' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.");
1697+
(Error 3350, Line 42, Col 14, Line 42, Col 46, "Feature 'Allow let! and use! type annotations without requiring parentheses' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
1698+
]
1699+
1700+
[<Fact>]
1701+
let ``Preview: and! with record patterns and type annotations works without parentheses`` () =
1702+
FSharp """
1703+
module Test
1704+
1705+
type Person = { Name: string; Age: int }
1706+
type User = { Id: int; Username: string }
1707+
1708+
type ParallelBuilder() =
1709+
member _.Return(x) = async { return x }
1710+
member _.ReturnFrom(computation: Async<'T>) = computation
1711+
member _.Bind(computation: Async<'T>, binder: 'T -> Async<'U>) =
1712+
async {
1713+
let! x = computation
1714+
return! binder x
1715+
}
1716+
member _.Bind2(comp1: Async<'T1>, comp2: Async<'T2>, binder: 'T1 * 'T2 -> Async<'U>) =
1717+
async {
1718+
let! task1 = Async.StartChild comp1
1719+
let! task2 = Async.StartChild comp2
1720+
let! result1 = task1
1721+
let! result2 = task2
1722+
return! binder (result1, result2)
1723+
}
1724+
1725+
member _.Zero() = async.Zero()
1726+
member _.Combine(comp1, comp2) = async.Combine(comp1, comp2)
1727+
member _.Delay(f) = async.Delay(f)
1728+
1729+
let parallelCE = ParallelBuilder()
1730+
1731+
let asyncPerson() = async { return { Name = "John"; Age = 30 } }
1732+
let asyncUser() = async { return { Id = 1; Username = "john_doe" } }
1733+
1734+
let testParallel1() =
1735+
parallelCE {
1736+
let! ({ Name = name; Age = age }: Person) = asyncPerson()
1737+
and! ({ Id = id; Username = username }: User) = asyncUser()
1738+
return (name, age, id, username)
1739+
}
1740+
1741+
let testParallel2() =
1742+
parallelCE {
1743+
let! { Name = name; Age = age }: Person = asyncPerson()
1744+
and! { Id = id; Username = username }: User = asyncUser()
1745+
return (name, age, id, username)
1746+
}
1747+
1748+
let result1 = testParallel1() |> Async.RunSynchronously
1749+
let result2 = testParallel2() |> Async.RunSynchronously
1750+
1751+
if result1 <> ("John", 30, 1, "john_doe") then
1752+
failwithf $"Expected ('John', 30, 1, 'john_doe'), but got %A{result1}"
1753+
if result2 <> ("John", 30, 1, "john_doe") then
1754+
failwithf $"Expected ('John', 30, 1, 'john_doe'), but got %A{result2}"
1755+
"""
1756+
|> withLangVersionPreview
1757+
|> asExe
1758+
|> compileAndRun
1759+
|> shouldSucceed
1760+
1761+
[<Fact>]
1762+
let ``Version 9.0: and! with union patterns and type annotations requires parentheses`` () =
1763+
FSharp """
1764+
module Test
1765+
1766+
type MyOption<'T> = Some of 'T | None
1767+
1768+
type ParallelBuilder() =
1769+
member _.Return(x) = async { return x }
1770+
member _.ReturnFrom(computation: Async<'T>) = computation
1771+
member _.Bind(computation: Async<'T>, binder: 'T -> Async<'U>) =
1772+
async {
1773+
let! x = computation
1774+
return! binder x
1775+
}
1776+
member _.Bind2(comp1: Async<'T1>, comp2: Async<'T2>, binder: 'T1 * 'T2 -> Async<'U>) =
1777+
async {
1778+
let! task1 = Async.StartChild comp1
1779+
let! task2 = Async.StartChild comp2
1780+
let! result1 = task1
1781+
let! result2 = task2
1782+
return! binder (result1, result2)
1783+
}
1784+
1785+
member _.Zero() = async.Zero()
1786+
member _.Combine(comp1, comp2) = async.Combine(comp1, comp2)
1787+
member _.Delay(f) = async.Delay(f)
1788+
1789+
let parallelCE = ParallelBuilder()
1790+
1791+
let asyncOption1() = async { return MyOption.Some 42 }
1792+
let asyncOption2() = async { return MyOption.Some "hello" }
1793+
1794+
let testParallel() =
1795+
parallelCE {
1796+
let! (Some value1): MyOption<int> = asyncOption1()
1797+
and! (Some value2): MyOption<string> = asyncOption2()
1798+
return (value1, value2)
1799+
}
1800+
1801+
let testParallel2() =
1802+
parallelCE {
1803+
let! Some value1: MyOption<int> = asyncOption1()
1804+
and! Some value2: MyOption<string> = asyncOption2()
1805+
return (value1, value2)
1806+
}
1807+
"""
1808+
|> withLangVersion90
1809+
|> typecheck
1810+
|> shouldFail
1811+
|> withDiagnostics [
1812+
(Error 3350, Line 41, Col 14, Line 41, Col 46, "Feature 'Allow let! and use! type annotations without requiring parentheses' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.");
1813+
(Error 3350, Line 40, Col 14, Line 40, Col 41, "Feature 'Allow let! and use! type annotations without requiring parentheses' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
1814+
]
1815+
1816+
[<Fact>]
1817+
let ``Preview: and! with union patterns and type annotations works without parentheses`` () =
1818+
FSharp """
1819+
module Test
1820+
1821+
type MyOption<'T> = Some of 'T | None
1822+
1823+
type ParallelBuilder() =
1824+
member _.Return(x) = async { return x }
1825+
member _.ReturnFrom(computation: Async<'T>) = computation
1826+
member _.Bind(computation: Async<'T>, binder: 'T -> Async<'U>) =
1827+
async {
1828+
let! x = computation
1829+
return! binder x
1830+
}
1831+
member _.Bind2(comp1: Async<'T1>, comp2: Async<'T2>, binder: 'T1 * 'T2 -> Async<'U>) =
1832+
async {
1833+
let! task1 = Async.StartChild comp1
1834+
let! task2 = Async.StartChild comp2
1835+
let! result1 = task1
1836+
let! result2 = task2
1837+
return! binder (result1, result2)
1838+
}
1839+
1840+
member _.Zero() = async.Zero()
1841+
member _.Combine(comp1, comp2) = async.Combine(comp1, comp2)
1842+
member _.Delay(f) = async.Delay(f)
1843+
1844+
let parallelCE = ParallelBuilder()
1845+
1846+
let asyncOption1() = async { return MyOption.Some 42 }
1847+
let asyncOption2() = async { return MyOption.Some "hello" }
1848+
1849+
let testParallel1() =
1850+
parallelCE {
1851+
let! (Some value1): MyOption<int> = asyncOption1()
1852+
and! (Some value2): MyOption<string> = asyncOption2()
1853+
return (value1, value2)
1854+
}
1855+
1856+
let testParallel2() =
1857+
parallelCE {
1858+
let! Some value1: MyOption<int> = asyncOption1()
1859+
and! Some value2: MyOption<string> = asyncOption2()
1860+
return (value1, value2)
1861+
}
1862+
1863+
let result1 = testParallel1() |> Async.RunSynchronously
1864+
let result2 = testParallel2() |> Async.RunSynchronously
1865+
1866+
if result1 <> (42, "hello") then
1867+
failwithf $"Expected (42, 'hello'), but got %A{result1}"
1868+
if result2 <> (42, "hello") then
1869+
failwithf $"Expected (42, 'hello'), but got %A{result2}"
1870+
"""
1871+
|> withLangVersionPreview
1872+
|> asExe
1873+
|> compileAndRun
1874+
|> shouldSucceed
1875+
1876+
[<Fact>]
1877+
let ``Preview: and! with mixed patterns and type annotations works`` () =
1878+
FSharp """
1879+
module Test
1880+
1881+
type Person = { Name: string; Age: int }
1882+
1883+
type ParallelBuilder() =
1884+
member _.Return(x) = async { return x }
1885+
member _.ReturnFrom(computation: Async<'T>) = computation
1886+
member _.Bind(computation: Async<'T>, binder: 'T -> Async<'U>) =
1887+
async {
1888+
let! x = computation
1889+
return! binder x
1890+
}
1891+
member _.Bind2(comp1: Async<'T1>, comp2: Async<'T2>, binder: 'T1 * 'T2 -> Async<'U>) =
1892+
async {
1893+
let! task1 = Async.StartChild comp1
1894+
let! task2 = Async.StartChild comp2
1895+
let! result1 = task1
1896+
let! result2 = task2
1897+
return! binder (result1, result2)
1898+
}
1899+
1900+
member _.Zero() = async.Zero()
1901+
member _.Combine(comp1, comp2) = async.Combine(comp1, comp2)
1902+
member _.Delay(f) = async.Delay(f)
1903+
1904+
let parallelCE = ParallelBuilder()
1905+
1906+
let asyncInt() = async { return 42 }
1907+
let asyncPerson() = async { return { Name = "Alice"; Age = 25 } }
1908+
1909+
// Test mixing different pattern types with type annotations
1910+
let testMixed() =
1911+
parallelCE {
1912+
let! x: int = asyncInt()
1913+
and! { Name = name; Age = age }: Person = asyncPerson()
1914+
return (x, name, age)
1915+
}
1916+
1917+
// Test with parentheses on one and not the other
1918+
let testMixed2() =
1919+
parallelCE {
1920+
let! (y: int) = asyncInt()
1921+
and! { Name = name2; Age = age2 }: Person = asyncPerson()
1922+
return (y, name2, age2)
1923+
}
1924+
1925+
let result1 = testMixed() |> Async.RunSynchronously
1926+
let result2 = testMixed2() |> Async.RunSynchronously
1927+
1928+
if result1 <> (42, "Alice", 25) then
1929+
failwithf $"Expected (42, 'Alice', 25), but got %A{result1}"
1930+
if result2 <> (42, "Alice", 25) then
1931+
failwithf $"Expected (42, 'Alice', 25), but got %A{result2}"
1932+
"""
1933+
|> withLangVersionPreview
1934+
|> asExe
1935+
|> compileAndRun
1936+
|> shouldSucceed
1937+
1938+
[<Fact>]
1939+
let ``Preview: multiple and! with type annotations works`` () =
1940+
FSharp """
1941+
module Test
1942+
1943+
type Builder() =
1944+
member _.Return(x) = async { return x }
1945+
member _.Bind(computation: Async<'T>, binder: 'T -> Async<'U>) =
1946+
async {
1947+
let! x = computation
1948+
return! binder x
1949+
}
1950+
member _.Bind3(comp1: Async<'T1>, comp2: Async<'T2>, comp3: Async<'T3>, binder: 'T1 * 'T2 * 'T3 -> Async<'U>) =
1951+
async {
1952+
let! task1 = Async.StartChild comp1
1953+
let! task2 = Async.StartChild comp2
1954+
let! task3 = Async.StartChild comp3
1955+
let! result1 = task1
1956+
let! result2 = task2
1957+
let! result3 = task3
1958+
return! binder (result1, result2, result3)
1959+
}
1960+
1961+
member _.Zero() = async.Zero()
1962+
member _.Combine(comp1, comp2) = async.Combine(comp1, comp2)
1963+
member _.Delay(f) = async.Delay(f)
1964+
1965+
let builder = Builder()
1966+
1967+
let asyncInt() = async { return 42 }
1968+
let asyncString() = async { return "test" }
1969+
let asyncFloat() = async { return 3.14 }
1970+
1971+
// Test multiple and! with type annotations
1972+
let testMultiple() =
1973+
builder {
1974+
let! x: int = asyncInt()
1975+
and! y: string = asyncString()
1976+
and! z: float = asyncFloat()
1977+
return (x, y, z)
1978+
}
1979+
1980+
let result = testMultiple() |> Async.RunSynchronously
1981+
1982+
if result <> (42, "test", 3.14) then
1983+
failwithf $"Expected (42, 'test', 3.14), but got %A{result}"
1984+
"""
1985+
|> withLangVersionPreview
1986+
|> asExe
1987+
|> compileAndRun
1988+
|> shouldSucceed
1989+
1990+
[<Fact>]
1991+
let ``Preview: and! with generic type annotations works`` () =
1992+
FSharp """
1993+
module Test
1994+
1995+
type Result<'T, 'E> = Ok of 'T | Error of 'E
1996+
1997+
type ResultBuilder() =
1998+
member _.Return(x) = Ok x
1999+
member _.Bind(m: Result<'T, 'E>, f: 'T -> Result<'U, 'E>) =
2000+
match m with
2001+
| Ok x -> f x
2002+
| Error e -> Error e
2003+
member _.Bind2(m1: Result<'T1, 'E>, m2: Result<'T2, 'E>, f: 'T1 * 'T2 -> Result<'U, 'E>) =
2004+
match m1, m2 with
2005+
| Ok x1, Ok x2 -> f (x1, x2)
2006+
| Error e, _ -> Error e
2007+
| _, Error e -> Error e
2008+
2009+
let result = ResultBuilder()
2010+
2011+
let getValue1() = Ok 42
2012+
let getValue2() = Ok "success"
2013+
2014+
let test() =
2015+
result {
2016+
let! x: int = getValue1()
2017+
and! y: string = getValue2()
2018+
return (x, y)
2019+
}
2020+
2021+
match test() with
2022+
| Ok (42, "success") -> printfn "Test passed"
2023+
| _ -> failwith "Test failed"
2024+
"""
2025+
|> withLangVersionPreview
2026+
|> asExe
2027+
|> compileAndRun
16422028
|> shouldSucceed

0 commit comments

Comments
 (0)