diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt
index 27d6bfd4b49..4b5f756f06d 100644
--- a/src/fsharp/FSComp.txt
+++ b/src/fsharp/FSComp.txt
@@ -574,6 +574,7 @@ tcUseWhenPatternGuard,"Character range matches have been removed in F#. Consider
736,tcExprUndelayed,"TcExprUndelayed: delayed"
737,tcExpressionRequiresSequence,"This expression form may only be used in sequence and computation expressions"
738,tcInvalidObjectExpressionSyntaxForm,"Invalid object expression. Objects without overrides or interfaces should use the expression form 'new Type(args)' without braces."
+739,tcInvalidObjectSequenceOrRecordExpression,"Invalid object, sequence or record expression"
740,tcInvalidSequenceExpressionSyntaxForm,"Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'"
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"
741,tcUnableToParseFormatString,"Unable to parse format string '%s'"
diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs
index c8c67a4ddf1..a88ebdcf9a1 100644
--- a/src/fsharp/LanguageFeatures.fs
+++ b/src/fsharp/LanguageFeatures.fs
@@ -25,6 +25,8 @@ type LanguageFeature =
| WildCardInForLoop = 3
| RelaxWhitespace = 4
| NameOf = 5
+ | ImplicitYield = 6
+
/// LanguageVersion management
type LanguageVersion (specifiedVersion) =
@@ -49,6 +51,7 @@ type LanguageVersion (specifiedVersion) =
LanguageFeature.WildCardInForLoop, previewVersion
LanguageFeature.RelaxWhitespace, previewVersion
LanguageFeature.NameOf, previewVersion
+ LanguageFeature.ImplicitYield, previewVersion
|]
let specified =
diff --git a/src/fsharp/LanguageFeatures.fsi b/src/fsharp/LanguageFeatures.fsi
index fef3df9ba83..44eb178840b 100644
--- a/src/fsharp/LanguageFeatures.fsi
+++ b/src/fsharp/LanguageFeatures.fsi
@@ -12,6 +12,8 @@ type LanguageFeature =
| WildCardInForLoop = 3
| RelaxWhitespace = 4
| NameOf = 5
+ | ImplicitYield = 6
+
/// LanguageVersion management
type LanguageVersion =
diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs
index 0364200cca3..a9dd3f5c74d 100644
--- a/src/fsharp/TypeChecker.fs
+++ b/src/fsharp/TypeChecker.fs
@@ -3518,14 +3518,84 @@ let (|ExprAsPat|_|) (f: SynExpr) =
None
| _ -> None
+/// Check if a computation or sequence expression is syntactically free of 'yield' (though not yield!)
+let YieldFree cenv expr =
+ if cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield then
+
+ // Implement yield free logic for F# Language including the LanguageFeature.ImplicitYield
+ let rec YieldFree expr =
+ match expr with
+ | SynExpr.Sequential (_, _, e1, e2, _) ->
+ YieldFree e1 && YieldFree e2
+
+ | SynExpr.IfThenElse (_, e2, e3opt, _, _, _, _) ->
+ YieldFree e2 && Option.forall YieldFree e3opt
+
+ | SynExpr.TryWith (e1, _, clauses, _, _, _, _) ->
+ YieldFree e1 && clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
+
+ | (SynExpr.Match (_, _, clauses, _) | SynExpr.MatchBang (_, _, clauses, _)) ->
+ clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
+
+ | SynExpr.For (_, _, _, _, _, body, _)
+ | SynExpr.TryFinally (body, _, _, _, _)
+ | SynExpr.LetOrUse (_, _, _, body, _)
+ | SynExpr.While (_, _, body, _)
+ | SynExpr.ForEach (_, _, _, _, _, body, _) ->
+ YieldFree body
+
+ | SynExpr.LetOrUseBang(_, _, _, _, _, body, _) ->
+ YieldFree body
+
+ | SynExpr.YieldOrReturn((true, _), _, _) -> false
+
+ | _ -> true
+
+ YieldFree expr
+ else
+ // Implement yield free logic for F# Language without the LanguageFeature.ImplicitYield
+ let rec YieldFree expr =
+ match expr with
+ | SynExpr.Sequential (_, _, e1, e2, _) ->
+ YieldFree e1 && YieldFree e2
+
+ | SynExpr.IfThenElse (_, e2, e3opt, _, _, _, _) ->
+ YieldFree e2 && Option.forall YieldFree e3opt
+
+ | SynExpr.TryWith (e1, _, clauses, _, _, _, _) ->
+ YieldFree e1 && clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
+
+ | (SynExpr.Match (_, _, clauses, _) | SynExpr.MatchBang (_, _, clauses, _)) ->
+ clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
+
+ | SynExpr.For (_, _, _, _, _, body, _)
+ | SynExpr.TryFinally (body, _, _, _, _)
+ | SynExpr.LetOrUse (_, _, _, body, _)
+ | SynExpr.While (_, _, body, _)
+ | SynExpr.ForEach (_, _, _, _, _, body, _) ->
+ YieldFree body
+
+ | SynExpr.LetOrUseBang _
+ | SynExpr.YieldOrReturnFrom _
+ | SynExpr.YieldOrReturn _
+ | SynExpr.ImplicitZero _
+ | SynExpr.Do _ -> false
+
+ | _ -> true
+
+ YieldFree expr
+
+
/// Determine if a syntactic expression inside 'seq { ... }' or '[...]' counts as a "simple sequence
/// of semicolon separated values". For example [1;2;3].
+/// 'acceptDeprecated' is true for the '[ ... ]' case, where we allow the syntax '[ if g then t else e ]' but ask it to be parenthesized
///
-let (|SimpleSemicolonSequence|_|) cexpr =
+let (|SimpleSemicolonSequence|_|) cenv acceptDeprecated cexpr =
let IsSimpleSemicolonSequenceElement expr =
- match expr with
- | SynExpr.IfThenElse _
+ match expr with
+ | SynExpr.IfThenElse _ when acceptDeprecated && YieldFree cenv expr -> true
+ | SynExpr.IfThenElse _
| SynExpr.TryWith _
| SynExpr.Match _
| SynExpr.For _
@@ -5734,6 +5804,13 @@ and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ =
expr, overallTy, tpenv
and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) =
+
+ // LanguageFeatures.ImplicitYield do not require this validation
+ let implicitYieldEnabled = cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield
+ let validateObjectSequenceOrRecordExpression = not implicitYieldEnabled
+ let validateExpressionWithIfRequiresParenethesis = not implicitYieldEnabled
+ let acceptDeprecatedIfThenExpression = not implicitYieldEnabled
+
match synExpr with
| SynExpr.Paren (expr2, _, _, mWholeExprIncludingParentheses) ->
// We invoke CallExprHasTypeSink for every construct which is atomic in the syntax, i.e. where a '.' immediately following the
@@ -5932,6 +6009,8 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) =
match comp with
| SynExpr.New _ ->
errorR(Error(FSComp.SR.tcInvalidObjectExpressionSyntaxForm(), m))
+ | SimpleSemicolonSequence cenv false _ when validateObjectSequenceOrRecordExpression ->
+ errorR(Error(FSComp.SR.tcInvalidObjectSequenceOrRecordExpression(), m))
| _ ->
()
if not !isNotNakedRefCell && not cenv.g.compilingFslib then
@@ -5941,9 +6020,12 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) =
| SynExpr.ArrayOrListOfSeqExpr (isArray, comp, m) ->
CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.DisplayEnv, env.eAccessRights)
-
match comp with
- | SynExpr.CompExpr (_, _, SimpleSemicolonSequence elems, _) ->
+ | SynExpr.CompExpr (_, _, (SimpleSemicolonSequence cenv acceptDeprecatedIfThenExpression elems as body), _) ->
+ match body with
+ | SimpleSemicolonSequence cenv false _ -> ()
+ | _ when validateExpressionWithIfRequiresParenethesis -> errorR(Deprecated(FSComp.SR.tcExpressionWithIfRequiresParenthesis(), m))
+ | _ -> ()
let replacementExpr =
if isArray then
@@ -7331,31 +7413,6 @@ and TcQuotationExpr cenv overallTy env tpenv (_oper, raw, ast, isFromQueryExpres
/// Ignores an attribute
and IgnoreAttribute _ = None
-/// Check if a computation or sequence expression is syntactically free of 'yield' (though not yield!)
-and YieldFree expr =
- match expr with
- | SynExpr.Sequential (_, _, e1, e2, _) -> YieldFree e1 && YieldFree e2
- | SynExpr.IfThenElse (_, e2, e3opt, _, _, _, _) -> YieldFree e2 && Option.forall YieldFree e3opt
- | SynExpr.TryWith (e1, _, clauses, _, _, _, _) ->
- YieldFree e1 && clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
- | (SynExpr.Match (_, _, clauses, _) | SynExpr.MatchBang (_, _, clauses, _)) ->
- clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
- | SynExpr.For (_, _, _, _, _, body, _)
- | SynExpr.TryFinally (body, _, _, _, _)
- | SynExpr.LetOrUse (_, _, _, body, _)
- | SynExpr.LetOrUseBang(_, _, _, _, _, body, _)
- | SynExpr.LetOrUse (_, _, _, body, _)
- | SynExpr.While (_, _, body, _)
- | SynExpr.ForEach (_, _, _, _, _, body, _) ->
- YieldFree body
-
- // 'yield!' in expressions doesn't trigger the 'yield free' rule
- //| SynExpr.YieldOrReturnFrom _
- | SynExpr.YieldOrReturn((true, _), _, _) ->
- false
-
- | _ -> true
-
/// Used for all computation expressions except sequence expressions
and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builderTy tpenv (comp: SynExpr) =
@@ -7814,7 +7871,9 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
// If there are no 'yield' in the computation expression, and the builder supports 'Yield',
// then allow the type-directed rule interpreting non-unit-typed expressions in statement
// positions as 'yield'. 'yield!' may be present in the computation expression.
- let enableImplicitYield = hasMethInfo "Yield" && hasMethInfo "Combine" && hasMethInfo "Delay" && YieldFree comp
+ let enableImplicitYield =
+ cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield
+ && (hasMethInfo "Yield" && hasMethInfo "Combine" && hasMethInfo "Delay" && YieldFree cenv comp)
// q - a flag indicating if custom operators are allowed. They are not allowed inside try/with, try/finally, if/then/else etc.
// varSpace - a lazy data structure indicating the variables bound so far in the overall computation
@@ -8200,8 +8259,7 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
| _ ->
Some (trans true q varSpace innerComp2 (fun holeFill ->
let fillExpr =
- if enableImplicitYield then
-
+ if enableImplicitYield then
// When implicit yields are enabled, then if the 'innerComp1' checks as type
// 'unit' we interpret the expression as a sequential, and when it doesn't
// have type 'unit' we interpret it as a 'Yield + Combine'.
@@ -8443,7 +8501,9 @@ and TcSequenceExpression cenv env tpenv comp overallTy m =
// If there are no 'yield' in the computation expression then allow the type-directed rule
// interpreting non-unit-typed expressions in statement positions as 'yield'. 'yield!' may be
// present in the computation expression.
- let enableImplicitYield = YieldFree comp
+ let enableImplicitYield =
+ cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield
+ && (YieldFree cenv comp)
let mkDelayedExpr (coreExpr: Expr) =
let m = coreExpr.Range
@@ -8505,6 +8565,9 @@ and TcSequenceExpression cenv env tpenv comp overallTy m =
Some(mkSeqFinally cenv env innerExprMark genOuterTy innerExpr unwindExpr, tpenv)
+ | SynExpr.Paren (_, _, _, m) when not (cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield)->
+ error(Error(FSComp.SR.tcConstructIsAmbiguousInSequenceExpression(), m))
+
| SynExpr.ImplicitZero m ->
Some(mkSeqEmpty cenv env m genOuterTy, tpenv )
diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf
index 6995c485abb..7c1b38a4b5f 100644
--- a/src/fsharp/xlf/FSComp.txt.cs.xlf
+++ b/src/fsharp/xlf/FSComp.txt.cs.xlf
@@ -2847,6 +2847,11 @@
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.
+
+ Invalid object, sequence or record expression
+ Neplatný výraz objektu, pořadí nebo záznamu
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'Neplatný výraz záznamu, pořadí nebo výpočtu. Výrazy pořadí by měly mít notaci seq {{ ... }}.
diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf
index 1d4725f1824..33a03002ea8 100644
--- a/src/fsharp/xlf/FSComp.txt.de.xlf
+++ b/src/fsharp/xlf/FSComp.txt.de.xlf
@@ -2847,6 +2847,11 @@
Ungültiger Objektausdruck. Objekte ohne Überschreibungen oder Schnittstellen sollten das Ausdrucksformat "new Type(args)" ohne geschweifte Klammern verwenden.
+
+ Invalid object, sequence or record expression
+ Ungültiger Objekt-, Sequenz- oder Datensatzausdruck.
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'Ungültiger Datensatz-, Sequenz- oder Berechnungsausdruck. Sequenzausdrücke müssen das Format "seq {{ ... }}" besitzen.
diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf
index dba9ebb7f77..07a6a376d6c 100644
--- a/src/fsharp/xlf/FSComp.txt.es.xlf
+++ b/src/fsharp/xlf/FSComp.txt.es.xlf
@@ -2847,6 +2847,11 @@
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.
+
+ Invalid object, sequence or record expression
+ Expresión de objeto, secuencia o registro no válida.
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'Expresión de registro, secuencia o cómputo no válida. Las expresiones de secuencia deben tener el formato 'seq {{ ... }}'.
diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf
index 067c0d42c98..db443013ccc 100644
--- a/src/fsharp/xlf/FSComp.txt.fr.xlf
+++ b/src/fsharp/xlf/FSComp.txt.fr.xlf
@@ -2847,6 +2847,11 @@
Expression d'objet non valide. Les objets sans substitutions ou interfaces doivent utiliser la forme d'expression 'new Type(args)' sans accolades.
+
+ Invalid object, sequence or record expression
+ Expression d'objet, de séquence ou d'enregistrement non valide
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'Expression d'enregistrement, de séquence ou de calcul non valide. Les expressions de séquence doivent avoir le format 'seq {{ ... }}'
diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf
index 6ff1a468356..27d3af91a0e 100644
--- a/src/fsharp/xlf/FSComp.txt.it.xlf
+++ b/src/fsharp/xlf/FSComp.txt.it.xlf
@@ -2847,6 +2847,11 @@
Espressione oggetto non valida. Gli oggetti senza override o interfacce devono usare il formato di espressione 'new Type(args)' senza parentesi graffe.
+
+ Invalid object, sequence or record expression
+ Espressione record, sequenza o oggetto non valida
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'Espressione di calcolo, sequenza o record non valida. Il formato delle espressioni sequenza deve essere 'seq {{ ... }}'
diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf
index 822ef18990e..47430c5e72b 100644
--- a/src/fsharp/xlf/FSComp.txt.ja.xlf
+++ b/src/fsharp/xlf/FSComp.txt.ja.xlf
@@ -2847,6 +2847,11 @@
オブジェクト式が無効です。オーバーライドまたはインターフェイスがないオブジェクトには、かっこなしで 'new Type(args)' という形式の式を使用してください。
+
+ Invalid object, sequence or record expression
+ オブジェクト式、シーケンス式、またはレコード式が無効です
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'無効なレコード、シーケンス式、またはコンピュテーション式です。シーケンス式は 'seq {{ ... }}' という形式にしてください。
diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf
index b77f3b4cad4..2f3708ed03f 100644
--- a/src/fsharp/xlf/FSComp.txt.ko.xlf
+++ b/src/fsharp/xlf/FSComp.txt.ko.xlf
@@ -2847,6 +2847,11 @@
개체 식이 잘못되었습니다. 재정의 또는 인터페이스가 없는 개체는 중괄호 없이 식 형식 'new Type(args)'을 사용해야 합니다.
+
+ Invalid object, sequence or record expression
+ 개체, 시퀀스 또는 레코드 식이 잘못되었습니다.
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'레코드, 시퀀스 또는 계산 식이 잘못되었습니다. 시퀀스 식의 형식은 'seq {{ ... }}'여야 합니다.
diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf
index 0f3e6ef69b3..4b92b5b6a51 100644
--- a/src/fsharp/xlf/FSComp.txt.pl.xlf
+++ b/src/fsharp/xlf/FSComp.txt.pl.xlf
@@ -2847,6 +2847,11 @@
Nieprawidłowe wyrażenie obiektu. Obiekty bez przesłonięć lub interfejsy powinny używać wyrażenia w postaci „new Typ(argumenty)” bez nawiasów.
+
+ Invalid object, sequence or record expression
+ Nieprawidłowe wyrażenie obiektu, sekwencji lub rekordu
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'Nieprawidłowe wyrażenie rekordu, sekwencji lub obliczenia. Wyrażenia sekwencji powinny mieć postać „seq {{ ... }}”
diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf
index 2e4ea8c6dcb..d679c9502a5 100644
--- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf
+++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf
@@ -2847,6 +2847,11 @@
Expressão de objeto inválida. Objetos sem substituições ou interfaces devem usar o formato de expressão 'new Type(args)' sem as chaves.
+
+ Invalid object, sequence or record expression
+ Expressão de objeto, sequência ou registro inválida
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'Expressão de registro, sequência ou computação inválida. Expressões de sequência devem estar na forma 'seq {{ ... }}'
diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf
index 5ead2841146..3fc4173787b 100644
--- a/src/fsharp/xlf/FSComp.txt.ru.xlf
+++ b/src/fsharp/xlf/FSComp.txt.ru.xlf
@@ -2847,6 +2847,11 @@
Недопустимое выражение объекта. Объекты без переопределений или интерфейсов должны использовать форму выражения "new Type(args)" без фигурных скобок.
+
+ Invalid object, sequence or record expression
+ Недопустимое выражение объекта, последовательности или записи
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'Недопустимая запись, выражение последовательности или вычислительное выражение. Выражения последовательностей должны иметь форму "seq {{ ... }}'
diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf
index db70140c760..a04bc7ada54 100644
--- a/src/fsharp/xlf/FSComp.txt.tr.xlf
+++ b/src/fsharp/xlf/FSComp.txt.tr.xlf
@@ -2847,6 +2847,11 @@
Geçersiz nesne ifadesi. Geçersiz kılmaların ve arabirimlerin olmadığı nesneler küme ayraçsız 'new Type(args)' ifade biçimini kullanmalıdır.
+
+ Invalid object, sequence or record expression
+ Geçersiz nesne, dizi veya kayıt ifadesi
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'Geçersiz kayıt, dizi veya hesaplama ifadesi. Dizi ifadeleri 'seq {{ ... }}' biçiminde olmalıdır
diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf
index d90cfb843c7..38918ceec9f 100644
--- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf
+++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf
@@ -2847,6 +2847,11 @@
对象表达式无效。没有重写或接口的对象应使用不带括号的表达式格式“new Type(args)”。
+
+ Invalid object, sequence or record expression
+ 对象、序列或记录表达式无效
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'记录、序列或计算表达式无效。序列表达式的格式应为“seq {{ ... }}”}}'
diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf
index 6bdcae208b5..1a02de7e416 100644
--- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf
+++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf
@@ -2847,6 +2847,11 @@
無效的物件運算式。沒有覆寫或介面的物件應該使用不加大括號的運算式形式 'new Type(args)'。
+
+ Invalid object, sequence or record expression
+ 無效的物件、順序或記錄運算式
+
+ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}'無效的記錄、循序項或計算運算式。循序項運算式應該是 'seq {{ ... }}' 形式。
diff --git a/tests/fsharp/single-test.fs b/tests/fsharp/single-test.fs
index c1707f619e2..6a24d80bd54 100644
--- a/tests/fsharp/single-test.fs
+++ b/tests/fsharp/single-test.fs
@@ -379,9 +379,13 @@ let singleTestBuildAndRunVersion dir p version =
let cfg = testConfig dir
singleTestBuildAndRunCore cfg "" p version
-let singleNegTest (cfg: TestConfig) testname =
+let singleVersionedNegTest (cfg: TestConfig) version testname =
- let cfg = { cfg with fsc_flags = sprintf "%s --define:NEGATIVE" cfg.fsc_flags }
+ let cfg = {
+ cfg with
+ fsc_flags = sprintf "%s %s --define:NEGATIVE" cfg.fsc_flags (if not (String.IsNullOrEmpty(version)) then "--langversion:" + version else "")
+ fsi_flags = sprintf "%s %s" cfg.fsi_flags (if not (String.IsNullOrEmpty(version)) then "--langversion:" + version else "")
+ }
// REM == Set baseline (fsc vs vs, in case the vs baseline exists)
let VSBSLFILE =
@@ -405,7 +409,8 @@ let singleNegTest (cfg: TestConfig) testname =
]
if fileExists cfg (testname + "-pre.fs")
- then fsc cfg "%s -a -o:%s-pre.dll" cfg.fsc_flags testname [testname + "-pre.fs"]
+ then
+ fsc cfg "%s -a -o:%s-pre.dll" cfg.fsc_flags testname [testname + "-pre.fs"]
else ()
if fileExists cfg (testname + "-pre.fsx") then
@@ -444,3 +449,5 @@ let singleNegTest (cfg: TestConfig) testname =
log "***** %s.err %s.bsl differed: a bug or baseline may need updating" testname testname
log "***** %s.vserr %s differed: a bug or baseline may need updating" testname VSBSLFILE
failwithf "%s.err %s.bsl differ; %A; %s.vserr %s differ; %A" testname testname l1 testname VSBSLFILE l2
+
+let singleNegTest (cfg: TestConfig) testname = singleVersionedNegTest (cfg: TestConfig) "" testname
diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs
index e065d6bee92..fe30c684bfa 100644
--- a/tests/fsharp/tests.fs
+++ b/tests/fsharp/tests.fs
@@ -29,7 +29,7 @@ let FSI_BASIC = FSI_FILE
#endif
// ^^^^^^^^^^^^ To run these tests in F# Interactive , 'build net40', then send this chunk, then evaluate body of a test ^^^^^^^^^^^^
-module CoreTests =
+module CoreTests =
// These tests are enabled for .NET Framework and .NET Core
[]
let ``access-FSC_BASIC``() = singleTestBuildAndRun "core/access" FSC_BASIC
@@ -1829,7 +1829,6 @@ module VersionTests =
[]
let ``nameof-fsi``() = singleTestBuildAndRunVersion "core/nameof/version47" FSI_BASIC "preview"
-
#if !FSHARP_SUITE_DRIVES_CORECLR_TESTS
module ToolsTests =
@@ -2383,14 +2382,21 @@ module TypecheckTests =
[]
let ``type check neg23`` () = singleNegTest (testConfig "typecheck/sigs") "neg23"
- []
- let ``type check neg24`` () =
- let cfg = testConfig "typecheck/sigs"
+ []
+ let ``type check neg24 version 4.6`` () =
+ let cfg = testConfig "typecheck/sigs/version46"
// For some reason this warning is off by default in the test framework but in this case we are testing for it
let cfg = { cfg with fsc_flags = cfg.fsc_flags.Replace("--nowarn:20", "") }
- singleNegTest cfg "neg24"
+ singleVersionedNegTest cfg "4.6" "neg24"
[]
+ let ``type check neg24 version 4.7`` () =
+ let cfg = testConfig "typecheck/sigs/version47"
+ // For some reason this warning is off by default in the test framework but in this case we are testing for it
+ let cfg = { cfg with fsc_flags = cfg.fsc_flags.Replace("--nowarn:20", "") }
+ singleVersionedNegTest cfg "preview" "neg24"
+
+ []
let ``type check neg25`` () = singleNegTest (testConfig "typecheck/sigs") "neg25"
[]
diff --git a/tests/fsharp/typecheck/sigs/version46/neg24.bsl b/tests/fsharp/typecheck/sigs/version46/neg24.bsl
new file mode 100644
index 00000000000..96a64e8c88f
--- /dev/null
+++ b/tests/fsharp/typecheck/sigs/version46/neg24.bsl
@@ -0,0 +1,30 @@
+
+neg24.fs(11,14,11,39): typecheck error FS0035: This construct is deprecated: 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
+
+neg24.fs(12,14,12,41): typecheck error FS0035: This construct is deprecated: 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
+
+neg24.fs(13,14,13,33): typecheck error FS0035: This construct is deprecated: 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
+
+neg24.fs(14,14,14,41): typecheck error FS0035: This construct is deprecated: 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
+
+neg24.fs(15,14,15,43): typecheck error FS0035: This construct is deprecated: 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
+
+neg24.fs(16,14,16,35): typecheck error FS0035: This construct is deprecated: 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
+
+neg24.fs(17,18,17,45): typecheck error FS0739: Invalid object, sequence or record expression
+
+neg24.fs(17,20,17,43): typecheck error FS0793: This construct is ambiguous as part of a sequence expression. Nested expressions may be written using 'let _ = (...)' and nested sequences using 'yield! seq {... }'.
+
+neg24.fs(53,24,53,30): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form.
+
+neg24.fs(55,31,55,37): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form.
+
+neg24.fs(57,38,57,42): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form.
+
+neg24.fs(60,24,60,34): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form.
+
+neg24.fs(62,31,62,41): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form.
+
+neg24.fs(64,44,64,48): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form.
+
+neg24.fs(70,15,70,18): typecheck error FS0495: The member or object constructor 'M' has no argument or settable return property 'qez'. The required signature is member C.M : abc:int * def:string -> int.
\ No newline at end of file
diff --git a/tests/fsharp/typecheck/sigs/version46/neg24.fs b/tests/fsharp/typecheck/sigs/version46/neg24.fs
new file mode 100644
index 00000000000..745cb52fffc
--- /dev/null
+++ b/tests/fsharp/typecheck/sigs/version46/neg24.fs
@@ -0,0 +1,70 @@
+module Test
+open Microsoft.FSharp.Quotations
+
+
+let test2 (v : Expr<'a> -> Expr<'b>) = <@ fun (i: 'a) -> %v <@i@> @>
+
+let test (v : 'a -> Expr<'b>) = <@ fun (i: 'a) -> %(v i) @>
+
+// expect warning
+module Negative =
+ let v1 = [ if true then 1 else 2 ]
+ let v2 = [ if true then () else () ]
+ let v6 = [ if true then () ]
+ let a1 = [| if true then 1 else 2 |]
+ let a2 = [| if true then () else () |]
+ let a6 = [| if true then () |]
+ let s3 = seq { (if true then 1 else 2) }
+
+// expect no warning
+module Positive =
+ let v3 = [ (if true then 1 else 2) ]
+ let v4 = [ if true then yield 1 else yield 2 ]
+ let v5 = [ if true then yield 1 ]
+ let a3 = [| (if true then 1 else 2) |]
+ let a4 = [| if true then yield 1 else yield 2 |]
+ let a5 = [| if true then yield 1 |]
+ let s2 = seq { if true then () else () }
+ let s6 = seq { if true then () }
+ let s4 = seq { if true then yield 1 else yield 2 }
+ let s5 = seq { if true then yield 1 }
+
+
+module BadCurriedExtensionMember =
+ type C() =
+ member x.P = 1
+
+ module M1 =
+ type C with
+ member x.M1 a b = a + b
+ member x.M2 (a,b) c = a + b + c
+
+ module M2 =
+ type C with
+ member x.M1 a b = a + b
+ member x.M2 (a,b) c = a + b + c
+
+ open M1
+ open M2
+
+ let c = C()
+
+ // negative test - error expected here
+ let x1 : int = c.M1 3 4
+ // negative test - error expected here
+ let x2 : int -> int = c.M1 3
+ // negative test - error expected here
+ let x3 : int -> int -> int = c.M1
+
+ // negative test - error expected here
+ let y1 : int = c.M2 (3,4) 4
+ // negative test - error expected here
+ let y2 : int -> int = c.M2 (3,4)
+ // negative test - error expected here
+ let y3 : int * int -> int -> int = c.M2
+
+type C() =
+ member x.M(abc:int,def:string) = abc + def.Length
+
+// Check that the error for a named argument/setter that does not exist is located in a good place
+let _ = C().M(qez=3)
diff --git a/tests/fsharp/typecheck/sigs/neg24.bsl b/tests/fsharp/typecheck/sigs/version47/neg24.bsl
similarity index 100%
rename from tests/fsharp/typecheck/sigs/neg24.bsl
rename to tests/fsharp/typecheck/sigs/version47/neg24.bsl
diff --git a/tests/fsharp/typecheck/sigs/neg24.fs b/tests/fsharp/typecheck/sigs/version47/neg24.fs
similarity index 100%
rename from tests/fsharp/typecheck/sigs/neg24.fs
rename to tests/fsharp/typecheck/sigs/version47/neg24.fs
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/env.lst b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/env.lst
index e0c8f701ba8..5f210dd6e49 100644
--- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/env.lst
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/env.lst
@@ -1,6 +1,10 @@
- SOURCE=W_IfThenElse01.fs SCFLAGS="--test:ErrorRanges" # W_IfThenElse01.fs
- SOURCE=W_IfThenElse02.fs SCFLAGS="--test:ErrorRanges" # W_IfThenElse02.fs
- SOURCE=W_IfThenElse03.fs SCFLAGS="--test:ErrorRanges" # W_IfThenElse03.fs
+ SOURCE=version46/W_IfThenElse01.fs SCFLAGS="--langversion:4.6 --test:ErrorRanges" # version46 W_IfThenElse01.fs
+ SOURCE=version46/W_IfThenElse02.fs SCFLAGS="--langversion:4.6 --test:ErrorRanges" # version46 W_IfThenElse02.fs
+ SOURCE=version46/W_IfThenElse03.fs SCFLAGS="--langversion:4.6 --test:ErrorRanges" # version46 W_IfThenElse03.fs
+ SOURCE=version47/W_IfThenElse01.fs SCFLAGS="--langversion:preview --test:ErrorRanges" # version47 W_IfThenElse01.fs
+ SOURCE=version47/W_IfThenElse02.fs SCFLAGS="--langversion:preview --test:ErrorRanges" # version47 W_IfThenElse02.fs
+ SOURCE=version47/W_IfThenElse03.fs SCFLAGS="--langversion:preview --test:ErrorRanges" # version47 W_IfThenElse03.fs
+
SOURCE=IfThenElse04.fs SCFLAGS="--test:ErrorRanges --warnaserror" # IfThenElse04.fs
SOURCE=IfThenElse05.fs SCFLAGS="--test:ErrorRanges --warnaserror" # IfThenElse05.fs
SOURCE=IfThenElse06.fs SCFLAGS="--test:ErrorRanges --warnaserror" # IfThenElse06.fs
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version46/W_IfThenElse01.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version46/W_IfThenElse01.fs
new file mode 100644
index 00000000000..4e948ea575f
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version46/W_IfThenElse01.fs
@@ -0,0 +1,11 @@
+// #Regression #Conformance #DataExpressions #Sequences
+// Regression test for FSHARP1.0:4527
+//.+'if ... then ... else'
+
+// warning FS0035: This construct is deprecated: 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.
+
+let p = [ if true then 1 else 2 ]
+(if p = [ 1 ] then 0 else 1) |> exit
\ No newline at end of file
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version46/W_IfThenElse02.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version46/W_IfThenElse02.fs
new file mode 100644
index 00000000000..805af8ee0ea
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version46/W_IfThenElse02.fs
@@ -0,0 +1,11 @@
+// #Regression #Conformance #DataExpressions #Sequences
+// Regression test for FSHARP1.0:4527
+//.+'if ... then ... else'
+
+// warning FS0035: This construct is deprecated: 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.
+
+let p = [ if true then 1 else printfn "hello"; 3 ]
+(if p = [ 1 ] then 0 else 1) |> exit
\ No newline at end of file
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version46/W_IfThenElse03.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version46/W_IfThenElse03.fs
new file mode 100644
index 00000000000..9a357a9f2c6
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version46/W_IfThenElse03.fs
@@ -0,0 +1,11 @@
+// #Regression #Conformance #DataExpressions #Sequences
+// Regression test for FSHARP1.0:4527
+//.+'if ... then ... else'
+
+// warning FS0035: This construct is deprecated: 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.
+
+let p = [ if true then printfn "hello"; () ];;
+(if p = [ () ] then 0 else 1) |> exit
\ No newline at end of file
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse01.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version47/W_IfThenElse01.fs
similarity index 100%
rename from tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse01.fs
rename to tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version47/W_IfThenElse01.fs
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse02.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version47/W_IfThenElse02.fs
similarity index 100%
rename from tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse02.fs
rename to tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version47/W_IfThenElse02.fs
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse03.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version47/W_IfThenElse03.fs
similarity index 100%
rename from tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse03.fs
rename to tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/version47/W_IfThenElse03.fs
diff --git a/tests/fsharpqa/Source/Warnings/env.lst b/tests/fsharpqa/Source/Warnings/env.lst
index 383c291e906..3986ab5bc90 100644
--- a/tests/fsharpqa/Source/Warnings/env.lst
+++ b/tests/fsharpqa/Source/Warnings/env.lst
@@ -47,7 +47,7 @@
SOURCE=GuardHasWrongType.fs # GuardHasWrongType.fs
SOURCE=ElseBranchHasWrongType.fs # ElseBranchHasWrongType.fs
SOURCE=ElseBranchHasWrongType2.fs # ElseBranchHasWrongType2.fs
- SOURCE=ElseBranchHasWrongType3.fs # ElseBranchHasWrongType3.fs
+ SOURCE=ElseBranchHasWrongType3.fs # ElseBranchHasWrongType3.fs
SOURCE=ElseBranchHasWrongType4.fs # ElseBranchHasWrongType4.fs
SOURCE=NestedElseBranchHasWrongType.fs # NestedElseBranchHasWrongType.fs
SOURCE=ElseBranchHasWrongContextType.fs # ElseBranchHasWrongContextType.fs
@@ -77,9 +77,12 @@
SOURCE=WarnIfPossibleDotNetPropertySetter.fs
SOURCE=DontWarnIfPropertyWithoutSetter.fs
SOURCE=WarnIfImplicitlyDiscarded.fs
- SOURCE=WarnIfDiscardedInList.fs
- SOURCE=WarnIfDiscardedInList2.fs
- SOURCE=WarnIfDiscardedInList3.fs
+ SOURCE=version46/WarnIfDiscardedInList.fs SCFLAGS="--langversion:4.6" #version46/WarnIfDiscardedInList
+ SOURCE=version46/WarnIfDiscardedInList2.fs SCFLAGS="--langversion:4.6" #version46/WarnIfDiscardedInList2
+ SOURCE=version46/WarnIfDiscardedInList3.fs SCFLAGS="--langversion:4.6" #version46/WarnIfDiscardedInList3
+ SOURCE=version47/WarnIfDiscardedInList.fs SCFLAGS="--langversion:preview" #version47/WarnIfDiscardedInList
+ SOURCE=version47/WarnIfDiscardedInList2.fs SCFLAGS="--langversion:preview" #version47/WarnIfDiscardedInList2
+ SOURCE=version47/WarnIfDiscardedInList3.fs SCFLAGS="--langversion:preview" #version47/WarnIfDiscardedInList3
SOURCE=WarnOnlyOnLastExpression.fs
SOURCE=WarnIfPossiblePropertySetter.fs
SOURCE=DoCannotHaveVisibilityDeclarations.fs
diff --git a/tests/fsharpqa/Source/Warnings/version46/WarnIfDiscardedInList.fs b/tests/fsharpqa/Source/Warnings/version46/WarnIfDiscardedInList.fs
new file mode 100644
index 00000000000..d47a4c13769
--- /dev/null
+++ b/tests/fsharpqa/Source/Warnings/version46/WarnIfDiscardedInList.fs
@@ -0,0 +1,14 @@
+// #Warnings
+//
+
+let div _ _ = 1
+let subView _ _ = [1; 2]
+
+// elmish view
+let view model dispatch =
+ [
+ yield! subView model dispatch
+ div [] []
+ ]
+
+exit 0
\ No newline at end of file
diff --git a/tests/fsharpqa/Source/Warnings/version46/WarnIfDiscardedInList2.fs b/tests/fsharpqa/Source/Warnings/version46/WarnIfDiscardedInList2.fs
new file mode 100644
index 00000000000..cf0a8cc6e89
--- /dev/null
+++ b/tests/fsharpqa/Source/Warnings/version46/WarnIfDiscardedInList2.fs
@@ -0,0 +1,19 @@
+// #Warnings
+//
+
+// stupid things to make the sample compile
+let div _ _ = 1
+let subView _ _ = [1; 2]
+let y = 1
+
+// elmish view
+let view model dispatch =
+ [
+ div [] [
+ match y with
+ | 1 -> yield! subView model dispatch
+ | _ -> subView model dispatch
+ ]
+ ]
+
+exit 0
\ No newline at end of file
diff --git a/tests/fsharpqa/Source/Warnings/version46/WarnIfDiscardedInList3.fs b/tests/fsharpqa/Source/Warnings/version46/WarnIfDiscardedInList3.fs
new file mode 100644
index 00000000000..238d4388f9e
--- /dev/null
+++ b/tests/fsharpqa/Source/Warnings/version46/WarnIfDiscardedInList3.fs
@@ -0,0 +1,19 @@
+// #Warnings
+//
+
+// stupid things to make the sample compile
+let div _ _ = 1
+let subView _ _ = true
+let y = 1
+
+// elmish view
+let view model dispatch =
+ [
+ div [] [
+ match y with
+ | 1 -> ()
+ | _ -> subView model dispatch
+ ]
+ ]
+
+exit 0
\ No newline at end of file
diff --git a/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList.fs b/tests/fsharpqa/Source/Warnings/version47/WarnIfDiscardedInList.fs
similarity index 100%
rename from tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList.fs
rename to tests/fsharpqa/Source/Warnings/version47/WarnIfDiscardedInList.fs
diff --git a/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList2.fs b/tests/fsharpqa/Source/Warnings/version47/WarnIfDiscardedInList2.fs
similarity index 100%
rename from tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList2.fs
rename to tests/fsharpqa/Source/Warnings/version47/WarnIfDiscardedInList2.fs
diff --git a/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList3.fs b/tests/fsharpqa/Source/Warnings/version47/WarnIfDiscardedInList3.fs
similarity index 100%
rename from tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList3.fs
rename to tests/fsharpqa/Source/Warnings/version47/WarnIfDiscardedInList3.fs