Repository navigation
Allow interpolated strings in constant expressions #20753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5048,7 +5048,7 @@ and TcStaticConstantParameter (cenv: cenv) (env: TcEnv) tpenv kind (StripParenTy | |
| | SynType.StaticConstantExpr(e, _ ) -> | ||
|
|
||
| // If an error occurs, don't try to recover, since the constant expression will be nothing like what we need | ||
| let te, tpenv' = TcExprNoRecover cenv (MustEqual kind) env tpenv e | ||
| let te, tpenv' = TcExprNoRecover cenv (MustEqual kind) { env with eInConstantContext = true } tpenv e | ||
|
|
||
| // Evaluate the constant expression using static attribute argument rules | ||
| let te = EvalLiteralExprOrAttribArg g te | ||
|
|
@@ -7803,6 +7803,44 @@ and TcInterpolatedStringViaConcat (cenv: cenv, overallTy: OverallTy, env: TcEnv, | |
|
|
||
| TcPropagatingExprLeafThenConvert cenv overallTy g.string_ty env m (fun () -> resultExpr, tpenv) | ||
|
|
||
| /// Fold a string-typed interpolated string in a constant context to its text (RFC FS-1352). Each hole must be | ||
| /// a non-null constant string without alignment or format specifiers. | ||
| and TcConstantInterpolatedString (cenv: cenv, overallTy: OverallTy, env: TcEnv, m: range, tpenv: UnscopedTyparEnv, parts: SynInterpolatedStringPart list) = | ||
| let g = cenv.g | ||
| checkLanguageFeatureAndRecover g.langVersion LanguageFeature.ConstantInterpolatedStrings m | ||
|
|
||
| let holeText (fill: Expr) (formatting: SynInterpolationFormatting) (mHole: range) = | ||
| let invalidHole () = | ||
| errorR (Error(FSComp.SR.tcConstantInterpolatedStringHole (), mHole)) | ||
| ValueNone | ||
|
|
||
| match formatting with | ||
| | SynInterpolationFormatting.DotNet(None, None) when isStringTy g (tyOfExpr g fill) -> | ||
| match EvalLiteralExprOrAttribArg g fill with | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 🕵️ FS0039 for module LaterHole
let dir = "data"
[<System.Obsolete($"""{dir + "/"}{missing}""")>]
let A = 1 |
||
| | Expr.Const(Const.String text, _, _) -> ValueSome text | ||
| | Expr.Const(Const.Zero, _, _) -> invalidHole () | ||
| | _ -> ValueNone // EvalLiteralExprOrAttribArg has reported that the hole is not a constant | ||
| | _ -> invalidHole () | ||
|
|
||
| let text = Text.StringBuilder() | ||
| let mutable tpenvAcc = tpenv | ||
| // Only the first hole that breaks a rule is reported; later holes are still type-checked. | ||
| let mutable holesAreConstant = true | ||
|
|
||
| for part in parts do | ||
| match part with | ||
| | SynInterpolatedStringPart.String(s, _) -> text.Append(s.Replace("%%", "%")) |> ignore | ||
| | SynInterpolatedStringPart.FillExpr(synFill, formatting) -> | ||
| let fill, tpenvAfter = TcExprFlex2 cenv (NewInferenceType g) env false tpenvAcc synFill | ||
| tpenvAcc <- tpenvAfter | ||
|
|
||
| if holesAreConstant then | ||
| match holeText fill formatting synFill.Range with | ||
| | ValueSome hole -> text.Append(hole: string) |> ignore | ||
| | ValueNone -> holesAreConstant <- false | ||
|
|
||
| TcPropagatingExprLeafThenConvert cenv overallTy g.string_ty env m (fun () -> mkString g m (text.ToString()), tpenvAcc) | ||
|
|
||
| /// Check an interpolated string expression | ||
| and [<TailCall>] warnForFunctionValuesInFillExprs (g: TcGlobals) argTys synFillExprs = | ||
| match argTys, synFillExprs with | ||
|
|
@@ -7950,6 +7988,8 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn | |
| else | ||
| let str = mkString g m printfFormatString | ||
| mkCallNewFormat g m printerTy printerArgTy printerResidueTy printerResultTy printerTupleTy str, tpenv | ||
| elif isString && env.eInConstantContext then | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 🕵️ Previously valid short-circuit literals now fail with FS3925 in preview and FS3350 in stable versions — constant restrictions reach the unevaluated RHS. module ShortCircuit
[<Literal>]
let Flag = false && ($"{1}" = "1") |
||
| TcConstantInterpolatedString (cenv, overallTy, env, m, tpenv, parts) | ||
| elif isString then | ||
| // String-typed interpolation: lower to a reflection-free System.String.Concat of the parts, | ||
| // type-checking each hole in place (no separate batch, no flat fill-expression list). | ||
|
|
@@ -11806,7 +11846,7 @@ and TcLiteral (cenv: cenv) overallTy env tpenv (attrs, synLiteralValExpr) = | |
| hasFlag valFlags WellKnownValAttributes.LiteralAttribute | ||
|
|
||
| if hasLiteralAttr then | ||
| let literalValExpr, _ = TcExpr cenv (MustEqual overallTy) env tpenv synLiteralValExpr | ||
| let literalValExpr, _ = TcExpr cenv (MustEqual overallTy) { env with eInConstantContext = true } tpenv synLiteralValExpr | ||
| match EvalLiteralExprOrAttribArg g literalValExpr with | ||
| | Expr.Const (c, _, ty) -> | ||
| if c = Const.Zero && isStructTy g ty then | ||
|
|
@@ -12012,7 +12052,7 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn | |
| let meths = minfos |> List.map (fun minfo -> minfo, None) | ||
| let afterResolution = ForNewConstructors cenv.tcSink env tyId.idRange methodName minfos | ||
| let (expr, attributeAssignedNamedItems, _), _ = | ||
| TcMethodApplication true cenv env tpenv None [] mAttr mAttr methodName None ad PossiblyMutates false meths afterResolution NormalValUse [arg] (MustEqual ty) None [] | ||
| TcMethodApplication true cenv { env with eInConstantContext = true } tpenv None [] mAttr mAttr methodName None ad PossiblyMutates false meths afterResolution NormalValUse [arg] (MustEqual ty) None [] | ||
|
|
||
| UnifyTypes cenv env mAttr ty (tyOfExpr g expr) | ||
|
|
||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in cc218d6: added
A type provider static argument can be a constant interpolated string, which passesconst ($"{Root}/items")and a[<Literal>]interpolated string to a provider and checks the text the provider received. It fails with FS0267 when the constant context is removed fromTcStaticConstantParameter.It uses a small provider in
tests/fsharp/typeProviders/staticStringParameterrather thanHelloWorldTypeWithStaticStringParameter: the helloWorld provider script is only built by the .NET Framework suite and does not compile on .NET (FS0041 onStartsWith), and it cannot report the argument's text back.