diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index 586b91c41b0..1176c8dea81 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -2677,9 +2677,26 @@ let UndoIfFailed f = ReportWarnings warns true +let UndoIfFailedOrWarnings f = + let trace = Trace.New() + let res = + try + f trace + |> CheckNoErrorsAndGetWarnings + with e -> None + match res with + | Some [] -> + true + | _ -> + trace.Undo() + false + let AddCxTypeEqualsTypeUndoIfFailed denv css m ty1 ty2 = UndoIfFailed (fun trace -> SolveTypeEqualsTypeKeepAbbrevs (MakeConstraintSolverEnv ContextInfo.NoContext css m denv) 0 m (WithTrace trace) ty1 ty2) +let AddCxTypeEqualsTypeUndoIfFailedOrWarnings denv css m ty1 ty2 = + UndoIfFailedOrWarnings (fun trace -> SolveTypeEqualsTypeKeepAbbrevs (MakeConstraintSolverEnv ContextInfo.NoContext css m denv) 0 m (WithTrace trace) ty1 ty2) + let AddCxTypeEqualsTypeMatchingOnlyUndoIfFailed denv css m ty1 ty2 = let csenv = { MakeConstraintSolverEnv ContextInfo.NoContext css m denv with MatchingOnly = true } UndoIfFailed (fun trace -> SolveTypeEqualsTypeKeepAbbrevs csenv 0 m (WithTrace trace) ty1 ty2) diff --git a/src/fsharp/ConstraintSolver.fsi b/src/fsharp/ConstraintSolver.fsi index 59c271b126b..1fce009f616 100644 --- a/src/fsharp/ConstraintSolver.fsi +++ b/src/fsharp/ConstraintSolver.fsi @@ -126,6 +126,7 @@ val CheckDeclaredTypars : DisplayEnv -> ConstraintSolverSt val AddConstraint : ConstraintSolverEnv -> int -> Range.range -> OptionalTrace -> Typar -> TyparConstraint -> OperationResult val AddCxTypeEqualsType : ContextInfo -> DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> unit val AddCxTypeEqualsTypeUndoIfFailed : DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool +val AddCxTypeEqualsTypeUndoIfFailedOrWarnings : DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool val AddCxTypeEqualsTypeMatchingOnlyUndoIfFailed : DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool val AddCxTypeMustSubsumeType : ContextInfo -> DisplayEnv -> ConstraintSolverState -> range -> OptionalTrace -> TType -> TType -> unit val AddCxTypeMustSubsumeTypeUndoIfFailed : DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 4b5f756f06d..27d6bfd4b49 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -574,7 +574,6 @@ 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/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 2a1df70149b..8e06b79227b 100644 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -846,6 +846,10 @@ let UnifyUnitType cenv (env: TcEnv) m ty expr = false +let TryUnifyUnitTypeWithoutWarning cenv (env:TcEnv) m ty = + let denv = env.DisplayEnv + AddCxTypeEqualsTypeUndoIfFailedOrWarnings denv cenv.css m ty cenv.g.unit_ty + // Logically extends System.AttributeTargets module AttributeTargets = let FieldDecl = AttributeTargets.Field ||| AttributeTargets.Property @@ -3515,32 +3519,11 @@ let (|ExprAsPat|_|) (f: SynExpr) = /// 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|_|) acceptDeprecated c = - - 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.YieldOrReturnFrom _ - | SynExpr.YieldOrReturn _ - | SynExpr.LetOrUseBang _ - | SynExpr.ImplicitZero _ - | SynExpr.Do _ -> false - | _ -> true +let (|SimpleSemicolonSequence|_|) cexpr = - let rec IsSimpleSemicolonSequenceElement expr = + let IsSimpleSemicolonSequenceElement expr = match expr with - | SynExpr.IfThenElse _ when acceptDeprecated && YieldFree expr -> true | SynExpr.IfThenElse _ | SynExpr.TryWith _ | SynExpr.Match _ @@ -3553,15 +3536,14 @@ let (|SimpleSemicolonSequence|_|) acceptDeprecated c = | SynExpr.Do _ | SynExpr.MatchBang _ | SynExpr.LetOrUseBang _ - | SynExpr.ImplicitZero _ | SynExpr.While _ -> false | _ -> true - let rec GetSimpleSemicolonSequenceOfComprehension expr acc = + let rec TryGetSimpleSemicolonSequenceOfComprehension expr acc = match expr with | SynExpr.Sequential (_, true, e1, e2, _) -> if IsSimpleSemicolonSequenceElement e1 then - GetSimpleSemicolonSequenceOfComprehension e2 (e1 :: acc) + TryGetSimpleSemicolonSequenceOfComprehension e2 (e1 :: acc) else None | e -> @@ -3570,10 +3552,7 @@ let (|SimpleSemicolonSequence|_|) acceptDeprecated c = else None - if YieldFree c then - GetSimpleSemicolonSequenceOfComprehension c [] - else - None + TryGetSimpleSemicolonSequenceOfComprehension cexpr [] //------------------------------------------------------------------------- // Mutually recursive shapes @@ -5680,6 +5659,12 @@ and TcStmt cenv env tpenv synExpr = else mkCompGenSequential m expr (mkUnit cenv.g m), tpenv +and TryTcStmt cenv env tpenv synExpr = + let expr, ty, tpenv = TcExprOfUnknownType cenv env tpenv synExpr + let m = synExpr.Range + let hasTypeUnit = TryUnifyUnitTypeWithoutWarning cenv env m ty + hasTypeUnit, expr, tpenv + /// During checking of expressions of the form (x(y)).z(w1, w2) /// keep a stack of things on the right. This lets us recognize /// method applications and other item-based syntax. @@ -5946,25 +5931,18 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = match comp with | SynExpr.New _ -> errorR(Error(FSComp.SR.tcInvalidObjectExpressionSyntaxForm(), m)) - | SimpleSemicolonSequence false _ -> - errorR(Error(FSComp.SR.tcInvalidObjectSequenceOrRecordExpression(), m)) | _ -> () if not !isNotNakedRefCell && not cenv.g.compilingFslib then error(Error(FSComp.SR.tcInvalidSequenceExpressionSyntaxForm(), m)) - TcComputationOrSequenceExpression cenv env overallTy m None tpenv comp + TcSequenceExpression cenv env tpenv comp overallTy m | SynExpr.ArrayOrListOfSeqExpr (isArray, comp, m) -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.DisplayEnv, env.eAccessRights) match comp with - | SynExpr.CompExpr (_, _, (SimpleSemicolonSequence true elems as body), _) -> - match body with - | SimpleSemicolonSequence false _ -> - () - | _ -> - errorR(Deprecated(FSComp.SR.tcExpressionWithIfRequiresParenthesis(), m)) + | SynExpr.CompExpr (_, _, SimpleSemicolonSequence elems, _) -> let replacementExpr = if isArray then @@ -6063,6 +6041,19 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = let expr2, tpenv = TcStmtThatCantBeCtorBody cenv env tpenv synExpr2 Expr.Sequential (expr1, expr2, ThenDoSeq, sp, m), tpenv + // Used to implement the type-directed 'implicit yield' rule for computation expressions + | SynExpr.SequentialOrImplicitYield (sp, synExpr1, synExpr2, otherExpr, m) -> + let isStmt, expr1, tpenv = TryTcStmt cenv env tpenv synExpr1 + if isStmt then + let env = ShrinkContext env m synExpr2.Range + let expr2, tpenv = TcExprThatCanBeCtorBody cenv overallTy env tpenv synExpr2 + Expr.Sequential(expr1, expr2, NormalSeq, sp, m), tpenv + else + // The first expression wasn't unit-typed, so proceed to the alternative interpretation + // Note a copy of the first expression is embedded in 'otherExpr' and thus + // this will type-check the first expression over again. + TcExpr cenv overallTy env tpenv otherExpr + | SynExpr.Do (synInnerExpr, m) -> UnifyTypes cenv env m overallTy cenv.g.unit_ty TcStmtThatCantBeCtorBody cenv env tpenv synInnerExpr @@ -7336,24 +7327,38 @@ and TcQuotationExpr cenv overallTy env tpenv (_oper, raw, ast, isFromQueryExpres // We serialize the quoted expression to bytes in IlxGen after type inference etc. is complete. expr, tpenv -//------------------------------------------------------------------------- -// TcComputationOrSequenceExpression -//------------------------------------------------------------------------- - -and TcComputationOrSequenceExpression cenv (env: TcEnv) overallTy m interpValOpt tpenv comp = - match interpValOpt with - | Some (interpExpr: Expr, builderTy) -> - TcComputationExpression cenv env overallTy m interpExpr builderTy tpenv comp - | None -> - TcSequenceExpression cenv env tpenv comp overallTy m - /// Ignores an attribute and IgnoreAttribute _ = None -// Used for all computation expressions except sequence expressions -and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv comp = +/// 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 - //dprintfn "TcComputationOrSequenceExpression, comp = \n%A\n-------------------\n" comp +/// Used for all computation expressions except sequence expressions +and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builderTy tpenv (comp: SynExpr) = + + //dprintfn "TcComputationExpression, comp = \n%A\n-------------------\n" comp let ad = env.eAccessRights let mkSynDelay2 (e: SynExpr) = mkSynDelay (e.Range.MakeSynthetic()) e @@ -7382,19 +7387,18 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv let builderVal = mkSynIdGet m builderValName mkSynApp1 (SynExpr.DotGet (builderVal, range0, LongIdentWithDots([mkSynId m nm], []), m)) args m - let sourceMethInfo = TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad "Source" builderTy + let hasMethInfo nm = TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad nm builderTy |> isNil |> not + + let sourceMethInfo = TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad "Source" builderTy + // Optionally wrap sources of "let!", "yield!", "use!" in "query.Source" let mkSourceExpr callExpr = match sourceMethInfo with | [] -> callExpr | _ -> mkSynCall "Source" callExpr.Range [callExpr] - /// Decide if the builder is an auto-quote builder - let isAutoQuote = - match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad "Quote" builderTy with - | [] -> false - | _ -> true + let isAutoQuote = hasMethInfo "Quote" let customOperationMethods = AllMethInfosOfTypeInScope ResultCollectionSettings.AllResults cenv.infoReader env.NameEnv None ad IgnoreOverrides mBuilderVal builderTy @@ -7552,7 +7556,6 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv let (_, argInfo) = List.item i argInfos HasFSharpAttribute cenv.g cenv.g.attrib_ProjectionParameterAttribute argInfo.Attribs - let (|ForEachThen|_|) e = match e with | SynExpr.ForEach (_spBind, SeqExprOnly false, isFromSource, pat1, expr1, SynExpr.Sequential (_, true, clause, rest, _), _) -> Some (isFromSource, pat1, expr1, clause, rest) @@ -7705,7 +7708,6 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv | _ -> None - let (|StripApps|) e = let rec strip e = match e with @@ -7764,6 +7766,20 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv | SynExpr.Sequential (_sp, true, dataComp1, dataComp2, _) -> (dataComp1, Some dataComp2) | _ -> (e, None) + // "cexpr; cexpr" is treated as builder.Combine(cexpr1, cexpr1) + // This is not pretty - we have to decide which range markers we use for the calls to Combine and Delay + // NOTE: we should probably suppress these sequence points altogether + let rangeForCombine innerComp1 = + match innerComp1 with + | SynExpr.IfThenElse (_, _, _, _, _, mIfToThen, _m) -> mIfToThen + | SynExpr.Match (SequencePointAtBinding mMatch, _, _, _) -> mMatch + | SynExpr.TryWith (_, _, _, _, _, SequencePointAtTry mTry, _) -> mTry + | SynExpr.TryFinally (_, _, _, SequencePointAtTry mTry, _) -> mTry + | SynExpr.For (SequencePointAtForLoop mBind, _, _, _, _, _, _) -> mBind + | SynExpr.ForEach (SequencePointAtForLoop mBind, _, _, _, _, _, _) -> mBind + | SynExpr.While (SequencePointAtWhileLoop mWhile, _, _, _) -> mWhile + | _ -> innerComp1.Range + // Check for 'where x > y', 'select x, y' and other mis-applications of infix operators, give a good error message, and return a flag let checkForBinaryApp comp = match comp with @@ -7794,6 +7810,11 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv let emptyVarSpace = LazyWithContext.NotLazy ([], env) + // 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 + // 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 // comp - the computation expression being analyzed @@ -8160,16 +8181,7 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv // "cexpr; cexpr" is treated as builder.Combine(cexpr1, cexpr1) // This is not pretty - we have to decide which range markers we use for the calls to Combine and Delay // NOTE: we should probably suppress these sequence points altogether - let m1 = - match innerComp1 with - | SynExpr.IfThenElse (_, _, _, _, _, mIfToThen, _m) -> mIfToThen - | SynExpr.Match (SequencePointAtBinding mMatch, _, _, _) -> mMatch - | SynExpr.TryWith (_, _, _, _, _, SequencePointAtTry mTry, _) -> mTry - | SynExpr.TryFinally (_, _, _, SequencePointAtTry mTry, _) -> mTry - | SynExpr.For (SequencePointAtForLoop mBind, _, _, _, _, _, _) -> mBind - | SynExpr.ForEach (SequencePointAtForLoop mBind, _, _, _, _, _, _) -> mBind - | SynExpr.While (SequencePointAtWhileLoop mWhile, _, _, _) -> mWhile - | _ -> innerComp1.Range + let m1 = rangeForCombine innerComp1 if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Combine" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Combine"), m)) if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Delay" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), m)) Some (translatedCtxt (mkSynCall "Combine" m1 [c; mkSynCall "Delay" m1 [mkSynDelay innerComp2.Range (transNoQueryOps innerComp2)]])) @@ -8185,7 +8197,21 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv Some(trans true q varSpace (SynExpr.LetOrUseBang (sp, false, true, SynPat.Const(SynConst.Unit, rhsExpr.Range), rhsExpr, innerComp2, m)) translatedCtxt) // "expr; cexpr" is treated as sequential execution | _ -> - Some (trans true q varSpace innerComp2 (fun holeFill -> translatedCtxt (SynExpr.Sequential (sp, true, innerComp1, holeFill, m)))) + Some (trans true q varSpace innerComp2 (fun holeFill -> + let fillExpr = + 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'. + let combineExpr = + let m1 = rangeForCombine innerComp1 + let implicitYieldExpr = mkSynCall "Yield" comp.Range [innerComp1] + mkSynCall "Combine" m1 [implicitYieldExpr; mkSynCall "Delay" m1 [mkSynDelay holeFill.Range holeFill]] + SynExpr.SequentialOrImplicitYield(sp, innerComp1, holeFill, combineExpr, m) + else + SynExpr.Sequential(sp, true, innerComp1, holeFill, m) + translatedCtxt fillExpr)) | SynExpr.IfThenElse (guardExpr, thenComp, elseCompOpt, spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch) -> match elseCompOpt with @@ -8314,7 +8340,6 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv Some (translatedCtxt yieldExpr) else Some (translatedCtxt (mkSynCall "ReturnFrom" m [yieldExpr])) - | SynExpr.YieldOrReturn ((isYield, _), yieldExpr, m) -> let methName = (if isYield then "Yield" else "Return") @@ -8324,7 +8349,9 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv | _ -> None - and transNoQueryOps comp = trans true false emptyVarSpace comp id + and transNoQueryOps comp = + trans true false emptyVarSpace comp id + and trans firstTry q varSpace comp translatedCtxt = match tryTrans firstTry q varSpace comp translatedCtxt with | Some e -> e @@ -8340,8 +8367,9 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Return" builderTy) then SynExpr.ImplicitZero m else - SynExpr.YieldOrReturn ((false, true), SynExpr.Const (SynConst.Unit, m), m) - trans true q varSpace (SynExpr.LetOrUseBang (NoSequencePointAtDoBinding, false, false, SynPat.Const(SynConst.Unit, mUnit), rhsExpr, bodyExpr, m)) translatedCtxt + SynExpr.YieldOrReturn((false, true), SynExpr.Const (SynConst.Unit, m), m) + trans true q varSpace (SynExpr.LetOrUseBang(NoSequencePointAtDoBinding, false, false, SynPat.Const(SynConst.Unit, mUnit), rhsExpr, bodyExpr, m)) translatedCtxt + // "expr;" in final position is treated as { expr; zero } // Suppress the sequence point on the "zero" | _ -> @@ -8353,21 +8381,27 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv 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 true q varSpace (SynExpr.ImplicitZero comp.Range) (fun holeFill -> translatedCtxt (SynExpr.Sequential (SuppressSequencePointOnStmtOfSequential, true, comp, holeFill, comp.Range))) + trans true q varSpace (SynExpr.ImplicitZero comp.Range) (fun holeFill -> + let fillExpr = + if enableImplicitYield then + let implicitYieldExpr = mkSynCall "Yield" comp.Range [comp] + SynExpr.SequentialOrImplicitYield(SuppressSequencePointOnStmtOfSequential, comp, holeFill, implicitYieldExpr, comp.Range) + else + SynExpr.Sequential(SuppressSequencePointOnStmtOfSequential, true, comp, holeFill, comp.Range) + translatedCtxt fillExpr) - let basicSynExpr = trans true (hasCustomOperations ()) (LazyWithContext.NotLazy ([], env)) comp (fun holeFill -> holeFill) + let basicSynExpr = + trans true (hasCustomOperations ()) (LazyWithContext.NotLazy ([], env)) comp (fun holeFill -> holeFill) let delayedExpr = match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad "Delay" builderTy with | [] -> basicSynExpr | _ -> mkSynCall "Delay" mBuilderVal [(mkSynDelay2 basicSynExpr)] - let quotedSynExpr = if isAutoQuote then SynExpr.Quote (mkSynIdGet (mBuilderVal.MakeSynthetic()) (CompileOpName "<@ @>"), (*isRaw=*)false, delayedExpr, (*isFromQueryExpression=*)true, mWhole) else delayedExpr - let runExpr = match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad "Run" builderTy with @@ -8405,6 +8439,11 @@ and TcSequenceExpression cenv env tpenv comp overallTy m = // Allow subsumption at 'yield' if the element type is nominal prior to the analysis of the body of the sequence expression let flex = not (isTyparTy cenv.g genEnumElemTy) + // 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 mkDelayedExpr (coreExpr: Expr) = let m = coreExpr.Range let overallTy = tyOfExpr cenv.g coreExpr @@ -8464,8 +8503,6 @@ and TcSequenceExpression cenv env tpenv comp overallTy m = let innerExprMark = innerExpr.Range Some(mkSeqFinally cenv env innerExprMark genOuterTy innerExpr unwindExpr, tpenv) - | SynExpr.Paren (_, _, _, m) -> - error(Error(FSComp.SR.tcConstructIsAmbiguousInSequenceExpression(), m)) | SynExpr.ImplicitZero m -> Some(mkSeqEmpty cenv env m genOuterTy, tpenv ) @@ -8476,17 +8513,15 @@ and TcSequenceExpression cenv env tpenv comp overallTy m = | SynExpr.Sequential (sp, true, innerComp1, innerComp2, m) -> // "expr; cexpr" is treated as sequential execution // "cexpr; cexpr" is treated as append - match tryTcSequenceExprBody env genOuterTy tpenv innerComp1 with - | None -> - let innerExpr1, tpenv = TcStmtThatCantBeCtorBody cenv env tpenv innerComp1 - let innerExpr2, tpenv = tcSequenceExprBody env genOuterTy tpenv innerComp2 - - Some(Expr.Sequential (innerExpr1, innerExpr2, NormalSeq, sp, m), tpenv) - - | Some (innerExpr1, tpenv) -> + let res, tpenv = tcSequenceExprBodyAsSequenceOrStatement env genOuterTy tpenv innerComp1 + match res with + | Choice1Of2 innerExpr1 -> let innerExpr2, tpenv = tcSequenceExprBody env genOuterTy tpenv innerComp2 let innerExpr2 = mkDelayedExpr innerExpr2 Some(mkSeqAppend cenv env innerComp1.Range genOuterTy innerExpr1 innerExpr2, tpenv) + | Choice2Of2 stmt1 -> + let innerExpr2, tpenv = tcSequenceExprBody env genOuterTy tpenv innerComp2 + Some(Expr.Sequential(stmt1, innerExpr2, NormalSeq, sp, m), tpenv) | SynExpr.IfThenElse (guardExpr, thenComp, elseCompOpt, spIfToThen, _isRecovery, mIfToThen, mIfToEndOfElseBranch) -> let guardExpr', tpenv = TcExpr cenv cenv.g.bool_ty env tpenv guardExpr @@ -8560,15 +8595,34 @@ and TcSequenceExpression cenv env tpenv comp overallTy m = | _ -> None and tcSequenceExprBody env genOuterTy tpenv comp = + let res, tpenv = tcSequenceExprBodyAsSequenceOrStatement env genOuterTy tpenv comp + match res with + | Choice1Of2 expr -> + expr, tpenv + | Choice2Of2 stmt -> + let m = comp.Range + let resExpr = Expr.Sequential(stmt, mkSeqEmpty cenv env m genOuterTy, NormalSeq, SuppressSequencePointOnStmtOfSequential, m) + resExpr, tpenv + + and tcSequenceExprBodyAsSequenceOrStatement env genOuterTy tpenv comp = match tryTcSequenceExprBody env genOuterTy tpenv comp with - | Some e -> e + | Some (expr, tpenv) -> Choice1Of2 expr, tpenv | None -> - // seq { ...; expr } is treated as 'seq { ... ; expr; yield! Seq.empty }' - // Note this means seq { ...; () } is treated as 'seq { ... ; (); yield! Seq.empty }' - let m = comp.Range let env = { env with eContextInfo = ContextInfo.SequenceExpression genOuterTy } - let expr, tpenv = TcStmtThatCantBeCtorBody cenv env tpenv comp - Expr.Sequential (expr, mkSeqEmpty cenv env m genOuterTy, NormalSeq, SuppressSequencePointOnStmtOfSequential, m), tpenv + if enableImplicitYield then + let hasTypeUnit, expr, tpenv = TryTcStmt cenv env tpenv comp + if hasTypeUnit then + Choice2Of2 expr, tpenv + else + let genResultTy = NewInferenceType () + UnifyTypes cenv env m genOuterTy (mkSeqTy cenv.g genResultTy) + let exprTy = tyOfExpr cenv.g expr + AddCxTypeMustSubsumeType env.eContextInfo env.DisplayEnv cenv.css m NoTrace genResultTy exprTy + let resExpr = mkCallSeqSingleton cenv.g m genResultTy (mkCoerceExpr(expr, genResultTy, m, exprTy)) + Choice1Of2 resExpr, tpenv + else + let stmt, tpenv = TcStmtThatCantBeCtorBody cenv env tpenv comp + Choice2Of2 stmt, tpenv let coreExpr, tpenv = tcSequenceExprBody env overallTy tpenv comp let delayedExpr = mkDelayedExpr coreExpr @@ -8788,7 +8842,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( // OK, 'expr' doesn't have function type, but perhaps 'expr' is a computation expression builder, and 'arg' is '{ ... }' match synArg with | SynExpr.CompExpr (false, _isNotNakedRefCell, comp, _m) -> - let bodyOfCompExpr, tpenv = TcComputationOrSequenceExpression cenv env overallTy mFunExpr (Some(expr.Expr, exprty)) tpenv comp + let bodyOfCompExpr, tpenv = TcComputationExpression cenv env overallTy mFunExpr expr.Expr exprty tpenv comp TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed | _ -> error (NotAFunction(denv, overallTy, mFunExpr, mArg)) @@ -9172,6 +9226,7 @@ and TcItemThen cenv overallTy env tpenv (item, mItem, rest, afterResolution) del | SynExpr.TryFinally _ | SynExpr.Lazy _ | SynExpr.Sequential _ + | SynExpr.SequentialOrImplicitYield _ | SynExpr.LetOrUse _ | SynExpr.DotSet _ | SynExpr.DotIndexedSet _ diff --git a/src/fsharp/ast.fs b/src/fsharp/ast.fs index 57343ec57e4..7eefb1470a1 100644 --- a/src/fsharp/ast.fs +++ b/src/fsharp/ast.fs @@ -672,7 +672,7 @@ and /// F# syntax: lazy expr | Lazy of SynExpr * range: range - /// Seq(seqPoint, isTrueSeq, e1, e2, m) + /// Sequential(seqPoint, isTrueSeq, e1, e2, m) /// isTrueSeq: false indicates "let v = a in b; v" /// /// F# syntax: expr; expr @@ -750,10 +750,12 @@ and /// Computation expressions only, based on JOIN_IN token from lex filter | JoinIn of SynExpr * range * SynExpr * range: range - /// F# syntax: - /// Computation expressions only, implied by final "do" or "do!" + /// Used internally during type checking for translating computation expressions. | ImplicitZero of range: range + /// Used internally during type checking for translating computation expressions. + | SequentialOrImplicitYield of seqPoint:SequencePointInfoForSeq * expr1:SynExpr * expr2:SynExpr * ifNotStmt:SynExpr * range:range + /// F# syntax: yield expr /// F# syntax: return expr /// Computation expressions only @@ -834,6 +836,7 @@ and | SynExpr.TryWith (range=m) | SynExpr.TryFinally (range=m) | SynExpr.Sequential (range=m) + | SynExpr.SequentialOrImplicitYield (range=m) | SynExpr.ArbitraryAfterError (range=m) | SynExpr.FromParseError (range=m) | SynExpr.DiscardAfterMissingQualificationAfterDot (range=m) @@ -873,138 +876,25 @@ and /// range ignoring any (parse error) extra trailing dots member e.RangeSansAnyExtraDot = match e with - | SynExpr.Paren (range=m) - | SynExpr.Quote (range=m) - | SynExpr.Const (range=m) - | SynExpr.Typed (range=m) - | SynExpr.Tuple (range=m) - | SynExpr.ArrayOrList (range=m) - | SynExpr.AnonRecd (range=m) - | SynExpr.Record (range=m) - | SynExpr.New (range=m) - | SynExpr.ObjExpr (range=m) - | SynExpr.While (range=m) - | SynExpr.For (range=m) - | SynExpr.ForEach (range=m) - | SynExpr.CompExpr (range=m) - | SynExpr.ArrayOrListOfSeqExpr (range=m) - | SynExpr.Lambda (range=m) - | SynExpr.Match (range=m) - | SynExpr.MatchLambda (range=m) - | SynExpr.Do (range=m) - | SynExpr.Assert (range=m) - | SynExpr.App (range=m) - | SynExpr.TypeApp (range=m) - | SynExpr.LetOrUse (range=m) - | SynExpr.TryWith (range=m) - | SynExpr.TryFinally (range=m) - | SynExpr.Sequential (range=m) - | SynExpr.ArbitraryAfterError (range=m) - | SynExpr.FromParseError (range=m) - | SynExpr.IfThenElse (range=m) - | SynExpr.LongIdentSet (range=m) - | SynExpr.NamedIndexedPropertySet (range=m) - | SynExpr.DotIndexedGet (range=m) - | SynExpr.DotIndexedSet (range=m) - | SynExpr.DotSet (range=m) - | SynExpr.Set (range=m) - | SynExpr.DotNamedIndexedPropertySet (range=m) - | SynExpr.LibraryOnlyUnionCaseFieldGet (range=m) - | SynExpr.LibraryOnlyUnionCaseFieldSet (range=m) - | SynExpr.LibraryOnlyILAssembly (range=m) - | SynExpr.LibraryOnlyStaticOptimization (range=m) - | SynExpr.TypeTest (range=m) - | SynExpr.Upcast (range=m) - | SynExpr.AddressOf (range=m) - | SynExpr.Downcast (range=m) - | SynExpr.JoinIn (range=m) - | SynExpr.InferredUpcast (range=m) - | SynExpr.InferredDowncast (range=m) - | SynExpr.Null (range=m) - | SynExpr.Lazy (range=m) - | SynExpr.TraitCall (range=m) - | SynExpr.ImplicitZero (range=m) - | SynExpr.YieldOrReturn (range=m) - | SynExpr.YieldOrReturnFrom (range=m) - | SynExpr.LetOrUseBang (range=m) - | SynExpr.MatchBang (range=m) - | SynExpr.DoBang (range=m) -> m | SynExpr.DotGet (expr, _, lidwd, m) -> if lidwd.ThereIsAnExtraDotAtTheEnd then unionRanges expr.Range lidwd.RangeSansAnyExtraDot else m | SynExpr.LongIdent (_, lidwd, _, _) -> lidwd.RangeSansAnyExtraDot | SynExpr.DiscardAfterMissingQualificationAfterDot (expr, _) -> expr.Range - | SynExpr.Fixed (_, m) -> m - | SynExpr.Ident id -> id.idRange + | _ -> e.Range /// 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 member e.RangeOfFirstPortion = match e with - // haven't bothered making these cases better than just .Range - | SynExpr.Quote (range=m) - | SynExpr.Const (range=m) - | SynExpr.Typed (range=m) - | SynExpr.Tuple (range=m) - | SynExpr.ArrayOrList (range=m) - | SynExpr.AnonRecd (range=m) - | SynExpr.Record (range=m) - | SynExpr.New (range=m) - | SynExpr.ObjExpr (range=m) - | SynExpr.While (range=m) - | SynExpr.For (range=m) - | SynExpr.CompExpr (range=m) - | SynExpr.ArrayOrListOfSeqExpr (range=m) - | SynExpr.Lambda (range=m) - | SynExpr.Match (range=m) - | SynExpr.MatchLambda (range=m) - | SynExpr.Do (range=m) - | SynExpr.Assert (range=m) - | SynExpr.TypeApp (range=m) - | SynExpr.LetOrUse (range=m) - | SynExpr.TryWith (range=m) - | SynExpr.TryFinally (range=m) - | SynExpr.ArbitraryAfterError (range=m) - | SynExpr.FromParseError (range=m) - | SynExpr.DiscardAfterMissingQualificationAfterDot (range=m) - | SynExpr.IfThenElse (range=m) - | SynExpr.LongIdent (range=m) - | SynExpr.LongIdentSet (range=m) - | SynExpr.NamedIndexedPropertySet (range=m) - | SynExpr.DotIndexedGet (range=m) - | SynExpr.DotIndexedSet (range=m) - | SynExpr.DotGet (range=m) - | SynExpr.DotSet (range=m) - | SynExpr.Set (range=m) - | SynExpr.DotNamedIndexedPropertySet (range=m) - | SynExpr.LibraryOnlyUnionCaseFieldGet (range=m) - | SynExpr.LibraryOnlyUnionCaseFieldSet (range=m) - | SynExpr.LibraryOnlyILAssembly (range=m) - | SynExpr.LibraryOnlyStaticOptimization (range=m) - | SynExpr.TypeTest (range=m) - | SynExpr.Upcast (range=m) - | SynExpr.AddressOf (range=m) - | SynExpr.Downcast (range=m) - | SynExpr.JoinIn (range=m) - | SynExpr.InferredUpcast (range=m) - | SynExpr.InferredDowncast (range=m) - | SynExpr.Null (range=m) - | SynExpr.Lazy (range=m) - | SynExpr.TraitCall (range=m) - | SynExpr.ImplicitZero (range=m) - | SynExpr.YieldOrReturn (range=m) - | SynExpr.YieldOrReturnFrom (range=m) - | SynExpr.LetOrUseBang (range=m) - | SynExpr.MatchBang (range=m) - | SynExpr.DoBang (range=m) -> m // these are better than just .Range, and also commonly applicable inside queries | SynExpr.Paren (_, m, _, _) -> m | SynExpr.Sequential (_, _, e1, _, _) + | SynExpr.SequentialOrImplicitYield (_, e1, _, _, _) | SynExpr.App (_, _, e1, _, _) -> e1.RangeOfFirstPortion | SynExpr.ForEach (_, _, _, pat, _, _, r) -> let start = r.Start let e = (pat.Range: range).Start mkRange r.FileName start e - | SynExpr.Ident id -> id.idRange - | SynExpr.Fixed (_, m) -> m + | _ -> e.Range and [] @@ -2580,6 +2470,8 @@ let rec synExprContainsError inpExpr = walkExpr e1 || walkExpr e2 | SynExpr.Sequential (_, _, e1, e2, _) -> walkExpr e1 || walkExpr e2 + | SynExpr.SequentialOrImplicitYield (_, e1, e2, _, _) -> + walkExpr e1 || walkExpr e2 | SynExpr.IfThenElse (e1, e2, e3opt, _, _, _, _) -> walkExpr e1 || walkExpr e2 || walkExprOpt e3opt | SynExpr.DotIndexedGet (e1, es, _, _) -> diff --git a/src/fsharp/service/ServiceParseTreeWalk.fs b/src/fsharp/service/ServiceParseTreeWalk.fs index abd3472a680..eeab436524f 100755 --- a/src/fsharp/service/ServiceParseTreeWalk.fs +++ b/src/fsharp/service/ServiceParseTreeWalk.fs @@ -412,6 +412,7 @@ module public AstTraversal = dive synExpr2 synExpr2.Range traverseSynExpr] |> pick expr | SynExpr.Lazy (synExpr, _range) -> traverseSynExpr synExpr + | SynExpr.SequentialOrImplicitYield (_sequencePointInfoForSeq, synExpr, synExpr2, _, _range) | SynExpr.Sequential (_sequencePointInfoForSeq, _, synExpr, synExpr2, _range) -> [dive synExpr synExpr.Range traverseSynExpr dive synExpr2 synExpr2.Range traverseSynExpr] diff --git a/src/fsharp/service/ServiceUntypedParse.fs b/src/fsharp/service/ServiceUntypedParse.fs index f98fae2f720..84c8947d13d 100755 --- a/src/fsharp/service/ServiceUntypedParse.fs +++ b/src/fsharp/service/ServiceUntypedParse.fs @@ -299,6 +299,7 @@ type FSharpParseFileResults(errors: FSharpErrorInfo[], input: Ast.ParsedInput op yield! walkTrySeqPt spTry yield! walkFinallySeqPt spFinally + | SynExpr.SequentialOrImplicitYield (spSeq, e1, e2, _, _) | SynExpr.Sequential (spSeq, _, e1, e2, _) -> yield! walkExpr (match spSeq with SuppressSequencePointOnStmtOfSequential -> false | _ -> true) e1 yield! walkExpr (match spSeq with SuppressSequencePointOnExprOfSequential -> false | _ -> true) e2 diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 7c1b38a4b5f..6995c485abb 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -2847,11 +2847,6 @@ 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 33a03002ea8..1d4725f1824 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -2847,11 +2847,6 @@ 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 07a6a376d6c..dba9ebb7f77 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -2847,11 +2847,6 @@ 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 db443013ccc..067c0d42c98 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -2847,11 +2847,6 @@ 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 27d3af91a0e..6ff1a468356 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -2847,11 +2847,6 @@ 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 47430c5e72b..822ef18990e 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -2847,11 +2847,6 @@ オブジェクト式が無効です。オーバーライドまたはインターフェイスがないオブジェクトには、かっこなしで '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 2f3708ed03f..b77f3b4cad4 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -2847,11 +2847,6 @@ 개체 식이 잘못되었습니다. 재정의 또는 인터페이스가 없는 개체는 중괄호 없이 식 형식 '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 4b92b5b6a51..0f3e6ef69b3 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -2847,11 +2847,6 @@ 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 d679c9502a5..2e4ea8c6dcb 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -2847,11 +2847,6 @@ 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 3fc4173787b..5ead2841146 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -2847,11 +2847,6 @@ Недопустимое выражение объекта. Объекты без переопределений или интерфейсов должны использовать форму выражения "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 a04bc7ada54..db70140c760 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -2847,11 +2847,6 @@ 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 38918ceec9f..d90cfb843c7 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -2847,11 +2847,6 @@ 对象表达式无效。没有重写或接口的对象应使用不带括号的表达式格式“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 1a02de7e416..6bdcae208b5 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -2847,11 +2847,6 @@ 無效的物件運算式。沒有覆寫或介面的物件應該使用不加大括號的運算式形式 '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/tests.fs b/tests/fsharp/tests.fs index cd9a7c8b687..fd403d80ad6 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -2372,7 +2372,11 @@ module TypecheckTests = let ``type check neg23`` () = singleNegTest (testConfig "typecheck/sigs") "neg23" [] - let ``type check neg24`` () = singleNegTest (testConfig "typecheck/sigs") "neg24" + let ``type check neg24`` () = + let cfg = testConfig "typecheck/sigs" + // 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" [] let ``type check neg25`` () = singleNegTest (testConfig "typecheck/sigs") "neg25" diff --git a/tests/fsharp/typecheck/sigs/neg24.bsl b/tests/fsharp/typecheck/sigs/neg24.bsl index b782269bb54..f276c01968b 100644 --- a/tests/fsharp/typecheck/sigs/neg24.bsl +++ b/tests/fsharp/typecheck/sigs/neg24.bsl @@ -1,30 +1,44 @@ -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(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(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(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(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(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(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(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(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(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(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(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(17,18,17,45): typecheck error FS0739: Invalid object, sequence or record expression +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. -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(300,29,300,30): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. -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(301,17,301,18): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. -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(302,33,302,34): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'unit'. This element has type 'int'. -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(302,36,302,37): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'unit'. This element has type 'int'. -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(304,11,305,32): typecheck error FS0193: Type constraint mismatch. The type + 'int' +is not compatible with type + 'unit' -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(308,30,308,31): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. -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. +neg24.fs(309,31,309,32): typecheck error FS0001: This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'int'. + +neg24.fs(312,33,312,34): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. + +neg24.fs(313,38,313,39): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. + +neg24.fs(313,47,313,48): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. + +neg24.fs(331,24,331,25): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +neg24.fs(337,30,337,31): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +neg24.fs(337,37,337,42): typecheck error FS0020: The result of this expression has type 'obj' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. diff --git a/tests/fsharp/typecheck/sigs/neg24.fs b/tests/fsharp/typecheck/sigs/neg24.fs index 22a8f4df45f..6e1e072cf1a 100644 --- a/tests/fsharp/typecheck/sigs/neg24.fs +++ b/tests/fsharp/typecheck/sigs/neg24.fs @@ -6,15 +6,15 @@ 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) } + +module OldNegative = + let v1 = [ if true then 1 else 2 ] // no longer an error or warning + let v2 = [ if true then () else () ] // no longer an error or warning + let v6 = [ if true then () ] // no longer an error or warning + let a1 = [| if true then 1 else 2 |] // no longer an error or warning + let a2 = [| if true then () else () |] // no longer an error or warning + let a6 = [| if true then () |] // no longer an error or warning + let s3 = seq { (if true then 1 else 2) } // no longer an error or warning // expect no warning module Positive = @@ -69,3 +69,271 @@ type C() = // Check that the error for a named argument/setter that does not exist is located in a good place let _ = C().M(qez=3) +module ListPositive2 = + // In this example, implicit yield is enabled becaue there is no explicit 'yield' + let v3 = + [ if true then 1 else 2 ] + + // In this example, implicit yield is enabled because there is no explicit 'yield'. + // When using implicit yield, statements are detected via a type-directed rule which tries + // checks the statement without an expected type and then checks if the type of the resulting + // expression has type 'unit'. + let v3a = + [ printfn "hello" + if true then 1 else 2 // implicit yield enabled + ] + + // In this example, implicit yield is enabled even though there is an explicit 'yield!' + // This is because using 'yield!' is the only way to yield anything + let v3b = + [ printfn "hello" + if true then 1 else 2 + yield! [] ] + + // This example checks subsumption is permitted when using implicit yield + let v3c : obj list = + [ printfn "hello" + if true then 1 else obj() ] + + // Another check that implicit yield is enabled , even though there is a `yield!` + let v3d = + [ if true then 1 else 2 + yield! [] ] + + // Another check that implicit yield is enabled , even though there is a `yield!` + let v3e = + [ yield! [] + if true then 1 else 2 + ] + + // Another check that implicit yield is enabled + let v3f = + [ if true then + printfn "hello" + 1 + else + 2 ] + + // Another check that implicit yield is enabled + let v3g = + [ if true then + 1 + else + printfn "hello" + 2 ] + + // Another check that implicit yield is enabled + let v3h = + [ for i in 1 .. 10 do + 10 + printfn "hello" ] + + // Another check that implicit yield is enabled + let v5 = + [ if true then 1 ] + + // Another check that implicit yield is enabled + let v5a = + [ printfn "hello"; + if true then 1 ] + + // Another check that implicit yield is enabled + let v5b = + [ if true then + printfn "hello" + 1 + ] + +module ArrayPositive2 = + let a3 = + [| (if true then 1 else 2) |] // simple single element sequence + + let a5 = + [| if true then 1 |] + + let l10 = + [ printfn "hello"; yield 1; yield 2 ] // expect ok - the printfn has type unit and is not interpreted as a yield + + // simple case of explicit yield + let l12 : int list = + [ printfn "hello" + if true then yield 1 else yield 2 ] + + // check subsumption is allowed when using explicit yield + let l13 : obj list = + [ printfn "hello" + if true then yield 1 else yield 2 ] + + // check subsumption is allowed when using explicit yield + let l14 : obj list = + [ printfn "hello" + if true then yield 1 ] + +module SeqPositive2 = + let s2 = + seq { if true then () else () } + + let s6 = + seq { if true then () } + + let s4 = + seq { if true then 1 else 2 } + + let s6 = + seq { if true then 1 } + + let s7 = + seq { match 1 with 1 -> 4 | 2 -> 5 | 3 -> 6 | _ -> () } + +module BuilderPositive2 = + type L<'T> = { Make: (unit -> 'T list) } + let L f = { Make = f } + + type ListBuilder() = + member __.Combine(x1: L<'T>, x2: L<'T>) = L(fun () -> x1.Make() @ x2.Make()) + member __.Delay(f: unit -> L<'T>) = L(fun () -> f().Make()) + member __.Zero() = L(fun () -> []) + member __.Yield(a: 'T) = L(fun () -> [a]) + member __.YieldFrom(x: L<'T>) = x + + let list = ListBuilder() + let empty<'T> : L<'T> = list.Zero() + + let v3 = + list { if true then 1 else 2 } // implicit yield enabled + + let v3y = + list { if true then yield 1 else yield 2 } // equivalent explicit yield + + let v3a = + list { + printfn "hello" + if true then 1 else 2 // implicit yield enabled + } + + let v3ay = + list { + printfn "hello" + if true then yield 1 else yield 2 // equivalent explicit yield + } + + let v3b = + list { + printfn "hello" + if true then 1 else 2 // implicit yield, even though there is a `yield!` + yield! empty + } + + let v3bc = + list { + printfn "hello" + if true then yield 1 else yield 2 // equivalent explicit yield + yield! empty + } + + + + + + + + + + + + + + let v3d = + list { + if true then 1 else 2 // implicit yield enabled , even though there is a `yield!` + yield! empty + } + + let v3dy = + list { + if true then yield 1 else yield 2 // equivalent explicit yield + yield! empty + } + + let v3e = + list { + yield! empty + if true then 1 else 2 // implicit yield enabled , even though there is a `yield!` + } + + let v3f = + list { + if true then + printfn "hello" + 1 + else 2 + } + + let v3g = + list { + if true then + 1 + else + printfn "hello" + 2 + } + + let v5 = + list { + if true then 1 + } + + let v5a = + list { + printfn "hello"; + if true then 1 + } + + let v5b = + list { + if true then + printfn "hello" + 1 + } + +module ListNegative2 = + let v4 = [ if true then 1 else yield 2 ] // expect warning about "1" being ignored. There is a 'yield' so statements are statements. + let l11 = [ 4; yield 1; yield 2 ] // expect warning about "1" being ignored. There is a 'yield' so statements are statements. + let l9 = [ printfn "hello"; 1; 2 ] // Note, this is interpreted as a "SimpleSemicolonSequence", so we get "All elements of a list must be of the same type as the first element, which here is 'unit'. This element..." + let v3a : unit list = + [ printfn "hello" + if true then 1 else 2 ] + +module ArrayNegative2 = + let a4 = [| if true then 1 else yield 2 |] // expect warning about "1" being ignored. There is a 'yield' so statements are statements. + let a4 = [| (if true then 1) |] + +module SeqNegative2 = + let s5 = seq { if true then 1 else yield 2 } // expect warning about "1" being ignored. There is a 'yield' so statements are statements. + let s8 = seq { match 1 with 1 -> 4 | 2 -> 5 | 3 -> yield 6 | _ -> () } // expect warning about "4" being ignored. There is a 'yield' so statements are statements. + +module BuilderNegative2 = + type L<'T> = { Make: (unit -> 'T list) } + let L f = { Make = f } + + type ListBuilder() = + member __.Combine(x1: L<'T>, x2: L<'T>) = L(fun () -> x1.Make() @ x2.Make()) + member __.Delay(f: unit -> L<'T>) = L(fun () -> f().Make()) + member __.Zero() = L(fun () -> []) + member __.Yield(a: 'T) = L(fun () -> [a]) + member __.YieldFrom(x: L<'T>) = x + + let list = ListBuilder() + + let v3c : L = + list { + printfn "hello" + if true then 1 else obj() + } + + let v3c : L = + list { + printfn "hello" + if true then yield 1 else obj() + } + diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse01.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse01.fs index 56a7a819935..c2b85aece6a 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse01.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse01.fs @@ -1,11 +1,11 @@ // #Regression #Conformance #DataExpressions #Sequences -// Regression test for FSHARP1.0:4527 -//.+'if ... then ... else' +// Note, implicit yield is enabled because no 'yield' is used + + + + + -// 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 diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse02.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse02.fs index 724a9b55cc3..cabe197b92d 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse02.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse02.fs @@ -1,11 +1,11 @@ // #Regression #Conformance #DataExpressions #Sequences -// Regression test for FSHARP1.0:4527 -//.+'if ... then ... else' +// Note, implicit yield is enabled because no 'yield' is used -// 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 + + + + + +let p = [ if false then 1 else printfn "hello"; 3 ] +(if p = [ 3 ] then 0 else 1) |> exit diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse03.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse03.fs index 0d139cd7151..286fecdce6a 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse03.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/SequenceExpressions/W_IfThenElse03.fs @@ -1,11 +1,11 @@ // #Regression #Conformance #DataExpressions #Sequences -// Regression test for FSHARP1.0:4527 -//.+'if ... then ... else' +// Note, implicit yield is enabled because no 'yield' is used -// 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 + + + + + +let p : unit list = [ if true then printfn "hello"; () ];; // note, both unit-typed expressions interpreted as side-effecting operations +(match p with [ ] -> 0 | _ -> 1) |> exit diff --git a/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList.fs b/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList.fs index d47a4c13769..87bf47412c4 100644 --- a/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList.fs +++ b/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList.fs @@ -1,5 +1,5 @@ -// #Warnings -// +// This no longer gives a warning because implicit yields are now allowed + let div _ _ = 1 let subView _ _ = [1; 2] diff --git a/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList2.fs b/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList2.fs index d360da4d666..d7ca60baec4 100644 --- a/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList2.fs +++ b/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList2.fs @@ -1,9 +1,10 @@ -// #Warnings -// +// This no longer gives a warning because implicit yields are now allowed + // stupid things to make the sample compile let div _ _ = 1 let subView _ _ = [1; 2] +let subView2 _ _ = 1 let y = 1 // elmish view @@ -12,7 +13,7 @@ let view model dispatch = div [] [ match y with | 1 -> yield! subView model dispatch - | _ -> subView model dispatch + | _ -> subView2 model dispatch ] ] diff --git a/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList3.fs b/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList3.fs index 238d4388f9e..e5035827521 100644 --- a/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList3.fs +++ b/tests/fsharpqa/Source/Warnings/WarnIfDiscardedInList3.fs @@ -1,5 +1,5 @@ -// #Warnings -// +// This no longer gives a warning because implicit yields are now allowed + // stupid things to make the sample compile let div _ _ = 1