From 7bcdfba44bc7cd4abf6b2a17ae47a24f73088e1f Mon Sep 17 00:00:00 2001 From: "Kevin Ransom (msft)" Date: Mon, 8 Apr 2024 06:11:06 -0700 Subject: [PATCH 1/8] Fix 16071 --- FSharp.DependencyManager.Nuget ignoring sources (#16991) * Fix 16071 * tweaks * Automated command ran: fantomas Co-authored-by: KevinRansom <5175830+KevinRansom@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Petr --- .../FSharp.DependencyManager.Utilities.fs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Utilities.fs b/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Utilities.fs index 875ccec4dd2..3cbac354977 100644 --- a/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Utilities.fs +++ b/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.Utilities.fs @@ -320,10 +320,9 @@ module internal Utilities = // https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json // Use enabled feeds only (see NuGet.Commands.ListSourceRunner.Run) and strip off the flags. let pattern = - @"(\s*\d+\.+\s*)(?'name'\S*)(\s*)\[(?'enabled'Enabled|Disabled)\](\s*)$(\s*)(?'uri'\S*)" + @"(\s*\d+\.+\s*)(?'name'\S*)(\s*)\[(?'enabled'Enabled|Disabled)\](\s*)(?'uri'[^\0\r\n]*)" - let regex = - new Regex(pattern, RegexOptions.Multiline ||| RegexOptions.ExplicitCapture) + let regex = new Regex(pattern, RegexOptions.ExplicitCapture) let sourcelist = String.concat Environment.NewLine stdOut From 099340946d6a515c69cd5cc3d93ccd8055d31e87 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Mon, 8 Apr 2024 19:12:35 +0200 Subject: [PATCH 2/8] Fix StackOverflow in big-ish nested CEs (#17002) * Fix StackOverflow in big-ish nested CEs * Automated command ran: fantomas Co-authored-by: vzarytovskii <1260985+vzarytovskii@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../Checking/CheckComputationExpressions.fs | 152 ++++++++++-------- 1 file changed, 81 insertions(+), 71 deletions(-) diff --git a/src/Compiler/Checking/CheckComputationExpressions.fs b/src/Compiler/Checking/CheckComputationExpressions.fs index 3384b247b1f..2aa454f9508 100644 --- a/src/Compiler/Checking/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/CheckComputationExpressions.fs @@ -2596,83 +2596,93 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol trans CompExprTranslationPass.Initial CustomOperationsMode.Denied emptyVarSpace comp id and trans firstTry q varSpace comp translatedCtxt = - match tryTrans firstTry q varSpace comp translatedCtxt with - | Some e -> e - | None -> - // This only occurs in final position in a sequence - match comp with - // "do! expr;" in final position is treated as { let! () = expr in return () } when Return is provided (and no Zero with Default attribute is available) or as { let! () = expr in zero } otherwise - | SynExpr.DoBang(rhsExpr, m) -> - let mUnit = rhsExpr.Range - let rhsExpr = mkSourceExpr rhsExpr + cenv.stackGuard.Guard + <| fun () -> + match tryTrans firstTry q varSpace comp translatedCtxt with + | Some e -> e + | None -> + // This only occurs in final position in a sequence + match comp with + // "do! expr;" in final position is treated as { let! () = expr in return () } when Return is provided (and no Zero with Default attribute is available) or as { let! () = expr in zero } otherwise + | SynExpr.DoBang(rhsExpr, m) -> + let mUnit = rhsExpr.Range + let rhsExpr = mkSourceExpr rhsExpr - if isQuery then - error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), m)) + if isQuery then + error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), m)) - let bodyExpr = - if - isNil ( - TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Return" builderTy + let bodyExpr = + if + isNil ( + TryFindIntrinsicOrExtensionMethInfo + ResultCollectionSettings.AtMostOneResult + cenv + env + m + ad + "Return" + builderTy + ) + then + SynExpr.ImplicitZero m + else + match + TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Zero" builderTy + with + | minfo :: _ when MethInfoHasAttribute cenv.g m cenv.g.attrib_DefaultValueAttribute minfo -> + SynExpr.ImplicitZero m + | _ -> SynExpr.YieldOrReturn((false, true), SynExpr.Const(SynConst.Unit, m), m) + + let letBangBind = + SynExpr.LetOrUseBang( + DebugPointAtBinding.NoneAtDo, + false, + false, + SynPat.Const(SynConst.Unit, mUnit), + rhsExpr, + [], + bodyExpr, + m, + SynExprLetOrUseBangTrivia.Zero ) - then - SynExpr.ImplicitZero m - else - match - TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Zero" builderTy - with - | minfo :: _ when MethInfoHasAttribute cenv.g m cenv.g.attrib_DefaultValueAttribute minfo -> SynExpr.ImplicitZero m - | _ -> SynExpr.YieldOrReturn((false, true), SynExpr.Const(SynConst.Unit, m), m) - let letBangBind = - SynExpr.LetOrUseBang( - DebugPointAtBinding.NoneAtDo, - false, - false, - SynPat.Const(SynConst.Unit, mUnit), - rhsExpr, - [], - bodyExpr, - m, - SynExprLetOrUseBangTrivia.Zero - ) - - trans CompExprTranslationPass.Initial q varSpace letBangBind translatedCtxt + trans CompExprTranslationPass.Initial q varSpace letBangBind translatedCtxt - // "expr;" in final position is treated as { expr; zero } - // Suppress the sequence point on the "zero" - | _ -> - // Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore comp - if isQuery && checkForBinaryApp comp then - trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) translatedCtxt - else - if isQuery && not comp.IsArbExprAndThusAlreadyReportedError then - match comp with - | SynExpr.JoinIn _ -> () // an error will be reported later when we process innerComp1 as a sequential - | _ -> errorR (Error(FSComp.SR.tcUnrecognizedQueryOperator (), comp.RangeOfFirstPortion)) - - trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) (fun holeFill -> - let fillExpr = - if enableImplicitYield then - let implicitYieldExpr = mkSynCall "Yield" comp.Range [ comp ] - - SynExpr.SequentialOrImplicitYield( - DebugPointAtSequential.SuppressExpr, - comp, - holeFill, - implicitYieldExpr, - comp.Range - ) - else - SynExpr.Sequential( - DebugPointAtSequential.SuppressExpr, - true, - comp, - holeFill, - comp.Range, - SynExprSequentialTrivia.Zero - ) + // "expr;" in final position is treated as { expr; zero } + // Suppress the sequence point on the "zero" + | _ -> + // Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore comp + if isQuery && checkForBinaryApp comp then + trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) translatedCtxt + else + if isQuery && not comp.IsArbExprAndThusAlreadyReportedError then + match comp with + | SynExpr.JoinIn _ -> () // an error will be reported later when we process innerComp1 as a sequential + | _ -> errorR (Error(FSComp.SR.tcUnrecognizedQueryOperator (), comp.RangeOfFirstPortion)) + + trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) (fun holeFill -> + let fillExpr = + if enableImplicitYield then + let implicitYieldExpr = mkSynCall "Yield" comp.Range [ comp ] + + SynExpr.SequentialOrImplicitYield( + DebugPointAtSequential.SuppressExpr, + comp, + holeFill, + implicitYieldExpr, + comp.Range + ) + else + SynExpr.Sequential( + DebugPointAtSequential.SuppressExpr, + true, + comp, + holeFill, + comp.Range, + SynExprSequentialTrivia.Zero + ) - translatedCtxt fillExpr) + translatedCtxt fillExpr) and transBind q varSpace bindRange addBindDebugPoint bindName bindArgs (consumePat: SynPat) (innerComp: SynExpr) translatedCtxt = From 253c6a6ab04f5f9917db54e7de0a35bf5e0564bd Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Wed, 10 Apr 2024 07:21:09 -0400 Subject: [PATCH 3/8] Parens: some more (#17012) * Keep parens for prefix & infix apps in copy exprs * Better handling of nested arrow-sensitive constructs * Can't have bare typed exprs in records * Keep parens around unit in func/method invocation * We can't know purely from the syntax whether we need the double parens. * Handle app chains depending on pseudo-dot prec * Add space around underscores * Keep parens around hanging tuples * Handle some simple cases of #16999 * Update release notes * Update release notes --- .../.FSharp.Compiler.Service/8.0.300.md | 2 +- docs/release-notes/.VisualStudio/17.10.md | 2 +- src/Compiler/Service/SynExpr.fs | 141 +++++++-- src/Compiler/Service/SynPat.fs | 46 +++ .../CodeFixes/RemoveUnnecessaryParentheses.fs | 6 +- .../RemoveUnnecessaryParenthesesTests.fs | 271 +++++++++++++++++- 6 files changed, 435 insertions(+), 33 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index d01125b6b9d..57bc1578db3 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -8,7 +8,7 @@ * Code generated files with > 64K methods and generated symbols crash when loaded. Use infered sequence points for debugging. ([Issue #16399](https://github.com/dotnet/fsharp/issues/16399), [#PR 16514](https://github.com/dotnet/fsharp/pull/16514)) * `nameof Module` expressions and patterns are processed to link files in `--test:GraphBasedChecking`. ([PR #16550](https://github.com/dotnet/fsharp/pull/16550), [PR #16743](https://github.com/dotnet/fsharp/pull/16743)) * Graph Based Checking doesn't throw on invalid parsed input so it can be used for IDE scenarios ([PR #16575](https://github.com/dotnet/fsharp/pull/16575), [PR #16588](https://github.com/dotnet/fsharp/pull/16588), [PR #16643](https://github.com/dotnet/fsharp/pull/16643)) -* Various parenthesization API fixes. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578), [PR #16666](https://github.com/dotnet/fsharp/pull/16666), [PR #16901](https://github.com/dotnet/fsharp/pull/16901), [PR #16973](https://github.com/dotnet/fsharp/pull/16973)) +* Various parenthesization API fixes. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578), [PR #16666](https://github.com/dotnet/fsharp/pull/16666), [PR #16901](https://github.com/dotnet/fsharp/pull/16901), [PR #16973](https://github.com/dotnet/fsharp/pull/16973), [PR #17012](https://github.com/dotnet/fsharp/pull/17012)) * Keep parens for problematic exprs (`if`, `match`, etc.) in `$"{(…):N0}"`, `$"{(…),-3}"`, etc. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578)) * Fix crash in DOTNET_SYSTEM_GLOBALIZATION_INVARIANT mode [#PR 16471](https://github.com/dotnet/fsharp/pull/16471)) * Fix16572 - Fixed the preview feature enabling Is properties for union case did not work correctly with let .rec and .fsi files ([PR #16657](https://github.com/dotnet/fsharp/pull/16657)) diff --git a/docs/release-notes/.VisualStudio/17.10.md b/docs/release-notes/.VisualStudio/17.10.md index 3059b1b8868..45bcbf80406 100644 --- a/docs/release-notes/.VisualStudio/17.10.md +++ b/docs/release-notes/.VisualStudio/17.10.md @@ -1,7 +1,7 @@ ### Fixed * Show signature help mid-pipeline in more scenarios. ([PR #16462](https://github.com/dotnet/fsharp/pull/16462)) -* Various unneeded parentheses code fix improvements. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578), [PR #16666](https://github.com/dotnet/fsharp/pull/16666), [PR #16789](https://github.com/dotnet/fsharp/pull/16789), [PR #16901](https://github.com/dotnet/fsharp/pull/16901)) +* Various unneeded parentheses code fix improvements. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578), [PR #16666](https://github.com/dotnet/fsharp/pull/16666), [PR #16789](https://github.com/dotnet/fsharp/pull/16789), [PR #16901](https://github.com/dotnet/fsharp/pull/16901), [PR #17012](https://github.com/dotnet/fsharp/pull/17012)) ### Changed diff --git a/src/Compiler/Service/SynExpr.fs b/src/Compiler/Service/SynExpr.fs index 46bf646a213..2715d721fc9 100644 --- a/src/Compiler/Service/SynExpr.fs +++ b/src/Compiler/Service/SynExpr.fs @@ -472,6 +472,21 @@ module SynExpr = | SynExpr.Lambda _ as expr -> Some expr | _ -> None) + /// Matches a dangling arrow-sensitive construct. + [] + let (|ArrowSensitive|_|) = + dangling (function + | SynExpr.Match _ + | SynExpr.MatchBang _ + | SynExpr.MatchLambda _ + | SynExpr.TryWith _ + | SynExpr.Lambda _ + | SynExpr.Typed _ + | SynExpr.TypeTest _ + | SynExpr.Upcast _ + | SynExpr.Downcast _ as expr -> Some expr + | _ -> None) + /// Matches a nested dangling construct that could become problematic /// if the surrounding parens were removed. [] @@ -543,14 +558,14 @@ module SynExpr = let shouldBeParenthesizedInContext = shouldBeParenthesizedInContext getSourceLineStr let containsSensitiveIndentation = containsSensitiveIndentation getSourceLineStr + let (|StartsWith|) (s: string) = s[0] + // Matches if the given expression starts with a symbol, e.g., <@ … @>, $"…", @"…", +1, -1… let (|StartsWithSymbol|_|) = let (|TextStartsWith|) (m: range) = let line = getSourceLineStr m.StartLine line[m.StartColumn] - let (|StartsWith|) (s: string) = s[0] - function | SynExpr.Quote _ | SynExpr.InterpolatedString _ @@ -638,7 +653,9 @@ module SynExpr = SyntaxNode.SynExpr(SynExpr.App(funcExpr = SynExpr.LongIdent _ | SynExpr.DotGet _ | SynExpr.Ident _)) :: _ | SynExpr.Tuple(isStruct = false), SyntaxNode.SynExpr(SynExpr.Paren _) :: SyntaxNode.SynExpr(SynExpr.App( - funcExpr = SynExpr.LongIdent _ | SynExpr.DotGet _ | SynExpr.Ident _)) :: _ -> true + funcExpr = SynExpr.LongIdent _ | SynExpr.DotGet _ | SynExpr.Ident _)) :: _ + | SynExpr.Const(SynConst.Unit, _), + SyntaxNode.SynExpr(SynExpr.App(funcExpr = SynExpr.LongIdent _ | SynExpr.DotGet _ | SynExpr.Ident _)) :: _ -> true // Already parenthesized. | _, SyntaxNode.SynExpr(SynExpr.Paren _) :: _ -> false @@ -693,6 +710,28 @@ module SynExpr = -> true + // Hanging tuples: + // + // let _ = + // ( + // 1, 2, + // 3, 4 + // ) + // + // or + // + // [ + // 1, 2, + // 3, 4 + // (1, 2, + // 3, 4) + // ] + | SynExpr.Tuple(isStruct = false; exprs = exprs; range = range), _ when + range.StartLine <> range.EndLine + && exprs |> List.exists (fun e -> e.Range.StartColumn < range.StartColumn) + -> + true + // Check for nested matches, e.g., // // match … with … -> (…, match … with … -> … | … -> …) | … -> … @@ -781,10 +820,26 @@ module SynExpr = // (f x)[z] // (f(x))[z] // x.M(y)[z] - | _, SyntaxNode.SynExpr(SynExpr.App _) :: SyntaxNode.SynExpr(SynExpr.DotGet _ | SynExpr.DotIndexedGet _ | SynExpr.DotLambda _) :: _ - | SynExpr.App _, SyntaxNode.SynExpr(SynExpr.App(argExpr = SynExpr.ArrayOrListComputed(isArray = false))) :: _ - | _, - SyntaxNode.SynExpr(SynExpr.App _) :: SyntaxNode.SynExpr(SynExpr.App(argExpr = SynExpr.ArrayOrListComputed(isArray = false))) :: _ -> + // M(x).N <- y + | SynExpr.App _, SyntaxNode.SynExpr(SynExpr.App(argExpr = SynExpr.ArrayOrListComputed(isArray = false))) :: _ -> true + + | _, SyntaxNode.SynExpr(SynExpr.App _) :: path + | _, SyntaxNode.SynExpr(OuterBinaryExpr expr (Dot, _)) :: SyntaxNode.SynExpr(SynExpr.App _) :: path when + let rec appChainDependsOnDotOrPseudoDotPrecedence path = + match path with + | SyntaxNode.SynExpr(SynExpr.DotGet _) :: _ + | SyntaxNode.SynExpr(SynExpr.DotLambda _) :: _ + | SyntaxNode.SynExpr(SynExpr.DotIndexedGet _) :: _ + | SyntaxNode.SynExpr(SynExpr.Set _) :: _ + | SyntaxNode.SynExpr(SynExpr.DotSet _) :: _ + | SyntaxNode.SynExpr(SynExpr.DotIndexedSet _) :: _ + | SyntaxNode.SynExpr(SynExpr.DotNamedIndexedPropertySet _) :: _ + | SyntaxNode.SynExpr(SynExpr.App(argExpr = SynExpr.ArrayOrListComputed(isArray = false))) :: _ -> true + | SyntaxNode.SynExpr(SynExpr.App _) :: path -> appChainDependsOnDotOrPseudoDotPrecedence path + | _ -> false + + appChainDependsOnDotOrPseudoDotPrecedence path + -> true // The :: operator is parsed differently from other symbolic infix operators, @@ -873,23 +928,22 @@ module SynExpr = | SynExpr.TryFinally(trivia = trivia), Dangling.Try tryExpr when problematic tryExpr.Range trivia.FinallyKeyword -> true - | SynExpr.Match(clauses = clauses; trivia = { WithKeyword = withKeyword }), Dangling.Match matchOrTry when - problematic matchOrTry.Range withKeyword - || anyProblematic matchOrTry.Range clauses + | SynExpr.Match(clauses = clauses; trivia = { WithKeyword = withKeyword }), Dangling.ArrowSensitive dangling when + problematic dangling.Range withKeyword || anyProblematic dangling.Range clauses -> true - | SynExpr.MatchBang(clauses = clauses; trivia = { WithKeyword = withKeyword }), Dangling.Match matchOrTry when - problematic matchOrTry.Range withKeyword - || anyProblematic matchOrTry.Range clauses + | SynExpr.MatchBang(clauses = clauses; trivia = { WithKeyword = withKeyword }), Dangling.ArrowSensitive dangling when + problematic dangling.Range withKeyword || anyProblematic dangling.Range clauses -> true - | SynExpr.MatchLambda(matchClauses = clauses), Dangling.Match matchOrTry when anyProblematic matchOrTry.Range clauses -> true + | SynExpr.MatchLambda(matchClauses = clauses), Dangling.ArrowSensitive dangling when anyProblematic dangling.Range clauses -> + true - | SynExpr.TryWith(withCases = clauses; trivia = trivia), Dangling.Match matchOrTry when - problematic matchOrTry.Range trivia.WithKeyword - || anyProblematic matchOrTry.Range clauses + | SynExpr.TryWith(withCases = clauses; trivia = trivia), Dangling.ArrowSensitive dangling when + problematic dangling.Range trivia.WithKeyword + || anyProblematic dangling.Range clauses -> true @@ -903,12 +957,36 @@ module SynExpr = // match x with // | 3 | _ -> y) -> () // | _ -> () - | _, Dangling.Match matchOrTry when - let line = getSourceLineStr matchOrTry.Range.EndLine - let endCol = matchOrTry.Range.EndColumn - - line.Length > endCol + 1 - && line.AsSpan(endCol + 1).TrimStart(' ').StartsWith("->".AsSpan()) + | _, Dangling.ArrowSensitive dangling when + let rec ancestralTrailingArrow path = + match path with + | SyntaxNode.SynMatchClause _ :: _ -> shouldBeParenthesizedInContext path dangling + + | SyntaxNode.SynExpr(SynExpr.Tuple _) :: path + | SyntaxNode.SynExpr(SynExpr.App _) :: path + | SyntaxNode.SynExpr(SynExpr.IfThenElse _) :: path + | SyntaxNode.SynExpr(SynExpr.IfThenElse _) :: path + | SyntaxNode.SynExpr(SynExpr.Sequential _) :: path + | SyntaxNode.SynExpr(SynExpr.YieldOrReturn _) :: path + | SyntaxNode.SynExpr(SynExpr.YieldOrReturnFrom _) :: path + | SyntaxNode.SynExpr(SynExpr.Set _) :: path + | SyntaxNode.SynExpr(SynExpr.DotSet _) :: path + | SyntaxNode.SynExpr(SynExpr.DotNamedIndexedPropertySet _) :: path + | SyntaxNode.SynExpr(SynExpr.DotIndexedSet _) :: path + | SyntaxNode.SynExpr(SynExpr.LongIdentSet _) :: path + | SyntaxNode.SynExpr(SynExpr.LetOrUse _) :: path + | SyntaxNode.SynExpr(SynExpr.Lambda _) :: path + | SyntaxNode.SynExpr(SynExpr.Match _) :: path + | SyntaxNode.SynExpr(SynExpr.MatchLambda _) :: path + | SyntaxNode.SynExpr(SynExpr.MatchBang _) :: path + | SyntaxNode.SynExpr(SynExpr.TryWith _) :: path + | SyntaxNode.SynExpr(SynExpr.TryFinally _) :: path + | SyntaxNode.SynExpr(SynExpr.Do _) :: path + | SyntaxNode.SynExpr(SynExpr.DoBang _) :: path -> ancestralTrailingArrow path + + | _ -> false + + ancestralTrailingArrow outerPath -> true @@ -939,8 +1017,19 @@ module SynExpr = | SynInterpolatedStringPart.FillExpr(qualifiers = Some _) -> true | _ -> false) - | SynExpr.Record(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), Dangling.Problematic _ - | SynExpr.AnonRecd(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), Dangling.Problematic _ -> true + // { (!x) with … } + | SynExpr.Record(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), + SynExpr.App(isInfix = false; funcExpr = FuncExpr.SymbolicOperator(StartsWith('!' | '~'))) + | SynExpr.AnonRecd(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), + SynExpr.App(isInfix = false; funcExpr = FuncExpr.SymbolicOperator(StartsWith('!' | '~'))) -> false + + // { (+x) with … } + // { (x + y) with … } + // { (x |> f) with … } + // { (printfn "…"; x) with … } + | SynExpr.Record(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), (PrefixApp _ | InfixApp _ | Dangling.Problematic _) + | SynExpr.AnonRecd(copyInfo = Some(SynExpr.Paren(expr = Is inner), _)), (PrefixApp _ | InfixApp _ | Dangling.Problematic _) -> + true | SynExpr.Record(recordFields = recordFields), Dangling.Problematic _ -> let rec loop recordFields = @@ -964,8 +1053,6 @@ module SynExpr = | SynExpr.Paren _, SynExpr.Typed _ | SynExpr.Quote _, SynExpr.Typed _ - | SynExpr.AnonRecd _, SynExpr.Typed _ - | SynExpr.Record _, SynExpr.Typed _ | SynExpr.While(doExpr = SynExpr.Paren(expr = Is inner)), SynExpr.Typed _ | SynExpr.WhileBang(doExpr = SynExpr.Paren(expr = Is inner)), SynExpr.Typed _ | SynExpr.For(doBody = Is inner), SynExpr.Typed _ diff --git a/src/Compiler/Service/SynPat.fs b/src/Compiler/Service/SynPat.fs index 0016acb26d0..8ed9cd69ff1 100644 --- a/src/Compiler/Service/SynPat.fs +++ b/src/Compiler/Service/SynPat.fs @@ -127,6 +127,52 @@ module SynPat = MemberKind = SynMemberKind.PropertyGetSet | SynMemberKind.PropertyGet | SynMemberKind.PropertySet }))) :: _ -> true + // Parens must be kept when there is a multiline expression + // to the right whose offsides line would be shifted if the + // parentheses were removed from a leading pattern on the same line, e.g., + // + // match maybe with + // | Some(x) -> let y = x * 2 + // let z = 99 + // x + y + z + // | None -> 3 + // + // or + // + // let (x) = printfn "…" + // printfn "…" + | _ when + // This is arbitrary and will result in some false positives. + let maxBacktracking = 10 + + let rec wouldMoveRhsOffsides n pat path = + if n = maxBacktracking then + true + else + // This does not thoroughly search the trailing + // expression — nor does it go up the expression + // tree and search farther rightward, or look at record bindings, + // etc., etc., etc. — and will result in some false negatives. + match path with + // Expand the range to that of the outer pattern, since + // the parens may extend beyond the inner pat + | SyntaxNode.SynPat outer :: path when n = 1 -> wouldMoveRhsOffsides (n + 1) outer path + | SyntaxNode.SynPat _ :: path -> wouldMoveRhsOffsides (n + 1) pat path + + | SyntaxNode.SynExpr(SynExpr.Lambda(body = rhs)) :: _ + | SyntaxNode.SynExpr(SynExpr.LetOrUse(body = rhs)) :: _ + | SyntaxNode.SynExpr(SynExpr.LetOrUseBang(body = rhs)) :: _ + | SyntaxNode.SynBinding(SynBinding(expr = rhs)) :: _ + | SyntaxNode.SynMatchClause(SynMatchClause(resultExpr = rhs)) :: _ -> + let rhsRange = rhs.Range + rhsRange.StartLine <> rhsRange.EndLine && pat.Range.EndLine = rhsRange.StartLine + + | _ -> false + + wouldMoveRhsOffsides 1 pat path + -> + true + // () is parsed as this. | SynPat.Const(SynConst.Unit, _), _ -> true diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnnecessaryParentheses.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnnecessaryParentheses.fs index d072d2154b3..2065cf03951 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnnecessaryParentheses.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnnecessaryParentheses.fs @@ -206,8 +206,8 @@ type internal FSharpRemoveUnnecessaryParenthesesCodeFixProvider [ None | _, '=', (Punctuation | Symbol) -> Some ShouldPutSpaceBefore - | _, LetterOrDigit, '(' -> None - | _, (LetterOrDigit | '`'), _ -> Some ShouldPutSpaceBefore + | _, ('_' | LetterOrDigit), '(' -> None + | _, ('_' | LetterOrDigit | '`'), _ -> Some ShouldPutSpaceBefore | _, (Punctuation | Symbol), (Punctuation | Symbol) -> Some ShouldPutSpaceBefore | _ -> None @@ -219,7 +219,7 @@ type internal FSharpRemoveUnnecessaryParenthesesCodeFixProvider [ None | _, ('+' | '-' | '%' | '&' | '!' | '~') -> None | (Punctuation | Symbol), (Punctuation | Symbol | LetterOrDigit) -> Some ShouldPutSpaceAfter - | LetterOrDigit, LetterOrDigit -> Some ShouldPutSpaceAfter + | ('_' | LetterOrDigit), ('_' | LetterOrDigit) -> Some ShouldPutSpaceAfter | _ -> None let (|WouldTurnInfixIntoPrefix|_|) (s: string) = diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs index 13227d8eb42..7370b63b1b3 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs @@ -388,6 +388,21 @@ let _ = | _ -> 3) " + "match () with () when (box x :? int) -> () | _ -> ()", "match () with () when (box x :? int) -> () | _ -> ()" + + " + match () with + | () when (box x :? int) + -> () + | _ -> () + ", + " + match () with + | () when box x :? int + -> () + | _ -> () + " + // Do "do (ignore 3)", "do ignore 3" @@ -962,6 +977,23 @@ in x x " + " + [ + 1, 2, + 3, 4 + (1, 2, + 3, 4) + ] + ", + " + [ + 1, 2, + 3, 4 + (1, 2, + 3, 4) + ] + " + // IfThenElse "if (3 = 3) then 3 else 3", "if 3 = 3 then 3 else 3" "if 3 = 3 then (3) else 3", "if 3 = 3 then 3 else 3" @@ -1265,8 +1297,11 @@ in x memberData { // Paren "id ()", "id ()" - "id (())", "id ()" + "id (())", "id (())" "id ((x))", "id (x)" + "x.M(())", "x.M(())" + "x.M (())", "x.M (())" + "x.M.N(())", "x.M.N(())" // Quote "id (<@ x @>)", "id <@ x @>" @@ -1368,6 +1403,11 @@ in x "{| A = (fun () -> ()); B = 3 |}", "{| A = (fun () -> ()); B = 3 |}" "{| A = (let x = 3 in x); B = 3 |}", "{| A = (let x = 3 in x); B = 3 |}" "{| (try {||} with _ -> reraise ()) with A = 4 |}", "{| (try {||} with _ -> reraise ()) with A = 4 |}" + "{| (x |> id) with A = 4 |}", "{| (x |> id) with A = 4 |}" + "{| (box x :?> T) with A = 4 |}", "{| (box x :?> T) with A = 4 |}" + "{| (+x) with A = 4 |}", "{| (+x) with A = 4 |}" + "{| (!x) with A = 4 |}", "{| !x with A = 4 |}" + "{| (! x) with A = 4 |}", "{| ! x with A = 4 |}" " {| A = (fun () -> ()) @@ -1407,6 +1447,17 @@ in x A = 4 |} " + " + {| + A = ([] : int list list) + |} + ", + " + {| + A = ([] : int list list) + |} + " + // ArrayOrList "id ([])", "id []" "id ([||])", "id [||]" @@ -1420,6 +1471,11 @@ in x "{ A = (let x = 3 in x); B = 3 }", "{ A = (let x = 3 in x); B = 3 }" "{ A.B.C.D.X = (match () with () -> ()); A.B.C.D.Y = 3 }", "{ A.B.C.D.X = (match () with () -> ()); A.B.C.D.Y = 3 }" "{ (try { A = 3 } with _ -> reraise ()) with A = 4 }", "{ (try { A = 3 } with _ -> reraise ()) with A = 4 }" + "{ (x |> id) with A = 4 }", "{ (x |> id) with A = 4 }" + "{ (box x :?> T) with A = 4 }", "{ (box x :?> T) with A = 4 }" + "{ (+x) with A = 4 }", "{ (+x) with A = 4 }" + "{ (!x) with A = 4 }", "{ !x with A = 4 }" + "{ (! x) with A = 4 }", "{ ! x with A = 4 }" " { A = (fun () -> ()) @@ -1459,6 +1515,17 @@ in x A = 4 } " + " + { + A = ([] : int list list) + } + ", + " + { + A = ([] : int list list) + } + " + // New "id (new obj())", "id (new obj())" @@ -1615,6 +1682,11 @@ in x "id(id)id", "id id id" "id (id id) id", "id (id id) id" // While it would be valid in this case to remove the parens, it is not in general. "id ((<|) ((+) x)) y", "id ((<|) ((+) x)) y" + "(int)x", "int x" + "(uint32)x", "uint32 x" + "(int)_x", "int _x" + "(uint32)_x", "uint32 _x" + "(f_)x", "f_ x" "~~~(-1)", "~~~ -1" "~~~(-x)", "~~~(-x)" @@ -1712,6 +1784,9 @@ in x "let mutable x = y in (x <- z) |> id", "let mutable x = y in (x <- z) |> id" "let mutable x = y in ((); x <- z) |> id", "let mutable x = y in ((); x <- z) |> id" "let mutable x = y in (if true then x <- z) |> id", "let mutable x = y in (if true then x <- z) |> id" + "M(x).N <- y", "M(x).N <- y" + "A(x).B(x).M(x).N <- y", "A(x).B(x).M(x).N <- y" + "A(x)(x)(x).N <- y", "A(x)(x)(x).N <- y" // DotIndexedGet "id ([x].[y])", "id [x].[y]" @@ -2119,6 +2194,93 @@ let _ = (2 + 2) { return 5 } [] let ``Infix operators with leading and trailing chars`` expr expected = expectFix expr expected + let failing = + memberData { + // See https://github.com/dotnet/fsharp/issues/16999 + """ + (x) < (printfn $"{y}" + y) + """, + """ + (x) < (printfn $"{y}" + y) + """ + + // See https://github.com/dotnet/fsharp/issues/16999 + """ + id (x) < (printfn $"{y}" + y) + """, + """ + id (x) < (printfn $"{y}" + y) + """ + + // See https://github.com/dotnet/fsharp/issues/16999 + """ + id (id (id (x))) < (printfn $"{y}" + y) + """, + """ + id (id (id (x))) < (printfn $"{y}" + y) + """ + + // See https://github.com/dotnet/fsharp/issues/16999 + """ + (x) <> z && x < (printfn $"{y}" + y) + """, + """ + (x) <> z && x < (printfn $"{y}" + y) + """ + + // See https://github.com/dotnet/fsharp/issues/16999 + """ + (x) < match y with + | Some y -> let y = y + y + | y) + """, + """ + (x) < match y with + | Some y -> let y = y + y + | y) + """ + + // See https://github.com/dotnet/fsharp/issues/16999 + """ + printfn "1"; printfn ("2"); (id <| match y with Some y -> let y = y + y + | None -> 3) + """, + """ + printfn "1"; printfn ("2"); (id <| match y with Some y -> let y = y + y + | None -> 3) + """ + + // See https://github.com/dotnet/fsharp/issues/16999 + """ + printfn ("1" + ); printfn "2"; (id <| match y with Some y -> let y = y + y + | None -> 3) + """, + """ + printfn ("1" + ); printfn "2"; (id <| match y with Some y -> let y = y + y + | None -> 3) + """ + } + + [] + let ``Failing tests`` expr expected = + Assert.ThrowsAsync(fun () -> expectFix expr expected) + module Patterns = type SynPat = | Const of string @@ -2805,6 +2967,113 @@ module Patterns = | _ -> () " + " + match maybe with + | Some(x) -> let y = x * 2 + let z = 99 + x + y + z + | None -> 3 + ", + " + match maybe with + | Some(x) -> let y = x * 2 + let z = 99 + x + y + z + | None -> 3 + " + + " + match maybe with + | Some(x) -> id <| (let y = x * 2 + let z = 99 + x + y + z) + | None -> 3 + ", + " + match maybe with + | Some(x) -> id <| (let y = x * 2 + let z = 99 + x + y + z) + | None -> 3 + " + + " + match maybe with + | Some( + x + ) -> let y = x * 2 + let z = 99 + x + y + z + | None -> 3 + ", + " + match maybe with + | Some( + x + ) -> let y = x * 2 + let z = 99 + x + y + z + | None -> 3 + " + + " + match q with + | { A = Some( + x + ) } -> let y = x * 2 + let z = 99 + x + y + z + | { A = None } -> 3 + ", + " + match q with + | { A = Some( + x + ) } -> let y = x * 2 + let z = 99 + x + y + z + | { A = None } -> 3 + " + + // This removal is somewhat ugly, albeit valid. + // Maybe we can make it nicer someday. + " + match q with + | { A = Some ( + x + ) + } -> let y = x * 2 + let z = 99 + x + y + z + | { A = None } -> 3 + ", + " + match q with + | { A = Some + x + } -> let y = x * 2 + let z = 99 + x + y + z + | { A = None } -> 3 + " + + " + match q with + | { A = Some (x) + } -> let y = x * 2 + let z = 99 + x + y + z + | { A = None } -> 3 + ", + " + match q with + | { A = Some x + } -> let y = x * 2 + let z = 99 + x + y + z + | { A = None } -> 3 + " + " type T () = member this.Item From 6b6cca98093b841086df987244719a7708fcc882 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Wed, 10 Apr 2024 08:16:43 -0400 Subject: [PATCH 4/8] =?UTF-8?q?Expected=20=E2=86=94=20actual=20(#17014)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FSharp.Core/PrimTypes.fs | 226 +++++++++--------- 1 file changed, 113 insertions(+), 113 deletions(-) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs index b07b0d43999..e2b6882e146 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs @@ -831,63 +831,63 @@ module internal RangeTestsHelpers = Assert.Throws (typeof, (fun () -> regressionExceptionAfterEndVariableStepIntegralRange zero two)) |> ignore let inline common (min0, min1, min2, min3) (max0, max1, max2, max3) (zero, one, two, three) = - Assert.AreEqual ({min0 .. min3}, seq {yield min0; yield min1; yield min2; yield min3}) - Assert.AreEqual ({min0 .. one .. min3}, seq {min0; min1; min2; min3}) - Assert.AreEqual ({min0 .. two .. min3}, seq {min0; min2}) - Assert.AreEqual ({min0 .. three .. min3}, seq {min0; min3}) - - Assert.AreEqual ([min0 .. min3], [min0; min1; min2; min3]) - Assert.AreEqual ([min0 .. one .. min3], [min0; min1; min2; min3]) - Assert.AreEqual ([min0 .. two .. min3], [min0; min2]) - Assert.AreEqual ([min0 .. three .. min3], [min0; min3]) - - Assert.AreEqual ([|min0 .. min3|], [|min0; min1; min2; min3|]) - Assert.AreEqual ([|min0 .. one .. min3|], [|min0; min1; min2; min3|]) - Assert.AreEqual ([|min0 .. two .. min3|], [|min0; min2|]) - Assert.AreEqual ([|min0 .. three .. min3|], [|min0; min3|]) - - Assert.AreEqual ({max3 .. max0}, seq {yield max3; yield max2; yield max1; yield max0}) - Assert.AreEqual ({max3 .. one .. max0}, seq {max3; max2; max1; max0}) - Assert.AreEqual ({max3 .. two .. max0}, seq {max3; max1}) - Assert.AreEqual ({max3 .. three .. max0}, seq {max3; max0}) - - Assert.AreEqual ([max3 .. max0], [max3; max2; max1; max0]) - Assert.AreEqual ([max3 .. one .. max0], [max3; max2; max1; max0]) - Assert.AreEqual ([max3 .. two .. max0], [max3; max1]) - Assert.AreEqual ([max3 .. three .. max0], [max3; max0]) - - Assert.AreEqual ([|max3 .. max0|], [|max3; max2; max1; max0|]) - Assert.AreEqual ([|max3 .. one .. max0|], [|max3; max2; max1; max0|]) - Assert.AreEqual ([|max3 .. two .. max0|], [|max3; max1|]) - Assert.AreEqual ([|max3 .. three .. max0|], [|max3; max0|]) - - Assert.AreEqual ({max0 .. min0}, Seq.empty) - Assert.AreEqual ({max0 .. one .. min0}, Seq.empty) - Assert.AreEqual ({max0 .. two .. min0}, Seq.empty) - Assert.AreEqual ({max0 .. three .. min0}, Seq.empty) - - Assert.AreEqual ([max0 .. min0], []) - Assert.AreEqual ([max0 .. one .. min0], []) - Assert.AreEqual ([max0 .. two .. min0], []) - Assert.AreEqual ([max0 .. three .. min0], []) - - Assert.AreEqual ([|max0 .. min0|], [||]) - Assert.AreEqual ([|max0 .. one .. min0|], [||]) - Assert.AreEqual ([|max0 .. two .. min0|], [||]) - Assert.AreEqual ([|max0 .. three .. min0|], [||]) + Assert.AreEqual (seq {yield min0; yield min1; yield min2; yield min3}, {min0 .. min3}) + Assert.AreEqual (seq {min0; min1; min2; min3}, {min0 .. one .. min3}) + Assert.AreEqual (seq {min0; min2}, {min0 .. two .. min3}) + Assert.AreEqual (seq {min0; min3}, {min0 .. three .. min3}) + + Assert.AreEqual ([min0; min1; min2; min3], [min0 .. min3]) + Assert.AreEqual ([min0; min1; min2; min3], [min0 .. one .. min3]) + Assert.AreEqual ([min0; min2], [min0 .. two .. min3]) + Assert.AreEqual ([min0; min3], [min0 .. three .. min3]) + + Assert.AreEqual ([|min0; min1; min2; min3|], [|min0 .. min3|]) + Assert.AreEqual ([|min0; min1; min2; min3|], [|min0 .. one .. min3|]) + Assert.AreEqual ([|min0; min2|], [|min0 .. two .. min3|]) + Assert.AreEqual ([|min0; min3|], [|min0 .. three .. min3|]) + + Assert.AreEqual (seq {yield max3; yield max2; yield max1; yield max0}, {max3 .. max0}) + Assert.AreEqual (seq {max3; max2; max1; max0}, {max3 .. one .. max0}) + Assert.AreEqual (seq {max3; max1}, {max3 .. two .. max0}) + Assert.AreEqual (seq {max3; max0}, {max3 .. three .. max0}) + + Assert.AreEqual ([max3; max2; max1; max0], [max3 .. max0]) + Assert.AreEqual ([max3; max2; max1; max0], [max3 .. one .. max0]) + Assert.AreEqual ([max3; max1], [max3 .. two .. max0]) + Assert.AreEqual ([max3; max0], [max3 .. three .. max0]) + + Assert.AreEqual ([|max3; max2; max1; max0|], [|max3 .. max0|]) + Assert.AreEqual ([|max3; max2; max1; max0|], [|max3 .. one .. max0|]) + Assert.AreEqual ([|max3; max1|], [|max3 .. two .. max0|]) + Assert.AreEqual ([|max3; max0|], [|max3 .. three .. max0|]) + + Assert.AreEqual (Seq.empty, {max0 .. min0}) + Assert.AreEqual (Seq.empty, {max0 .. one .. min0}) + Assert.AreEqual (Seq.empty, {max0 .. two .. min0}) + Assert.AreEqual (Seq.empty, {max0 .. three .. min0}) + + Assert.AreEqual ([], [max0 .. min0]) + Assert.AreEqual ([], [max0 .. one .. min0]) + Assert.AreEqual ([], [max0 .. two .. min0]) + Assert.AreEqual ([], [max0 .. three .. min0]) + + Assert.AreEqual ([||], [|max0 .. min0|]) + Assert.AreEqual ([||], [|max0 .. one .. min0|]) + Assert.AreEqual ([||], [|max0 .. two .. min0|]) + Assert.AreEqual ([||], [|max0 .. three .. min0|]) exceptions zero one two // tests for singleStepRangeEnumerator, as it only is used if start and/or end are not the // minimum or maximum of the number range and it is counting by 1s - Assert.AreEqual ({min1 .. min3}, seq {min1; min2; min3}) - Assert.AreEqual ({max3 .. max1}, seq {max3; max2; max1}) + Assert.AreEqual (seq {min1; min2; min3}, {min1 .. min3}) + Assert.AreEqual (seq {max3; max2; max1}, {max3 .. max1}) - Assert.AreEqual ([min1 .. min3], [min1; min2; min3]) - Assert.AreEqual ([max3 .. max1], [max3; max2; max1]) + Assert.AreEqual ([min1; min2; min3], [min1 .. min3]) + Assert.AreEqual ([max3; max2; max1], [max3 .. max1]) - Assert.AreEqual ([|min1 .. min3|], [|min1; min2; min3|]) - Assert.AreEqual ([|max3 .. max1|], [|max3; max2; max1|]) + Assert.AreEqual ([|min1; min2; min3|], [|min1 .. min3|]) + Assert.AreEqual ([|max3; max2; max1|], [|max3 .. max1|]) let inline signed zero one min0 max0 = let two = one + one @@ -903,71 +903,71 @@ module internal RangeTestsHelpers = common (min0, min1, min2, min3) (max0, max1, max2, max3) (zero, one, two, three) - Assert.AreEqual ({min0 .. max0 .. max0}, seq { min0; min0 + max0; min0 + max0 + max0 }) - Assert.AreEqual ({min0 .. max1 .. max0}, seq { min0; min0 + max1; min0 + max1 + max1 }) - Assert.AreEqual ({min0 .. max2 .. max0}, seq { min0; min0 + max2; min0 + max2 + max2 }) - Assert.AreEqual ({min0 .. max3 .. max0}, seq { min0; min0 + max3; min0 + max3 + max3 }) + Assert.AreEqual (seq { min0; min0 + max0; min0 + max0 + max0 }, {min0 .. max0 .. max0}) + Assert.AreEqual (seq { min0; min0 + max1; min0 + max1 + max1 }, {min0 .. max1 .. max0}) + Assert.AreEqual (seq { min0; min0 + max2; min0 + max2 + max2 }, {min0 .. max2 .. max0}) + Assert.AreEqual (seq { min0; min0 + max3; min0 + max3 + max3 }, {min0 .. max3 .. max0}) - Assert.AreEqual ([min0 .. max0 .. max0], [ min0; min0 + max0; min0 + max0 + max0 ]) - Assert.AreEqual ([min0 .. max1 .. max0], [ min0; min0 + max1; min0 + max1 + max1 ]) - Assert.AreEqual ([min0 .. max2 .. max0], [ min0; min0 + max2; min0 + max2 + max2 ]) - Assert.AreEqual ([min0 .. max3 .. max0], [ min0; min0 + max3; min0 + max3 + max3 ]) + Assert.AreEqual ([ min0; min0 + max0; min0 + max0 + max0 ], [min0 .. max0 .. max0]) + Assert.AreEqual ([ min0; min0 + max1; min0 + max1 + max1 ], [min0 .. max1 .. max0]) + Assert.AreEqual ([ min0; min0 + max2; min0 + max2 + max2 ], [min0 .. max2 .. max0]) + Assert.AreEqual ([ min0; min0 + max3; min0 + max3 + max3 ], [min0 .. max3 .. max0]) - Assert.AreEqual ([|min0 .. max0 .. max0|], [| min0; min0 + max0; min0 + max0 + max0 |]) - Assert.AreEqual ([|min0 .. max1 .. max0|], [| min0; min0 + max1; min0 + max1 + max1 |]) - Assert.AreEqual ([|min0 .. max2 .. max0|], [| min0; min0 + max2; min0 + max2 + max2 |]) - Assert.AreEqual ([|min0 .. max3 .. max0|], [| min0; min0 + max3; min0 + max3 + max3 |]) + Assert.AreEqual ([| min0; min0 + max0; min0 + max0 + max0 |], [|min0 .. max0 .. max0|]) + Assert.AreEqual ([| min0; min0 + max1; min0 + max1 + max1 |], [|min0 .. max1 .. max0|]) + Assert.AreEqual ([| min0; min0 + max2; min0 + max2 + max2 |], [|min0 .. max2 .. max0|]) + Assert.AreEqual ([| min0; min0 + max3; min0 + max3 + max3 |], [|min0 .. max3 .. max0|]) - Assert.AreEqual ({min3 .. -one .. min0}, seq {min3; min2; min1; min0}) - Assert.AreEqual ({min3 .. -two .. min0}, seq {min3; min1}) - Assert.AreEqual ({min3 .. -three .. min0}, seq {min3; min0}) + Assert.AreEqual (seq {min3; min2; min1; min0}, {min3 .. -one .. min0}) + Assert.AreEqual (seq {min3; min1}, {min3 .. -two .. min0}) + Assert.AreEqual (seq {min3; min0}, {min3 .. -three .. min0}) - Assert.AreEqual ([min3 .. -one .. min0], [min3; min2; min1; min0]) - Assert.AreEqual ([min3 .. -two .. min0], [min3; min1]) - Assert.AreEqual ([min3 .. -three .. min0], [min3; min0]) + Assert.AreEqual ([min3; min2; min1; min0], [min3 .. -one .. min0]) + Assert.AreEqual ([min3; min1], [min3 .. -two .. min0]) + Assert.AreEqual ([min3; min0], [min3 .. -three .. min0]) - Assert.AreEqual ([|min3 .. -one .. min0|], [|min3; min2; min1; min0|]) - Assert.AreEqual ([|min3 .. -two .. min0|], [|min3; min1|]) - Assert.AreEqual ([|min3 .. -three .. min0|], [|min3; min0|]) + Assert.AreEqual ([|min3; min2; min1; min0|], [|min3 .. -one .. min0|]) + Assert.AreEqual ([|min3; min1|], [|min3 .. -two .. min0|]) + Assert.AreEqual ([|min3; min0|], [|min3 .. -three .. min0|]) - Assert.AreEqual ({max0 .. -one .. max3}, seq {max0; max1; max2; max3}) - Assert.AreEqual ({max0 .. -two .. max3}, seq {max0; max2}) - Assert.AreEqual ({max0 .. -three .. max3}, seq {max0; max3}) + Assert.AreEqual (seq {max0; max1; max2; max3}, {max0 .. -one .. max3}) + Assert.AreEqual (seq {max0; max2}, {max0 .. -two .. max3}) + Assert.AreEqual (seq {max0; max3}, {max0 .. -three .. max3}) - Assert.AreEqual ([max0 .. -one .. max3], [max0; max1; max2; max3]) - Assert.AreEqual ([max0 .. -two .. max3], [max0; max2]) - Assert.AreEqual ([max0 .. -three .. max3], [max0; max3]) + Assert.AreEqual ([max0; max1; max2; max3], [max0 .. -one .. max3]) + Assert.AreEqual ([max0; max2], [max0 .. -two .. max3]) + Assert.AreEqual ([max0; max3], [max0 .. -three .. max3]) - Assert.AreEqual ([|max0 .. -one .. max3|], [|max0; max1; max2; max3|]) - Assert.AreEqual ([|max0 .. -two .. max3|], [|max0; max2|]) - Assert.AreEqual ([|max0 .. -three .. max3|], [|max0; max3|]) + Assert.AreEqual ([|max0; max1; max2; max3|], [|max0 .. -one .. max3|]) + Assert.AreEqual ([|max0; max2|], [|max0 .. -two .. max3|]) + Assert.AreEqual ([|max0; max3|], [|max0 .. -three .. max3|]) - Assert.AreEqual ({min0 .. -one .. max0}, Seq.empty) - Assert.AreEqual ({min0 .. -two .. max0}, Seq.empty) - Assert.AreEqual ({min0 .. -three .. max0}, Seq.empty) + Assert.AreEqual (Seq.empty, {min0 .. -one .. max0}) + Assert.AreEqual (Seq.empty, {min0 .. -two .. max0}) + Assert.AreEqual (Seq.empty, {min0 .. -three .. max0}) - Assert.AreEqual ([min0 .. -one .. max0], []) - Assert.AreEqual ([min0 .. -two .. max0], []) - Assert.AreEqual ([min0 .. -three .. max0], []) + Assert.AreEqual ([], [min0 .. -one .. max0]) + Assert.AreEqual ([], [min0 .. -two .. max0]) + Assert.AreEqual ([], [min0 .. -three .. max0]) - Assert.AreEqual ([|min0 .. -one .. max0|], [||]) - Assert.AreEqual ([|min0 .. -two .. max0|], [||]) - Assert.AreEqual ([|min0 .. -three .. max0|], [||]) + Assert.AreEqual ([||], [|min0 .. -one .. max0|]) + Assert.AreEqual ([||], [|min0 .. -two .. max0|]) + Assert.AreEqual ([||], [|min0 .. -three .. max0|]) - Assert.AreEqual ({max0 .. min0 .. min0}, seq {max0; max0 + min0}) - Assert.AreEqual ({max0 .. min1 .. min0}, seq {max0; max0 + min1; max0 + min1 + min1 }) - Assert.AreEqual ({max0 .. min2 .. min0}, seq {max0; max0 + min2; max0 + min2 + min2 }) - Assert.AreEqual ({max0 .. min3 .. min0}, seq {max0; max0 + min3; max0 + min3 + min3 }) + Assert.AreEqual (seq {max0; max0 + min0}, {max0 .. min0 .. min0}) + Assert.AreEqual (seq {max0; max0 + min1; max0 + min1 + min1 }, {max0 .. min1 .. min0}) + Assert.AreEqual (seq {max0; max0 + min2; max0 + min2 + min2 }, {max0 .. min2 .. min0}) + Assert.AreEqual (seq {max0; max0 + min3; max0 + min3 + min3 }, {max0 .. min3 .. min0}) - Assert.AreEqual ([max0 .. min0 .. min0], [max0; max0 + min0]) - Assert.AreEqual ([max0 .. min1 .. min0], [max0; max0 + min1; max0 + min1 + min1 ]) - Assert.AreEqual ([max0 .. min2 .. min0], [max0; max0 + min2; max0 + min2 + min2 ]) - Assert.AreEqual ([max0 .. min3 .. min0], [max0; max0 + min3; max0 + min3 + min3 ]) + Assert.AreEqual ([max0; max0 + min0], [max0 .. min0 .. min0]) + Assert.AreEqual ([max0; max0 + min1; max0 + min1 + min1 ], [max0 .. min1 .. min0]) + Assert.AreEqual ([max0; max0 + min2; max0 + min2 + min2 ], [max0 .. min2 .. min0]) + Assert.AreEqual ([max0; max0 + min3; max0 + min3 + min3 ], [max0 .. min3 .. min0]) - Assert.AreEqual ([|max0 .. min0 .. min0|], [|max0; max0 + min0|]) - Assert.AreEqual ([|max0 .. min1 .. min0|], [|max0; max0 + min1; max0 + min1 + min1 |]) - Assert.AreEqual ([|max0 .. min2 .. min0|], [|max0; max0 + min2; max0 + min2 + min2 |]) - Assert.AreEqual ([|max0 .. min3 .. min0|], [|max0; max0 + min3; max0 + min3 + min3 |]) + Assert.AreEqual ([|max0; max0 + min0|], [|max0 .. min0 .. min0|]) + Assert.AreEqual ([|max0; max0 + min1; max0 + min1 + min1 |], [|max0 .. min1 .. min0|]) + Assert.AreEqual ([|max0; max0 + min2; max0 + min2 + min2 |], [|max0 .. min2 .. min0|]) + Assert.AreEqual ([|max0; max0 + min3; max0 + min3 + min3 |], [|max0 .. min3 .. min0|]) let inline unsigned zero one min0 max0 = let two = one + one @@ -983,20 +983,20 @@ module internal RangeTestsHelpers = common (min0, min1, min2, min3) (max0, max1, max2, max3) (zero, one, two, three) - Assert.AreEqual ({min0 .. max0 .. max0}, seq {yield min0; yield min0 + max0}) - Assert.AreEqual ({min0 .. max1 .. max0}, seq {min0; min0 + max1}) - Assert.AreEqual ({min0 .. max2 .. max0}, seq {min0; min0 + max2}) - Assert.AreEqual ({min0 .. max3 .. max0}, seq {min0; min0 + max3}) + Assert.AreEqual (seq {yield min0; yield min0 + max0}, {min0 .. max0 .. max0}) + Assert.AreEqual (seq {min0; min0 + max1}, {min0 .. max1 .. max0}) + Assert.AreEqual (seq {min0; min0 + max2}, {min0 .. max2 .. max0}) + Assert.AreEqual (seq {min0; min0 + max3}, {min0 .. max3 .. max0}) - Assert.AreEqual ([min0 .. max0 .. max0], [min0; min0 + max0]) - Assert.AreEqual ([min0 .. max1 .. max0], [min0; min0 + max1]) - Assert.AreEqual ([min0 .. max2 .. max0], [min0; min0 + max2]) - Assert.AreEqual ([min0 .. max3 .. max0], [min0; min0 + max3]) + Assert.AreEqual ([min0; min0 + max0], [min0 .. max0 .. max0]) + Assert.AreEqual ([min0; min0 + max1], [min0 .. max1 .. max0]) + Assert.AreEqual ([min0; min0 + max2], [min0 .. max2 .. max0]) + Assert.AreEqual ([min0; min0 + max3], [min0 .. max3 .. max0]) - Assert.AreEqual ([|min0 .. max0 .. max0|], [|min0; min0 + max0|]) - Assert.AreEqual ([|min0 .. max1 .. max0|], [|min0; min0 + max1|]) - Assert.AreEqual ([|min0 .. max2 .. max0|], [|min0; min0 + max2|]) - Assert.AreEqual ([|min0 .. max3 .. max0|], [|min0; min0 + max3|]) + Assert.AreEqual ([|min0; min0 + max0|], [|min0 .. max0 .. max0|]) + Assert.AreEqual ([|min0; min0 + max1|], [|min0 .. max1 .. max0|]) + Assert.AreEqual ([|min0; min0 + max2|], [|min0 .. max2 .. max0|]) + Assert.AreEqual ([|min0; min0 + max3|], [|min0 .. max3 .. max0|]) // Note to future contributors: if the code gen for ranges is not correct, // some of these tests may loop forever or use up all available memory instead of failing outright. From 3c8490cc96c4f166cdb8d158b0e142114c826a78 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 11 Apr 2024 12:53:42 +0200 Subject: [PATCH 5/8] Fix MEF issues with options (#17015) It seems something changed about MEF import w.r.t. private members. --- vsintegration/src/FSharp.Editor/Options/EditorOptions.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs index e9b7f60252a..d260a602a7c 100644 --- a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs +++ b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs @@ -168,7 +168,7 @@ type EditorOptions() = member _.Formatting: FormattingOptions = store.Get() [)>] - member private _.SettingsStore = store + member _.SettingsStore = store member _.With value = store.Register value From 7bade311060fdb053eb3e7e89cc00f0725810283 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 11 Apr 2024 13:07:14 +0200 Subject: [PATCH 6/8] Update to 9p2 SDK (#17009) * Update to 9p2 SDK * Added PackageProjectUrl * Added RepositoryUrl * Fix sb --------- Co-authored-by: Petr --- .devcontainer/devcontainer.json | 12 +++++------- Directory.Build.props | 2 ++ eng/SourceBuildPrebuiltBaseline.xml | 6 +++--- eng/Versions.props | 2 +- global.json | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 44cf398c407..b0b82686f2c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,14 +1,12 @@ // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: { "name": "F#", - "image": "mcr.microsoft.com/dotnet/sdk:8.0", + "image": "mcr.microsoft.com/dotnet/sdk:9.0.100-preview.2", "features": { - "ghcr.io/devcontainers/features/common-utils:2": {}, - "ghcr.io/devcontainers/features/git:1": {}, - "ghcr.io/devcontainers/features/github-cli:1": { - "version": "2" - }, - "ghcr.io/devcontainers/features/dotnet:2": {} + "ghcr.io/devcontainers/features/common-utils:2.4.2": {}, + "ghcr.io/devcontainers/features/git:1.2.0": {}, + "ghcr.io/devcontainers/features/github-cli:1.0.11": {}, + "ghcr.io/devcontainers/features/dotnet:2.0.5": {} }, "hostRequirements": { "cpus": 2, diff --git a/Directory.Build.props b/Directory.Build.props index e8e24051b1d..e53ebf98156 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,8 @@ + https://github.com/dotnet/fsharp + https://github.com/dotnet/fsharp $(FSharpLangVersion) $(MSBuildThisFileDirectory) true diff --git a/eng/SourceBuildPrebuiltBaseline.xml b/eng/SourceBuildPrebuiltBaseline.xml index 18c94ed53e3..001c3d14879 100644 --- a/eng/SourceBuildPrebuiltBaseline.xml +++ b/eng/SourceBuildPrebuiltBaseline.xml @@ -9,9 +9,9 @@ These will go away when repo updates targeting to net8.0 Tracked with https://github.com/dotnet/fsharp/issues/14765 --> - - - + + + diff --git a/eng/Versions.props b/eng/Versions.props index 17d084022bd..b0215a834a2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -39,7 +39,7 @@ $(FCSMajorVersion)$(FCSMinorVersion)$(FCSBuildVersion) - 8.0.100 + 8.0.200 $(FSCorePackageVersionValue)-$(PreReleaseVersionLabel).* diff --git a/global.json b/global.json index 1d7b86d8b37..a312669c66e 100644 --- a/global.json +++ b/global.json @@ -1,17 +1,17 @@ { "sdk": { - "version": "8.0.101", + "version": "9.0.100-preview.2.24157.14", "allowPrerelease": true }, "tools": { - "dotnet": "8.0.101", + "dotnet": "9.0.100-preview.2.24157.14", "vs": { "version": "17.8", "components": [ "Microsoft.VisualStudio.Component.FSharp" ] }, - "xcopy-msbuild": "17.8.1-2" + "xcopy-msbuild": "17.8.5" }, "native-tools": { "perl": "5.38.0.1" From fae65c5274a2671f25997b7c98e1a8e5ace9b33d Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 11 Apr 2024 14:41:33 +0200 Subject: [PATCH 7/8] 17.11 versioning (#17027) --- azure-pipelines.yml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index eceff869ba2..91bf26d1340 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -29,11 +29,11 @@ variables: # Should be 'current' release branch name, i.e. 'release/dev17.10' in dotnet/fsharp/refs/heads/main, 'release/dev17.10' in dotnet/fsharp/refs/heads/release/dev17.10 and 'release/dev17.9' in dotnet/fsharp/refs/heads/release/dev17.9 # Should **never** be 'main' in dotnet/fsharp/refs/heads/main, since it will start inserting to VS twice. - name: FSharpReleaseBranchName - value: release/dev17.10 + value: release/dev17.11 # VS Insertion branch name (NOT the same as F# branch) - # Should be previous release branch in 'main' and 'main' in release branch + # Should be previous release branch or 'main' in 'main' and 'main' in release branch # (since for all *new* release branches we insert into VS main and for all *previous* releases we insert into corresponding VS release), - # i.e. 'rel/d17.9' in dotnet/fsharp/refs/heads/main and 'main' in F# dotnet/fsharp/refs/heads/release/dev17.10 + # i.e. 'rel/d17.9' *or* 'main' in dotnet/fsharp/refs/heads/main and 'main' in F# dotnet/fsharp/refs/heads/release/dev17.10 (latest release branch) - name: VSInsertionTargetBranchName value: main - name: _TeamName @@ -85,7 +85,7 @@ extends: # Signed build # #-------------------------------------------------------------------------------------------------------------------# # Localization: we only run it for specific release branches - - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/release/dev17.10') }}: + - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/release/dev17.11') }}: - template: /eng/common/templates-official/job/onelocbuild.yml@self parameters: MirrorRepo: fsharp diff --git a/eng/Versions.props b/eng/Versions.props index b0215a834a2..6146affd95a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -14,7 +14,7 @@ 8 0 - 300 + 400 0 @@ -56,7 +56,7 @@ 17 - 10 + 11 $(VSMajorVersion).0 $(VSMajorVersion).$(VSMinorVersion).0 $(VSAssemblyVersionPrefix).0 From e1343ce0dc842ee96fb4d525d63dc7ae6bbf6b58 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Fri, 12 Apr 2024 12:57:11 +0200 Subject: [PATCH 8/8] Update azure-pipelines.yml --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 41e408f1f31..91bf26d1340 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -35,7 +35,7 @@ variables: # (since for all *new* release branches we insert into VS main and for all *previous* releases we insert into corresponding VS release), # i.e. 'rel/d17.9' *or* 'main' in dotnet/fsharp/refs/heads/main and 'main' in F# dotnet/fsharp/refs/heads/release/dev17.10 (latest release branch) - name: VSInsertionTargetBranchName - value: rel/d17.10 + value: main - name: _TeamName value: FSharp - name: TeamName