Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 61 additions & 12 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,19 @@ let dontInferTypars = ExplicitTyparInfo ([], [], false)

let noArgOrRetAttribs = ArgAndRetAttribs ([], [])

[<RequireQualifiedAccess>]
type LiteralArgumentType =
/// Literal defined at call site
///
/// call "literal"
| Inline

/// F# literal value or IL constant
///
/// let [<Literal>] lit = "x"
/// call lit
| StaticField

/// A flag to represent the sort of bindings are we processing.
/// Processing "declaration" and "class" bindings that make up a module (such as "let x = 1 let y = 2")
/// shares the same code paths (e.g. TcLetBinding and TcLetrecBindings) as processing expression bindings (such as "let x = 1 in ...")
Expand Down Expand Up @@ -5450,7 +5463,7 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE
| SynExpr.Const (SynConst.String (s, _, m), _) ->
TcNonControlFlowExpr env <| fun env ->
CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights)
TcConstStringExpr cenv overallTy env m tpenv s
TcConstStringExpr cenv overallTy env m tpenv s LiteralArgumentType.Inline

| SynExpr.InterpolatedString (parts, _, m) ->
TcNonControlFlowExpr env <| fun env ->
Expand Down Expand Up @@ -6963,16 +6976,32 @@ and TcObjectExpr (cenv: cenv) env tpenv (objTy, realObjTy, argopt, binds, extraI
//-------------------------------------------------------------------------

/// Check a constant string expression. It might be a 'printf' format string
and TcConstStringExpr cenv (overallTy: OverallTy) env m tpenv (s: string) =
and TcConstStringExpr cenv (overallTy: OverallTy) env m tpenv (s: string) literalType =
let rec isFormat g ty =
match stripTyEqns g ty with
| TType_app (tcref, _, _) -> tyconRefEq g tcref g.format4_tcr || tyconRefEq g tcref g.format_tcr
| TType_var (typar, _) ->
typar.Constraints
|> List.exists (fun c ->
match c with
| TyparConstraint.CoercesTo (ty, _) -> isFormat g ty
| _ -> false)
| _ -> false

let g = cenv.g

if AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit g.string_ty then
mkString g m s, tpenv
if isFormat g overallTy.Commit then
if literalType = LiteralArgumentType.StaticField then
checkLanguageFeatureAndRecover g.langVersion LanguageFeature.NonInlineLiteralsAsPrintfFormat m

TcFormatStringExpr cenv overallTy env m tpenv s literalType
else
TcFormatStringExpr cenv overallTy env m tpenv s
if literalType = LiteralArgumentType.Inline && not (isObjTy g overallTy.Commit) then
AddCxTypeEqualsType env.eContextInfo env.DisplayEnv cenv.css m overallTy.Commit g.string_ty

mkString g m s, tpenv

and TcFormatStringExpr cenv (overallTy: OverallTy) env m tpenv (fmtString: string) =
and TcFormatStringExpr cenv (overallTy: OverallTy) env m tpenv (fmtString: string) formatStringLiteralType =
let g = cenv.g
let aty = NewInferenceType g
let bty = NewInferenceType g
Expand All @@ -6986,7 +7015,11 @@ and TcFormatStringExpr cenv (overallTy: OverallTy) env m tpenv (fmtString: strin

if ok then
// Parse the format string to work out the phantom types
let formatStringCheckContext = match cenv.tcSink.CurrentSink with None -> None | Some sink -> sink.FormatStringCheckContext
let formatStringCheckContext =
match cenv.tcSink.CurrentSink, formatStringLiteralType with
| Some sink, LiteralArgumentType.Inline -> sink.FormatStringCheckContext
| _ -> None

let normalizedString = (fmtString.Replace("\r\n", "\n").Replace("\r", "\n"))

let _argTys, atyRequired, etyRequired, _percentATys, specifierLocations, _dotnetFormatString =
Expand Down Expand Up @@ -8765,7 +8798,14 @@ and TcValueItemThen cenv overallTy env vref tpenv mItem afterResolution delayed
// Value get
| _ ->
let _, vExpr, isSpecial, _, _, tpenv = TcVal true cenv env tpenv vref None (Some afterResolution) mItem
let vexpFlex = (if isSpecial then MakeApplicableExprNoFlex cenv vExpr else MakeApplicableExprWithFlex cenv env vExpr)

let vExpr, tpenv =
match vExpr with
| Expr.Const (Const.String value, _, _) -> TcConstStringExpr cenv overallTy env mItem tpenv value LiteralArgumentType.StaticField
| _ -> vExpr, tpenv

let vexpFlex = if isSpecial then MakeApplicableExprNoFlex cenv vExpr else MakeApplicableExprWithFlex cenv env vExpr

PropagateThenTcDelayed cenv overallTy env tpenv mItem vexpFlex vexpFlex.Type ExprAtomicFlag.Atomic delayed

and TcPropertyItemThen cenv overallTy env nm pinfos tpenv mItem afterResolution staticTyOpt delayed =
Expand Down Expand Up @@ -8836,10 +8876,12 @@ and TcILFieldItemThen cenv overallTy env finfo tpenv mItem delayed =

| _ ->
// Get static IL field
let expr =
let (expr, tpenv), isSpecial =
match finfo.LiteralValue with
| Some (ILFieldInit.String value) when typeEquiv g exprTy g.string_ty ->
TcConstStringExpr cenv overallTy env mItem tpenv value LiteralArgumentType.StaticField, true
| Some lit ->
Expr.Const (TcFieldInit mItem lit, mItem, exprTy)
(Expr.Const (TcFieldInit mItem lit, mItem, exprTy), tpenv), false
| None ->
let isStruct = finfo.IsValueType
let boxity = if isStruct then AsValue else AsObject
Expand All @@ -8854,9 +8896,16 @@ and TcILFieldItemThen cenv overallTy env finfo tpenv mItem delayed =
// Add an I_nop if this is an initonly field to make sure we never recognize it as an lvalue. See mkExprAddrOfExpr.
if finfo.IsInitOnly then AI_nop ]

mkAsmExpr (ilInstrs, finfo.TypeInst, [], [exprTy], mItem)
(mkAsmExpr (ilInstrs, finfo.TypeInst, [], [exprTy], mItem), tpenv), false

PropagateThenTcDelayed cenv overallTy env tpenv mItem (MakeApplicableExprWithFlex cenv env expr) exprTy ExprAtomicFlag.Atomic delayed
let exprTy, exprFlex =
if isSpecial then
let exprFlex = MakeApplicableExprNoFlex cenv expr
exprFlex.Type, exprFlex
else
exprTy, MakeApplicableExprWithFlex cenv env expr

PropagateThenTcDelayed cenv overallTy env tpenv mItem exprFlex exprTy ExprAtomicFlag.Atomic delayed

and TcRecdFieldItemThen cenv overallTy env rfinfo tpenv mItem delayed =
let g = cenv.g
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1564,6 +1564,7 @@ featureErrorReportingOnStaticClasses,"Error reporting on static classes"
featureTryWithInSeqExpressions,"Support for try-with in sequence expressions"
featureWarningWhenCopyAndUpdateRecordChangesAllFields,"Raises warnings when an copy-and-update record expression changes all fields of a record."
featureStaticMembersInInterfaces,"Static members in interfaces"
featureNonInlineLiteralsAsPrintfFormat,"String values marked as literals and IL constants as printf format"
3353,fsiInvalidDirective,"Invalid directive '#%s %s'"
3354,tcNotAFunctionButIndexerNamedIndexingNotYetEnabled,"This value supports indexing, e.g. '%s.[index]'. The syntax '%s[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation."
3354,tcNotAFunctionButIndexerIndexingNotYetEnabled,"This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation."
Expand Down
3 changes: 3 additions & 0 deletions src/Compiler/Facilities/LanguageFeatures.fs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type LanguageFeature =
| TryWithInSeqExpression
| WarningWhenCopyAndUpdateRecordChangesAllFields
| StaticMembersInInterfaces
| NonInlineLiteralsAsPrintfFormat

/// LanguageVersion management
type LanguageVersion(versionText) =
Expand Down Expand Up @@ -144,6 +145,7 @@ type LanguageVersion(versionText) =
LanguageFeature.TryWithInSeqExpression, previewVersion
LanguageFeature.WarningWhenCopyAndUpdateRecordChangesAllFields, previewVersion
LanguageFeature.StaticMembersInInterfaces, previewVersion
LanguageFeature.NonInlineLiteralsAsPrintfFormat, previewVersion

]

