From 9d3917ae5843e5800508320245fb5e562af49519 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Tue, 11 Jun 2024 18:55:29 +0800 Subject: [PATCH 01/16] Support CallerArgumentExpression --- src/Compiler/Checking/MethodCalls.fs | 24 +++++--- src/Compiler/Checking/PostInferenceChecks.fs | 6 ++ src/Compiler/Checking/infos.fs | 38 ++++++++----- src/Compiler/Checking/infos.fsi | 1 + src/Compiler/Service/ServiceStructure.fs | 59 +++++++++++++++++--- src/Compiler/TypedTree/TcGlobals.fs | 3 +- src/Compiler/Utilities/range.fsi | 2 + 7 files changed, 103 insertions(+), 30 deletions(-) diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 46f32c53431..b09e1866a78 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1389,7 +1389,7 @@ let emptyPreBinder (e: Expr) = e /// Get the expression that must be inserted on the caller side for a CallerSide optional arg, /// i.e. one where there is no corresponding caller arg. -let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: CalledArg) currCalledArgTy currDfltVal eCallerMemberName mMethExpr = +let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: CalledArg) currCalledArgTy currDfltVal eCallerMemberName mMethExpr unnamedArgs = match currDfltVal with | MissingValue -> // Add an I_nop if this is an initonly field to make sure we never recognize it as an lvalue. See mkExprAddrOfExpr. @@ -1406,7 +1406,7 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C let ctorArgs = [Expr.Const (tcFieldInit mMethExpr fieldInit, mMethExpr, inst)] emptyPreBinder, Expr.Op (TOp.ILCall (false, false, true, true, NormalValUse, false, false, ctor, [inst], [], [currCalledArgTy]), [], ctorArgs, mMethExpr) | ByrefTy g inst -> - GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg inst (PassByRef(inst, currDfltVal)) eCallerMemberName mMethExpr + GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg inst (PassByRef(inst, currDfltVal)) eCallerMemberName mMethExpr unnamedArgs | _ -> match calledArg.CallerInfo, eCallerMemberName with | CallerLineNumber, _ when typeEquiv g currCalledArgTy g.int_ty -> @@ -1416,6 +1416,16 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C emptyPreBinder, Expr.Const (Const.String fileName, mMethExpr, currCalledArgTy) | CallerMemberName, Some callerName when (typeEquiv g currCalledArgTy g.string_ty) -> emptyPreBinder, Expr.Const (Const.String callerName, mMethExpr, currCalledArgTy) + | CallerArgumentExpression param, _ when typeEquiv g currCalledArgTy g.string_ty -> + let str = + unnamedArgs + |> List.tryPick (fun { CalledArg=called; CallerArg=caller } -> + match called.NameOpt with + | Some x when x.idText = param -> + Some (Const.String (caller.Range.DebugCode)) + | _ -> None) + |> Option.defaultWith (fun _ -> tcFieldInit mMethExpr fieldInit) + emptyPreBinder, Expr.Const (str, mMethExpr, currCalledArgTy) | _ -> emptyPreBinder, Expr.Const (tcFieldInit mMethExpr fieldInit, mMethExpr, currCalledArgTy) @@ -1439,7 +1449,7 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C | PassByRef (ty, dfltVal2) -> let v, _ = mkCompGenLocal mMethExpr "defaultByrefArg" ty - let wrapper2, rhs = GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg currCalledArgTy dfltVal2 eCallerMemberName mMethExpr + let wrapper2, rhs = GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg currCalledArgTy dfltVal2 eCallerMemberName mMethExpr unnamedArgs (wrapper2 >> mkCompGenLet mMethExpr v rhs), mkValAddr mMethExpr false (mkLocalValRef v) /// Get the expression that must be inserted on the caller side for a CalleeSide optional arg where @@ -1469,7 +1479,7 @@ let GetDefaultExpressionForCalleeSideOptionalArg g (calledArg: CalledArg) eCalle /// Get the expression that must be inserted on the caller side for an optional arg where /// no caller argument has been provided. -let GetDefaultExpressionForOptionalArg tcFieldInit g (calledArg: CalledArg) eCallerMemberName mItem (mMethExpr: range) = +let GetDefaultExpressionForOptionalArg tcFieldInit g (calledArg: CalledArg) eCallerMemberName mItem (mMethExpr: range) unnamedArgs = let calledArgTy = calledArg.CalledArgumentType let preBinder, expr = match calledArg.OptArgInfo with @@ -1477,7 +1487,7 @@ let GetDefaultExpressionForOptionalArg tcFieldInit g (calledArg: CalledArg) eCal error(InternalError("Unexpected NotOptional", mItem)) | CallerSide dfltVal -> - GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg calledArgTy dfltVal eCallerMemberName mMethExpr + GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg calledArgTy dfltVal eCallerMemberName mMethExpr unnamedArgs | CalleeSide -> emptyPreBinder, GetDefaultExpressionForCalleeSideOptionalArg g calledArg eCallerMemberName mMethExpr @@ -1534,7 +1544,7 @@ let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader: mkOptionToNullable g m (destOptionTy g callerArgTy) callerArgExpr else // CSharpMethod(?x=b) when 'b' has optional type and 'x' has non-nullable type --> CSharpMethod(x=Option.defaultValue DEFAULT v) - let _wrapper, defaultExpr = GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg calledArgTy dfltVal eCallerMemberName m + let _wrapper, defaultExpr = GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg calledArgTy dfltVal eCallerMemberName m [assignedArg] let ty = destOptionTy g callerArgTy mkOptionDefaultValue g m ty defaultExpr callerArgExpr else @@ -1594,7 +1604,7 @@ let AdjustCallerArgsForOptionals tcVal tcFieldInit eCallerMemberName (infoReader // i.e. there is no corresponding caller arg. let optArgs, optArgPreBinder = (emptyPreBinder, calledMeth.UnnamedCalledOptArgs) ||> List.mapFold (fun preBinder calledArg -> - let preBinder2, arg = GetDefaultExpressionForOptionalArg tcFieldInit g calledArg eCallerMemberName mItem mMethExpr + let preBinder2, arg = GetDefaultExpressionForOptionalArg tcFieldInit g calledArg eCallerMemberName mItem mMethExpr unnamedArgs arg, (preBinder >> preBinder2)) let adjustedNormalUnnamedArgs = List.map (AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName infoReader ad) unnamedArgs diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index c7090709cca..b94ec73032a 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -2365,6 +2365,12 @@ let CheckEntityDefn cenv env (tycon: Entity) = if not (typeEquiv g g.string_ty ty) then errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo.ToString(), "string", NicePrint.minimalStringOfType cenv.denv ty), m)) | CalleeSide, CallerMemberName -> + if not ((isOptionTy g ty) && (typeEquiv g g.string_ty (destOptionTy g ty))) then + errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo.ToString(), "string", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m)) + | CallerSide _, CallerArgumentExpression _ -> + if not (typeEquiv g g.string_ty ty) then + errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo.ToString(), "string", NicePrint.minimalStringOfType cenv.denv ty), m)) + | CalleeSide, CallerArgumentExpression _ -> if not ((isOptionTy g ty) && (typeEquiv g g.string_ty (destOptionTy g ty))) then errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo.ToString(), "string", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m))) diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index c90d49f3dcc..74637a34708 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -238,6 +238,7 @@ type CallerInfo = | CallerLineNumber | CallerMemberName | CallerFilePath + | CallerArgumentExpression of paramName: string override x.ToString() = sprintf "%+A" x @@ -315,20 +316,23 @@ let CrackParamAttribsInfo g (ty: TType, argInfo: ArgReprInfo) = let isCallerLineNumberArg = HasFSharpAttribute g g.attrib_CallerLineNumberAttribute argInfo.Attribs let isCallerFilePathArg = HasFSharpAttribute g g.attrib_CallerFilePathAttribute argInfo.Attribs let isCallerMemberNameArg = HasFSharpAttribute g g.attrib_CallerMemberNameAttribute argInfo.Attribs + let callerArgumentExpressionArg = TryFindFSharpAttributeOpt g g.attrib_CallerArgumentExpressionAttribute argInfo.Attribs let callerInfo = - match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg with - | false, false, false -> NoCallerInfo - | true, false, false -> CallerLineNumber - | false, true, false -> CallerFilePath - | false, false, true -> CallerMemberName - | false, true, true -> + match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg, callerArgumentExpressionArg with + | false, false, false, None -> NoCallerInfo + | true, false, false, None -> CallerLineNumber + | false, true, false, None -> CallerFilePath + | false, false, true, None -> CallerMemberName + | false, false, false, Some(Attrib(_, _, (AttribStringArg x :: _), _, _, _, _)) -> + CallerArgumentExpression(x) + | false, true, true, _ -> match TryFindFSharpAttribute g g.attrib_CallerMemberNameAttribute argInfo.Attribs with | Some(Attrib(_, _, _, _, _, _, callerMemberNameAttributeRange)) -> warning(Error(FSComp.SR.CallerMemberNameIsOverriden(argInfo.Name.Value.idText), callerMemberNameAttributeRange)) CallerFilePath | _ -> failwith "Impossible" - | _, _, _ -> + | _, _, _, _ -> // if multiple caller info attributes are specified, pick the "wrong" one here // so that we get an error later match tryDestOptionTy g ty with @@ -1191,14 +1195,22 @@ type MethInfo = let isCallerLineNumberArg = TryFindILAttribute g.attrib_CallerLineNumberAttribute attrs let isCallerFilePathArg = TryFindILAttribute g.attrib_CallerFilePathAttribute attrs let isCallerMemberNameArg = TryFindILAttribute g.attrib_CallerMemberNameAttribute attrs + let isCallerArgumentExpressionArg = TryFindILAttributeOpt g.attrib_CallerArgumentExpressionAttribute attrs let callerInfo = - match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg with - | false, false, false -> NoCallerInfo - | true, false, false -> CallerLineNumber - | false, true, false -> CallerFilePath - | false, false, true -> CallerMemberName - | _, _, _ -> + match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg, isCallerArgumentExpressionArg with + | false, false, false, false -> NoCallerInfo + | true, false, false, false -> CallerLineNumber + | false, true, false, false -> CallerFilePath + | false, false, true, false -> CallerMemberName + | false, false, false, true -> + match g.attrib_CallerArgumentExpressionAttribute with + | Some (AttribInfo(tref,_)) -> + match TryDecodeILAttribute tref attrs with + | Some ([ILAttribElem.String (Some name) ], _) -> CallerArgumentExpression(name) + | _ -> NoCallerInfo + | None -> NoCallerInfo + | _, _, _, _ -> // if multiple caller info attributes are specified, pick the "wrong" one here // so that we get an error later if p.Type.TypeRef.FullName = "System.Int32" then CallerFilePath diff --git a/src/Compiler/Checking/infos.fsi b/src/Compiler/Checking/infos.fsi index a2b178d92ac..25fdac7cb33 100644 --- a/src/Compiler/Checking/infos.fsi +++ b/src/Compiler/Checking/infos.fsi @@ -101,6 +101,7 @@ type CallerInfo = | CallerLineNumber | CallerMemberName | CallerFilePath + | CallerArgumentExpression of paramName: string [] type ReflectedArgInfo = diff --git a/src/Compiler/Service/ServiceStructure.fs b/src/Compiler/Service/ServiceStructure.fs index 1d0f7c7f8ec..6299dd11c7e 100644 --- a/src/Compiler/Service/ServiceStructure.fs +++ b/src/Compiler/Service/ServiceStructure.fs @@ -839,22 +839,40 @@ module Structure = elif line.StartsWithOrdinal("//") then Some SingleLine else None + /// Determine if a line is //#region or //#endregion or else some thing + let (|BeginRegion|EndRegion|NotRegion|) = + let regex = System.Text.RegularExpressions.Regex("^\\s*//\\s*#(end)?region", System.Text.RegularExpressions.RegexOptions.Compiled) + fun (line: string) -> + let result = regex.Match(line) + match result.Success, result.Groups[1].Success with + | false, _ -> NotRegion + | true, false -> BeginRegion + | true, true -> EndRegion + let getCommentRanges trivia (lines: string[]) = let rec loop (lastLineNum, currentComment, result as state) (lines: string list) lineNum = match lines with | [] -> state | lineStr :: rest -> match lineStr.TrimStart(), currentComment with + | (Comment SingleLine & (BeginRegion | EndRegion)), _ -> + let result' = + match currentComment with + | Some comment -> comment :: result + | None -> result + let comments = CommentList.New SingleLine (lineNum, lineStr) + loop (lineNum, Some comments, result') rest (lineNum + 1) | Comment commentType, Some comment -> - loop - (if comment.Type = commentType && lineNum = lastLineNum + 1 then - comment.Lines.Add(lineNum, lineStr) - lineNum, currentComment, result - else - let comments = CommentList.New commentType (lineNum, lineStr) - lineNum, Some comments, comment :: result) - rest - (lineNum + 1) + let comments, result' = + match commentType, comment.Lines[comment.Lines.Count - 1] with + | SingleLine, (_, NotRegion) + | XmlDoc, _ when comment.Type = commentType && lineNum = lastLineNum + 1 -> + comment.Lines.Add(lineNum, lineStr) + currentComment, result + | _ -> + let comments = CommentList.New commentType (lineNum, lineStr) + Some comments, comment :: result + loop (lineNum, comments, result') rest (lineNum + 1) | Comment commentType, None -> let comments = CommentList.New commentType (lineNum, lineStr) loop (lineNum, Some comments, result) rest (lineNum + 1) @@ -893,6 +911,29 @@ module Structure = }) |> acc.AddRange + let _, scopes = + comments + |> List.filter (fun comment -> comment.Type = SingleLine && comment.Lines.Count = 1) + |> List.fold (fun (stack, state) comment -> + match stack, comment.Lines[0] with + | _, (_, BeginRegion as startLine) -> startLine :: stack, state + | (startLine, startStr) :: rest, (endLine, (EndRegion as endStr)) -> + let startCol = startStr.IndexOf '/' + let endCol = endStr.TrimEnd().Length + + let range = mkRange "" (mkPos (startLine + 1) startCol) (mkPos (endLine + 1) endCol) + let scope = + { + Scope = Scope.Comment + Collapse = Collapse.Same + Range = range + CollapseRange = range + } + rest, scope :: state + | _, (_, EndRegion as endLine) -> endLine :: stack, state + | _ -> stack, state) ([], []) + acc.AddRange scopes + for trivia in trivia do match trivia with | CommentTrivia.BlockComment m when m.StartLine <> m.EndLine -> diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 69a99dfe119..9566eb3f3cc 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1074,7 +1074,7 @@ type TcGlobals( // Adding an unnecessary "let" instead of inlining into a muiti-line pipelined compute-once "member val" that is too complex for @dsyme let v_attribs_Unsupported = [ tryFindSysAttrib "System.Runtime.CompilerServices.ModuleInitializerAttribute" - tryFindSysAttrib "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" + // tryFindSysAttrib "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" tryFindSysAttrib "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute" tryFindSysAttrib "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute" tryFindSysAttrib "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute" @@ -1492,6 +1492,7 @@ type TcGlobals( member val attrib_ExtensionAttribute = findSysAttrib "System.Runtime.CompilerServices.ExtensionAttribute" member val attrib_CallerLineNumberAttribute = findSysAttrib "System.Runtime.CompilerServices.CallerLineNumberAttribute" member val attrib_CallerFilePathAttribute = findSysAttrib "System.Runtime.CompilerServices.CallerFilePathAttribute" + member val attrib_CallerArgumentExpressionAttribute = tryFindSysAttrib "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" member val attrib_CallerMemberNameAttribute = findSysAttrib "System.Runtime.CompilerServices.CallerMemberNameAttribute" member val attrib_ReferenceAssemblyAttribute = findSysAttrib "System.Runtime.CompilerServices.ReferenceAssemblyAttribute" member val attrib_SkipLocalsInitAttribute = findSysAttrib "System.Runtime.CompilerServices.SkipLocalsInitAttribute" diff --git a/src/Compiler/Utilities/range.fsi b/src/Compiler/Utilities/range.fsi index 7b422fcd307..c952ac7f9a4 100755 --- a/src/Compiler/Utilities/range.fsi +++ b/src/Compiler/Utilities/range.fsi @@ -122,6 +122,8 @@ type Range = /// The range where all values are zero static member Zero: range + + member internal DebugCode: string /// Represents a range within a file and range = Range From dec3d3edc1caaf890b15cb70922796a2dd262e23 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Sun, 11 Aug 2024 17:21:18 +0800 Subject: [PATCH 02/16] fix for fsi --- src/Compiler/Checking/MethodCalls.fs | 4 +++- src/Compiler/Driver/CompilerConfig.fs | 4 ++++ src/Compiler/Driver/CompilerConfig.fsi | 4 ++++ src/Compiler/Driver/CompilerImports.fs | 3 ++- src/Compiler/Interactive/fsi.fs | 2 ++ src/Compiler/TypedTree/TcGlobals.fs | 27 +++++++++++++++++++++++++- src/Compiler/TypedTree/TcGlobals.fsi | 7 ++++++- 7 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index d34b306c3cc..7dda8b368d2 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1431,7 +1431,9 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C |> List.tryPick (fun { CalledArg=called; CallerArg=caller } -> match called.NameOpt with | Some x when x.idText = param -> - Some (Const.String (caller.Range.DebugCode)) + match g.GetCodeText caller.Range with + | ValueSome code -> Some (Const.String code) + | ValueNone -> None | _ -> None) |> Option.defaultWith (fun _ -> tcFieldInit mMethExpr fieldInit) emptyPreBinder, Expr.Const (str, mMethExpr, currCalledArgTy) diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 4a1d0d18c74..09818c34819 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -619,6 +619,8 @@ type TcConfigBuilder = mutable dumpSignatureData: bool mutable realsig: bool + + mutable getLine: (string -> int -> string) voption } // Directories to start probing in @@ -829,6 +831,7 @@ type TcConfigBuilder = dumpSignatureData = false realsig = true strictIndentation = None + getLine = ValueNone } member tcConfigB.FxResolver = @@ -1373,6 +1376,7 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member _.typeCheckingConfig = data.typeCheckingConfig member _.dumpSignatureData = data.dumpSignatureData member _.realsig = data.realsig + member _.getLine = data.getLine static member Create(builder, validate) = use _ = UseBuildPhase BuildPhase.Parameter diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index f21ae429029..0a3193f6ef3 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -525,6 +525,8 @@ type TcConfigBuilder = mutable dumpSignatureData: bool mutable realsig: bool + + mutable getLine: (string -> int -> string) voption } static member CreateNew: @@ -904,6 +906,8 @@ type TcConfig = member realsig: bool + member getLine: (string -> int -> string) voption + /// Represents a computation to return a TcConfig. Normally this is just a constant immutable TcConfig, /// but for F# Interactive it may be based on an underlying mutable TcConfigBuilder. [] diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 334a834db32..a1adeb451a3 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2614,7 +2614,8 @@ and [] TcImports tcConfig.noDebugAttributes, tcConfig.pathMap, tcConfig.langVersion, - tcConfig.realsig + tcConfig.realsig, + tcConfig.getLine ) #if DEBUG diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 5904071dd8a..b3b94bb763f 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -4661,6 +4661,8 @@ type FsiEvaluationSession if List.isEmpty fsiOptions.SourceFiles then fsiConsolePrompt.PrintAhead() + do tcConfigB.getLine <- ValueSome fsiStdinSyphon.GetLine + let fsiConsoleInput = FsiConsoleInput(fsi, fsiOptions, inReader, outWriter) /// The single, global interactive checker that can be safely used in conjunction with other operations diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 786b694bbf9..3e166a3d0a8 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -190,7 +190,8 @@ type TcGlobals( noDebugAttributes: bool, pathMap: PathMap, langVersion: LanguageVersion, - realsig: bool) = + realsig: bool, + getLine: (string -> int -> string) voption) = let v_langFeatureNullness = langVersion.SupportsFeature LanguageFeature.NullnessChecking @@ -1980,6 +1981,30 @@ type TcGlobals( | _ -> None + member _.GetCodeText (m: Text.Range) = + let endCol = m.EndColumn - 1 + let startCol = m.StartColumn - 1 + + let s = + match getLine with + | ValueSome f -> + [for i in m.StartLine..m.EndLine -> f m.FileName i] + |> String.concat "\n" + | ValueNone -> + try + if FileSystem.IsInvalidPathShim m.FileName then + System.String.Empty + elif not (FileSystem.FileExistsShim m.FileName) then + System.String.Empty + else + FileSystem.OpenFileForReadShim(m.FileName).ReadLines() + |> Seq.skip (m.StartLine - 1) + |> Seq.take (m.EndLine - m.StartLine + 1) + |> String.concat "\n" + with e -> System.String.Empty + if System.String.IsNullOrEmpty s then ValueNone else + ValueSome <| s.Substring(startCol + 1, s.LastIndexOf("\n", System.StringComparison.Ordinal) + 1 - startCol + endCol) + #if DEBUG // This global is only used during debug output let mutable global_g = None : TcGlobals option diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index b0b4a4d496b..0650086e708 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -147,7 +147,8 @@ type internal TcGlobals = noDebugAttributes: bool * pathMap: Internal.Utilities.PathMap * langVersion: FSharp.Compiler.Features.LanguageVersion * - realsig: bool -> + realsig: bool * + getLine: (string -> int -> string) voption -> TcGlobals static member IsInEmbeddableKnownSet: name: string -> bool @@ -320,6 +321,8 @@ type internal TcGlobals = member attrib_CallerLineNumberAttribute: BuiltinAttribInfo + member attrib_CallerArgumentExpressionAttribute: BuiltinAttribInfo option + member attrib_CallerMemberNameAttribute: BuiltinAttribInfo member attrib_ClassAttribute: BuiltinAttribInfo @@ -1365,6 +1368,8 @@ type internal TcGlobals = member voidptr_tcr: FSharp.Compiler.TypedTree.EntityRef + member GetCodeText: m: Text.Range -> string voption + #if DEBUG // This global is only used during debug output val mutable internal global_g: TcGlobals option From e5d7763d46e8d174e08861ea2364042f7f66a71a Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Sun, 11 Aug 2024 17:28:45 +0800 Subject: [PATCH 03/16] revert unnecessary changes --- src/Compiler/Service/ServiceStructure.fs | 59 ++++-------------------- src/Compiler/TypedTree/TcGlobals.fs | 6 +-- src/Compiler/Utilities/range.fsi | 2 - 3 files changed, 11 insertions(+), 56 deletions(-) diff --git a/src/Compiler/Service/ServiceStructure.fs b/src/Compiler/Service/ServiceStructure.fs index 6299dd11c7e..1d0f7c7f8ec 100644 --- a/src/Compiler/Service/ServiceStructure.fs +++ b/src/Compiler/Service/ServiceStructure.fs @@ -839,40 +839,22 @@ module Structure = elif line.StartsWithOrdinal("//") then Some SingleLine else None - /// Determine if a line is //#region or //#endregion or else some thing - let (|BeginRegion|EndRegion|NotRegion|) = - let regex = System.Text.RegularExpressions.Regex("^\\s*//\\s*#(end)?region", System.Text.RegularExpressions.RegexOptions.Compiled) - fun (line: string) -> - let result = regex.Match(line) - match result.Success, result.Groups[1].Success with - | false, _ -> NotRegion - | true, false -> BeginRegion - | true, true -> EndRegion - let getCommentRanges trivia (lines: string[]) = let rec loop (lastLineNum, currentComment, result as state) (lines: string list) lineNum = match lines with | [] -> state | lineStr :: rest -> match lineStr.TrimStart(), currentComment with - | (Comment SingleLine & (BeginRegion | EndRegion)), _ -> - let result' = - match currentComment with - | Some comment -> comment :: result - | None -> result - let comments = CommentList.New SingleLine (lineNum, lineStr) - loop (lineNum, Some comments, result') rest (lineNum + 1) | Comment commentType, Some comment -> - let comments, result' = - match commentType, comment.Lines[comment.Lines.Count - 1] with - | SingleLine, (_, NotRegion) - | XmlDoc, _ when comment.Type = commentType && lineNum = lastLineNum + 1 -> - comment.Lines.Add(lineNum, lineStr) - currentComment, result - | _ -> - let comments = CommentList.New commentType (lineNum, lineStr) - Some comments, comment :: result - loop (lineNum, comments, result') rest (lineNum + 1) + loop + (if comment.Type = commentType && lineNum = lastLineNum + 1 then + comment.Lines.Add(lineNum, lineStr) + lineNum, currentComment, result + else + let comments = CommentList.New commentType (lineNum, lineStr) + lineNum, Some comments, comment :: result) + rest + (lineNum + 1) | Comment commentType, None -> let comments = CommentList.New commentType (lineNum, lineStr) loop (lineNum, Some comments, result) rest (lineNum + 1) @@ -911,29 +893,6 @@ module Structure = }) |> acc.AddRange - let _, scopes = - comments - |> List.filter (fun comment -> comment.Type = SingleLine && comment.Lines.Count = 1) - |> List.fold (fun (stack, state) comment -> - match stack, comment.Lines[0] with - | _, (_, BeginRegion as startLine) -> startLine :: stack, state - | (startLine, startStr) :: rest, (endLine, (EndRegion as endStr)) -> - let startCol = startStr.IndexOf '/' - let endCol = endStr.TrimEnd().Length - - let range = mkRange "" (mkPos (startLine + 1) startCol) (mkPos (endLine + 1) endCol) - let scope = - { - Scope = Scope.Comment - Collapse = Collapse.Same - Range = range - CollapseRange = range - } - rest, scope :: state - | _, (_, EndRegion as endLine) -> endLine :: stack, state - | _ -> stack, state) ([], []) - acc.AddRange scopes - for trivia in trivia do match trivia with | CommentTrivia.BlockComment m when m.StartLine <> m.EndLine -> diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 3e166a3d0a8..732ef43295d 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1083,7 +1083,6 @@ type TcGlobals( // Adding an unnecessary "let" instead of inlining into a muiti-line pipelined compute-once "member val" that is too complex for @dsyme let v_attribs_Unsupported = [ tryFindSysAttrib "System.Runtime.CompilerServices.ModuleInitializerAttribute" - // tryFindSysAttrib "System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" tryFindSysAttrib "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute" tryFindSysAttrib "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute" tryFindSysAttrib "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute" @@ -1992,9 +1991,8 @@ type TcGlobals( |> String.concat "\n" | ValueNone -> try - if FileSystem.IsInvalidPathShim m.FileName then - System.String.Empty - elif not (FileSystem.FileExistsShim m.FileName) then + if FileSystem.IsInvalidPathShim m.FileName || + not (FileSystem.FileExistsShim m.FileName) then System.String.Empty else FileSystem.OpenFileForReadShim(m.FileName).ReadLines() diff --git a/src/Compiler/Utilities/range.fsi b/src/Compiler/Utilities/range.fsi index c952ac7f9a4..7b422fcd307 100755 --- a/src/Compiler/Utilities/range.fsi +++ b/src/Compiler/Utilities/range.fsi @@ -122,8 +122,6 @@ type Range = /// The range where all values are zero static member Zero: range - - member internal DebugCode: string /// Represents a range within a file and range = Range From 5119bb693f2ce6a20dfb6d9f99d90e2679416d1d Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Sun, 11 Aug 2024 23:45:34 +0800 Subject: [PATCH 04/16] Read and store file content before compilation --- src/Compiler/Driver/CompilerConfig.fs | 4 ++-- src/Compiler/Driver/CompilerConfig.fsi | 4 ++-- src/Compiler/Driver/ScriptClosure.fs | 1 + src/Compiler/Driver/fsc.fs | 2 ++ src/Compiler/Interactive/fsi.fs | 2 +- src/Compiler/Service/IncrementalBuild.fs | 2 ++ src/Compiler/Service/TransparentCompiler.fs | 2 ++ src/Compiler/Service/service.fs | 3 +++ src/Compiler/TypedTree/TcGlobals.fs | 21 +++++---------------- src/Compiler/TypedTree/TcGlobals.fsi | 2 +- src/Compiler/Utilities/range.fs | 14 ++++++++++++++ src/Compiler/Utilities/range.fsi | 7 +++++++ 12 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 09818c34819..ca6d1575c67 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -620,7 +620,7 @@ type TcConfigBuilder = mutable realsig: bool - mutable getLine: (string -> int -> string) voption + mutable getLine: string -> int -> string } // Directories to start probing in @@ -831,7 +831,7 @@ type TcConfigBuilder = dumpSignatureData = false realsig = true strictIndentation = None - getLine = ValueNone + getLine = FileContent.getLine } member tcConfigB.FxResolver = diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index 0a3193f6ef3..5cf3d40ccf8 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -526,7 +526,7 @@ type TcConfigBuilder = mutable realsig: bool - mutable getLine: (string -> int -> string) voption + mutable getLine: string -> int -> string } static member CreateNew: @@ -906,7 +906,7 @@ type TcConfig = member realsig: bool - member getLine: (string -> int -> string) voption + member getLine: (string -> int -> string) /// Represents a computation to return a TcConfig. Normally this is just a constant immutable TcConfig, /// but for F# Interactive it may be based on an underlying mutable TcConfigBuilder. diff --git a/src/Compiler/Driver/ScriptClosure.fs b/src/Compiler/Driver/ScriptClosure.fs index 2374fd6793b..8a068671128 100644 --- a/src/Compiler/Driver/ScriptClosure.fs +++ b/src/Compiler/Driver/ScriptClosure.fs @@ -159,6 +159,7 @@ module ScriptPreprocessClosure = reduceMemoryUsage ) = + FileContent.readFiles [fileName] let projectDir = Path.GetDirectoryName fileName let isInteractive = (codeContext = CodeContext.CompilationAndEvaluation) let isInvalidationSupported = (codeContext = CodeContext.Editing) diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index 34322176136..d8c40781210 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -621,6 +621,8 @@ let main1 // Register framework tcImports to be disposed in future disposables.Register frameworkTcImports + + FileContent.readFiles sourceFiles // Parse sourceFiles ReportTime tcConfig "Parse inputs" diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index b3b94bb763f..f0faafe8d2f 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -4661,7 +4661,7 @@ type FsiEvaluationSession if List.isEmpty fsiOptions.SourceFiles then fsiConsolePrompt.PrintAhead() - do tcConfigB.getLine <- ValueSome fsiStdinSyphon.GetLine + do tcConfigB.getLine <- fsiStdinSyphon.GetLine let fsiConsoleInput = FsiConsoleInput(fsi, fsiOptions, inReader, outWriter) diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index 43a7a9cde96..187ee95e026 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -1467,6 +1467,8 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc tcConfigB, sourceFilesNew + FileContent.readFiles sourceFiles + // If this is a builder for a script, re-apply the settings inferred from the // script and its load closure to the configuration. // diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 734dd2a1eee..27e682f94bb 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -817,6 +817,8 @@ type internal TransparentCompiler tcConfigB.parallelReferenceResolution <- parallelReferenceResolution tcConfigB.captureIdentifiersWhenParsing <- captureIdentifiersWhenParsing + + FileContent.readFiles sourceFilesNew return tcConfigB, sourceFilesNew, loadClosureOpt } diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 5a1535b6f2d..b4969287384 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -643,6 +643,9 @@ type FSharpChecker // Apply command-line arguments and collect more source files if they are in the arguments let sourceFilesNew = ApplyCommandLineArgs(tcConfigB, sourceFiles, argv) + + FileContent.readFiles sourceFilesNew + FSharpParsingOptions.FromTcConfigBuilder(tcConfigB, Array.ofList sourceFilesNew, isInteractive), errorScope.Diagnostics member ic.GetParsingOptionsFromCommandLineArgs(argv, ?isInteractive: bool, ?isEditing) = diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 732ef43295d..8f8879f0360 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -191,7 +191,8 @@ type TcGlobals( pathMap: PathMap, langVersion: LanguageVersion, realsig: bool, - getLine: (string -> int -> string) voption) = + // Get a line string from a code file. Use to implement `CallerArgumentExpression` + getLine: string -> int -> string) = let v_langFeatureNullness = langVersion.SupportsFeature LanguageFeature.NullnessChecking @@ -1985,21 +1986,9 @@ type TcGlobals( let startCol = m.StartColumn - 1 let s = - match getLine with - | ValueSome f -> - [for i in m.StartLine..m.EndLine -> f m.FileName i] - |> String.concat "\n" - | ValueNone -> - try - if FileSystem.IsInvalidPathShim m.FileName || - not (FileSystem.FileExistsShim m.FileName) then - System.String.Empty - else - FileSystem.OpenFileForReadShim(m.FileName).ReadLines() - |> Seq.skip (m.StartLine - 1) - |> Seq.take (m.EndLine - m.StartLine + 1) - |> String.concat "\n" - with e -> System.String.Empty + [| for i in m.StartLine..m.EndLine -> getLine m.FileName i |] + |> String.concat "\n" + printfn "%A" (m, s) if System.String.IsNullOrEmpty s then ValueNone else ValueSome <| s.Substring(startCol + 1, s.LastIndexOf("\n", System.StringComparison.Ordinal) + 1 - startCol + endCol) diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index 0650086e708..e59a79f7904 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -148,7 +148,7 @@ type internal TcGlobals = pathMap: Internal.Utilities.PathMap * langVersion: FSharp.Compiler.Features.LanguageVersion * realsig: bool * - getLine: (string -> int -> string) voption -> + getLine: (string -> int -> string) -> TcGlobals static member IsInEmbeddableKnownSet: name: string -> bool diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index 678ab07f452..d7191b5bf0a 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -566,3 +566,17 @@ module Range = | None -> mkRange file (mkPos 1 0) (mkPos 1 80) with _ -> mkRange file (mkPos 1 0) (mkPos 1 80) + +module internal FileContent = + let private dict = ConcurrentDictionary() + + let readFiles (fileNames: string list) = + for fileName in fileNames do + if FileSystem.FileExistsShim fileName then + use fileStream = FileSystem.OpenFileForReadShim(fileName) + dict[fileName] <- fileStream.ReadAllLines() + + let getLine fileName line = + match dict.TryGetValue fileName with + | true, lines when lines.Length > line -> lines[line - 1] + | _ -> String.Empty \ No newline at end of file diff --git a/src/Compiler/Utilities/range.fsi b/src/Compiler/Utilities/range.fsi index 7b422fcd307..ed68d7f5eb2 100755 --- a/src/Compiler/Utilities/range.fsi +++ b/src/Compiler/Utilities/range.fsi @@ -269,4 +269,11 @@ module Line = /// Convert a line number from one-based line counting (used internally in the F# compiler and in F# error messages) to zero-based line counting (used by Visual Studio) val toZ: int -> Line0 +/// Store code file content. Use to implement `CallerArgumentExpression` +module internal FileContent = + /// Read all file contents + val readFiles: fileNames: string list -> unit + + /// Get a line string from already read files + val getLine: fileName: string -> line: int -> string From c9146724dc068dbb0479a924280cdfd2c9d4c190 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Sun, 11 Aug 2024 23:57:44 +0800 Subject: [PATCH 05/16] Change test; Add release note --- .../.FSharp.Compiler.Service/9.0.100.md | 1 + .../ErrorMessages/UnsupportedAttributes.fs | 15 ++++----------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index f05d847075d..c0225d23f73 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -13,6 +13,7 @@ * Parser: recover on missing union case fields (PR [#17452](https://github.com/dotnet/fsharp/pull/17452)) * Parser: recover on missing union case field types (PR [#17455](https://github.com/dotnet/fsharp/pull/17455)) * Sink: report function domain type ([PR #17470](https://github.com/dotnet/fsharp/pull/17470)) +* Support `CallerArgumentExpression` ([Language Suggestion #966](https://github.com/fsharp/fslang-suggestions/issues/966), [PR #17519](https://github.com/dotnet/fsharp/pull/17519)) ### Changed diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs index 3eb78de55b4..a117a089a03 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs @@ -23,13 +23,6 @@ type C() = |> typecheck |> shouldFail |> withResults [ - { Error = Warning 202 - Range = { StartLine = 3 - StartColumn = 13 - EndLine = 3 - EndColumn = 41 } - Message = - "This attribute is currently unsupported by the F# compiler. Applying it will not achieve its intended effect." } { Error = Warning 202 Range = { StartLine = 4 StartColumn = 7 @@ -37,13 +30,13 @@ type C() = EndColumn = 24 } Message = "This attribute is currently unsupported by the F# compiler. Applying it will not achieve its intended effect." } - { Error = Warning 202 + { Error = Warning 1247 Range = { StartLine = 6 - StartColumn = 22 + StartColumn = 14 EndLine = 6 - EndColumn = 82 } + EndColumn = 15 } Message = - "This attribute is currently unsupported by the F# compiler. Applying it will not achieve its intended effect." } + "'CallerArgumentExpression \"w\"' can only be applied to optional arguments" } { Error = Warning 202 Range = { StartLine = 7 StartColumn = 7 From 536cf34cc6a4b266ddd1073d86386fb9e47e0805 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Mon, 12 Aug 2024 00:45:04 +0800 Subject: [PATCH 06/16] Add tests Put under lang version flag --- src/Compiler/Checking/MethodCalls.fs | 2 +- src/Compiler/FSComp.txt | 1 + src/Compiler/Facilities/LanguageFeatures.fs | 3 ++ src/Compiler/Facilities/LanguageFeatures.fsi | 1 + src/Compiler/TypedTree/TcGlobals.fs | 1 - .../CallerArgumentExpression.fs | 43 +++++++++++++++++++ .../ErrorMessages/UnsupportedAttributes.fs | 2 +- .../FSharp.Compiler.ComponentTests.fsproj | 2 + 8 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 7dda8b368d2..977ee8b5bc9 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1425,7 +1425,7 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C emptyPreBinder, Expr.Const (Const.String fileName, mMethExpr, currCalledArgTy) | CallerMemberName, Some callerName when (typeEquiv g currCalledArgTy g.string_ty) -> emptyPreBinder, Expr.Const (Const.String callerName, mMethExpr, currCalledArgTy) - | CallerArgumentExpression param, _ when typeEquiv g currCalledArgTy g.string_ty -> + | CallerArgumentExpression param, _ when g.langVersion.SupportsFeature LanguageFeature.SupportCallerArgumentExpression && typeEquiv g currCalledArgTy g.string_ty -> let str = unnamedArgs |> List.tryPick (fun { CalledArg=called; CallerArg=caller } -> diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 62412a7698a..e313e8f96bf 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1776,3 +1776,4 @@ featureParsedHashDirectiveArgumentNonString,"# directives with non-quoted string 3869,featureParsedHashDirectiveUnexpectedIdentifier,"Unexpected identifier '%s'." featureEmptyBodiedComputationExpressions,"Support for computation expressions with empty bodies: builder {{ }}" 3870,parsExpectingUnionCaseField,"Expecting union case field" +featureEmptyBodiedComputationExpressions,"Support `CallerArgumentExpression`" \ No newline at end of file diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 2fd2e150bcc..3cd1c36bdb3 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -92,6 +92,7 @@ type LanguageFeature = | LowerSimpleMappingsInComprehensionsToFastLoops | ParsedHashDirectiveArgumentNonQuotes | EmptyBodiedComputationExpressions + | SupportCallerArgumentExpression /// LanguageVersion management type LanguageVersion(versionText) = @@ -215,6 +216,7 @@ type LanguageVersion(versionText) = LanguageFeature.UnmanagedConstraintCsharpInterop, previewVersion // not enabled because: https://github.com/dotnet/fsharp/issues/17509 LanguageFeature.EnforceAttributeTargets, previewVersion // not enabled because: https://github.com/dotnet/fsharp/issues/17514 LanguageFeature.FromEndSlicing, previewVersion // Unfinished features --- needs work + LanguageFeature.SupportCallerArgumentExpression, previewVersion ] static let defaultLanguageVersion = LanguageVersion("default") @@ -368,6 +370,7 @@ type LanguageVersion(versionText) = FSComp.SR.featureLowerSimpleMappingsInComprehensionsToFastLoops () | LanguageFeature.ParsedHashDirectiveArgumentNonQuotes -> FSComp.SR.featureParsedHashDirectiveArgumentNonString () | LanguageFeature.EmptyBodiedComputationExpressions -> FSComp.SR.featureEmptyBodiedComputationExpressions () + | LanguageFeature.SupportCallerArgumentExpression -> FSComp.SR.featureSupportCallerArgumentExpression () /// Get a version string associated with the given feature. static member GetFeatureVersionString feature = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 64f20d3f55a..0fc4d71cec2 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -83,6 +83,7 @@ type LanguageFeature = | LowerSimpleMappingsInComprehensionsToFastLoops | ParsedHashDirectiveArgumentNonQuotes | EmptyBodiedComputationExpressions + | SupportCallerArgumentExpression /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 8f8879f0360..4d223773a78 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1988,7 +1988,6 @@ type TcGlobals( let s = [| for i in m.StartLine..m.EndLine -> getLine m.FileName i |] |> String.concat "\n" - printfn "%A" (m, s) if System.String.IsNullOrEmpty s then ValueNone else ValueSome <| s.Substring(startCol + 1, s.LastIndexOf("\n", System.StringComparison.Ordinal) + 1 - startCol + endCol) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs new file mode 100644 index 00000000000..78e7917e555 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Conformance.BasicGrammarElements + +open Xunit +open FSharp.Test.Compiler + +module CustomAttributes_CallerArgumentExpression = + + [] + let ``Can consume CallerArgumentExpression in BCL methods`` () = + FSharp """ +try System.ArgumentNullException.ThrowIfNullOrWhiteSpace(Seq.init 50 (fun _ -> " ") + (* comment *) + |> String.concat " ") +with :? System.ArgumentException as ex -> + assert (ex.Message.Contains("(Parameter 'Seq.init 50 (fun _ -> \" \")\n (* comment *) \n |> String.concat \" \"")) +""" + |> withLangVersionPreview + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``Can define in F#`` () = + FSharp """# 1 "C:\\Program.fs" +open System.Runtime.InteropServices +type A() = +static member aa ( + a, + []b: string, + []c: int, + []d: string, + []e: string) = + a,b,c,d,e + +let stringABC = "abc" +assert (A.aa(stringABC) = ("abc", ".ctor", 12, "C:\Program.fs", "stringABC")) + """ + |> withLangVersionPreview + |> compileAndRun + |> shouldSucceed + |> ignore diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs index a117a089a03..8f11db7aa58 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UnsupportedAttributes.fs @@ -30,7 +30,7 @@ type C() = EndColumn = 24 } Message = "This attribute is currently unsupported by the F# compiler. Applying it will not achieve its intended effect." } - { Error = Warning 1247 + { Error = Error 1247 Range = { StartLine = 6 StartColumn = 14 EndLine = 6 diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 0509d424f8b..98d598800a0 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -37,6 +37,7 @@ + @@ -338,6 +339,7 @@ + From 3fc46425ca54af00d0ec9c78fe93ac23fa1749ad Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Mon, 12 Aug 2024 00:57:06 +0800 Subject: [PATCH 07/16] fix build; format --- docs/release-notes/.Language/preview.md | 1 + src/Compiler/Driver/ScriptClosure.fs | 2 +- src/Compiler/Driver/fsc.fs | 2 +- src/Compiler/FSComp.txt | 2 +- src/Compiler/Service/TransparentCompiler.fs | 2 +- src/Compiler/Service/service.fs | 2 +- src/Compiler/Utilities/range.fs | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index 6c2d5f0597b..b71dc8b0016 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -10,6 +10,7 @@ * Allow #nowarn to support the FS prefix on error codes to disable warnings ([Issue #17206](https://github.com/dotnet/fsharp/issues/16447), [PR #17209](https://github.com/dotnet/fsharp/pull/17209)) * Allow ParsedHashDirectives to have argument types other than strings ([Issue #17240](https://github.com/dotnet/fsharp/issues/16447), [PR #17209](https://github.com/dotnet/fsharp/pull/17209)) * Support empty-bodied computation expressions. ([Language suggestion #1232](https://github.com/fsharp/fslang-suggestions/issues/1232), [PR #17352](https://github.com/dotnet/fsharp/pull/17352)) +* Support `CallerArgumentExpression` ([Language Suggestion #966](https://github.com/fsharp/fslang-suggestions/issues/966), [PR #17519](https://github.com/dotnet/fsharp/pull/17519)) ### Fixed diff --git a/src/Compiler/Driver/ScriptClosure.fs b/src/Compiler/Driver/ScriptClosure.fs index 8a068671128..6ed6b5077cb 100644 --- a/src/Compiler/Driver/ScriptClosure.fs +++ b/src/Compiler/Driver/ScriptClosure.fs @@ -159,7 +159,7 @@ module ScriptPreprocessClosure = reduceMemoryUsage ) = - FileContent.readFiles [fileName] + FileContent.readFiles [ fileName ] let projectDir = Path.GetDirectoryName fileName let isInteractive = (codeContext = CodeContext.CompilationAndEvaluation) let isInvalidationSupported = (codeContext = CodeContext.Editing) diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index d8c40781210..b4215e971ea 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -621,7 +621,7 @@ let main1 // Register framework tcImports to be disposed in future disposables.Register frameworkTcImports - + FileContent.readFiles sourceFiles // Parse sourceFiles diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index e313e8f96bf..a816a48cbfc 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1776,4 +1776,4 @@ featureParsedHashDirectiveArgumentNonString,"# directives with non-quoted string 3869,featureParsedHashDirectiveUnexpectedIdentifier,"Unexpected identifier '%s'." featureEmptyBodiedComputationExpressions,"Support for computation expressions with empty bodies: builder {{ }}" 3870,parsExpectingUnionCaseField,"Expecting union case field" -featureEmptyBodiedComputationExpressions,"Support `CallerArgumentExpression`" \ No newline at end of file +featureSupportCallerArgumentExpression,"Support `CallerArgumentExpression`" \ No newline at end of file diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 27e682f94bb..2f5b8de8d5d 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -817,7 +817,7 @@ type internal TransparentCompiler tcConfigB.parallelReferenceResolution <- parallelReferenceResolution tcConfigB.captureIdentifiersWhenParsing <- captureIdentifiersWhenParsing - + FileContent.readFiles sourceFilesNew return tcConfigB, sourceFilesNew, loadClosureOpt diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index b4969287384..46d722c0a8e 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -643,7 +643,7 @@ type FSharpChecker // Apply command-line arguments and collect more source files if they are in the arguments let sourceFilesNew = ApplyCommandLineArgs(tcConfigB, sourceFiles, argv) - + FileContent.readFiles sourceFilesNew FSharpParsingOptions.FromTcConfigBuilder(tcConfigB, Array.ofList sourceFilesNew, isInteractive), errorScope.Diagnostics diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index d7191b5bf0a..a7118a34ed0 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -579,4 +579,4 @@ module internal FileContent = let getLine fileName line = match dict.TryGetValue fileName with | true, lines when lines.Length > line -> lines[line - 1] - | _ -> String.Empty \ No newline at end of file + | _ -> String.Empty From 550daa4daa62cabd5c2726af156798d816fab392 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Fri, 16 Aug 2024 03:35:24 +0800 Subject: [PATCH 08/16] Support `#line` Simplify code --- src/Compiler/Checking/MethodCalls.fs | 6 +- src/Compiler/Driver/CompilerConfig.fs | 4 - src/Compiler/Driver/CompilerConfig.fsi | 4 - src/Compiler/Driver/CompilerImports.fs | 3 +- src/Compiler/Driver/ScriptClosure.fs | 2 +- src/Compiler/Driver/fsc.fs | 2 +- src/Compiler/Facilities/prim-lexing.fs | 16 +- src/Compiler/Facilities/prim-lexing.fsi | 2 + src/Compiler/Interactive/fsi.fs | 11 +- src/Compiler/Service/IncrementalBuild.fs | 2 +- src/Compiler/Service/TransparentCompiler.fs | 2 +- src/Compiler/Service/service.fs | 2 +- src/Compiler/SyntaxTree/ParseHelpers.fs | 7 +- src/Compiler/TypedTree/TcGlobals.fs | 14 +- src/Compiler/TypedTree/TcGlobals.fsi | 3 +- src/Compiler/Utilities/range.fs | 154 ++++++++++++++++++-- src/Compiler/Utilities/range.fsi | 50 ++++++- src/Compiler/xlf/FSComp.txt.cs.xlf | 5 + src/Compiler/xlf/FSComp.txt.de.xlf | 5 + src/Compiler/xlf/FSComp.txt.es.xlf | 5 + src/Compiler/xlf/FSComp.txt.fr.xlf | 5 + src/Compiler/xlf/FSComp.txt.it.xlf | 5 + src/Compiler/xlf/FSComp.txt.ja.xlf | 5 + src/Compiler/xlf/FSComp.txt.ko.xlf | 5 + src/Compiler/xlf/FSComp.txt.pl.xlf | 5 + src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 5 + src/Compiler/xlf/FSComp.txt.ru.xlf | 5 + src/Compiler/xlf/FSComp.txt.tr.xlf | 5 + src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 5 + src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 5 + 30 files changed, 293 insertions(+), 56 deletions(-) diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 977ee8b5bc9..3cb8ec6c846 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1431,9 +1431,9 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C |> List.tryPick (fun { CalledArg=called; CallerArg=caller } -> match called.NameOpt with | Some x when x.idText = param -> - match g.GetCodeText caller.Range with - | ValueSome code -> Some (Const.String code) - | ValueNone -> None + let code = FileContent.getCodeText caller.Range + if System.String.IsNullOrEmpty code then None + else Some (Const.String code) | _ -> None) |> Option.defaultWith (fun _ -> tcFieldInit mMethExpr fieldInit) emptyPreBinder, Expr.Const (str, mMethExpr, currCalledArgTy) diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index ca6d1575c67..4a1d0d18c74 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -619,8 +619,6 @@ type TcConfigBuilder = mutable dumpSignatureData: bool mutable realsig: bool - - mutable getLine: string -> int -> string } // Directories to start probing in @@ -831,7 +829,6 @@ type TcConfigBuilder = dumpSignatureData = false realsig = true strictIndentation = None - getLine = FileContent.getLine } member tcConfigB.FxResolver = @@ -1376,7 +1373,6 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member _.typeCheckingConfig = data.typeCheckingConfig member _.dumpSignatureData = data.dumpSignatureData member _.realsig = data.realsig - member _.getLine = data.getLine static member Create(builder, validate) = use _ = UseBuildPhase BuildPhase.Parameter diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index 5cf3d40ccf8..f21ae429029 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -525,8 +525,6 @@ type TcConfigBuilder = mutable dumpSignatureData: bool mutable realsig: bool - - mutable getLine: string -> int -> string } static member CreateNew: @@ -906,8 +904,6 @@ type TcConfig = member realsig: bool - member getLine: (string -> int -> string) - /// Represents a computation to return a TcConfig. Normally this is just a constant immutable TcConfig, /// but for F# Interactive it may be based on an underlying mutable TcConfigBuilder. [] diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index a1adeb451a3..334a834db32 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2614,8 +2614,7 @@ and [] TcImports tcConfig.noDebugAttributes, tcConfig.pathMap, tcConfig.langVersion, - tcConfig.realsig, - tcConfig.getLine + tcConfig.realsig ) #if DEBUG diff --git a/src/Compiler/Driver/ScriptClosure.fs b/src/Compiler/Driver/ScriptClosure.fs index 6ed6b5077cb..5f37683445a 100644 --- a/src/Compiler/Driver/ScriptClosure.fs +++ b/src/Compiler/Driver/ScriptClosure.fs @@ -159,7 +159,7 @@ module ScriptPreprocessClosure = reduceMemoryUsage ) = - FileContent.readFiles [ fileName ] + FileContent.readFileContents [ fileName ] let projectDir = Path.GetDirectoryName fileName let isInteractive = (codeContext = CodeContext.CompilationAndEvaluation) let isInvalidationSupported = (codeContext = CodeContext.Editing) diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index b4215e971ea..71b47477476 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -622,7 +622,7 @@ let main1 // Register framework tcImports to be disposed in future disposables.Register frameworkTcImports - FileContent.readFiles sourceFiles + FileContent.readFileContents sourceFiles // Parse sourceFiles ReportTime tcConfig "Parse inputs" diff --git a/src/Compiler/Facilities/prim-lexing.fs b/src/Compiler/Facilities/prim-lexing.fs index 6b927ef4a96..452d636a3be 100644 --- a/src/Compiler/Facilities/prim-lexing.fs +++ b/src/Compiler/Facilities/prim-lexing.fs @@ -206,15 +206,17 @@ open System.Collections.Generic [] type internal Position = val FileIndex: int + val OriginalFileIndex: int val Line: int val OriginalLine: int val AbsoluteOffset: int val StartOfLineAbsoluteOffset: int member x.Column = x.AbsoluteOffset - x.StartOfLineAbsoluteOffset - new(fileIndex: int, line: int, originalLine: int, startOfLineAbsoluteOffset: int, absoluteOffset: int) = + new(fileIndex: int, originalFileIndex: int, line: int, originalLine: int, startOfLineAbsoluteOffset: int, absoluteOffset: int) = { FileIndex = fileIndex + OriginalFileIndex = originalFileIndex Line = line OriginalLine = originalLine AbsoluteOffset = absoluteOffset @@ -222,25 +224,25 @@ type internal Position = } member x.NextLine = - Position(x.FileIndex, x.Line + 1, x.OriginalLine + 1, x.AbsoluteOffset, x.AbsoluteOffset) + Position(x.FileIndex, x.OriginalFileIndex, x.Line + 1, x.OriginalLine + 1, x.AbsoluteOffset, x.AbsoluteOffset) member x.EndOfToken n = - Position(x.FileIndex, x.Line, x.OriginalLine, x.StartOfLineAbsoluteOffset, x.AbsoluteOffset + n) + Position(x.FileIndex, x.OriginalFileIndex, x.Line, x.OriginalLine, x.StartOfLineAbsoluteOffset, x.AbsoluteOffset + n) member x.ShiftColumnBy by = - Position(x.FileIndex, x.Line, x.OriginalLine, x.StartOfLineAbsoluteOffset, x.AbsoluteOffset + by) + Position(x.FileIndex, x.OriginalFileIndex, x.Line, x.OriginalLine, x.StartOfLineAbsoluteOffset, x.AbsoluteOffset + by) member x.ColumnMinusOne = - Position(x.FileIndex, x.Line, x.OriginalLine, x.StartOfLineAbsoluteOffset, x.StartOfLineAbsoluteOffset - 1) + Position(x.FileIndex, x.OriginalFileIndex, x.Line, x.OriginalLine, x.StartOfLineAbsoluteOffset, x.StartOfLineAbsoluteOffset - 1) member x.ApplyLineDirective(fileIdx, line) = - Position(fileIdx, line, x.OriginalLine, x.AbsoluteOffset, x.AbsoluteOffset) + Position(fileIdx, x.OriginalFileIndex, line, x.OriginalLine + 1, x.AbsoluteOffset, x.AbsoluteOffset) override p.ToString() = $"({p.Line},{p.Column})" static member Empty = Position() - static member FirstLine fileIdx = Position(fileIdx, 1, 0, 0, 0) + static member FirstLine fileIdx = Position(fileIdx, fileIdx, 1, 1, 0, 0) type internal LexBufferFiller<'Char> = LexBuffer<'Char> -> unit diff --git a/src/Compiler/Facilities/prim-lexing.fsi b/src/Compiler/Facilities/prim-lexing.fsi index ff13f96c9e1..b58c3e26ef7 100644 --- a/src/Compiler/Facilities/prim-lexing.fsi +++ b/src/Compiler/Facilities/prim-lexing.fsi @@ -72,6 +72,8 @@ type internal Position = /// The file index for the file associated with the input stream, use fileOfFileIndex to decode val FileIndex: int + val OriginalFileIndex: int + /// The line number in the input stream, assuming fresh positions have been updated /// for the new line by modifying the EndPos property of the LexBuffer. val Line: int diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index f0faafe8d2f..0977303e84a 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -831,6 +831,15 @@ type internal FsiStdinSyphon(errorWriter: TextWriter) = let lines = text.Split '\n' if 0 < i && i <= lines.Length then lines[i - 1] else "" + /// Gets the indicated line in the syphon text + member _.GetLineNoPrune fileName i = + if fileName <> stdinMockFileName then + "" + else + let text = syphonText.ToString() + let lines = text.Split '\n' + if 0 < i && i <= lines.Length then lines[i - 1] else "" + /// Display the given error. member syphon.PrintDiagnostic(tcConfig: TcConfig, diagnostic: PhasedDiagnostic) = ignoreAllErrors (fun () -> @@ -4661,7 +4670,7 @@ type FsiEvaluationSession if List.isEmpty fsiOptions.SourceFiles then fsiConsolePrompt.PrintAhead() - do tcConfigB.getLine <- fsiStdinSyphon.GetLine + do FileContent.getLineDynamic <- fsiStdinSyphon.GetLineNoPrune let fsiConsoleInput = FsiConsoleInput(fsi, fsiOptions, inReader, outWriter) diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index 187ee95e026..b7693da2c92 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -1467,7 +1467,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc tcConfigB, sourceFilesNew - FileContent.readFiles sourceFiles + FileContent.readFileContents sourceFiles // If this is a builder for a script, re-apply the settings inferred from the // script and its load closure to the configuration. diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 2f5b8de8d5d..6b710c8a70f 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -818,7 +818,7 @@ type internal TransparentCompiler tcConfigB.parallelReferenceResolution <- parallelReferenceResolution tcConfigB.captureIdentifiersWhenParsing <- captureIdentifiersWhenParsing - FileContent.readFiles sourceFilesNew + FileContent.readFileContents sourceFilesNew return tcConfigB, sourceFilesNew, loadClosureOpt } diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 46d722c0a8e..fd6a0b0f0ef 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -644,7 +644,7 @@ type FSharpChecker // Apply command-line arguments and collect more source files if they are in the arguments let sourceFilesNew = ApplyCommandLineArgs(tcConfigB, sourceFiles, argv) - FileContent.readFiles sourceFilesNew + FileContent.readFileContents sourceFilesNew FSharpParsingOptions.FromTcConfigBuilder(tcConfigB, Array.ofList sourceFilesNew, isInteractive), errorScope.Diagnostics diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fs b/src/Compiler/SyntaxTree/ParseHelpers.fs index d90e395c0c9..d6667e75249 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fs +++ b/src/Compiler/SyntaxTree/ParseHelpers.fs @@ -40,10 +40,15 @@ let warningStringOfPos (p: pos) = warningStringOfCoords p.Line p.Column /// Get an F# compiler position from a lexer position let posOfLexPosition (p: Position) = mkPos p.Line p.Column +let posOfLexOriginalPosition (p: Position) = mkPos p.OriginalLine p.Column /// Get an F# compiler range from a lexer range let mkSynRange (p1: Position) (p2: Position) = - mkFileIndexRange p1.FileIndex (posOfLexPosition p1) (posOfLexPosition p2) + if p1.OriginalFileIndex <> p1.FileIndex || p1.OriginalLine <> p2.Line then + mkFileIndexRangeWithOriginRange + p1.FileIndex (posOfLexPosition p1) (posOfLexPosition p2) + p1.OriginalFileIndex (posOfLexOriginalPosition p1) (posOfLexOriginalPosition p2) + else mkFileIndexRange p1.FileIndex (posOfLexPosition p1) (posOfLexPosition p2) type LexBuffer<'Char> with diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 4d223773a78..fbc5af28fc1 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -190,9 +190,7 @@ type TcGlobals( noDebugAttributes: bool, pathMap: PathMap, langVersion: LanguageVersion, - realsig: bool, - // Get a line string from a code file. Use to implement `CallerArgumentExpression` - getLine: string -> int -> string) = + realsig: bool) = let v_langFeatureNullness = langVersion.SupportsFeature LanguageFeature.NullnessChecking @@ -1981,16 +1979,6 @@ type TcGlobals( | _ -> None - member _.GetCodeText (m: Text.Range) = - let endCol = m.EndColumn - 1 - let startCol = m.StartColumn - 1 - - let s = - [| for i in m.StartLine..m.EndLine -> getLine m.FileName i |] - |> String.concat "\n" - if System.String.IsNullOrEmpty s then ValueNone else - ValueSome <| s.Substring(startCol + 1, s.LastIndexOf("\n", System.StringComparison.Ordinal) + 1 - startCol + endCol) - #if DEBUG // This global is only used during debug output let mutable global_g = None : TcGlobals option diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index e59a79f7904..c970c4a52cc 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -147,8 +147,7 @@ type internal TcGlobals = noDebugAttributes: bool * pathMap: Internal.Utilities.PathMap * langVersion: FSharp.Compiler.Features.LanguageVersion * - realsig: bool * - getLine: (string -> int -> string) -> + realsig: bool -> TcGlobals static member IsInEmbeddableKnownSet: name: string -> bool diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index a7118a34ed0..ac081f9df93 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -260,8 +260,8 @@ module FileIndex = [] [ {DebugCode}")>] -type Range(code1: int64, code2: int64) = - static member Zero = range (0L, 0L) +type _Range(code1: int64, code2: int64) = + static member Zero = _range (0L, 0L) new(fIdx, bl, bc, el, ec) = let code1 = @@ -273,9 +273,9 @@ type Range(code1: int64, code2: int64) = ((int64 bl <<< startLineShift) &&& startLineMask) ||| ((int64 (el - bl) <<< heightShift) &&& heightMask) - range (code1, code2) + _range (code1, code2) - new(fIdx, b: pos, e: pos) = range (fIdx, b.Line, b.Column, e.Line, e.Column) + new(fIdx, b: pos, e: pos) = _range (fIdx, b.Line, b.Column, e.Line, e.Column) member _.StartLine = int32 (uint64 (code2 &&& startLineMask) >>> startLineShift) @@ -307,18 +307,18 @@ type Range(code1: int64, code2: int64) = member _.FileIndex = int32 (code1 &&& fileIndexMask) - member m.StartRange = range (m.FileIndex, m.Start, m.Start) + member m.StartRange = _range (m.FileIndex, m.Start, m.Start) - member m.EndRange = range (m.FileIndex, m.End, m.End) + member m.EndRange = _range (m.FileIndex, m.End, m.End) member m.FileName = fileOfFileIndex m.FileIndex member m.ShortFileName = Path.GetFileName(fileOfFileIndex m.FileIndex) member _.MakeSynthetic() = - range (code1, code2 ||| isSyntheticMask) + _range (code1, code2 ||| isSyntheticMask) - member m.IsAdjacentTo(otherRange: Range) = + member m.IsAdjacentTo(otherRange: _Range) = m.FileIndex = otherRange.FileIndex && m.End.Encoding = otherRange.Start.Encoding member _.NoteSourceConstruct(kind) = @@ -335,7 +335,7 @@ type Range(code1: int64, code2: int64) = | NotedSourceConstruct.Combine -> 8 | NotedSourceConstruct.DelayOrQuoteOrRun -> 9 - range (code1, (code2 &&& ~~~debugPointKindMask) ||| (int64 code <<< debugPointKindShift)) + _range (code1, (code2 &&& ~~~debugPointKindMask) ||| (int64 code <<< debugPointKindShift)) member _.Code1 = code1 @@ -369,14 +369,14 @@ type Range(code1: int64, code2: int64) = with e -> e.ToString() - member _.Equals(m2: range) = + member _.Equals(m2: _range) = let code2 = code2 &&& ~~~(debugPointKindMask ||| isSyntheticMask) let rcode2 = m2.Code2 &&& ~~~(debugPointKindMask ||| isSyntheticMask) code1 = m2.Code1 && code2 = rcode2 override m.Equals(obj) = match obj with - | :? range as m2 -> m.Equals(m2) + | :? _range as m2 -> m.Equals(m2) | _ -> false override _.GetHashCode() = @@ -386,6 +386,112 @@ type Range(code1: int64, code2: int64) = override r.ToString() = sprintf "(%d,%d--%d,%d)" r.StartLine r.StartColumn r.EndLine r.EndColumn + member m.IsZero = m.Equals _range.Zero + +and _range = _Range + + +[] +[ ({StartLine},{StartColumn}-{EndLine},{EndColumn}) {ShortFileName} -> {DebugCode}")>] +type Range(range1: _range, range2: _range) = + static member Zero = range (_range.Zero, _range.Zero) + + new(fIdx, bl, bc, el, ec) = + range(_range (fIdx, bl, bc, el, ec), _Range.Zero) + + new(fIdx, bl, bc, el, ec, fIdx2, bl2, bc2, el2, ec2) = + range(_range (fIdx, bl, bc, el, ec), _range (fIdx2, bl2, bc2, el2, ec2)) + + new(fIdx, b: pos, e: pos) = range (_range(fIdx, b.Line, b.Column, e.Line, e.Column), _range.Zero) + + new(fIdx, b: pos, e: pos, fIdx2, b2: pos, e2: pos) = range (_range(fIdx, b.Line, b.Column, e.Line, e.Column), _range(fIdx2, b2.Line, b2.Column, e2.Line, e2.Column)) + + member _.StartLine = range1.StartLine + + member _.StartColumn = range1.StartColumn + + member _.EndLine = range1.EndLine + + member _.EndColumn = range1.EndColumn + + member _.IsSynthetic = range1.IsSynthetic + + member _.NotedSourceConstruct = range1.NotedSourceConstruct + + member _.Start = range1.Start + + member _.End = range1.End + + member _.FileIndex = range1.FileIndex + + member _.StartRange = Range(range1.StartRange, range2.StartRange) + + member _.EndRange = Range(range1.EndRange, range2.EndRange) + + member _.FileName = range1.FileName + + member _.ShortFileName = range1.ShortFileName + + member _.MakeSynthetic() = range (range1.MakeSynthetic(), range2.MakeSynthetic()) + + member _.IsAdjacentTo(otherRange: Range) = range1.IsAdjacentTo otherRange.Range1 + + member _.NoteSourceConstruct(kind) = range(range1.NoteSourceConstruct kind, range2.NoteSourceConstruct kind) + + member _.Code1 = range1.Code1 + + member _.Code2 = range1.Code2 + + member _.Range1 = range1 + + member _.Range2 = range2 + + member _.DebugCode = range1.DebugCode + + member _.Equals(m2: range) = + range1.Equals m2.Range1 && range2.Equals m2.Range2 + + override m.Equals(obj) = + match obj with + | :? range as m2 -> m.Equals(m2) + | _ -> false + + override _.GetHashCode() = + range1.GetHashCode() + range2.GetHashCode() + + override _.ToString() = + range1.ToString() + + if range2.IsZero then String.Empty else $"(from: {range2.ToString()})" + + member _.HasOriginalRange = not range2.IsZero + + member _.OriginalStartLine = range2.StartLine + + member _.OriginalStartColumn = range2.StartColumn + + member _.OriginalEndLine = range2.EndLine + + member _.OriginalEndColumn = range2.EndColumn + + member _.OriginalIsSynthetic = range2.IsSynthetic + + member _.OriginalNotedSourceConstruct = range2.NotedSourceConstruct + + member _.OriginalStart = range2.Start + + member _.OriginalEnd = range2.End + + member _.OriginalFileIndex = range2.FileIndex + + member _.OriginalStartRange = Range(range2.StartRange, range2.StartRange) + + member _.OriginalEndRange = Range(range2.EndRange, range2.EndRange) + + member _.OriginalFileName = range2.FileName + + member _.OriginalShortFileName = range2.ShortFileName + + and range = Range #if CHECK_LINE0_TYPES // turn on to check that we correctly transform zero-based line counts to one-based line counts @@ -444,6 +550,8 @@ module Range = let mkFileIndexRange fileIndex startPos endPos = range (fileIndex, startPos, endPos) + let mkFileIndexRangeWithOriginRange fileIndex startPos endPos fileIndex2 startPos2 endPos2 = range (fileIndex, startPos, endPos, fileIndex2, startPos2, endPos2) + let posOrder = Order.orderOn (fun (p: pos) -> p.Line, p.Column) (Pair.order (Int32.order, Int32.order)) @@ -484,7 +592,11 @@ module Range = m2 let m = - range (m1.FileIndex, start.StartLine, start.StartColumn, finish.EndLine, finish.EndColumn) + if m1.OriginalFileIndex = m2.OriginalFileIndex then + range (m1.FileIndex, start.StartLine, start.StartColumn, finish.EndLine, finish.EndColumn, + m1.OriginalFileIndex, start.OriginalStartLine, start.OriginalStartColumn, finish.OriginalEndLine, finish.OriginalEndColumn) + else + range (m1.FileIndex, start.StartLine, start.StartColumn, finish.EndLine, finish.EndColumn) if m1.IsSynthetic || m2.IsSynthetic then m.MakeSynthetic() @@ -570,7 +682,7 @@ module Range = module internal FileContent = let private dict = ConcurrentDictionary() - let readFiles (fileNames: string list) = + let readFileContents (fileNames: string list) = for fileName in fileNames do if FileSystem.FileExistsShim fileName then use fileStream = FileSystem.OpenFileForReadShim(fileName) @@ -580,3 +692,19 @@ module internal FileContent = match dict.TryGetValue fileName with | true, lines when lines.Length > line -> lines[line - 1] | _ -> String.Empty + + let mutable getLineDynamic = getLine + + let getCodeText (m: range) = + let endCol = m.EndColumn - 1 + let startCol = m.StartColumn - 1 + + let s = + let filename, startLine, endLine = + if m.HasOriginalRange then m.OriginalFileName, m.OriginalStartLine, m.OriginalEndLine + else m.FileName, m.StartLine, m.EndLine + + [| for i in startLine..endLine -> getLineDynamic filename i |] + |> String.concat "\n" + if String.IsNullOrEmpty s then s else + s.Substring(startCol + 1, s.LastIndexOf("\n", StringComparison.Ordinal) + 1 - startCol + endCol) \ No newline at end of file diff --git a/src/Compiler/Utilities/range.fsi b/src/Compiler/Utilities/range.fsi index ed68d7f5eb2..bd368f7d369 100755 --- a/src/Compiler/Utilities/range.fsi +++ b/src/Compiler/Utilities/range.fsi @@ -107,6 +107,44 @@ type Range = /// service operations like dot-completion. member IsSynthetic: bool + member HasOriginalRange: bool + + /// The start line of the range + member OriginalStartLine: int + + /// The start column of the range + member OriginalStartColumn: int + + /// The line number for the end position of the range + member OriginalEndLine: int + + /// The column number for the end position of the range + member OriginalEndColumn: int + + /// The start position of the range + member OriginalStart: pos + + /// The end position of the range + member OriginalEnd: pos + + /// The empty range that is located at the start position of the range + member OriginalStartRange: range + + /// The empty range that is located at the end position of the range + member OriginalEndRange: range + + /// The file index for the range + member internal OriginalFileIndex: int + + /// The file name for the file of the range + member OriginalFileName: string + + /// Synthetic marks ranges which are produced by intermediate compilation phases. This + /// bit signifies that the range covers something that should not be visible to language + /// service operations like dot-completion. + member OriginalIsSynthetic: bool + + /// Convert a range to be synthetic member internal MakeSynthetic: unit -> range @@ -191,6 +229,8 @@ module Range = /// This view of range marks uses file indexes explicitly val mkFileIndexRange: FileIndex -> pos -> pos -> range + val mkFileIndexRangeWithOriginRange: FileIndex -> pos -> pos -> FileIndex -> pos -> pos -> range + /// This view hides the use of file indexes and just uses filenames val mkRange: string -> pos -> pos -> range @@ -273,7 +313,15 @@ module Line = module internal FileContent = /// Read all file contents - val readFiles: fileNames: string list -> unit + val readFileContents: fileNames: string list -> unit /// Get a line string from already read files val getLine: fileName: string -> line: int -> string + + /// Get a line string from already read files. + /// + /// Used by `getCodeText` to support `CallerArgumentExpression` in F# Interactive + val mutable getLineDynamic: (string -> int -> string) + + /// Get code text of the specific `range` + val getCodeText: range -> string diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index dc578af9a99..395b62d199f 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -587,6 +587,11 @@ reprezentace struktury aktivních vzorů + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties Vlastnosti testu případu sjednocení diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 0d5007fed66..28c51bf8185 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -587,6 +587,11 @@ Strukturdarstellung für aktive Muster + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties Eigenschaften von Union-Falltests diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index eee3b33c5c9..f6d6fd7e2ee 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -587,6 +587,11 @@ representación de struct para modelos activos + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties Propiedades de prueba de caso de unión diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 37b8637fac1..a51a72c8ee8 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -587,6 +587,11 @@ représentation de structure pour les modèles actifs + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties Propriétés du test de cas d’union diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 45f773a03e8..f8e336d8bc6 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -587,6 +587,11 @@ rappresentazione struct per criteri attivi + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties Proprietà test case di unione diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index c4b21520176..8123f554cb4 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -587,6 +587,11 @@ アクティブなパターンの構造体表現 + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties ユニオン ケースのテスト プロパティ diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 00d19be0919..531d4d3552d 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -587,6 +587,11 @@ 활성 패턴에 대한 구조체 표현 + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties 공용 구조체 사례 테스트 속성 diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index f9f8d75e2c0..26de66bc57b 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -587,6 +587,11 @@ reprezentacja struktury aktywnych wzorców + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties Właściwości testowe przypadku unii diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index b6ecb582a3d..ff5b0825181 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -587,6 +587,11 @@ representação estrutural para padrões ativos + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties Propriedades de teste de caso de união diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index a55d1afade8..e89ea429b01 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -587,6 +587,11 @@ представление структуры для активных шаблонов + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties Свойства теста союзного случая diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index da224bfc0ee..cc7e1431793 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -587,6 +587,11 @@ etkin desenler için yapı gösterimi + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties Birleşim durumu test özellikleri diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 26b945a8541..a8420dea45d 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -587,6 +587,11 @@ 活动模式的结构表示形式 + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties 联合用例测试属性 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 16d8255e6aa..0cdb26de227 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -587,6 +587,11 @@ 現用模式的結構表示法 + + Support `CallerArgumentExpression` + Support `CallerArgumentExpression` + + Union case test properties 聯集案例測試屬性 From 5cecb20945e67e929c724681ba0659bfdf5feb74 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Fri, 16 Aug 2024 03:39:11 +0800 Subject: [PATCH 09/16] format --- src/Compiler/SyntaxTree/ParseHelpers.fs | 13 +++-- src/Compiler/Utilities/range.fs | 72 +++++++++++++++---------- 2 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fs b/src/Compiler/SyntaxTree/ParseHelpers.fs index d6667e75249..fb721bcf520 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fs +++ b/src/Compiler/SyntaxTree/ParseHelpers.fs @@ -44,11 +44,16 @@ let posOfLexOriginalPosition (p: Position) = mkPos p.OriginalLine p.Column /// Get an F# compiler range from a lexer range let mkSynRange (p1: Position) (p2: Position) = - if p1.OriginalFileIndex <> p1.FileIndex || p1.OriginalLine <> p2.Line then + if p1.OriginalFileIndex <> p1.FileIndex || p1.OriginalLine <> p1.Line then mkFileIndexRangeWithOriginRange - p1.FileIndex (posOfLexPosition p1) (posOfLexPosition p2) - p1.OriginalFileIndex (posOfLexOriginalPosition p1) (posOfLexOriginalPosition p2) - else mkFileIndexRange p1.FileIndex (posOfLexPosition p1) (posOfLexPosition p2) + p1.FileIndex + (posOfLexPosition p1) + (posOfLexPosition p2) + p1.OriginalFileIndex + (posOfLexOriginalPosition p1) + (posOfLexOriginalPosition p2) + else + mkFileIndexRange p1.FileIndex (posOfLexPosition p1) (posOfLexPosition p2) type LexBuffer<'Char> with diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index ac081f9df93..f51919c01a8 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -390,21 +390,19 @@ type _Range(code1: int64, code2: int64) = and _range = _Range - [] [ ({StartLine},{StartColumn}-{EndLine},{EndColumn}) {ShortFileName} -> {DebugCode}")>] type Range(range1: _range, range2: _range) = static member Zero = range (_range.Zero, _range.Zero) - - new(fIdx, bl, bc, el, ec) = - range(_range (fIdx, bl, bc, el, ec), _Range.Zero) - new(fIdx, bl, bc, el, ec, fIdx2, bl2, bc2, el2, ec2) = - range(_range (fIdx, bl, bc, el, ec), _range (fIdx2, bl2, bc2, el2, ec2)) + new(fIdx, bl, bc, el, ec) = range (_range (fIdx, bl, bc, el, ec), _Range.Zero) + + new(fIdx, bl, bc, el, ec, fIdx2, bl2, bc2, el2, ec2) = range (_range (fIdx, bl, bc, el, ec), _range (fIdx2, bl2, bc2, el2, ec2)) - new(fIdx, b: pos, e: pos) = range (_range(fIdx, b.Line, b.Column, e.Line, e.Column), _range.Zero) + new(fIdx, b: pos, e: pos) = range (_range (fIdx, b.Line, b.Column, e.Line, e.Column), _range.Zero) - new(fIdx, b: pos, e: pos, fIdx2, b2: pos, e2: pos) = range (_range(fIdx, b.Line, b.Column, e.Line, e.Column), _range(fIdx2, b2.Line, b2.Column, e2.Line, e2.Column)) + new(fIdx, b: pos, e: pos, fIdx2, b2: pos, e2: pos) = + range (_range (fIdx, b.Line, b.Column, e.Line, e.Column), _range (fIdx2, b2.Line, b2.Column, e2.Line, e2.Column)) member _.StartLine = range1.StartLine @@ -432,11 +430,13 @@ type Range(range1: _range, range2: _range) = member _.ShortFileName = range1.ShortFileName - member _.MakeSynthetic() = range (range1.MakeSynthetic(), range2.MakeSynthetic()) + member _.MakeSynthetic() = + range (range1.MakeSynthetic(), range2.MakeSynthetic()) member _.IsAdjacentTo(otherRange: Range) = range1.IsAdjacentTo otherRange.Range1 - member _.NoteSourceConstruct(kind) = range(range1.NoteSourceConstruct kind, range2.NoteSourceConstruct kind) + member _.NoteSourceConstruct(kind) = + range (range1.NoteSourceConstruct kind, range2.NoteSourceConstruct kind) member _.Code1 = range1.Code1 @@ -448,7 +448,7 @@ type Range(range1: _range, range2: _range) = member _.DebugCode = range1.DebugCode - member _.Equals(m2: range) = + member _.Equals(m2: range) = range1.Equals m2.Range1 && range2.Equals m2.Range2 override m.Equals(obj) = @@ -456,12 +456,15 @@ type Range(range1: _range, range2: _range) = | :? range as m2 -> m.Equals(m2) | _ -> false - override _.GetHashCode() = + override _.GetHashCode() = range1.GetHashCode() + range2.GetHashCode() - override _.ToString() = - range1.ToString() + - if range2.IsZero then String.Empty else $"(from: {range2.ToString()})" + override _.ToString() = + range1.ToString() + + if range2.IsZero then + String.Empty + else + $"(from: {range2.ToString()})" member _.HasOriginalRange = not range2.IsZero @@ -491,7 +494,6 @@ type Range(range1: _range, range2: _range) = member _.OriginalShortFileName = range2.ShortFileName - and range = Range #if CHECK_LINE0_TYPES // turn on to check that we correctly transform zero-based line counts to one-based line counts @@ -550,7 +552,8 @@ module Range = let mkFileIndexRange fileIndex startPos endPos = range (fileIndex, startPos, endPos) - let mkFileIndexRangeWithOriginRange fileIndex startPos endPos fileIndex2 startPos2 endPos2 = range (fileIndex, startPos, endPos, fileIndex2, startPos2, endPos2) + let mkFileIndexRangeWithOriginRange fileIndex startPos endPos fileIndex2 startPos2 endPos2 = + range (fileIndex, startPos, endPos, fileIndex2, startPos2, endPos2) let posOrder = Order.orderOn (fun (p: pos) -> p.Line, p.Column) (Pair.order (Int32.order, Int32.order)) @@ -593,8 +596,18 @@ module Range = let m = if m1.OriginalFileIndex = m2.OriginalFileIndex then - range (m1.FileIndex, start.StartLine, start.StartColumn, finish.EndLine, finish.EndColumn, - m1.OriginalFileIndex, start.OriginalStartLine, start.OriginalStartColumn, finish.OriginalEndLine, finish.OriginalEndColumn) + range ( + m1.FileIndex, + start.StartLine, + start.StartColumn, + finish.EndLine, + finish.EndColumn, + m1.OriginalFileIndex, + start.OriginalStartLine, + start.OriginalStartColumn, + finish.OriginalEndLine, + finish.OriginalEndColumn + ) else range (m1.FileIndex, start.StartLine, start.StartColumn, finish.EndLine, finish.EndColumn) @@ -698,13 +711,18 @@ module internal FileContent = let getCodeText (m: range) = let endCol = m.EndColumn - 1 let startCol = m.StartColumn - 1 - - let s = - let filename, startLine, endLine = - if m.HasOriginalRange then m.OriginalFileName, m.OriginalStartLine, m.OriginalEndLine - else m.FileName, m.StartLine, m.EndLine - + + let s = + let filename, startLine, endLine = + if m.HasOriginalRange then + m.OriginalFileName, m.OriginalStartLine, m.OriginalEndLine + else + m.FileName, m.StartLine, m.EndLine + [| for i in startLine..endLine -> getLineDynamic filename i |] |> String.concat "\n" - if String.IsNullOrEmpty s then s else - s.Substring(startCol + 1, s.LastIndexOf("\n", StringComparison.Ordinal) + 1 - startCol + endCol) \ No newline at end of file + + if String.IsNullOrEmpty s then + s + else + s.Substring(startCol + 1, s.LastIndexOf("\n", StringComparison.Ordinal) + 1 - startCol + endCol) From 1b6cd563db2c015b999ef06ba0b7456d9202249e Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:15:53 +0800 Subject: [PATCH 10/16] support callee side optional arg add warning read the new line mark --- src/Compiler/Checking/MethodCalls.fs | 20 +++++- src/Compiler/Checking/PostInferenceChecks.fs | 37 ++++++++-- src/Compiler/FSComp.txt | 4 +- src/Compiler/Interactive/fsi.fs | 8 ++- src/Compiler/TypedTree/TcGlobals.fsi | 2 - src/Compiler/Utilities/range.fs | 76 ++++++++++++-------- src/Compiler/Utilities/range.fsi | 7 +- src/Compiler/xlf/FSComp.txt.cs.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.de.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.es.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.fr.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.it.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.ja.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.ko.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.pl.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.ru.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.tr.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 10 +++ src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 10 +++ 20 files changed, 239 insertions(+), 45 deletions(-) diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 3cb8ec6c846..a14f8ca3a00 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1466,7 +1466,7 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C /// Get the expression that must be inserted on the caller side for a CalleeSide optional arg where /// no caller argument has been provided. Normally this is 'None', however CallerMemberName and friends /// can be used with 'CalleeSide' optional arguments -let GetDefaultExpressionForCalleeSideOptionalArg g (calledArg: CalledArg) eCallerMemberName (mMethExpr: range) = +let GetDefaultExpressionForCalleeSideOptionalArg g (calledArg: CalledArg) eCallerMemberName (mMethExpr: range) unnamedArgs = let calledArgTy = calledArg.CalledArgumentType let calledNonOptTy = if isOptionTy g calledArgTy then @@ -1485,6 +1485,22 @@ let GetDefaultExpressionForCalleeSideOptionalArg g (calledArg: CalledArg) eCalle | CallerMemberName, Some(callerName) when typeEquiv g calledNonOptTy g.string_ty -> let memberNameExpr = Expr.Const (Const.String callerName, mMethExpr, calledNonOptTy) mkSome g calledNonOptTy memberNameExpr mMethExpr + + | CallerArgumentExpression param, _ when g.langVersion.SupportsFeature LanguageFeature.SupportCallerArgumentExpression && typeEquiv g calledNonOptTy g.string_ty -> + let exprOpt = + unnamedArgs + |> List.tryPick (fun { CalledArg=called; CallerArg=caller } -> + match called.NameOpt with + | Some x when x.idText = param -> + let code = FileContent.getCodeText caller.Range + if System.String.IsNullOrEmpty code then None + else Some (Expr.Const(Const.String code, mMethExpr, calledNonOptTy)) + | _ -> None) + + match exprOpt with + | Some expr -> mkSome g calledNonOptTy expr mMethExpr + | None -> mkNone g calledNonOptTy mMethExpr + | _ -> mkNone g calledNonOptTy mMethExpr @@ -1501,7 +1517,7 @@ let GetDefaultExpressionForOptionalArg tcFieldInit g (calledArg: CalledArg) eCal GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g calledArg calledArgTy dfltVal eCallerMemberName mMethExpr unnamedArgs | CalleeSide -> - emptyPreBinder, GetDefaultExpressionForCalleeSideOptionalArg g calledArg eCallerMemberName mMethExpr + emptyPreBinder, GetDefaultExpressionForCalleeSideOptionalArg g calledArg eCallerMemberName mMethExpr unnamedArgs // Combine the variable allocators (if any) let callerArg = CallerArg(calledArgTy, mMethExpr, false, expr) diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index a66c2033fe1..7991a9d6107 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -2333,15 +2333,34 @@ let CheckEntityDefn cenv env (tycon: Entity) = if numCurriedArgSets > 1 && others |> List.exists (fun minfo2 -> not (IsAbstractDefaultPair2 minfo minfo2)) then errorR(Error(FSComp.SR.chkDuplicateMethodCurried(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) + let paramDatas = minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) + if numCurriedArgSets > 1 && - (minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) + (paramDatas |> List.existsSquared (fun (ParamData(isParamArrayArg, _isInArg, isOutArg, optArgInfo, callerInfo, _, reflArgInfo, ty)) -> isParamArrayArg || isOutArg || reflArgInfo.AutoQuote || optArgInfo.IsOptional || callerInfo <> NoCallerInfo || isByrefLikeTy g m ty)) then errorR(Error(FSComp.SR.chkCurriedMethodsCantHaveOutParams(), m)) if numCurriedArgSets = 1 then - minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) - |> List.iterSquared (fun (ParamData(_, isInArg, _, optArgInfo, callerInfo, _, _, ty)) -> + let paramNames = + paramDatas + |> List.concat + |> List.choose (fun (ParamData(_, _, _, _, _, nameOpt, _, _)) -> nameOpt) + + let checkCallerArgumentExpression name (nameOpt: Ident option) = + match nameOpt with + | Some ident when name = ident.idText -> + warning(Error(FSComp.SR.tcCallerArgumentExpressionSelfReferential(name), m)) + | _ -> () + + if + paramNames + |> List.exists (fun i -> name = i.idText) + |> not + then warning(Error(FSComp.SR.tcCallerArgumentExpressionHasInvalidParameterName(name), m)) + + paramDatas + |> List.iterSquared (fun (ParamData(_, isInArg, _, optArgInfo, callerInfo, nameOpt, _, ty)) -> ignore isInArg match (optArgInfo, callerInfo) with | _, NoCallerInfo -> () @@ -2364,12 +2383,18 @@ let CheckEntityDefn cenv env (tycon: Entity) = | CalleeSide, CallerMemberName -> if not ((isOptionTy g ty) && (typeEquiv g g.string_ty (destOptionTy g ty))) then errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo.ToString(), "string", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m)) - | CallerSide _, CallerArgumentExpression _ -> + | CallerSide _, CallerArgumentExpression name -> if not (typeEquiv g g.string_ty ty) then errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo.ToString(), "string", NicePrint.minimalStringOfType cenv.denv ty), m)) - | CalleeSide, CallerArgumentExpression _ -> + + checkCallerArgumentExpression name nameOpt + + | CalleeSide, CallerArgumentExpression name -> if not ((isOptionTy g ty) && (typeEquiv g g.string_ty (destOptionTy g ty))) then - errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo.ToString(), "string", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m))) + errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo.ToString(), "string", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m)) + + checkCallerArgumentExpression name nameOpt + ) for pinfo in immediateProps do let nm = pinfo.PropertyName diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index a816a48cbfc..c286e8896c6 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1776,4 +1776,6 @@ featureParsedHashDirectiveArgumentNonString,"# directives with non-quoted string 3869,featureParsedHashDirectiveUnexpectedIdentifier,"Unexpected identifier '%s'." featureEmptyBodiedComputationExpressions,"Support for computation expressions with empty bodies: builder {{ }}" 3870,parsExpectingUnionCaseField,"Expecting union case field" -featureSupportCallerArgumentExpression,"Support `CallerArgumentExpression`" \ No newline at end of file +featureSupportCallerArgumentExpression,"Support `CallerArgumentExpression`" +3871,tcCallerArgumentExpressionSelfReferential,"This CallerArgumentExpression with argument '%s' will have no effect because it's self-referential." +3871,tcCallerArgumentExpressionHasInvalidParameterName,"This CallerArgumentExpression with argument '%s' will have no effect because it's applied with an invalid parameter name." \ No newline at end of file diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 0977303e84a..7fc5db927c8 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -4670,7 +4670,13 @@ type FsiEvaluationSession if List.isEmpty fsiOptions.SourceFiles then fsiConsolePrompt.PrintAhead() - do FileContent.getLineDynamic <- fsiStdinSyphon.GetLineNoPrune + do FileContent.getLineDynamic <- + { new FileContent.IFileContentGetLine with + member this.GetLine(fileName: string) (line: int): string = + fsiStdinSyphon.GetLineNoPrune fileName line + + member this.GetLineNewLineMark _: string = + "\n" } let fsiConsoleInput = FsiConsoleInput(fsi, fsiOptions, inReader, outWriter) diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index c970c4a52cc..4ab900b1ec7 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -1367,8 +1367,6 @@ type internal TcGlobals = member voidptr_tcr: FSharp.Compiler.TypedTree.EntityRef - member GetCodeText: m: Text.Range -> string voption - #if DEBUG // This global is only used during debug output val mutable internal global_g: TcGlobals option diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index f51919c01a8..326bafeeff6 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -260,8 +260,8 @@ module FileIndex = [] [ {DebugCode}")>] -type _Range(code1: int64, code2: int64) = - static member Zero = _range (0L, 0L) +type _RangeBackground(code1: int64, code2: int64) = + static member Zero = _rangeBackground (0L, 0L) new(fIdx, bl, bc, el, ec) = let code1 = @@ -273,9 +273,9 @@ type _Range(code1: int64, code2: int64) = ((int64 bl <<< startLineShift) &&& startLineMask) ||| ((int64 (el - bl) <<< heightShift) &&& heightMask) - _range (code1, code2) + _rangeBackground (code1, code2) - new(fIdx, b: pos, e: pos) = _range (fIdx, b.Line, b.Column, e.Line, e.Column) + new(fIdx, b: pos, e: pos) = _rangeBackground (fIdx, b.Line, b.Column, e.Line, e.Column) member _.StartLine = int32 (uint64 (code2 &&& startLineMask) >>> startLineShift) @@ -307,18 +307,18 @@ type _Range(code1: int64, code2: int64) = member _.FileIndex = int32 (code1 &&& fileIndexMask) - member m.StartRange = _range (m.FileIndex, m.Start, m.Start) + member m.StartRange = _rangeBackground (m.FileIndex, m.Start, m.Start) - member m.EndRange = _range (m.FileIndex, m.End, m.End) + member m.EndRange = _rangeBackground (m.FileIndex, m.End, m.End) member m.FileName = fileOfFileIndex m.FileIndex member m.ShortFileName = Path.GetFileName(fileOfFileIndex m.FileIndex) member _.MakeSynthetic() = - _range (code1, code2 ||| isSyntheticMask) + _rangeBackground (code1, code2 ||| isSyntheticMask) - member m.IsAdjacentTo(otherRange: _Range) = + member m.IsAdjacentTo(otherRange: _RangeBackground) = m.FileIndex = otherRange.FileIndex && m.End.Encoding = otherRange.Start.Encoding member _.NoteSourceConstruct(kind) = @@ -335,7 +335,7 @@ type _Range(code1: int64, code2: int64) = | NotedSourceConstruct.Combine -> 8 | NotedSourceConstruct.DelayOrQuoteOrRun -> 9 - _range (code1, (code2 &&& ~~~debugPointKindMask) ||| (int64 code <<< debugPointKindShift)) + _rangeBackground (code1, (code2 &&& ~~~debugPointKindMask) ||| (int64 code <<< debugPointKindShift)) member _.Code1 = code1 @@ -369,14 +369,14 @@ type _Range(code1: int64, code2: int64) = with e -> e.ToString() - member _.Equals(m2: _range) = + member _.Equals(m2: _rangeBackground) = let code2 = code2 &&& ~~~(debugPointKindMask ||| isSyntheticMask) let rcode2 = m2.Code2 &&& ~~~(debugPointKindMask ||| isSyntheticMask) code1 = m2.Code1 && code2 = rcode2 override m.Equals(obj) = match obj with - | :? _range as m2 -> m.Equals(m2) + | :? _rangeBackground as m2 -> m.Equals(m2) | _ -> false override _.GetHashCode() = @@ -386,23 +386,23 @@ type _Range(code1: int64, code2: int64) = override r.ToString() = sprintf "(%d,%d--%d,%d)" r.StartLine r.StartColumn r.EndLine r.EndColumn - member m.IsZero = m.Equals _range.Zero + member m.IsZero = m.Equals _rangeBackground.Zero -and _range = _Range +and _rangeBackground = _RangeBackground [] [ ({StartLine},{StartColumn}-{EndLine},{EndColumn}) {ShortFileName} -> {DebugCode}")>] -type Range(range1: _range, range2: _range) = - static member Zero = range (_range.Zero, _range.Zero) +type Range(range1: _rangeBackground, range2: _rangeBackground) = + static member Zero = range (_rangeBackground.Zero, _rangeBackground.Zero) - new(fIdx, bl, bc, el, ec) = range (_range (fIdx, bl, bc, el, ec), _Range.Zero) + new(fIdx, bl, bc, el, ec) = range (_rangeBackground (fIdx, bl, bc, el, ec), _RangeBackground.Zero) - new(fIdx, bl, bc, el, ec, fIdx2, bl2, bc2, el2, ec2) = range (_range (fIdx, bl, bc, el, ec), _range (fIdx2, bl2, bc2, el2, ec2)) + new(fIdx, bl, bc, el, ec, fIdx2, bl2, bc2, el2, ec2) = range (_rangeBackground (fIdx, bl, bc, el, ec), _rangeBackground (fIdx2, bl2, bc2, el2, ec2)) - new(fIdx, b: pos, e: pos) = range (_range (fIdx, b.Line, b.Column, e.Line, e.Column), _range.Zero) + new(fIdx, b: pos, e: pos) = range (_rangeBackground (fIdx, b.Line, b.Column, e.Line, e.Column), _rangeBackground.Zero) new(fIdx, b: pos, e: pos, fIdx2, b2: pos, e2: pos) = - range (_range (fIdx, b.Line, b.Column, e.Line, e.Column), _range (fIdx2, b2.Line, b2.Column, e2.Line, e2.Column)) + range (_rangeBackground (fIdx, b.Line, b.Column, e.Line, e.Column), _rangeBackground (fIdx2, b2.Line, b2.Column, e2.Line, e2.Column)) member _.StartLine = range1.StartLine @@ -693,20 +693,36 @@ module Range = mkRange file (mkPos 1 0) (mkPos 1 80) module internal FileContent = - let private dict = ConcurrentDictionary() + let private fileContentDict = ConcurrentDictionary() + let private newlineMarkDict = ConcurrentDictionary() let readFileContents (fileNames: string list) = for fileName in fileNames do if FileSystem.FileExistsShim fileName then use fileStream = FileSystem.OpenFileForReadShim(fileName) - dict[fileName] <- fileStream.ReadAllLines() - - let getLine fileName line = - match dict.TryGetValue fileName with - | true, lines when lines.Length > line -> lines[line - 1] - | _ -> String.Empty - - let mutable getLineDynamic = getLine + let text = fileStream.ReadAllText() + let newlineMark = + if text.IndexOf('\n') > -1 && text.IndexOf('\r') = -1 then + "\n" + else "\r\n" + newlineMarkDict[fileName] <- newlineMark + fileContentDict[fileName] <- text.Split([|newlineMark|], StringSplitOptions.None) + + type IFileContentGetLine = + abstract GetLine: fileName: string -> line: int -> string + abstract GetLineNewLineMark: fileName: string -> string + + let mutable getLineDynamic = + { new IFileContentGetLine with + member this.GetLine(fileName: string) (line: int): string = + match fileContentDict.TryGetValue fileName with + | true, lines when lines.Length > line -> lines[line - 1] + | _ -> String.Empty + + member this.GetLineNewLineMark(fileName: string): string = + match newlineMarkDict.TryGetValue fileName with + | true, res -> res + | _ -> String.Empty } let getCodeText (m: range) = let endCol = m.EndColumn - 1 @@ -719,8 +735,8 @@ module internal FileContent = else m.FileName, m.StartLine, m.EndLine - [| for i in startLine..endLine -> getLineDynamic filename i |] - |> String.concat "\n" + [| for i in startLine..endLine -> getLineDynamic.GetLine filename i |] + |> String.concat (getLineDynamic.GetLineNewLineMark filename) if String.IsNullOrEmpty s then s diff --git a/src/Compiler/Utilities/range.fsi b/src/Compiler/Utilities/range.fsi index bd368f7d369..b7ceac1c725 100755 --- a/src/Compiler/Utilities/range.fsi +++ b/src/Compiler/Utilities/range.fsi @@ -315,13 +315,14 @@ module internal FileContent = /// Read all file contents val readFileContents: fileNames: string list -> unit - /// Get a line string from already read files - val getLine: fileName: string -> line: int -> string + type IFileContentGetLine = + abstract GetLine: fileName: string -> line: int -> string + abstract GetLineNewLineMark: fileName: string -> string /// Get a line string from already read files. /// /// Used by `getCodeText` to support `CallerArgumentExpression` in F# Interactive - val mutable getLineDynamic: (string -> int -> string) + val mutable getLineDynamic: IFileContentGetLine /// Get code text of the specific `range` val getCodeText: range -> string diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 395b62d199f..515a3cf09c2 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -1282,6 +1282,16 @@ Atributy nejde použít pro rozšíření typů. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Tento výraz záznamu kopírování a aktualizace mění všechna pole typu záznamu '{0}'. Zvažte použití syntaxe konstrukce záznamu. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 28c51bf8185..ef5096a1f9c 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -1282,6 +1282,16 @@ Attribute können nicht auf Typerweiterungen angewendet werden. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Dieser Ausdruck zum Kopieren und Aktualisieren von Datensätzen ändert alle Felder des Datensatztyps "{0}". Erwägen Sie stattdessen die Verwendung der Datensatzerstellungssyntax. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index f6d6fd7e2ee..8175ab017ac 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -1282,6 +1282,16 @@ Los atributos no se pueden aplicar a las extensiones de tipo. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Esta expresión de copia y actualización de registros cambia todos los campos de tipo de registro "{0}". Es preferible utilizar la sintaxis de construcción de registros. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index a51a72c8ee8..8fd21a431bf 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -1282,6 +1282,16 @@ Impossible d'appliquer des attributs aux extensions de type. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Cette expression d'enregistrement de copie et de mise à jour modifie tous les champs du type d'enregistrement '{0}'. Envisagez d'utiliser la syntaxe de construction d'enregistrement à la place. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index f8e336d8bc6..36e4b406f90 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -1282,6 +1282,16 @@ Gli attributi non possono essere applicati a estensioni di tipo. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Questa espressione di record di copia e aggiornamento modifica tutti i campi del tipo di record '{0}'. Provare a usare la sintassi di costruzione dei record. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 8123f554cb4..0413fc2a5e5 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -1282,6 +1282,16 @@ 属性を型拡張に適用することはできません。 + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. この copy-and-update レコード式は、レコードの種類が '{0}' であるすべてのフィールドを変更します。代わりにレコード構築構文を使用することを検討してください。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 531d4d3552d..518268744d8 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -1282,6 +1282,16 @@ 형식 확장에 특성을 적용할 수 없습니다. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. 이 레코드 복사 및 업데이트 식은 '{0}' 레코드 형식의 모든 필드를 변경합니다. 레코드 생성 구문을 대신 사용하는 것이 좋습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 26de66bc57b..e0de32a2e08 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -1282,6 +1282,16 @@ Atrybutów nie można stosować do rozszerzeń typu. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. To wyrażenie rekordu kopiowania i aktualizacji zmienia wszystkie pola typu rekordu „{0}”. Zamiast tego rozważ użycie składni konstrukcji rekordu. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index ff5b0825181..cf9c9dcca01 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -1282,6 +1282,16 @@ Os atributos não podem ser aplicados às extensões de tipo. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Essa expressão de registro copiar e atualizar altera todos os campos do tipo de registro '{0}'. Considere usar a sintaxe de construção de registro em vez disso. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index e89ea429b01..5856869f0f2 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -1282,6 +1282,16 @@ Атрибуты не могут быть применены к расширениям типа. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Это выражение записи копирования и обновления изменяет все поля типа записи "{0}". Вместо этого можно использовать синтаксис конструкции записи. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index cc7e1431793..606ad7dc697 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -1282,6 +1282,16 @@ Öznitelikler tür uzantılarına uygulanamaz. + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. Bu kopyalama ve güncelleştirme kayıt ifadesi, '{0}' kayıt türündeki tüm alanları değiştirir. Bunun yerine kayıt oluşturma söz dizimini kullanmayı deneyin. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index a8420dea45d..730a8fbbd40 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -1282,6 +1282,16 @@ 属性不可应用于类型扩展。 + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. 此复制和更新记录表达式更改记录类型“{0}”的所有字段。请考虑改用记录构造语法。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 0cdb26de227..c033f9071b9 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -1282,6 +1282,16 @@ 屬性無法套用到類型延伸模組。 + + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + This CallerArgumentExpression with argument '{0}' will have no effect because it's applied with an invalid parameter name. + + + + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + This CallerArgumentExpression with argument '{0}' will have no effect because it's self-referential. + + This copy-and-update record expression changes all fields of record type '{0}'. Consider using the record construction syntax instead. 此複製和更新記錄運算式將變更記錄類型為 '{0}' 的所有欄位。請考慮改用記錄建構語法。 From 68f2f6164471ec749c422eda474d99a85968f845 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:28:36 +0800 Subject: [PATCH 11/16] format code --- src/Compiler/Interactive/fsi.fs | 13 +++++++------ src/Compiler/Utilities/range.fs | 30 +++++++++++++++++++----------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 7fc5db927c8..e0324413551 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -4670,13 +4670,14 @@ type FsiEvaluationSession if List.isEmpty fsiOptions.SourceFiles then fsiConsolePrompt.PrintAhead() - do FileContent.getLineDynamic <- - { new FileContent.IFileContentGetLine with - member this.GetLine(fileName: string) (line: int): string = - fsiStdinSyphon.GetLineNoPrune fileName line + do + FileContent.getLineDynamic <- + { new FileContent.IFileContentGetLine with + member this.GetLine (fileName: string) (line: int) : string = + fsiStdinSyphon.GetLineNoPrune fileName line - member this.GetLineNewLineMark _: string = - "\n" } + member this.GetLineNewLineMark _ : string = "\n" + } let fsiConsoleInput = FsiConsoleInput(fsi, fsiOptions, inReader, outWriter) diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index 326bafeeff6..19849f97d79 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -397,12 +397,16 @@ type Range(range1: _rangeBackground, range2: _rangeBackground) = new(fIdx, bl, bc, el, ec) = range (_rangeBackground (fIdx, bl, bc, el, ec), _RangeBackground.Zero) - new(fIdx, bl, bc, el, ec, fIdx2, bl2, bc2, el2, ec2) = range (_rangeBackground (fIdx, bl, bc, el, ec), _rangeBackground (fIdx2, bl2, bc2, el2, ec2)) + new(fIdx, bl, bc, el, ec, fIdx2, bl2, bc2, el2, ec2) = + range (_rangeBackground (fIdx, bl, bc, el, ec), _rangeBackground (fIdx2, bl2, bc2, el2, ec2)) new(fIdx, b: pos, e: pos) = range (_rangeBackground (fIdx, b.Line, b.Column, e.Line, e.Column), _rangeBackground.Zero) new(fIdx, b: pos, e: pos, fIdx2, b2: pos, e2: pos) = - range (_rangeBackground (fIdx, b.Line, b.Column, e.Line, e.Column), _rangeBackground (fIdx2, b2.Line, b2.Column, e2.Line, e2.Column)) + range ( + _rangeBackground (fIdx, b.Line, b.Column, e.Line, e.Column), + _rangeBackground (fIdx2, b2.Line, b2.Column, e2.Line, e2.Column) + ) member _.StartLine = range1.StartLine @@ -701,28 +705,32 @@ module internal FileContent = if FileSystem.FileExistsShim fileName then use fileStream = FileSystem.OpenFileForReadShim(fileName) let text = fileStream.ReadAllText() + let newlineMark = if text.IndexOf('\n') > -1 && text.IndexOf('\r') = -1 then "\n" - else "\r\n" + else + "\r\n" + newlineMarkDict[fileName] <- newlineMark - fileContentDict[fileName] <- text.Split([|newlineMark|], StringSplitOptions.None) + fileContentDict[fileName] <- text.Split([| newlineMark |], StringSplitOptions.None) type IFileContentGetLine = abstract GetLine: fileName: string -> line: int -> string abstract GetLineNewLineMark: fileName: string -> string - let mutable getLineDynamic = + let mutable getLineDynamic = { new IFileContentGetLine with - member this.GetLine(fileName: string) (line: int): string = - match fileContentDict.TryGetValue fileName with - | true, lines when lines.Length > line -> lines[line - 1] - | _ -> String.Empty + member this.GetLine (fileName: string) (line: int) : string = + match fileContentDict.TryGetValue fileName with + | true, lines when lines.Length > line -> lines[line - 1] + | _ -> String.Empty - member this.GetLineNewLineMark(fileName: string): string = + member this.GetLineNewLineMark(fileName: string) : string = match newlineMarkDict.TryGetValue fileName with | true, res -> res - | _ -> String.Empty } + | _ -> String.Empty + } let getCodeText (m: range) = let endCol = m.EndColumn - 1 From 7e93270e63988f74028fb794e4a13bc66dcc9274 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Fri, 16 Aug 2024 18:29:17 +0800 Subject: [PATCH 12/16] fix build --- src/Compiler/Checking/MethodCalls.fs | 2 ++ src/Compiler/Checking/PostInferenceChecks.fs | 11 ++++------- src/Compiler/Driver/ScriptClosure.fs | 2 +- src/Compiler/Utilities/range.fs | 12 +++++++----- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 31fb9477473..76459d701cd 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1425,6 +1425,7 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C emptyPreBinder, Expr.Const (Const.String fileName, mMethExpr, currCalledArgTy) | CallerMemberName, Some callerName when (typeEquiv g currCalledArgTy g.string_ty) -> emptyPreBinder, Expr.Const (Const.String callerName, mMethExpr, currCalledArgTy) + | CallerArgumentExpression param, _ when g.langVersion.SupportsFeature LanguageFeature.SupportCallerArgumentExpression && typeEquiv g currCalledArgTy g.string_ty -> let str = unnamedArgs @@ -1437,6 +1438,7 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C | _ -> None) |> Option.defaultWith (fun _ -> tcFieldInit mMethExpr fieldInit) emptyPreBinder, Expr.Const (str, mMethExpr, currCalledArgTy) + | _ -> emptyPreBinder, Expr.Const (tcFieldInit mMethExpr fieldInit, mMethExpr, currCalledArgTy) diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index 4b8bc277785..5f169183925 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -2351,14 +2351,10 @@ let CheckEntityDefn cenv env (tycon: Entity) = match nameOpt with | Some ident when name = ident.idText -> warning(Error(FSComp.SR.tcCallerArgumentExpressionSelfReferential(name), m)) + | _ when paramNames |> List.forall (fun i -> name <> i.idText) -> + warning(Error(FSComp.SR.tcCallerArgumentExpressionHasInvalidParameterName(name), m)) | _ -> () - if - paramNames - |> List.exists (fun i -> name = i.idText) - |> not - then warning(Error(FSComp.SR.tcCallerArgumentExpressionHasInvalidParameterName(name), m)) - paramDatas |> List.iterSquared (fun (ParamData(_, isInArg, _, optArgInfo, callerInfo, nameOpt, _, ty)) -> ignore isInArg @@ -2382,7 +2378,8 @@ let CheckEntityDefn cenv env (tycon: Entity) = errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, "string", NicePrint.minimalStringOfType cenv.denv ty), m)) | CalleeSide, CallerMemberName -> if not ((isOptionTy g ty) && (typeEquiv g g.string_ty (destOptionTy g ty))) then - errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, "string", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m))) + errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, "string", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m)) + | CallerSide _, CallerArgumentExpression name -> if not (typeEquiv g g.string_ty ty) then errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, "string", NicePrint.minimalStringOfType cenv.denv ty), m)) diff --git a/src/Compiler/Driver/ScriptClosure.fs b/src/Compiler/Driver/ScriptClosure.fs index 4b0db0f6c32..34f808f25ee 100644 --- a/src/Compiler/Driver/ScriptClosure.fs +++ b/src/Compiler/Driver/ScriptClosure.fs @@ -161,7 +161,7 @@ module ScriptPreprocessClosure = FileContent.readFileContents [ fileName ] let projectDir = !! Path.GetDirectoryName(fileName) - + let isInteractive = (codeContext = CodeContext.CompilationAndEvaluation) let isInvalidationSupported = (codeContext = CodeContext.Editing) diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index 19849f97d79..263e911fce1 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -464,11 +464,13 @@ type Range(range1: _rangeBackground, range2: _rangeBackground) = range1.GetHashCode() + range2.GetHashCode() override _.ToString() = - range1.ToString() - + if range2.IsZero then - String.Empty - else - $"(from: {range2.ToString()})" + let fromText = + if range2.IsZero then + String.Empty + else + $"(from: {range2.ToString()})" + + $"{range1} {fromText}" member _.HasOriginalRange = not range2.IsZero From 5790db9d2fed39e4aa1b08927cf073458c231926 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Fri, 16 Aug 2024 21:48:06 +0800 Subject: [PATCH 13/16] fix test --- .../CustomAttributes/CallerArgumentExpression.fs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs index 78e7917e555..b4178018c5b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs @@ -9,7 +9,7 @@ module CustomAttributes_CallerArgumentExpression = [] let ``Can consume CallerArgumentExpression in BCL methods`` () = - FSharp """ + FSharp """module Program try System.ArgumentNullException.ThrowIfNullOrWhiteSpace(Seq.init 50 (fun _ -> " ") (* comment *) |> String.concat " ") @@ -23,10 +23,11 @@ with :? System.ArgumentException as ex -> [] let ``Can define in F#`` () = - FSharp """# 1 "C:\\Program.fs" + FSharp """module Program +# 1 "C:\\Program.fs" open System.Runtime.InteropServices type A() = -static member aa ( + static member aa ( a, []b: string, []c: int, From 46c4d46ffdd3ee73eabc694def793751fe1bc035 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Sun, 25 Aug 2024 17:01:15 +0800 Subject: [PATCH 14/16] try fix tests --- src/Compiler/Utilities/range.fs | 5 +- .../CallerArgumentExpression.fs | 66 +++++++++++++++---- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index 263e911fce1..22a1658fe88 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -751,4 +751,7 @@ module internal FileContent = if String.IsNullOrEmpty s then s else - s.Substring(startCol + 1, s.LastIndexOf("\n", StringComparison.Ordinal) + 1 - startCol + endCol) + try + s.Substring(startCol + 1, s.LastIndexOf("\n", StringComparison.Ordinal) + 1 - startCol + endCol) + with ex -> + raise(System.AggregationException($"ex: {ex}; (s: {s}, startCol: {startCol}, endCol: {endCol})", ex)) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs index b4178018c5b..830fdd9389b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs @@ -23,22 +23,62 @@ with :? System.ArgumentException as ex -> [] let ``Can define in F#`` () = - FSharp """module Program + FSharp """#if !NETCOREAPP3_0_OR_GREATER +namespace System.Runtime.CompilerServices + open System + [] + type CallerArgumentExpressionAttribute(parameterName) = + inherit Attribute() + member val ParameterName: string = parameterName +#endif + +module Program = + open System.Runtime.CompilerServices + type A() = + static member aa ( + a, + []b: string, + []c: int, + []d: string, + []e: string) = + a,b,c,d,e + + let stringABC = "abc" + assert (A.aa(stringABC) = ("abc", ".ctor", 22, "C:\Program.fs", "stringABC")) + """ + |> withLangVersionPreview + |> compileAndRun + |> shouldSucceed + |> ignore + + [] + let ``Can define in F# - with #line`` () = + FSharp """#if !NETCOREAPP3_0_OR_GREATER +namespace System.Runtime.CompilerServices + open System + [] + type CallerArgumentExpressionAttribute(parameterName) = + inherit Attribute() + member val ParameterName: string = parameterName +#endif + +module Program = # 1 "C:\\Program.fs" -open System.Runtime.InteropServices -type A() = - static member aa ( - a, - []b: string, - []c: int, - []d: string, - []e: string) = - a,b,c,d,e - -let stringABC = "abc" -assert (A.aa(stringABC) = ("abc", ".ctor", 12, "C:\Program.fs", "stringABC")) + open System.Runtime.CompilerServices + type A() = + static member aa ( + a, + []b: string, + []c: int, + []d: string, + []e: string) = + a,b,c,d,e + + let stringABC = "abc" + assert (A.aa(stringABC) = ("abc", ".ctor", 12, "C:\Program.fs", "stringABC")) """ |> withLangVersionPreview |> compileAndRun |> shouldSucceed |> ignore + From 8d792fa6664d51d5c5293f40c33c028450bd0169 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:10:53 +0800 Subject: [PATCH 15/16] fix build --- src/Compiler/Utilities/range.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs index 22a1658fe88..5248d3e9e5c 100755 --- a/src/Compiler/Utilities/range.fs +++ b/src/Compiler/Utilities/range.fs @@ -754,4 +754,4 @@ module internal FileContent = try s.Substring(startCol + 1, s.LastIndexOf("\n", StringComparison.Ordinal) + 1 - startCol + endCol) with ex -> - raise(System.AggregationException($"ex: {ex}; (s: {s}, startCol: {startCol}, endCol: {endCol})", ex)) + raise(System.AggregateException($"ex: {ex}; (s: {s}, startCol: {startCol}, endCol: {endCol})", ex)) From 65a4acc01b26258f1bebfdd2f6cb6f45edaf3b14 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+Tangent-90@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:29:19 +0800 Subject: [PATCH 16/16] test --- .../CustomAttributes/CallerArgumentExpression.fs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs index 830fdd9389b..5f342427532 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/CallerArgumentExpression.fs @@ -25,11 +25,13 @@ with :? System.ArgumentException as ex -> let ``Can define in F#`` () = FSharp """#if !NETCOREAPP3_0_OR_GREATER namespace System.Runtime.CompilerServices - open System - [] - type CallerArgumentExpressionAttribute(parameterName) = +open System +[] +type CallerArgumentExpressionAttribute(parameterName) = inherit Attribute() member val ParameterName: string = parameterName + +namespace global #endif module Program = @@ -55,11 +57,13 @@ module Program = let ``Can define in F# - with #line`` () = FSharp """#if !NETCOREAPP3_0_OR_GREATER namespace System.Runtime.CompilerServices - open System - [] - type CallerArgumentExpressionAttribute(parameterName) = +open System +[] +type CallerArgumentExpressionAttribute(parameterName) = inherit Attribute() member val ParameterName: string = parameterName + +namespace global #endif module Program =