Skip to content

Commit cfb414f

Browse files
dsymeKevinRansom
authored andcommitted
[RFC FS-1069] Implicit yields (allow dropping yield in list, array, sequence and computation expressions) (#6806)
* allow dropping yield in sequence expressions * update tests * update xlf * fix test * update baseline * implicit yield for computation expressions * fix tests, merge diag4 * fix test * update tests * fix tests * fix test * fix build * address PR * fix test * review feedback * make it match fsharp47
1 parent a7a66e3 commit cfb414f

29 files changed

Lines changed: 524 additions & 336 deletions

src/fsharp/ConstraintSolver.fs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2677,9 +2677,26 @@ let UndoIfFailed f =
26772677
ReportWarnings warns
26782678
true
26792679

2680+
let UndoIfFailedOrWarnings f =
2681+
let trace = Trace.New()
2682+
let res =
2683+
try
2684+
f trace
2685+
|> CheckNoErrorsAndGetWarnings
2686+
with e -> None
2687+
match res with
2688+
| Some [] ->
2689+
true
2690+
| _ ->
2691+
trace.Undo()
2692+
false
2693+
26802694
let AddCxTypeEqualsTypeUndoIfFailed denv css m ty1 ty2 =
26812695
UndoIfFailed (fun trace -> SolveTypeEqualsTypeKeepAbbrevs (MakeConstraintSolverEnv ContextInfo.NoContext css m denv) 0 m (WithTrace trace) ty1 ty2)
26822696

2697+
let AddCxTypeEqualsTypeUndoIfFailedOrWarnings denv css m ty1 ty2 =
2698+
UndoIfFailedOrWarnings (fun trace -> SolveTypeEqualsTypeKeepAbbrevs (MakeConstraintSolverEnv ContextInfo.NoContext css m denv) 0 m (WithTrace trace) ty1 ty2)
2699+
26832700
let AddCxTypeEqualsTypeMatchingOnlyUndoIfFailed denv css m ty1 ty2 =
26842701
let csenv = { MakeConstraintSolverEnv ContextInfo.NoContext css m denv with MatchingOnly = true }
26852702
UndoIfFailed (fun trace -> SolveTypeEqualsTypeKeepAbbrevs csenv 0 m (WithTrace trace) ty1 ty2)

src/fsharp/ConstraintSolver.fsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ val CheckDeclaredTypars : DisplayEnv -> ConstraintSolverSt
126126
val AddConstraint : ConstraintSolverEnv -> int -> Range.range -> OptionalTrace -> Typar -> TyparConstraint -> OperationResult<unit>
127127
val AddCxTypeEqualsType : ContextInfo -> DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> unit
128128
val AddCxTypeEqualsTypeUndoIfFailed : DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool
129+
val AddCxTypeEqualsTypeUndoIfFailedOrWarnings : DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool
129130
val AddCxTypeEqualsTypeMatchingOnlyUndoIfFailed : DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool
130131
val AddCxTypeMustSubsumeType : ContextInfo -> DisplayEnv -> ConstraintSolverState -> range -> OptionalTrace -> TType -> TType -> unit
131132
val AddCxTypeMustSubsumeTypeUndoIfFailed : DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool

src/fsharp/FSComp.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,6 @@ tcUseWhenPatternGuard,"Character range matches have been removed in F#. Consider
574574
736,tcExprUndelayed,"TcExprUndelayed: delayed"
575575
737,tcExpressionRequiresSequence,"This expression form may only be used in sequence and computation expressions"
576576
738,tcInvalidObjectExpressionSyntaxForm,"Invalid object expression. Objects without overrides or interfaces should use the expression form 'new Type(args)' without braces."
577-
739,tcInvalidObjectSequenceOrRecordExpression,"Invalid object, sequence or record expression"
578577
740,tcInvalidSequenceExpressionSyntaxForm,"Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'"
579578
tcExpressionWithIfRequiresParenthesis,"This list or array expression includes an element of the form 'if ... then ... else'. Parenthesize this expression to indicate it is an individual element of the list or array, to disambiguate this from a list generated using a sequence expression"
580579
741,tcUnableToParseFormatString,"Unable to parse format string '%s'"

src/fsharp/TypeChecker.fs

Lines changed: 152 additions & 97 deletions
Large diffs are not rendered by default.

src/fsharp/ast.fs

Lines changed: 11 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ and
672672
/// F# syntax: lazy expr
673673
| Lazy of SynExpr * range: range
674674

675-
/// Seq(seqPoint, isTrueSeq, e1, e2, m)
675+
/// Sequential(seqPoint, isTrueSeq, e1, e2, m)
676676
/// isTrueSeq: false indicates "let v = a in b; v"
677677
///
678678
/// F# syntax: expr; expr
@@ -750,10 +750,12 @@ and
750750
/// Computation expressions only, based on JOIN_IN token from lex filter
751751
| JoinIn of SynExpr * range * SynExpr * range: range
752752

753-
/// F# syntax: <implicit>
754-
/// Computation expressions only, implied by final "do" or "do!"
753+
/// Used internally during type checking for translating computation expressions.
755754
| ImplicitZero of range: range
756755

756+
/// Used internally during type checking for translating computation expressions.
757+
| SequentialOrImplicitYield of seqPoint:SequencePointInfoForSeq * expr1:SynExpr * expr2:SynExpr * ifNotStmt:SynExpr * range:range
758+
757759
/// F# syntax: yield expr
758760
/// F# syntax: return expr
759761
/// Computation expressions only
@@ -834,6 +836,7 @@ and
834836
| SynExpr.TryWith (range=m)
835837
| SynExpr.TryFinally (range=m)
836838
| SynExpr.Sequential (range=m)
839+
| SynExpr.SequentialOrImplicitYield (range=m)
837840
| SynExpr.ArbitraryAfterError (range=m)
838841
| SynExpr.FromParseError (range=m)
839842
| SynExpr.DiscardAfterMissingQualificationAfterDot (range=m)
@@ -873,138 +876,25 @@ and
873876
/// range ignoring any (parse error) extra trailing dots
874877
member e.RangeSansAnyExtraDot =
875878
match e with
876-
| SynExpr.Paren (range=m)
877-
| SynExpr.Quote (range=m)
878-
| SynExpr.Const (range=m)
879-
| SynExpr.Typed (range=m)
880-
| SynExpr.Tuple (range=m)
881-
| SynExpr.ArrayOrList (range=m)
882-
| SynExpr.AnonRecd (range=m)
883-
| SynExpr.Record (range=m)
884-
| SynExpr.New (range=m)
885-
| SynExpr.ObjExpr (range=m)
886-
| SynExpr.While (range=m)
887-
| SynExpr.For (range=m)
888-
| SynExpr.ForEach (range=m)
889-
| SynExpr.CompExpr (range=m)
890-
| SynExpr.ArrayOrListOfSeqExpr (range=m)
891-
| SynExpr.Lambda (range=m)
892-
| SynExpr.Match (range=m)
893-
| SynExpr.MatchLambda (range=m)
894-
| SynExpr.Do (range=m)
895-
| SynExpr.Assert (range=m)
896-
| SynExpr.App (range=m)
897-
| SynExpr.TypeApp (range=m)
898-
| SynExpr.LetOrUse (range=m)
899-
| SynExpr.TryWith (range=m)
900-
| SynExpr.TryFinally (range=m)
901-
| SynExpr.Sequential (range=m)
902-
| SynExpr.ArbitraryAfterError (range=m)
903-
| SynExpr.FromParseError (range=m)
904-
| SynExpr.IfThenElse (range=m)
905-
| SynExpr.LongIdentSet (range=m)
906-
| SynExpr.NamedIndexedPropertySet (range=m)
907-
| SynExpr.DotIndexedGet (range=m)
908-
| SynExpr.DotIndexedSet (range=m)
909-
| SynExpr.DotSet (range=m)
910-
| SynExpr.Set (range=m)
911-
| SynExpr.DotNamedIndexedPropertySet (range=m)
912-
| SynExpr.LibraryOnlyUnionCaseFieldGet (range=m)
913-
| SynExpr.LibraryOnlyUnionCaseFieldSet (range=m)
914-
| SynExpr.LibraryOnlyILAssembly (range=m)
915-
| SynExpr.LibraryOnlyStaticOptimization (range=m)
916-
| SynExpr.TypeTest (range=m)
917-
| SynExpr.Upcast (range=m)
918-
| SynExpr.AddressOf (range=m)
919-
| SynExpr.Downcast (range=m)
920-
| SynExpr.JoinIn (range=m)
921-
| SynExpr.InferredUpcast (range=m)
922-
| SynExpr.InferredDowncast (range=m)
923-
| SynExpr.Null (range=m)
924-
| SynExpr.Lazy (range=m)
925-
| SynExpr.TraitCall (range=m)
926-
| SynExpr.ImplicitZero (range=m)
927-
| SynExpr.YieldOrReturn (range=m)
928-
| SynExpr.YieldOrReturnFrom (range=m)
929-
| SynExpr.LetOrUseBang (range=m)
930-
| SynExpr.MatchBang (range=m)
931-
| SynExpr.DoBang (range=m) -> m
932879
| SynExpr.DotGet (expr, _, lidwd, m) -> if lidwd.ThereIsAnExtraDotAtTheEnd then unionRanges expr.Range lidwd.RangeSansAnyExtraDot else m
933880
| SynExpr.LongIdent (_, lidwd, _, _) -> lidwd.RangeSansAnyExtraDot
934881
| SynExpr.DiscardAfterMissingQualificationAfterDot (expr, _) -> expr.Range
935-
| SynExpr.Fixed (_, m) -> m
936-
| SynExpr.Ident id -> id.idRange
882+
| _ -> e.Range
937883

938884
/// Attempt to get the range of the first token or initial portion only - this is extremely ad-hoc, just a cheap way to improve a certain 'query custom operation' error range
939885
member e.RangeOfFirstPortion =
940886
match e with
941-
// haven't bothered making these cases better than just .Range
942-
| SynExpr.Quote (range=m)
943-
| SynExpr.Const (range=m)
944-
| SynExpr.Typed (range=m)
945-
| SynExpr.Tuple (range=m)
946-
| SynExpr.ArrayOrList (range=m)
947-
| SynExpr.AnonRecd (range=m)
948-
| SynExpr.Record (range=m)
949-
| SynExpr.New (range=m)
950-
| SynExpr.ObjExpr (range=m)
951-
| SynExpr.While (range=m)
952-
| SynExpr.For (range=m)
953-
| SynExpr.CompExpr (range=m)
954-
| SynExpr.ArrayOrListOfSeqExpr (range=m)
955-
| SynExpr.Lambda (range=m)
956-
| SynExpr.Match (range=m)
957-
| SynExpr.MatchLambda (range=m)
958-
| SynExpr.Do (range=m)
959-
| SynExpr.Assert (range=m)
960-
| SynExpr.TypeApp (range=m)
961-
| SynExpr.LetOrUse (range=m)
962-
| SynExpr.TryWith (range=m)
963-
| SynExpr.TryFinally (range=m)
964-
| SynExpr.ArbitraryAfterError (range=m)
965-
| SynExpr.FromParseError (range=m)
966-
| SynExpr.DiscardAfterMissingQualificationAfterDot (range=m)
967-
| SynExpr.IfThenElse (range=m)
968-
| SynExpr.LongIdent (range=m)
969-
| SynExpr.LongIdentSet (range=m)
970-
| SynExpr.NamedIndexedPropertySet (range=m)
971-
| SynExpr.DotIndexedGet (range=m)
972-
| SynExpr.DotIndexedSet (range=m)
973-
| SynExpr.DotGet (range=m)
974-
| SynExpr.DotSet (range=m)
975-
| SynExpr.Set (range=m)
976-
| SynExpr.DotNamedIndexedPropertySet (range=m)
977-
| SynExpr.LibraryOnlyUnionCaseFieldGet (range=m)
978-
| SynExpr.LibraryOnlyUnionCaseFieldSet (range=m)
979-
| SynExpr.LibraryOnlyILAssembly (range=m)
980-
| SynExpr.LibraryOnlyStaticOptimization (range=m)
981-
| SynExpr.TypeTest (range=m)
982-
| SynExpr.Upcast (range=m)
983-
| SynExpr.AddressOf (range=m)
984-
| SynExpr.Downcast (range=m)
985-
| SynExpr.JoinIn (range=m)
986-
| SynExpr.InferredUpcast (range=m)
987-
| SynExpr.InferredDowncast (range=m)
988-
| SynExpr.Null (range=m)
989-
| SynExpr.Lazy (range=m)
990-
| SynExpr.TraitCall (range=m)
991-
| SynExpr.ImplicitZero (range=m)
992-
| SynExpr.YieldOrReturn (range=m)
993-
| SynExpr.YieldOrReturnFrom (range=m)
994-
| SynExpr.LetOrUseBang (range=m)
995-
| SynExpr.MatchBang (range=m)
996-
| SynExpr.DoBang (range=m) -> m
997887
// these are better than just .Range, and also commonly applicable inside queries
998888
| SynExpr.Paren (_, m, _, _) -> m
999889
| SynExpr.Sequential (_, _, e1, _, _)
890+
| SynExpr.SequentialOrImplicitYield (_, e1, _, _, _)
1000891
| SynExpr.App (_, _, e1, _, _) ->
1001892
e1.RangeOfFirstPortion
1002893
| SynExpr.ForEach (_, _, _, pat, _, _, r) ->
1003894
let start = r.Start
1004895
let e = (pat.Range: range).Start
1005896
mkRange r.FileName start e
1006-
| SynExpr.Ident id -> id.idRange
1007-
| SynExpr.Fixed (_, m) -> m
897+
| _ -> e.Range
1008898

1009899
and
1010900
[<NoEquality; NoComparison; RequireQualifiedAccess>]
@@ -2580,6 +2470,8 @@ let rec synExprContainsError inpExpr =
25802470
walkExpr e1 || walkExpr e2
25812471
| SynExpr.Sequential (_, _, e1, e2, _) ->
25822472
walkExpr e1 || walkExpr e2
2473+
| SynExpr.SequentialOrImplicitYield (_, e1, e2, _, _) ->
2474+
walkExpr e1 || walkExpr e2
25832475
| SynExpr.IfThenElse (e1, e2, e3opt, _, _, _, _) ->
25842476
walkExpr e1 || walkExpr e2 || walkExprOpt e3opt
25852477
| SynExpr.DotIndexedGet (e1, es, _, _) ->

src/fsharp/service/ServiceParseTreeWalk.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ module public AstTraversal =
412412
dive synExpr2 synExpr2.Range traverseSynExpr]
413413
|> pick expr
414414
| SynExpr.Lazy (synExpr, _range) -> traverseSynExpr synExpr
415+
| SynExpr.SequentialOrImplicitYield (_sequencePointInfoForSeq, synExpr, synExpr2, _, _range)
415416
| SynExpr.Sequential (_sequencePointInfoForSeq, _, synExpr, synExpr2, _range) ->
416417
[dive synExpr synExpr.Range traverseSynExpr
417418
dive synExpr2 synExpr2.Range traverseSynExpr]

