Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve issue with implicit yields requiring Zero #10556

Merged
merged 4 commits into from Dec 1, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/fsharp/CheckComputationExpressions.fs
Expand Up @@ -950,7 +950,8 @@ let TcComputationExpression cenv env overallTy tpenv (mWhole, interpExpr: Expr,
error(Error(FSComp.SR.tcConstructIsAmbiguousInComputationExpression(), m))

| SynExpr.ImplicitZero m ->
if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Zero" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Zero"), m))
if (not enableImplicitYield) &&
isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Zero" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Zero"), m))
Some (translatedCtxt (mkSynCall "Zero" m []))
laenas marked this conversation as resolved.
Show resolved Hide resolved

| OptionalSequential (JoinOrGroupJoinOrZipClause (_, _, _, _, _, mClause), _)
Expand Down
Expand Up @@ -45,6 +45,7 @@
<Compile Include="Language\XmlComments.fs" />
<Compile Include="Language\CompilerDirectiveTests.fs" />
<Compile Include="Language\CodeQuotationTests.fs" />
<Compile Include="Language\ComputationExpressionTests.fs" />
<Compile Include="ConstraintSolver\PrimitiveConstraints.fs" />
<Compile Include="ConstraintSolver\MemberConstraints.fs" />
<Compile Include="Interop\SimpleInteropTests.fs" />
Expand All @@ -57,8 +58,4 @@
<ProjectReference Include="$(FSharpSourcesRoot)\fsharp\FSharp.Core\FSharp.Core.fsproj" />
<ProjectReference Include="$(FSharpTestsRoot)\FSharp.Test.Utilities\FSharp.Test.Utilities.fsproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="NewFolder\" />
</ItemGroup>
</Project>
@@ -0,0 +1,95 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace FSharp.Compiler.ComponentTests.Language

open Xunit
open FSharp.Test.Utilities.Compiler

module ComputationExpressionTests =
[<Fact>]
let ``A CE not using Zero does not require Zero``() =
FSharp """
module ComputationExpressionTests
type ListBuilder () =
member __.Combine (a: List<'T>, b) = a @ b
member __.Yield x = List.singleton x
member __.Delay expr = expr () : List<'T>

let lb = ListBuilder ()

let x = lb {1; 2;}
"""
|> compile
|> shouldSucceed
|> ignore

[<Fact>]
let ``A CE explicitly using Zero fails without a defined Zero``() =
FSharp """
module ComputationExpressionTests
type ListBuilder () =
member __.Combine (a: List<'T>, b) = a @ b
member __.Yield x = List.singleton x
member __.Delay expr = expr () : List<'T>

let lb = ListBuilder ()

let x = lb {1; 2;()}
"""
|> compile
|> shouldFail
|> withSingleDiagnostic (Error 39, Line 10, Col 18, Line 10, Col 20, "The type 'ListBuilder' does not define the field, constructor or member 'Zero'.")
|> ignore

[<Fact>]
let ``A CE explicitly using Zero succeeds with a defined Zero``() =
FSharp """
module ComputationExpressionTests
type ListBuilder () =
member __.Zero () = []
member __.Combine (a: List<'T>, b) = a @ b
member __.Yield x = List.singleton x
member __.Delay expr = expr () : List<'T>

let lb = ListBuilder ()

let x = lb {1; 2;()}
"""
|> compile
|> shouldSucceed
|> ignore

[<Fact>]
let ``A CE with a complete if-then expression does not require Zero``() =
FSharp """
module ComputationExpressionTests
type ListBuilder () =
member __.Combine (a: List<'T>, b) = a @ b
member __.Yield x = List.singleton x
member __.Delay expr = expr () : List<'T>

let lb = ListBuilder ()

let x = lb {1; 2; if true then 3 else 4;}
"""
|> compile
|> shouldSucceed
|> ignore

[<Fact>]
let ``A CE with a missing/empty else branch implicitly requires Zero``() =
FSharp """
module ComputationExpressionTests
type ListBuilder () =
member __.Combine (a: List<'T>, b) = a @ b
member __.Yield x = List.singleton x
member __.Delay expr = expr () : List<'T>

let lb = ListBuilder ()

let x = lb {1; 2; if true then 3;}
"""
|> compile
|> shouldFail
|> withSingleDiagnostic (Error 708, Line 10, Col 19, Line 10, Col 31, "This control construct may only be used if the computation expression builder defines a 'Zero' method")
|> ignore