Expand Down Expand Up @@ -261,6 +263,7 @@ type LanguageVersion(versionText) =
| LanguageFeature.TryWithInSeqExpression -> FSComp.SR.featureTryWithInSeqExpressions ()
| LanguageFeature.WarningWhenCopyAndUpdateRecordChangesAllFields -> FSComp.SR.featureWarningWhenCopyAndUpdateRecordChangesAllFields ()
| LanguageFeature.StaticMembersInInterfaces -> FSComp.SR.featureStaticMembersInInterfaces ()
| LanguageFeature.NonInlineLiteralsAsPrintfFormat -> FSComp.SR.featureNonInlineLiteralsAsPrintfFormat ()

/// Get a version string associated with the given feature.
static member GetFeatureVersionString feature =
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/Facilities/LanguageFeatures.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type LanguageFeature =
| TryWithInSeqExpression
| WarningWhenCopyAndUpdateRecordChangesAllFields
| StaticMembersInInterfaces
| NonInlineLiteralsAsPrintfFormat

/// LanguageVersion management
type LanguageVersion =
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/TypedTree/TcGlobals.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,8 @@ type TcGlobals(

member _.format_tcr = v_format_tcr

member _.format4_tcr = v_format4_tcr

member _.expr_tcr = v_expr_tcr

member _.raw_expr_tcr = v_raw_expr_tcr
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">neproměnné vzory napravo od vzorů typu „jako“</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">Nicht-Variablenmuster rechts neben as-Mustern</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">patrones no variables a la derecha de los patrones "as"</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">modèles non variables à droite de modèles « as »</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">modelli non variabili a destra dei modelli 'as'</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">'as' パターンの右側の非変数パターン</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ko.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">'as' 패턴의 오른쪽에 있는 변수가 아닌 패턴</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">stałe wzorce po prawej stronie wzorców typu „as”</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.pt-BR.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">padrões não-variáveis à direita dos padrões 'as'.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ru.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">шаблоны без переменных справа от шаблонов "as"</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.tr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">'as' desenlerinin sağındaki değişken olmayan desenler</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">"as" 模式右侧的非变量模式</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@
<target state="translated">nameof</target>
<note />
</trans-unit>
<trans-unit id="featureNonInlineLiteralsAsPrintfFormat">
<source>String values marked as literals and IL constants as printf format</source>
<target state="new">String values marked as literals and IL constants as printf format</target>
<note />
</trans-unit>
<trans-unit id="featureNonVariablePatternsToRightOfAsPatterns">
<source>non-variable patterns to the right of 'as' patterns</source>
<target state="translated">'as' 模式右邊的非變數模式</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@
<Compile Include="Language\ExtensionMethodTests.fs" />
<Compile Include="Language\SequenceExpressionTests.fs" />
<Compile Include="Language\StaticClassTests.fs" />
<Compile Include="Language\PrintfFormatTests.fs" />
<Compile Include="Language\InterfaceTests.fs" />
<Compile Include="ConstraintSolver\PrimitiveConstraints.fs" />
<Compile Include="ConstraintSolver\MemberConstraints.fs" />
Expand Down
Loading