src/fsharp/service/ServiceUntypedParse.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ type FSharpParseFileResults(errors: FSharpErrorInfo[], input: Ast.ParsedInput op
299299
yield! walkTrySeqPt spTry
300300
yield! walkFinallySeqPt spFinally
301301

302+
| SynExpr.SequentialOrImplicitYield (spSeq, e1, e2, _, _)
302303
| SynExpr.Sequential (spSeq, _, e1, e2, _) ->
303304
yield! walkExpr (match spSeq with SuppressSequencePointOnStmtOfSequential -> false | _ -> true) e1
304305
yield! walkExpr (match spSeq with SuppressSequencePointOnExprOfSequential -> false | _ -> true) e2

src/fsharp/xlf/FSComp.txt.cs.xlf

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2847,11 +2847,6 @@
28472847
<target state="translated">Neplatný objektový výraz. U objektů bez přepsání nebo rozhraní by se měl výraz formulovat pomocí notace new Type(args) bez složených závorek.</target>
28482848
<note />
28492849
</trans-unit>
2850-
<trans-unit id="tcInvalidObjectSequenceOrRecordExpression">
2851-
<source>Invalid object, sequence or record expression</source>
2852-
<target state="translated">Neplatný výraz objektu, pořadí nebo záznamu</target>
2853-
<note />
2854-
</trans-unit>
28552850
<trans-unit id="tcInvalidSequenceExpressionSyntaxForm">
28562851
<source>Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'</source>
28572852
<target state="translated">Neplatný výraz záznamu, pořadí nebo výpočtu. Výrazy pořadí by měly mít notaci seq {{ ... }}.</target>

src/fsharp/xlf/FSComp.txt.de.xlf

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2847,11 +2847,6 @@
28472847
<target state="translated">Ungültiger Objektausdruck. Objekte ohne Überschreibungen oder Schnittstellen sollten das Ausdrucksformat "new Type(args)" ohne geschweifte Klammern verwenden.</target>
28482848
<note />
28492849
</trans-unit>
2850-
<trans-unit id="tcInvalidObjectSequenceOrRecordExpression">
2851-
<source>Invalid object, sequence or record expression</source>
2852-
<target state="translated">Ungültiger Objekt-, Sequenz- oder Datensatzausdruck.</target>
2853-
<note />
2854-
</trans-unit>
28552850
<trans-unit id="tcInvalidSequenceExpressionSyntaxForm">
28562851
<source>Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'</source>
28572852
<target state="translated">Ungültiger Datensatz-, Sequenz- oder Berechnungsausdruck. Sequenzausdrücke müssen das Format "seq {{ ... }}" besitzen.</target>

src/fsharp/xlf/FSComp.txt.es.xlf

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2847,11 +2847,6 @@
28472847
<target state="translated">Expresión de objeto no válida. Los objetos sin invalidaciones ni interfaces deben usar el formato de expresión 'new Type(args)' sin llaves.</target>
28482848
<note />
28492849
</trans-unit>
2850-
<trans-unit id="tcInvalidObjectSequenceOrRecordExpression">
2851-
<source>Invalid object, sequence or record expression</source>
2852-
<target state="translated">Expresión de objeto, secuencia o registro no válida.</target>
2853-
<note />
2854-
</trans-unit>
28552850
<trans-unit id="tcInvalidSequenceExpressionSyntaxForm">
28562851
<source>Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'</source>
28572852
<target state="translated">Expresión de registro, secuencia o cómputo no válida. Las expresiones de secuencia deben tener el formato 'seq {{ ... }}'.</target>

0 commit comments

Comments
 (0)