diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs
index c90e75a3ae6..29d04082093 100644
--- a/src/fsharp/CompileOps.fs
+++ b/src/fsharp/CompileOps.fs
@@ -1004,6 +1004,8 @@ let OutputPhasedErrorR (os: StringBuilder) (err: PhasedDiagnostic) (canSuggestNa
| Parser.TOKEN_OLET(_) -> getErrorString("Parser.TOKEN.OLET")
| Parser.TOKEN_OBINDER
| Parser.TOKEN_BINDER -> getErrorString("Parser.TOKEN.BINDER")
+ | Parser.TOKEN_OAND_BANG
+ | Parser.TOKEN_AND_BANG -> getErrorString("Parser.TOKEN.AND.BANG")
| Parser.TOKEN_ODO -> getErrorString("Parser.TOKEN.ODO")
| Parser.TOKEN_OWITH -> getErrorString("Parser.TOKEN.OWITH")
| Parser.TOKEN_OFUNCTION -> getErrorString("Parser.TOKEN.OFUNCTION")
diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt
index de26c9b349a..6a4e5da6b1c 100644
--- a/src/fsharp/FSComp.txt
+++ b/src/fsharp/FSComp.txt
@@ -1475,6 +1475,9 @@ notAFunctionButMaybeDeclaration,"This value is not a function and cannot be appl
3301,chkInvalidFunctionReturnType,"The function or method has an invalid return type '%s'. This is not permitted by the rules of Common IL."
3302,packageManagementRequiresVFive,"The package management feature requires language version 5.0 use /langversion:preview"
3303,fromEndSlicingRequiresVFive,"From the end slicing with requires language version 5.0, use /langversion:preview."
+3343,tcRequireMergeSourcesOrBindN,"The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '%s' method or appropriate 'MergeSource' and 'Bind' methods"
+3344,tcAndBangNotSupported,"This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature."
+3345,tcInvalidUseBangBindingNoAndBangs,"use! may not be combined with and!"
useSdkRefs,"Use reference assemblies for .NET framework references when available (Enabled by default)."
fSharpBannerVersion,"%s for F# %s"
optsLangVersion,"Display the allowed values for language version, specify language version such as 'latest' or 'preview'"
diff --git a/src/fsharp/FSStrings.resx b/src/fsharp/FSStrings.resx
index cf3d3c92b29..a56e6f14219 100644
--- a/src/fsharp/FSStrings.resx
+++ b/src/fsharp/FSStrings.resx
@@ -564,6 +564,9 @@
keyword 'and'
+ !
+ keyword 'and!'
+
keyword 'as'
diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs
index 2170cee8f75..9d23f9e266e 100644
--- a/src/fsharp/LanguageFeatures.fs
+++ b/src/fsharp/LanguageFeatures.fs
@@ -28,6 +28,7 @@ type LanguageFeature =
| PackageManagement
| FromEndSlicing
| FixedIndexSlice3d4d
+ | AndBang
/// LanguageVersion management
type LanguageVersion (specifiedVersionAsString) =
@@ -61,6 +62,7 @@ type LanguageVersion (specifiedVersionAsString) =
LanguageFeature.NameOf, previewVersion
LanguageFeature.OpenStaticClasses, previewVersion
LanguageFeature.PackageManagement, previewVersion
+ LanguageFeature.AndBang, previewVersion
]
let specified =
diff --git a/src/fsharp/LanguageFeatures.fsi b/src/fsharp/LanguageFeatures.fsi
index 37a58a50b49..5f274351d72 100644
--- a/src/fsharp/LanguageFeatures.fsi
+++ b/src/fsharp/LanguageFeatures.fsi
@@ -16,7 +16,7 @@ type LanguageFeature =
| PackageManagement
| FromEndSlicing
| FixedIndexSlice3d4d
-
+ | AndBang
/// LanguageVersion management
type LanguageVersion =
diff --git a/src/fsharp/LexFilter.fs b/src/fsharp/LexFilter.fs
index 470b54709b8..d485399af83 100644
--- a/src/fsharp/LexFilter.fs
+++ b/src/fsharp/LexFilter.fs
@@ -1784,6 +1784,13 @@ type LexFilterImpl (lightSyntaxStatus: LightSyntaxStatus, compilingFsLib, lexer,
pushCtxt tokenTup (CtxtLetDecl(blockLet, tokenStartPos))
returnToken tokenLexbufState (if blockLet then OBINDER b else token)
+ // and! ... ~~~> CtxtLetDecl
+ | AND_BANG isUse, (ctxt :: _) ->
+ let blockLet = match ctxt with CtxtSeqBlock _ -> true | _ -> false
+ if debug then dprintf "AND!: entering CtxtLetDecl(blockLet=%b), awaiting EQUALS to go to CtxtSeqBlock (%a)\n" blockLet outputPos tokenStartPos
+ pushCtxt tokenTup (CtxtLetDecl(blockLet,tokenStartPos))
+ returnToken tokenLexbufState (if blockLet then OAND_BANG isUse else token)
+
| (VAL | STATIC | ABSTRACT | MEMBER | OVERRIDE | DEFAULT), ctxtStack when thereIsACtxtMemberBodyOnTheStackAndWeShouldPopStackForUpcomingMember ctxtStack ->
if debug then dprintf "STATIC/MEMBER/OVERRIDE/DEFAULT: already inside CtxtMemberBody, popping all that context before starting next member...\n"
// save this token, we'll consume it again later...
diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs
old mode 100644
new mode 100755
index c8880576868..ac71f5bb589
--- a/src/fsharp/TypeChecker.fs
+++ b/src/fsharp/TypeChecker.fs
@@ -1842,31 +1842,25 @@ let UseCombinedArity g declKind rhsExpr prelimScheme =
let UseNoArity prelimScheme =
BuildValScheme ExpressionBinding None prelimScheme
-let MakeSimpleVals cenv env names =
+/// Make and publish the Val nodes for a collection of simple (non-generic) value specifications
+let MakeAndPublishSimpleVals cenv env names =
let tyschemes = DontGeneralizeVals names
let valSchemes = NameMap.map UseNoArity tyschemes
let values = MakeAndPublishVals cenv env (ParentNone, false, ExpressionBinding, ValNotInRecScope, valSchemes, [], XmlDoc.Empty, None)
let vspecMap = NameMap.map fst values
values, vspecMap
-let MakeAndPublishSimpleVals cenv env m names mergeNamesInOneNameresEnv =
-
+/// Make and publish the Val nodes for a collection of value specifications at Lambda and Match positions
+///
+/// We merge the additions to the name resolution environment into one using a merged range so all values are brought
+/// into scope simultaneously. The technique used to do this is a disturbing and unfortunate hack that
+/// intercepts `NotifyNameResolution` calls being emitted by `MakeAndPublishSimpleVals`
+
+let MakeAndPublishSimpleValsForMergedScope cenv env m (names: NameMap<_>) =
let values, vspecMap =
- if not mergeNamesInOneNameresEnv then MakeSimpleVals cenv env names
+ if names.Count <= 1 then
+ MakeAndPublishSimpleVals cenv env names
else
- // reason: now during typecheck we create new name resolution environment for all components of tupled arguments in lambda.
- // When trying to find best environment for the given position first we pick the most deeply nested scope that contains given position
- // (and that will be lambda body - correct one), then we look for the better subtree on the left hand side
- // (and that will be name resolution environment containing second parameter parameter - without the first one).
- // fix: I've tried to make fix as local as possible to reduce overall impact on the source code.
- // Idea of the fix: replace existing typecheck results sink and capture all reported name resolutions (this will be all parameters in lambda).
- // After that - we restore the sink back, generate new name resolution environment that contains all captured names and report generated environment
- // to the old sink.
-
-
- // default behavior - send EnvWithScope notification for every resolved name
- // what we do here is override this default behavior and capture only all name resolution notifications
- // later we'll process them and create one name resolution env that will contain names from all notifications
let nameResolutions = ResizeArray()
let values, vspecMap =
let sink =
@@ -1875,14 +1869,14 @@ let MakeAndPublishSimpleVals cenv env m names mergeNamesInOneNameresEnv =
member this.NotifyNameResolution(pos, item, itemGroup, itemTyparInst, occurence, denv, nenv, ad, m, replacing) =
if not m.IsSynthetic then
nameResolutions.Add(pos, item, itemGroup, itemTyparInst, occurence, denv, nenv, ad, m, replacing)
- member this.NotifyExprHasType(_, _, _, _, _, _) = assert false // no expr typings in MakeSimpleVals
+ member this.NotifyExprHasType(_, _, _, _, _, _) = assert false // no expr typings in MakeAndPublishSimpleVals
member this.NotifyFormatSpecifierLocation(_, _) = ()
member this.NotifyOpenDeclaration(_) = ()
member this.CurrentSourceText = None
member this.FormatStringCheckContext = None }
use _h = WithNewTypecheckResultsSink(sink, cenv.tcSink)
- MakeSimpleVals cenv env names
+ MakeAndPublishSimpleVals cenv env names
if nameResolutions.Count <> 0 then
let (_, _, _, _, _, _, _, ad, m1, _replacing) = nameResolutions.[0]
@@ -1905,8 +1899,6 @@ let MakeAndPublishSimpleVals cenv env m names mergeNamesInOneNameresEnv =
let envinner = AddLocalValMap cenv.tcSink m vspecMap env
envinner, values, vspecMap
-
-
//-------------------------------------------------------------------------
// Helpers to freshen existing types and values, i.e. when a reference
// to C<_> occurs then generate C for a fresh type inference variable ?ty.
@@ -3535,7 +3527,7 @@ let YieldFree cenv expr =
| SynExpr.ForEach (_, _, _, _, _, body, _) ->
YieldFree body
- | SynExpr.LetOrUseBang(_, _, _, _, _, body, _) ->
+ | SynExpr.LetOrUseBang(_, _, _, _, _, _, body, _) ->
YieldFree body
| SynExpr.YieldOrReturn((true, _), _, _) -> false
@@ -6249,7 +6241,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) =
error(Error(FSComp.SR.tcConstructRequiresSequenceOrComputations(), m))
| SynExpr.DoBang (_, m)
- | SynExpr.LetOrUseBang (_, _, _, _, _, _, m) ->
+ | SynExpr.LetOrUseBang (range=m) ->
error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), m))
| SynExpr.MatchBang (_, _, _, m) ->
@@ -6261,7 +6253,7 @@ and TcIteratedLambdas cenv isFirst (env: TcEnv) overallTy takenNames tpenv e =
| SynExpr.Lambda (isMember, isSubsequent, spats, bodyExpr, m) when isMember || isFirst || isSubsequent ->
let domainTy, resultTy = UnifyFunctionType None cenv env.DisplayEnv m overallTy
let vs, (tpenv, names, takenNames) = TcSimplePats cenv isMember CheckCxs domainTy env (tpenv, Map.empty, takenNames) spats
- let envinner, _, vspecMap = MakeAndPublishSimpleVals cenv env m names true
+ let envinner, _, vspecMap = MakeAndPublishSimpleValsForMergedScope cenv env m names
let byrefs = vspecMap |> Map.map (fun _ v -> isByrefTy cenv.g v.Type, v)
let envinner = if isMember then envinner else ExitFamilyRegion envinner
let bodyExpr, tpenv = TcIteratedLambdas cenv false envinner resultTy takenNames tpenv bodyExpr
@@ -7529,6 +7521,9 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
| [] -> callExpr
| _ -> mkSynCall "Source" callExpr.Range [callExpr]
+ let mkSourceExprConditional isFromSource callExpr =
+ if isFromSource then mkSourceExpr callExpr else callExpr
+
/// Decide if the builder is an auto-quote builder
let isAutoQuote = hasMethInfo "Quote"
@@ -7979,7 +7974,7 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
if not q then error(Error(FSComp.SR.tcCustomOperationMayNotBeUsedHere(), nm.idRange))
- let firstSource = if isFromSource then mkSourceExpr firstSource else firstSource
+ let firstSource = mkSourceExprConditional isFromSource firstSource
let secondSource = mkSourceExpr secondSource
// Add the variables to the variable space, on demand
@@ -8123,11 +8118,12 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
| SynExpr.ForEach (spForLoop, SeqExprOnly _seqExprOnly, isFromSource, pat, sourceExpr, innerComp, _) ->
- let wrappedSourceExpr = if isFromSource then mkSourceExpr sourceExpr else sourceExpr
+ let wrappedSourceExpr = mkSourceExprConditional isFromSource sourceExpr
let mFor = match spForLoop with SequencePointAtForLoop m -> m | _ -> pat.Range
let mPat = pat.Range
let spBind = match spForLoop with SequencePointAtForLoop m -> SequencePointAtBinding m | NoSequencePointAtForLoop -> NoSequencePointAtStickyBinding
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mFor ad "For" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("For"), mFor))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mFor ad "For" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("For"), mFor))
// Add the variables to the query variable space, on demand
let varSpace =
@@ -8149,16 +8145,20 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
let mGuard = guardExpr.Range
let mWhile = match spWhile with SequencePointAtWhileLoop m -> m | _ -> mGuard
if isQuery then error(Error(FSComp.SR.tcNoWhileInQuery(), mWhile))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mWhile ad "While" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("While"), mWhile))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mWhile ad "Delay" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), mWhile))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mWhile ad "While" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("While"), mWhile))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mWhile ad "Delay" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), mWhile))
Some(trans true q varSpace innerComp (fun holeFill -> translatedCtxt (mkSynCall "While" mWhile [mkSynDelay2 guardExpr; mkSynCall "Delay" mWhile [mkSynDelay innerComp.Range holeFill]])) )
| SynExpr.TryFinally (innerComp, unwindExpr, mTryToLast, spTry, _spFinally) ->
let mTry = match spTry with SequencePointAtTry m -> m | _ -> mTryToLast
if isQuery then error(Error(FSComp.SR.tcNoTryFinallyInQuery(), mTry))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "TryFinally" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("TryFinally"), mTry))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "Delay" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), mTry))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "TryFinally" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("TryFinally"), mTry))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "Delay" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), mTry))
Some (translatedCtxt (mkSynCall "TryFinally" mTry [mkSynCall "Delay" mTry [mkSynDelay innerComp.Range (transNoQueryOps innerComp)]; mkSynDelay2 unwindExpr]))
| SynExpr.Paren (_, _, _, m) ->
@@ -8238,7 +8238,10 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
| StripApps(SingleIdent nm, args) ->
if args.Length = expectedArgCount then
// Check for the [] attribute on each argument position
- let args = args |> List.mapi (fun i arg -> if isCustomOperationProjectionParameter (i+1) nm then SynExpr.Lambda (false, false, varSpaceSimplePat, arg, arg.Range.MakeSynthetic()) else arg)
+ let args = args |> List.mapi (fun i arg ->
+ if isCustomOperationProjectionParameter (i+1) nm then
+ SynExpr.Lambda (false, false, varSpaceSimplePat, arg, arg.Range.MakeSynthetic())
+ else arg)
mkSynCall methInfo.DisplayName mClause (dataCompPrior :: args)
else
errorR(Error(FSComp.SR.tcCustomOperationHasIncorrectArgCount(nm.idText, expectedArgCount, args.Length), nm.idRange))
@@ -8266,7 +8269,7 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
// Rebind using either for ... or let!....
let rebind =
if maintainsVarSpaceUsingBind then
- SynExpr.LetOrUseBang (NoSequencePointAtLetBinding, false, false, intoPat, dataCompAfterOp, contExpr, intoPat.Range)
+ SynExpr.LetOrUseBang (NoSequencePointAtLetBinding, false, false, intoPat, dataCompAfterOp, [], contExpr, intoPat.Range)
else
SynExpr.ForEach (NoSequencePointAtForLoop, SeqExprOnly false, false, intoPat, dataCompAfterOp, contExpr, intoPat.Range)
@@ -8288,7 +8291,7 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
// Rebind using either for ... or let!....
let rebind =
if lastUsesBind then
- SynExpr.LetOrUseBang (NoSequencePointAtLetBinding, false, false, varSpacePat, dataCompPrior, compClausesExpr, compClausesExpr.Range)
+ SynExpr.LetOrUseBang (NoSequencePointAtLetBinding, false, false, varSpacePat, dataCompPrior, [], compClausesExpr, compClausesExpr.Range)
else
SynExpr.ForEach (NoSequencePointAtForLoop, SeqExprOnly false, false, varSpacePat, dataCompPrior, compClausesExpr, compClausesExpr.Range)
@@ -8316,8 +8319,10 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
// This is not pretty - we have to decide which range markers we use for the calls to Combine and Delay
// NOTE: we should probably suppress these sequence points altogether
let m1 = rangeForCombine innerComp1
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Combine" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Combine"), m))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Delay" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), m))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Combine" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Combine"), m))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Delay" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), m))
Some (translatedCtxt (mkSynCall "Combine" m1 [c; mkSynCall "Delay" m1 [mkSynDelay innerComp2.Range (transNoQueryOps innerComp2)]]))
| None ->
// "do! expr; cexpr" is treated as { let! () = expr in cexpr }
@@ -8328,7 +8333,8 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
| SuppressSequencePointOnStmtOfSequential -> SequencePointAtBinding m
| SuppressSequencePointOnExprOfSequential -> NoSequencePointAtDoBinding
| SequencePointsAtSeq -> SequencePointAtBinding m
- Some(trans true q varSpace (SynExpr.LetOrUseBang (sp, false, true, SynPat.Const(SynConst.Unit, rhsExpr.Range), rhsExpr, innerComp2, m)) translatedCtxt)
+ Some(trans true q varSpace (SynExpr.LetOrUseBang (sp, false, true, SynPat.Const(SynConst.Unit, rhsExpr.Range), rhsExpr, [], innerComp2, m)) translatedCtxt)
+
// "expr; cexpr" is treated as sequential execution
| _ ->
Some (trans true q varSpace innerComp2 (fun holeFill ->
@@ -8353,7 +8359,8 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
Some (translatedCtxt (SynExpr.IfThenElse (guardExpr, transNoQueryOps thenComp, Some(transNoQueryOps elseComp), spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch)))
| None ->
let elseComp =
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mIfToThen ad "Zero" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Zero"), mIfToThen))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mIfToThen ad "Zero" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Zero"), mIfToThen))
mkSynCall "Zero" mIfToThen []
Some (trans true q varSpace thenComp (fun holeFill -> translatedCtxt (SynExpr.IfThenElse (guardExpr, holeFill, Some elseComp, spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch))))
@@ -8385,7 +8392,6 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
// error case
error(Error(FSComp.SR.tcCustomOperationMayNotBeUsedInConjunctionWithNonSimpleLetBindings(), mQueryOp)))
-
Some (trans true q varSpace innerComp (fun holeFill -> translatedCtxt (SynExpr.LetOrUse (isRec, false, binds, holeFill, m))))
// 'use x = expr in expr'
@@ -8394,16 +8400,18 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
if isQuery then error(Error(FSComp.SR.tcUseMayNotBeUsedInQueries(), bindRange))
let innerCompRange = innerComp.Range
let consumeExpr = SynExpr.MatchLambda(false, innerCompRange, [Clause(pat, None, transNoQueryOps innerComp, innerCompRange, SequencePointAtTarget)], spBind, innerCompRange)
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Using" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Using"), bindRange))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Using" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Using"), bindRange))
Some (translatedCtxt (mkSynCall "Using" bindRange [rhsExpr; consumeExpr ]))
- // 'let! pat = expr in expr' --> build.Bind(e1, (function _argN -> match _argN with pat -> expr))
- | SynExpr.LetOrUseBang (spBind, false, isFromSource, pat, rhsExpr, innerComp, _) ->
+ // 'let! pat = expr in expr'
+ // --> build.Bind(e1, (fun _argN -> match _argN with pat -> expr))
+ // or
+ // --> build.BindReturn(e1, (fun _argN -> match _argN with pat -> expr-without-return))
+ | SynExpr.LetOrUseBang (spBind, false, isFromSource, pat, rhsExpr, [], innerComp, _) ->
let bindRange = match spBind with SequencePointAtBinding m -> m | _ -> rhsExpr.Range
if isQuery then error(Error(FSComp.SR.tcBindMayNotBeUsedInQueries(), bindRange))
- let innerRange = innerComp.Range
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Bind" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Bind"), bindRange))
// Add the variables to the query variable space, on demand
let varSpace =
@@ -8412,28 +8420,135 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
let _, _, vspecs, envinner, _ = TcMatchPattern cenv (NewInferenceType()) env tpenv (pat, None)
vspecs, envinner)
- let rhsExpr = if isFromSource then mkSourceExpr rhsExpr else rhsExpr
- Some (trans true q varSpace innerComp (fun holeFill ->
- let consumeExpr = SynExpr.MatchLambda (false, pat.Range, [Clause(pat, None, holeFill, innerRange, SequencePointAtTarget)], spBind, innerRange)
- translatedCtxt (mkSynCall "Bind" bindRange [rhsExpr; consumeExpr])))
+ let rhsExpr = mkSourceExprConditional isFromSource rhsExpr
+ Some (transBind q varSpace bindRange "Bind" [rhsExpr] pat spBind innerComp translatedCtxt)
- // 'use! pat = e1 in e2' --> build.Bind(e1, (function _argN -> match _argN with pat -> build.Using(x, (fun _argN -> match _argN with pat -> e2))))
- | SynExpr.LetOrUseBang (spBind, true, isFromSource, (SynPat.Named (SynPat.Wild _, id, false, _, _) as pat), rhsExpr, innerComp, _)
- | SynExpr.LetOrUseBang (spBind, true, isFromSource, (SynPat.LongIdent (LongIdentWithDots([id], _), _, _, _, _, _) as pat), rhsExpr, innerComp, _) ->
+ // 'use! pat = e1 in e2' --> build.Bind(e1, (function _argN -> match _argN with pat -> build.Using(x, (fun _argN -> match _argN with pat -> e2))))
+ | SynExpr.LetOrUseBang (spBind, true, isFromSource, (SynPat.Named (SynPat.Wild _, id, false, _, _) as pat) , rhsExpr, [], innerComp, _)
+ | SynExpr.LetOrUseBang (spBind, true, isFromSource, (SynPat.LongIdent (longDotId=LongIdentWithDots([id], _)) as pat), rhsExpr, [], innerComp, _) ->
let bindRange = match spBind with SequencePointAtBinding m -> m | _ -> rhsExpr.Range
if isQuery then error(Error(FSComp.SR.tcBindMayNotBeUsedInQueries(), bindRange))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Using" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Using"), bindRange))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Bind" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Bind"), bindRange))
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Using" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Using"), bindRange))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Bind" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Bind"), bindRange))
+
let consumeExpr = SynExpr.MatchLambda(false, bindRange, [Clause(pat, None, transNoQueryOps innerComp, innerComp.Range, SequencePointAtTarget)], spBind, bindRange)
let consumeExpr = mkSynCall "Using" bindRange [SynExpr.Ident(id); consumeExpr ]
let consumeExpr = SynExpr.MatchLambda(false, bindRange, [Clause(pat, None, consumeExpr, id.idRange, SequencePointAtTarget)], spBind, bindRange)
- let rhsExpr = if isFromSource then mkSourceExpr rhsExpr else rhsExpr
+ let rhsExpr = mkSourceExprConditional isFromSource rhsExpr
+ // TODO: consider allowing translation to BindReturn
Some(translatedCtxt (mkSynCall "Bind" bindRange [rhsExpr; consumeExpr]))
- // 'use! pat = e1 in e2' where 'pat' is not a simple name --> error
- | SynExpr.LetOrUseBang (_spBind, true, _isFromSource, pat, _rhsExpr, _innerComp, _) ->
- error(Error(FSComp.SR.tcInvalidUseBangBinding(), pat.Range))
+ // 'use! pat = e1 ... in e2' where 'pat' is not a simple name --> error
+ | SynExpr.LetOrUseBang (_spBind, true, _isFromSource, pat, _rhsExpr, andBangs, _innerComp, _) ->
+ if isNil andBangs then
+ error(Error(FSComp.SR.tcInvalidUseBangBinding(), pat.Range))
+ else
+ error(Error(FSComp.SR.tcInvalidUseBangBindingNoAndBangs(), comp.Range))
+
+ // 'let! pat1 = expr1 and! pat2 = expr2 in ...' -->
+ // build.BindN(expr1, expr2, ...)
+ // or
+ // build.BindNReturn(expr1, expr2, ...)
+ // or
+ // build.Bind(build.MergeSources(expr1, expr2), ...)
+ | SynExpr.LetOrUseBang(letSpBind, false, isFromSource, letPat, letRhsExpr, andBangBindings, innerComp, letBindRange) ->
+ if cenv.g.langVersion.SupportsFeature LanguageFeature.AndBang then
+ if isQuery then error(Error(FSComp.SR.tcBindMayNotBeUsedInQueries(), letBindRange))
+ let bindRange = match letSpBind with SequencePointAtBinding m -> m | _ -> letRhsExpr.Range
+ let sources = (letRhsExpr :: [for (_, _, _, _, andExpr, _) in andBangBindings -> andExpr ]) |> List.map (mkSourceExprConditional isFromSource)
+ let pats = letPat :: [for (_, _, _, andPat, _, _) in andBangBindings -> andPat ]
+ let sourcesRange = sources |> List.map (fun e -> e.Range) |> List.reduce unionRanges
+
+ let numSources = sources.Length
+ let bindReturnNName = "Bind"+string numSources+"Return"
+ let bindNName = "Bind"+string numSources
+
+ // Check if this is a Bind2Return etc.
+ let hasBindReturnN = not (isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad bindReturnNName builderTy))
+ if hasBindReturnN && Option.isSome (convertSimpleReturnToExpr varSpace innerComp) then
+ let consumePat = SynPat.Tuple(false, pats, letPat.Range)
+ Some (transBind q varSpace bindRange bindNName sources consumePat letSpBind innerComp translatedCtxt)
+
+ else
+
+ // Check if this is a Bind2 etc.
+ let hasBindN = not (isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad bindNName builderTy))
+ if hasBindN then
+ let consumePat = SynPat.Tuple(false, pats, letPat.Range)
+
+ // Add the variables to the query variable space, on demand
+ let varSpace =
+ addVarsToVarSpace varSpace (fun _mCustomOp env ->
+ use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
+ let _, _, vspecs, envinner, _ = TcMatchPattern cenv (NewInferenceType()) env tpenv (consumePat, None)
+ vspecs, envinner)
+
+ Some (transBind q varSpace bindRange bindNName sources consumePat letSpBind innerComp translatedCtxt)
+ else
+
+ // Look for the maximum supported MergeSources, MergeSources3, ...
+ let mkMergeSourcesName n = if n = 2 then "MergeSources" else "MergeSources"+(string n)
+
+ let maxMergeSources =
+ let rec loop (n: int) =
+ let mergeSourcesName = mkMergeSourcesName n
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad mergeSourcesName builderTy) then
+ (n-1)
+ else
+ loop (n+1)
+ loop 2
+
+ if maxMergeSources = 1 then error(Error(FSComp.SR.tcRequireMergeSourcesOrBindN(bindNName), bindRange))
+
+ let rec mergeSources (sourcesAndPats: (SynExpr * SynPat) list) =
+ let numSourcesAndPats = sourcesAndPats.Length
+ assert (numSourcesAndPats <> 0)
+ if numSourcesAndPats = 1 then
+ sourcesAndPats.[0]
+
+ elif numSourcesAndPats <= maxMergeSources then
+
+ // Call MergeSources2(e1, e2), MergeSources3(e1, e2, e3) etc
+ let mergeSourcesName = mkMergeSourcesName numSourcesAndPats
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad mergeSourcesName builderTy) then
+ error(Error(FSComp.SR.tcRequireMergeSourcesOrBindN(bindNName), bindRange))
+
+ let source = mkSynCall mergeSourcesName sourcesRange (List.map fst sourcesAndPats)
+ let pat = SynPat.Tuple(false, List.map snd sourcesAndPats, letPat.Range)
+ source, pat
+
+ else
+
+ // Call MergeSourcesMax(e1, e2, e3, e4, (...))
+ let nowSourcesAndPats, laterSourcesAndPats = List.splitAt (maxMergeSources - 1) sourcesAndPats
+ let mergeSourcesName = mkMergeSourcesName maxMergeSources
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad mergeSourcesName builderTy) then
+ error(Error(FSComp.SR.tcRequireMergeSourcesOrBindN(bindNName), bindRange))
+
+ let laterSource, laterPat = mergeSources laterSourcesAndPats
+ let source = mkSynCall mergeSourcesName sourcesRange (List.map fst nowSourcesAndPats @ [laterSource])
+ let pat = SynPat.Tuple(false, List.map snd nowSourcesAndPats @ [laterPat], letPat.Range)
+ source, pat
+
+ let mergedSources, consumePat = mergeSources (List.zip sources pats)
+
+ // Add the variables to the query variable space, on demand
+ let varSpace =
+ addVarsToVarSpace varSpace (fun _mCustomOp env ->
+ use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
+ let _, _, vspecs, envinner, _ = TcMatchPattern cenv (NewInferenceType()) env tpenv (consumePat, None)
+ vspecs, envinner)
+
+ // Build the 'Bind' call
+ Some (transBind q varSpace bindRange "Bind" [mergedSources] consumePat letSpBind innerComp translatedCtxt)
+ else
+ error(Error(FSComp.SR.tcAndBangNotSupported(), comp.Range))
| SynExpr.Match (spMatch, expr, clauses, m) ->
let mMatch = match spMatch with SequencePointAtBinding mMatch -> mMatch | _ -> m
@@ -8445,9 +8560,14 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
| SynExpr.MatchBang (spMatch, expr, clauses, m) ->
let mMatch = match spMatch with SequencePointAtBinding mMatch -> mMatch | _ -> m
if isQuery then error(Error(FSComp.SR.tcMatchMayNotBeUsedWithQuery(), mMatch))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mMatch ad "Bind" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Bind"), mMatch))
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mMatch ad "Bind" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Bind"), mMatch))
+
let clauses = clauses |> List.map (fun (Clause(pat, cond, innerComp, patm, sp)) -> Clause(pat, cond, transNoQueryOps innerComp, patm, sp))
let consumeExpr = SynExpr.MatchLambda (false, mMatch, clauses, spMatch, mMatch)
+
+ // TODO: consider allowing translation to BindReturn
Some(translatedCtxt (mkSynCall "Bind" mMatch [expr; consumeExpr]))
| SynExpr.TryWith (innerComp, _mTryToWith, clauses, _mWithToLast, mTryToLast, spTry, _spWith) ->
@@ -8456,14 +8576,19 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
if isQuery then error(Error(FSComp.SR.tcTryWithMayNotBeUsedInQueries(), mTry))
let clauses = clauses |> List.map (fun (Clause(pat, cond, clauseComp, patm, sp)) -> Clause(pat, cond, transNoQueryOps clauseComp, patm, sp))
let consumeExpr = SynExpr.MatchLambda(true, mTryToLast, clauses, NoSequencePointAtStickyBinding, mTryToLast)
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "TryWith" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("TryWith"), mTry))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "Delay" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), mTry))
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "TryWith" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("TryWith"), mTry))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "Delay" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), mTry))
+
Some(translatedCtxt (mkSynCall "TryWith" mTry [mkSynCall "Delay" mTry [mkSynDelay2 (transNoQueryOps innerComp)]; consumeExpr]))
| SynExpr.YieldOrReturnFrom ((isYield, _), yieldExpr, m) ->
let yieldExpr = mkSourceExpr yieldExpr
if isYield then
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "YieldFrom" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("YieldFrom"), m))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "YieldFrom" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("YieldFrom"), m))
Some (translatedCtxt (mkSynCall "YieldFrom" m [yieldExpr]))
else
@@ -8477,7 +8602,8 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
| SynExpr.YieldOrReturn ((isYield, _), yieldExpr, m) ->
let methName = (if isYield then "Yield" else "Return")
if isQuery && not isYield then error(Error(FSComp.SR.tcReturnMayNotBeUsedInQueries(), m))
- if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad methName builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod(methName), m))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad methName builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod(methName), m))
Some(translatedCtxt (mkSynCall methName m [yieldExpr]))
| _ -> None
@@ -8500,8 +8626,8 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Return" builderTy) then
SynExpr.ImplicitZero m
else
- SynExpr.YieldOrReturn((false, true), SynExpr.Const (SynConst.Unit, m), m)
- trans true q varSpace (SynExpr.LetOrUseBang(NoSequencePointAtDoBinding, false, false, SynPat.Const(SynConst.Unit, mUnit), rhsExpr, bodyExpr, m)) translatedCtxt
+ SynExpr.YieldOrReturn((false, true), SynExpr.Const(SynConst.Unit, m), m)
+ trans true q varSpace (SynExpr.LetOrUseBang (NoSequencePointAtDoBinding, false, false, SynPat.Const(SynConst.Unit, mUnit), rhsExpr, [], bodyExpr, m)) translatedCtxt
// "expr;" in final position is treated as { expr; zero }
// Suppress the sequence point on the "zero"
@@ -8523,6 +8649,104 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
SynExpr.Sequential(SuppressSequencePointOnStmtOfSequential, true, comp, holeFill, comp.Range)
translatedCtxt fillExpr)
+ and transBind q varSpace bindRange bindName bindArgs (consumePat: SynPat) spBind (innerComp: SynExpr) translatedCtxt =
+
+ let innerRange = innerComp.Range
+
+ let innerCompReturn =
+ if cenv.g.langVersion.SupportsFeature LanguageFeature.AndBang then
+ convertSimpleReturnToExpr varSpace innerComp
+ else None
+
+ match innerCompReturn with
+ | Some innerExpr when
+ (let bindName = bindName + "Return"
+ not (isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad bindName builderTy))) ->
+
+ let bindName = bindName + "Return"
+
+ // Build the `BindReturn` call
+ let consumeExpr = SynExpr.MatchLambda(false, consumePat.Range, [Clause(consumePat, None, innerExpr, innerRange, SequencePointAtTarget)], spBind, innerRange)
+ translatedCtxt (mkSynCall bindName bindRange (bindArgs @ [consumeExpr]))
+
+ | _ ->
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad bindName builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod(bindName), bindRange))
+
+ // Build the `Bind` call
+ trans true q varSpace innerComp (fun holeFill ->
+ let consumeExpr = SynExpr.MatchLambda(false, consumePat.Range, [Clause(consumePat, None, holeFill, innerRange, SequencePointAtTarget)], spBind, innerRange)
+ translatedCtxt (mkSynCall bindName bindRange (bindArgs @ [consumeExpr])))
+
+ and convertSimpleReturnToExpr varSpace innerComp =
+ match innerComp with
+ | SynExpr.YieldOrReturn ((false, _), returnExpr, _) -> Some returnExpr
+ | SynExpr.Match (spMatch, expr, clauses, m) ->
+ let clauses =
+ clauses |> List.map (fun (Clause(pat, cond, innerComp2, patm, sp)) ->
+ match convertSimpleReturnToExpr varSpace innerComp2 with
+ | None -> None
+ | Some innerExpr2 -> Some (Clause(pat, cond, innerExpr2, patm, sp)))
+ if clauses |> List.forall Option.isSome then
+ Some (SynExpr.Match (spMatch, expr, (clauses |> List.map Option.get), m))
+ else
+ None
+
+ | SynExpr.IfThenElse (guardExpr, thenComp, elseCompOpt, spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch) ->
+ match convertSimpleReturnToExpr varSpace thenComp with
+ | None -> None
+ | Some thenExpr ->
+ match Option.map (convertSimpleReturnToExpr varSpace) elseCompOpt with
+ | Some None -> None
+ | elseExprOpt ->
+ Some (SynExpr.IfThenElse (guardExpr, thenExpr, Option.bind id elseExprOpt, spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch) )
+
+ | SynExpr.LetOrUse (isRec, false, binds, innerComp, m) ->
+ match convertSimpleReturnToExpr varSpace innerComp with
+ | None -> None
+ | Some innerExpr -> Some (SynExpr.LetOrUse (isRec, false, binds, innerExpr, m))
+
+ | SynExpr.Sequential (sp, true, innerComp1, innerComp2, m) ->
+
+ // Check the first part isn't a computation expression construct
+ if isSimpleExpr innerComp1 then
+ // Check the second part is a simple return
+ match convertSimpleReturnToExpr varSpace innerComp2 with
+ | None -> None
+ | Some innerExpr2 -> Some (SynExpr.Sequential (sp, true, innerComp1, innerExpr2, m))
+ else
+ None
+
+ | _ -> None
+
+ /// Check is an expression has no computation expression constructs
+ and isSimpleExpr comp =
+
+ match comp with
+ | ForEachThenJoinOrGroupJoinOrZipClause _ -> false
+ | SynExpr.ForEach _ -> false
+ | SynExpr.For _ -> false
+ | SynExpr.While _ -> false
+ | SynExpr.TryFinally _ -> false
+ | SynExpr.ImplicitZero _ -> false
+ | OptionalSequential (JoinOrGroupJoinOrZipClause _, _) -> false
+ | OptionalSequential (CustomOperationClause _, _) -> false
+ | SynExpr.Sequential (_, _, innerComp1, innerComp2, _) -> isSimpleExpr innerComp1 && isSimpleExpr innerComp2
+ | SynExpr.IfThenElse (_, thenComp, elseCompOpt, _, _, _, _) ->
+ isSimpleExpr thenComp && (match elseCompOpt with None -> true | Some c -> isSimpleExpr c)
+ | SynExpr.LetOrUse (_, _, _, innerComp, _) -> isSimpleExpr innerComp
+ | SynExpr.LetOrUseBang _ -> false
+ | SynExpr.Match (_, _, clauses, _) ->
+ clauses |> List.forall (fun (Clause(_, _, innerComp, _, _)) -> isSimpleExpr innerComp)
+ | SynExpr.MatchBang _ -> false
+ | SynExpr.TryWith (innerComp, _, clauses, _, _, _, _) ->
+ isSimpleExpr innerComp &&
+ clauses |> List.forall (fun (Clause(_, _, clauseComp, _, _)) -> isSimpleExpr clauseComp)
+ | SynExpr.YieldOrReturnFrom _ -> false
+ | SynExpr.YieldOrReturn _ -> false
+ | _ -> true
+
let basicSynExpr =
trans true (hasCustomOperations ()) (LazyWithContext.NotLazy ([], env)) comp (fun holeFill -> holeFill)
@@ -8546,7 +8770,7 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
SynExpr.Lambda (false, false, SynSimplePats.SimplePats ([mkSynSimplePatVar false (mkSynId mBuilderVal builderValName)], mBuilderVal), runExpr, mBuilderVal)
let env =
- match comp with
+ match comp with
| SynExpr.YieldOrReturn ((true, _), _, _) -> { env with eContextInfo = ContextInfo.YieldInComputationExpression }
| SynExpr.YieldOrReturn ((_, true), _, _) -> { env with eContextInfo = ContextInfo.ReturnInComputationExpression }
| _ -> env
@@ -8693,7 +8917,7 @@ and TcSequenceExpression cenv env tpenv comp overallTy m =
//SEQPOINT NEEDED - we must consume spBind on this path
Some(mkSeqUsing cenv env wholeExprMark bindPatTy genOuterTy inputExpr consumeExpr, tpenv)
- | SynExpr.LetOrUseBang (_, _, _, _, _, _, m) ->
+ | SynExpr.LetOrUseBang (range=m) ->
error(Error(FSComp.SR.tcUseForInSequenceExpression(), m))
| SynExpr.Match (spMatch, expr, clauses, _) ->
@@ -8711,7 +8935,7 @@ and TcSequenceExpression cenv env tpenv comp overallTy m =
let matchv, matchExpr = CompilePatternForMatchClauses cenv env inputExprMark inputExprMark true ThrowIncompleteMatchException (Some inputExpr) inputExprTy genOuterTy tclauses
Some(mkLet spMatch inputExprMark matchv inputExpr matchExpr, tpenv)
- | SynExpr.TryWith (_, mTryToWith, _, _, _, _, _) ->
+ | SynExpr.TryWith (tryRange=mTryToWith) ->
error(Error(FSComp.SR.tcTryIllegalInSequenceExpression(), mTryToWith))
| SynExpr.YieldOrReturnFrom ((isYield, _), yieldExpr, m) ->
@@ -10587,7 +10811,7 @@ and TcAndPatternCompileMatchClauses mExpr matchm actionOnFailure cenv inputExprO
and TcMatchPattern cenv inputTy env tpenv (pat: SynPat, optWhenExpr) =
let m = pat.Range
let patf', (tpenv, names, _) = TcPat WarnOnUpperCase cenv env None (ValInline.Optional, permitInferTypars, noArgOrRetAttribs, false, None, false) (tpenv, Map.empty, Set.empty) inputTy pat
- let envinner, values, vspecMap = MakeAndPublishSimpleVals cenv env m names false
+ let envinner, values, vspecMap = MakeAndPublishSimpleValsForMergedScope cenv env m names
let optWhenExpr', tpenv =
match optWhenExpr with
| Some whenExpr ->
@@ -12670,7 +12894,7 @@ module IncrClassChecking =
let ctorArgNames, (_, names, _) = TcSimplePatsOfUnknownType cenv true CheckCxs env tpenv (SynSimplePats.SimplePats (spats, m))
// Create the values with the given names
- let _, vspecs = MakeSimpleVals cenv env names
+ let _, vspecs = MakeAndPublishSimpleVals cenv env names
if tcref.IsStructOrEnumTycon && isNil spats then
errorR (ParameterlessStructCtor(tcref.Range))
diff --git a/src/fsharp/ast.fs b/src/fsharp/ast.fs
index 524f73965ed..40e90b679a4 100644
--- a/src/fsharp/ast.fs
+++ b/src/fsharp/ast.fs
@@ -764,12 +764,13 @@ and
/// Computation expressions only
| YieldOrReturnFrom of (bool * bool) * expr: SynExpr * range: range
- /// SynExpr.LetOrUseBang (spBind, isUse, isFromSource, pat, rhsExpr, bodyExpr, mWholeExpr).
+ /// SynExpr.LetOrUseAndBang (spBind, isUse, isFromSource, pat, rhsExpr, mLetBangExpr, [(andBangSpBind, andBangIsUse, andBangIsFromSource, andBangPat, andBangRhsExpr, mAndBangExpr)], bodyExpr).
///
/// F# syntax: let! pat = expr in expr
/// F# syntax: use! pat = expr in expr
+ /// F# syntax: let! pat = expr and! ... and! ... and! pat = expr in expr
/// Computation expressions only
- | LetOrUseBang of bindSeqPoint: SequencePointInfoForBinding * isUse: bool * isFromSource: bool * SynPat * SynExpr * SynExpr * range: range
+ | LetOrUseBang of bindSeqPoint: SequencePointInfoForBinding * isUse: bool * isFromSource: bool * SynPat * rhs: SynExpr * andBangs:(SequencePointInfoForBinding * bool * bool * SynPat * SynExpr * range) list * body:SynExpr * range: range
/// F# syntax: match! expr with pat1 -> expr | ... | patN -> exprN
| MatchBang of matchSeqPoint: SequencePointInfoForBinding * expr: SynExpr * clauses: SynMatchClause list * range: range (* bool indicates if this is an exception match in a computation expression which throws unmatched exceptions *)
@@ -2475,6 +2476,6 @@ let rec synExprContainsError inpExpr =
| SynExpr.MatchBang (_, e, cl, _) ->
walkExpr e || walkMatchClauses cl
- | SynExpr.LetOrUseBang (_, _, _, _, e1, e2, _) ->
- walkExpr e1 || walkExpr e2
+ | SynExpr.LetOrUseBang (rhs=e1;body=e2;andBangs=es) ->
+ walkExpr e1 || walkExprs [ for (_,_,_,_,e,_) in es do yield e ] || walkExpr e2
walkExpr inpExpr
diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl
index 901a203b832..5970e1fb8c0 100644
--- a/src/fsharp/lex.fsl
+++ b/src/fsharp/lex.fsl
@@ -233,10 +233,12 @@ rule token args skip = parse
{ YIELD_BANG(false) }
| "match!"
{ MATCH_BANG }
+ | "and!"
+ { AND_BANG(false) }
| ident '!'
{ let tok = Keywords.KeywordOrIdentifierToken args lexbuf (lexemeTrimRight lexbuf 1)
match tok with
- | LET _ -> BINDER (lexemeTrimRight lexbuf 1)
+ | LET _ -> BINDER (lexemeTrimRight lexbuf 1)
| _ -> fail args lexbuf (FSComp.SR.lexIdentEndInMarkReserved("!")) (Keywords.KeywordOrIdentifierToken args lexbuf (lexeme lexbuf)) }
| ident ('#')
{ fail args lexbuf (FSComp.SR.lexIdentEndInMarkReserved("#")) (Keywords.KeywordOrIdentifierToken args lexbuf (lexeme lexbuf)) }
diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy
index e1d888196b5..66ee0bd792e 100644
--- a/src/fsharp/pars.fsy
+++ b/src/fsharp/pars.fsy
@@ -189,7 +189,7 @@ let rangeOfLongIdent(lid:LongIdent) =
%token CHAR
%token DECIMAL
%token <(string * string)> BIGNUM
-%token LET YIELD YIELD_BANG
+%token LET YIELD YIELD_BANG AND_BANG
%token LESS GREATER /* here the bool indicates if the tokens are part of a type application or type parameter declaration, e.g. C, detected by the lex filter */
%token PERCENT_OP BINDER
%token LQUOTE RQUOTE RQUOTE_DOT
@@ -218,6 +218,7 @@ let rangeOfLongIdent(lid:LongIdent) =
/* for offside rule */
%token OLET /* LexFilter #light converts 'LET' tokens to 'OLET' when starting (CtxtLetDecl(blockLet=true)) */
%token OBINDER /* LexFilter #light converts 'BINDER' tokens to 'OBINDER' when starting (CtxtLetDecl(blockLet=true)) */
+%token OAND_BANG /* LexFilter #light converts 'AND_BANG' tokens to 'OAND_BANG' when starting (CtxtLetDecl(blockLet=true)) */
%token ODO /* LexFilter #light converts 'DO' tokens to 'ODO' */
%token ODO_BANG /* LexFilter #light converts 'DO_BANG' tokens to 'ODO_BANG' */
%token OTHEN /* LexFilter #light converts 'THEN' tokens to 'OTHEN' */
@@ -453,7 +454,8 @@ let rangeOfLongIdent(lid:LongIdent) =
%nonassoc paren_pat_colon
%nonassoc paren_pat_attribs
%left OR BAR_BAR JOIN_IN
-%left AND /* check */
+%left AND
+%left AND_BANG
%left AMP AMP_AMP
%nonassoc pat_conj
%nonassoc expr_not
@@ -3060,6 +3062,20 @@ recover:
| error { debugPrint("recovering via error"); true }
| EOF { debugPrint("recovering via EOF"); false }
+morebinders:
+ | AND_BANG headBindingPattern EQUALS typedSeqExprBlock IN morebinders %prec expr_let
+ { let spBind = SequencePointAtBinding(rhs2 parseState 1 5) (* TODO Pretty sure this is wrong *)
+ let m = rhs parseState 1 (* TODO Pretty sure this is wrong *)
+ (spBind,$1,true,$2,$4,m) :: $6 }
+
+ | OAND_BANG headBindingPattern EQUALS typedSeqExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP morebinders %prec expr_let
+ { $5 "and!" (rhs parseState 1) // report unterminated error
+ let spBind = SequencePointAtBinding(rhs2 parseState 1 5) (* TODO Pretty sure this is wrong *)
+ let m = rhs parseState 1 (* TODO Pretty sure this is wrong *)
+ (spBind,$1,true,$2,$4,m) :: $7 }
+
+ | %prec prec_no_more_attr_bindings
+ { [] }
declExpr:
| defnBindings IN typedSeqExpr %prec expr_let
@@ -3353,27 +3369,35 @@ declExpr:
| YIELD_BANG declExpr
{ SynExpr.YieldOrReturnFrom (($1,not $1), $2, unionRanges (rhs parseState 1) $2.Range) }
- | BINDER headBindingPattern EQUALS typedSeqExprBlock IN opt_OBLOCKSEP typedSeqExprBlock %prec expr_let
+ | YIELD recover
+ { let mYieldAll = rhs parseState 1
+ SynExpr.YieldOrReturn (($1, not $1), arbExpr("yield", mYieldAll), mYieldAll) }
+
+ | YIELD_BANG recover
+ { let mYieldAll = rhs parseState 1
+ SynExpr.YieldOrReturnFrom (($1, not $1), arbExpr("yield!", mYieldAll), mYieldAll) }
+
+ | BINDER headBindingPattern EQUALS typedSeqExprBlock IN opt_OBLOCKSEP morebinders typedSeqExprBlock %prec expr_let
{ let spBind = SequencePointAtBinding(rhs2 parseState 1 5)
- let m = unionRanges (rhs parseState 1) $7.Range
- SynExpr.LetOrUseBang (spBind,($1 = "use"),true,$2,$4,$7,m) }
+ let m = unionRanges (rhs parseState 1) $8.Range
+ SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, $4, $7, $8, m) }
- | OBINDER headBindingPattern EQUALS typedSeqExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP typedSeqExprBlock %prec expr_let
+ | OBINDER headBindingPattern EQUALS typedSeqExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP morebinders typedSeqExprBlock %prec expr_let
{ $5 (if $1 = "use" then "use!" else "let!") (rhs parseState 1) // report unterminated error
let spBind = SequencePointAtBinding(unionRanges (rhs parseState 1) $4.Range)
- let m = unionRanges (rhs parseState 1) $7.Range
- SynExpr.LetOrUseBang (spBind,($1 = "use"),true,$2,$4,$7,m) }
+ let m = unionRanges (rhs parseState 1) $8.Range
+ SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, $4, $7, $8, m) }
| OBINDER headBindingPattern EQUALS typedSeqExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP error %prec expr_let
{ // error recovery that allows intellisense when writing incomplete computation expressions
let spBind = SequencePointAtBinding(unionRanges (rhs parseState 1) $4.Range)
let mAll = unionRanges (rhs parseState 1) (rhs parseState 7)
let m = $4.Range.EndRange // zero-width range
- SynExpr.LetOrUseBang (spBind,($1 = "use"),true,$2,$4, SynExpr.ImplicitZero m, mAll) }
+ SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, $4, [], SynExpr.ImplicitZero m, mAll) }
| DO_BANG typedSeqExpr IN opt_OBLOCKSEP typedSeqExprBlock %prec expr_let
{ let spBind = NoSequencePointAtDoBinding
- SynExpr.LetOrUseBang (spBind,false,true,SynPat.Const(SynConst.Unit,$2.Range),$2,$5, unionRanges (rhs parseState 1) $5.Range) }
+ SynExpr.LetOrUseBang(spBind, false, true, SynPat.Const(SynConst.Unit,$2.Range), $2, [], $5, unionRanges (rhs parseState 1) $5.Range) }
| ODO_BANG typedSeqExprBlock hardwhiteDefnBindingsTerminator %prec expr_let
{ SynExpr.DoBang ($2, unionRanges (rhs parseState 1) $2.Range) }
diff --git a/src/fsharp/service/ServiceAssemblyContent.fs b/src/fsharp/service/ServiceAssemblyContent.fs
index e495fa0428c..b826728b477 100644
--- a/src/fsharp/service/ServiceAssemblyContent.fs
+++ b/src/fsharp/service/ServiceAssemblyContent.fs
@@ -703,9 +703,13 @@ module ParsedInput =
addLongIdentWithDots ident
List.iter walkExpr [e1; e2; e3]
| SynExpr.JoinIn (e1, _, e2, _) -> List.iter walkExpr [e1; e2]
- | SynExpr.LetOrUseBang (_, _, _, pat, e1, e2, _) ->
+ | SynExpr.LetOrUseBang (_, _, _, pat, e1, es, e2, _) ->
walkPat pat
- List.iter walkExpr [e1; e2]
+ walkExpr e1
+ for (_,_,_,patAndBang,eAndBang,_) in es do
+ walkPat patAndBang
+ walkExpr eAndBang
+ walkExpr e2
| SynExpr.TraitCall (ts, sign, e, _) ->
List.iter walkTypar ts
walkMemberSig sign
diff --git a/src/fsharp/service/ServiceInterfaceStubGenerator.fs b/src/fsharp/service/ServiceInterfaceStubGenerator.fs
index dfaa9a537ae..e5461138bfd 100644
--- a/src/fsharp/service/ServiceInterfaceStubGenerator.fs
+++ b/src/fsharp/service/ServiceInterfaceStubGenerator.fs
@@ -896,8 +896,14 @@ module InterfaceStubGenerator =
| SynExpr.DoBang (synExpr, _range) ->
walkExpr synExpr
- | SynExpr.LetOrUseBang (_sequencePointInfoForBinding, _, _, _synPat, synExpr1, synExpr2, _range) ->
- List.tryPick walkExpr [synExpr1; synExpr2]
+ | SynExpr.LetOrUseBang (_sequencePointInfoForBinding, _, _, _synPat, synExpr1, synExprAndBangs, synExpr2, _range) ->
+ [
+ yield synExpr1
+ for (_,_,_,_,eAndBang,_) in synExprAndBangs do
+ yield eAndBang
+ yield synExpr2
+ ]
+ |> List.tryPick walkExpr
| SynExpr.LibraryOnlyILAssembly _
| SynExpr.LibraryOnlyStaticOptimization _
diff --git a/src/fsharp/service/ServiceLexing.fs b/src/fsharp/service/ServiceLexing.fs
old mode 100644
new mode 100755
index e0792c9d2a8..a0e2d57893e
--- a/src/fsharp/service/ServiceLexing.fs
+++ b/src/fsharp/service/ServiceLexing.fs
@@ -261,14 +261,14 @@ module internal TokenClassifications =
| MEMBER | STATIC | NAMESPACE
| OASSERT | OLAZY | ODECLEND | OBLOCKSEP | OEND | OBLOCKBEGIN | ORIGHT_BLOCK_END
| OBLOCKEND | OBLOCKEND_COMING_SOON | OBLOCKEND_IS_HERE | OTHEN | OELSE | OLET(_)
- | OBINDER _ | BINDER _ | ODO | OWITH | OFUNCTION | OFUN | ORESET | ODUMMY _ | DO_BANG
+ | OBINDER _ | OAND_BANG _ | BINDER _ | ODO | OWITH | OFUNCTION | OFUN | ORESET | ODUMMY _ | DO_BANG
| ODO_BANG | YIELD _ | YIELD_BANG _ | OINTERFACE_MEMBER
| ELIF | RARROW | LARROW | SIG | STRUCT
| UPCAST | DOWNCAST | NULL | RESERVED | MODULE | AND | AS | ASSERT | ASR
| DOWNTO | EXCEPTION | FALSE | FOR | FUN | FUNCTION
| FINALLY | LAZY | MATCH | MATCH_BANG | MUTABLE | NEW | OF | OPEN | OR | VOID | EXTERN
| INTERFACE | REC | TO | TRUE | TRY | TYPE | VAL | INLINE | WHEN | WHILE | WITH
- | IF | THEN | ELSE | DO | DONE | LET(_) | IN (*| NAMESPACE*) | CONST
+ | IF | THEN | ELSE | DO | DONE | LET _ | AND_BANG _ | IN | CONST
| HIGH_PRECEDENCE_PAREN_APP | FIXED
| HIGH_PRECEDENCE_BRACK_APP
| TYPE_COMING_SOON | TYPE_IS_HERE | MODULE_COMING_SOON | MODULE_IS_HERE ->
diff --git a/src/fsharp/service/ServiceParseTreeWalk.fs b/src/fsharp/service/ServiceParseTreeWalk.fs
index eeab436524f..a1c42f7fa75 100755
--- a/src/fsharp/service/ServiceParseTreeWalk.fs
+++ b/src/fsharp/service/ServiceParseTreeWalk.fs
@@ -473,10 +473,16 @@ module public AstTraversal =
| SynExpr.ImplicitZero (_range) -> None
| SynExpr.YieldOrReturn (_, synExpr, _range) -> traverseSynExpr synExpr
| SynExpr.YieldOrReturnFrom (_, synExpr, _range) -> traverseSynExpr synExpr
- | SynExpr.LetOrUseBang (_sequencePointInfoForBinding, _, _, synPat, synExpr, synExpr2, _range) ->
- [dive synPat synPat.Range traversePat
- dive synExpr synExpr.Range traverseSynExpr
- dive synExpr2 synExpr2.Range traverseSynExpr]
+ | SynExpr.LetOrUseBang(_sequencePointInfoForBinding, _, _, synPat, synExpr, andBangSynExprs, synExpr2, _range) ->
+ [
+ yield dive synPat synPat.Range traversePat
+ yield dive synExpr synExpr.Range traverseSynExpr
+ yield!
+ [ for (_,_,_,andBangSynPat,andBangSynExpr,_) in andBangSynExprs do
+ yield (dive andBangSynPat andBangSynPat.Range traversePat)
+ yield (dive andBangSynExpr andBangSynExpr.Range traverseSynExpr)]
+ yield dive synExpr2 synExpr2.Range traverseSynExpr
+ ]
|> pick expr
| SynExpr.MatchBang (_sequencePointInfoForBinding, synExpr, synMatchClauseList, _range) ->
[yield dive synExpr synExpr.Range traverseSynExpr
diff --git a/src/fsharp/service/ServiceStructure.fs b/src/fsharp/service/ServiceStructure.fs
index 56f2312da46..8df0fedbb89 100644
--- a/src/fsharp/service/ServiceStructure.fs
+++ b/src/fsharp/service/ServiceStructure.fs
@@ -245,14 +245,21 @@ module Structure =
| SynExpr.DoBang (e, r) ->
rcheck Scope.Do Collapse.Below r <| Range.modStart 3 r
parseExpr e
- | SynExpr.LetOrUseBang (_, _, _, pat, e1, e2, _) ->
- // for `let!` or `use!` the pattern begins at the end of the keyword so that
- // this scope can be used without adjustment if there is no `=` on the same line
- // if there is an `=` the range will be adjusted during the tooltip creation
- let r = Range.endToEnd pat.Range e1.Range
- rcheck Scope.LetOrUseBang Collapse.Below r r
- parseExpr e1
- parseExpr e2
+ | SynExpr.LetOrUseBang (_, _, _, pat, eLet, es, eBody, _) ->
+ [
+ yield eLet
+ yield! [ for (_,_,_,_,eAndBang,_) in es do yield eAndBang ]
+ ]
+ |> List.iter (fun e ->
+ // for `let!`, `use!` or `and!` the pattern begins at the end of the
+ // keyword so that this scope can be used without adjustment if there is no `=`
+ // on the same line. If there is an `=` the range will be adjusted during the
+ // tooltip creation
+ let r = Range.endToEnd pat.Range e.Range
+ rcheck Scope.LetOrUseBang Collapse.Below r r
+ parseExpr e
+ )
+ parseExpr eBody
| SynExpr.For (_, _, _, _, _, e, r)
| SynExpr.ForEach (_, _, _, _, _, e, r) ->
rcheck Scope.For Collapse.Below r r
diff --git a/src/fsharp/service/ServiceUntypedParse.fs b/src/fsharp/service/ServiceUntypedParse.fs
index f1422794746..399b3e87914 100755
--- a/src/fsharp/service/ServiceUntypedParse.fs
+++ b/src/fsharp/service/ServiceUntypedParse.fs
@@ -322,9 +322,12 @@ type FSharpParseFileResults(errors: FSharpErrorInfo[], input: Ast.ParsedInput op
yield! walkExpr false e2
yield! walkExpr false e3
- | SynExpr.LetOrUseBang (spBind, _, _, _, e1, e2, _) ->
+ | SynExpr.LetOrUseBang (spBind, _, _, _, e1, es, e2, _) ->
yield! walkBindSeqPt spBind
yield! walkExpr true e1
+ for (andBangSpBind,_,_,_,eAndBang,_) in es do
+ yield! walkBindSeqPt andBangSpBind
+ yield! walkExpr true eAndBang
yield! walkExpr true e2
| SynExpr.MatchBang (spBind, e, cl, _) ->
@@ -880,7 +883,14 @@ module UntypedParseImpl =
| SynExpr.Match (_, e, synMatchClauseList, _)
| SynExpr.MatchBang (_, e, synMatchClauseList, _) ->
walkExprWithKind parentKind e |> Option.orElse (List.tryPick walkClause synMatchClauseList)
- | SynExpr.LetOrUseBang (_, _, _, _, e1, e2, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2]
+ | SynExpr.LetOrUseBang(_, _, _, _, e1, es, e2, _) ->
+ [
+ yield e1
+ for (_,_,_,_,eAndBang,_) in es do
+ yield eAndBang
+ yield e2
+ ]
+ |> List.tryPick (walkExprWithKind parentKind)
| SynExpr.DoBang (e, _) -> walkExprWithKind parentKind e
| SynExpr.TraitCall (ts, sign, e, _) ->
List.tryPick walkTypar ts
diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf
index a2e4bf20810..3d85d19f7f4 100644
--- a/src/fsharp/xlf/FSComp.txt.cs.xlf
+++ b/src/fsharp/xlf/FSComp.txt.cs.xlf
@@ -57,6 +57,11 @@
Algoritmus {0} není podporovaný.
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
Atributy nejde použít pro rozšíření typů.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.Není definovaný obor názvů {0}.
diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf
index baf48ce914b..d3266324ea4 100644
--- a/src/fsharp/xlf/FSComp.txt.de.xlf
+++ b/src/fsharp/xlf/FSComp.txt.de.xlf
@@ -57,6 +57,11 @@
Algorithmus "{0}" wird nicht unterstützt
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
Attribute können nicht auf Typerweiterungen angewendet werden.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.Der Namespace "{0}" ist nicht definiert.
diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf
index 1d82a7a42cf..0fbf10ee041 100644
--- a/src/fsharp/xlf/FSComp.txt.es.xlf
+++ b/src/fsharp/xlf/FSComp.txt.es.xlf
@@ -57,6 +57,11 @@
No se admite el algoritmo '{0}'
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
Los atributos no se pueden aplicar a las extensiones de tipo.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.El espacio de nombres "{0}" no está definido.
diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf
index 54296abddfd..208b5df146f 100644
--- a/src/fsharp/xlf/FSComp.txt.fr.xlf
+++ b/src/fsharp/xlf/FSComp.txt.fr.xlf
@@ -57,6 +57,11 @@
Algorithme '{0}' non pris en charge
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
Impossible d'appliquer des attributs aux extensions de type.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.L'espace de noms '{0}' n'est pas défini.
diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf
index 850e1233e6a..87607c68dde 100644
--- a/src/fsharp/xlf/FSComp.txt.it.xlf
+++ b/src/fsharp/xlf/FSComp.txt.it.xlf
@@ -57,6 +57,11 @@
L'algoritmo '{0}' non è supportato
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
Gli attributi non possono essere applicati a estensioni di tipo.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.Lo spazio dei nomi '{0}' non è definito.
diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf
index 9267524fe89..fc807fd3da9 100644
--- a/src/fsharp/xlf/FSComp.txt.ja.xlf
+++ b/src/fsharp/xlf/FSComp.txt.ja.xlf
@@ -57,6 +57,11 @@
アルゴリズム '{0}' はサポートされていません
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
属性を型拡張に適用することはできません。
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.名前空間 '{0}' が定義されていません。
diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf
index 9aab61aa0f9..4354b83a019 100644
--- a/src/fsharp/xlf/FSComp.txt.ko.xlf
+++ b/src/fsharp/xlf/FSComp.txt.ko.xlf
@@ -57,6 +57,11 @@
{0}' 알고리즘은 지원되지 않습니다.
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
형식 확장에 특성을 적용할 수 없습니다.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.'{0}' 네임스페이스가 정의되지 않았습니다.
diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf
index 07c155e3203..2f9150028e5 100644
--- a/src/fsharp/xlf/FSComp.txt.pl.xlf
+++ b/src/fsharp/xlf/FSComp.txt.pl.xlf
@@ -57,6 +57,11 @@
Algorytm „{0}” nie jest obsługiwany
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
Atrybutów nie można stosować do rozszerzeń typu.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.Nie zdefiniowano przestrzeni nazw „{0}”.
diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf
index d6a95f10f37..f09542103c3 100644
--- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf
+++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf
@@ -57,6 +57,11 @@
Algoritmo '{0}' sem suporte
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
Os atributos não podem ser aplicados às extensões de tipo.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.O namespace '{0}' não está definido.
diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf
index d364e6e039c..0460038d6f9 100644
--- a/src/fsharp/xlf/FSComp.txt.ru.xlf
+++ b/src/fsharp/xlf/FSComp.txt.ru.xlf
@@ -57,6 +57,11 @@
Алгоритм "{0}" не поддерживается
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
Атрибуты не могут быть применены к расширениям типа.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.Пространство имен "{0}" не определено.
diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf
index 2f05dd2afee..8df54eda5f9 100644
--- a/src/fsharp/xlf/FSComp.txt.tr.xlf
+++ b/src/fsharp/xlf/FSComp.txt.tr.xlf
@@ -57,6 +57,11 @@
{0}' algoritması desteklenmiyor
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
Öznitelikler tür uzantılarına uygulanamaz.
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.'{0}' ad alanı tanımlı değil.
diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf
index 9ee2a500ffe..daf8925fab2 100644
--- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf
+++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf
@@ -57,6 +57,11 @@
不支持算法“{0}”
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
属性不可应用于类型扩展。
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.未定义命名空间“{0}”。
diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf
index ce66cb1b949..3fe7318b45e 100644
--- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf
+++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf
@@ -57,6 +57,11 @@
不支援演算法 '{0}'
+
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+ This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature.
+
+ This is the wrong anonymous record. It should have the fields {0}.This is the wrong anonymous record. It should have the fields {0}.
@@ -77,6 +82,16 @@
屬性無法套用到類型延伸模組。
+
+ use! may not be combined with and!
+ use! may not be combined with and!
+
+
+
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+ The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '{0}' method or appropriate 'MergeSource' and 'Bind' methods
+
+ The namespace '{0}' is not defined.未定義命名空間 '{0}'。
diff --git a/src/fsharp/xlf/FSStrings.cs.xlf b/src/fsharp/xlf/FSStrings.cs.xlf
index b998717df6e..c5ba4efd986 100644
--- a/src/fsharp/xlf/FSStrings.cs.xlf
+++ b/src/fsharp/xlf/FSStrings.cs.xlf
@@ -1627,6 +1627,11 @@
symbol |}
+
+ keyword 'and!'
+ keyword 'and!'
+
+