diff --git a/src/fsharp/CompilerConfig.fs b/src/fsharp/CompilerConfig.fs index 7c02d5880ce727bf07087aa410679fd8cb9f3467..d2bfa520d4d49a6587308a1bf25d76da00821a6d 100644 --- a/src/fsharp/CompilerConfig.fs +++ b/src/fsharp/CompilerConfig.fs @@ -720,7 +720,7 @@ type TcConfigBuilder = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parameter if sourceFiles = [] then errorR(Error(FSComp.SR.buildNoInputsSpecified(), rangeCmdArgs)) let ext() = match tcConfigB.target with CompilerTarget.Dll -> ".dll" | CompilerTarget.Module -> ".netmodule" | CompilerTarget.ConsoleExe | CompilerTarget.WinExe -> ".exe" - let implFiles = sourceFiles |> List.filter (fun lower -> List.exists (FileSystemUtils.checkSuffix (String.lowercase lower)) FSharpImplFileSuffixes) + let implFiles = sourceFiles |> List.filter (fun fileName -> List.exists (FileSystemUtils.checkSuffix fileName) FSharpImplFileSuffixes) let outfile = match tcConfigB.outputFile, List.rev implFiles with | None, [] -> "out" + ext() @@ -1168,8 +1168,7 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member tcConfig.ComputeLightSyntaxInitialStatus filename = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parameter - let lower = String.lowercase filename - let lightOnByDefault = List.exists (FileSystemUtils.checkSuffix lower) FSharpLightSyntaxFileSuffixes + let lightOnByDefault = List.exists (FileSystemUtils.checkSuffix filename) FSharpLightSyntaxFileSuffixes if lightOnByDefault then (tcConfig.light <> Some false) else (tcConfig.light = Some true ) member tcConfig.GetAvailableLoadedSources() = diff --git a/src/fsharp/ParseAndCheckInputs.fs b/src/fsharp/ParseAndCheckInputs.fs index 86e39d6e714364143b87df251df5164f83f6a09d..398d9b25287745d7494bd042a4b5e30bd8da972f 100644 --- a/src/fsharp/ParseAndCheckInputs.fs +++ b/src/fsharp/ParseAndCheckInputs.fs @@ -43,8 +43,7 @@ let CanonicalizeFilename filename = String.capitalize (try FileSystemUtils.chopExtension basic with _ -> basic) let IsScript filename = - let lower = String.lowercase filename - FSharpScriptFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) + FSharpScriptFileSuffixes |> List.exists (FileSystemUtils.checkSuffix filename) // Give a unique name to the different kinds of inputs. Used to correlate signature and implementation files // QualFileNameOfModuleName - files with a single module declaration or an anonymous module @@ -115,8 +114,7 @@ let PostParseModuleImpl (_i, defaultNamespace, isLastCompiland, filename, impl) | ParsedImplFileFragment.AnonModule (defs, m)-> let isLast, isExe = isLastCompiland - let lower = String.lowercase filename - if not (isLast && isExe) && not (doNotRequireNamespaceOrModuleSuffixes |> List.exists (FileSystemUtils.checkSuffix lower)) then + if not (isLast && isExe) && not (doNotRequireNamespaceOrModuleSuffixes |> List.exists (FileSystemUtils.checkSuffix filename)) then match defs with | SynModuleDecl.NestedModule _ :: _ -> errorR(Error(FSComp.SR.noEqualSignAfterModule(), trimRangeToLine m)) | _ -> errorR(Error(FSComp.SR.buildMultiFileRequiresNamespaceOrModule(), trimRangeToLine m)) @@ -145,8 +143,7 @@ let PostParseModuleSpec (_i, defaultNamespace, isLastCompiland, filename, intf) | ParsedSigFileFragment.AnonModule (defs, m) -> let isLast, isExe = isLastCompiland - let lower = String.lowercase filename - if not (isLast && isExe) && not (doNotRequireNamespaceOrModuleSuffixes |> List.exists (FileSystemUtils.checkSuffix lower)) then + if not (isLast && isExe) && not (doNotRequireNamespaceOrModuleSuffixes |> List.exists (FileSystemUtils.checkSuffix filename)) then match defs with | SynModuleSigDecl.NestedModule _ :: _ -> errorR(Error(FSComp.SR.noEqualSignAfterModule(), m)) | _ -> errorR(Error(FSComp.SR.buildMultiFileRequiresNamespaceOrModule(), m)) @@ -273,7 +270,6 @@ let ParseInput (lexer, diagnosticOptions:FSharpDiagnosticOptions, errorLogger: E // # 1000 "Line01.fs" // then it also asserts. But these are edge cases that can be fixed later, e.g. in bug 4651. //System.Diagnostics.Debug.Assert(System.IO.Path.IsPathRooted filename, sprintf "should be absolute: '%s'" filename) - let lower = String.lowercase filename // Delay sending errors and warnings until after the file is parsed. This gives us a chance to scrape the // #nowarn declarations for the file @@ -284,18 +280,18 @@ let ParseInput (lexer, diagnosticOptions:FSharpDiagnosticOptions, errorLogger: E let mutable scopedPragmas = [] try let input = - if mlCompatSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then + if mlCompatSuffixes |> List.exists (FileSystemUtils.checkSuffix filename) then if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then errorR(Error(FSComp.SR.buildInvalidSourceFileExtensionML filename, rangeStartup)) else mlCompatWarning (FSComp.SR.buildCompilingExtensionIsForML()) rangeStartup // Call the appropriate parser - for signature files or implementation files - if FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then + if FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix filename) then let impl = Parser.implementationFile lexer lexbuf let tripleSlashComments = LexbufLocalXmlDocStore.ReportInvalidXmlDocPositions(lexbuf) PostParseModuleImpls (defaultNamespace, filename, isLastCompiland, impl, lexbuf, tripleSlashComments) - elif FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then + elif FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix filename) then let intfs = Parser.signatureFile lexer lexbuf let tripleSlashComments = LexbufLocalXmlDocStore.ReportInvalidXmlDocPositions(lexbuf) PostParseModuleSpecs (defaultNamespace, filename, isLastCompiland, intfs, lexbuf, tripleSlashComments) @@ -350,8 +346,7 @@ let ReportParsingStatistics res = printfn "parsing yielded %d definitions" (List.collect flattenModImpl impls).Length let EmptyParsedInput(filename, isLastCompiland) = - let lower = String.lowercase filename - if FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) then + if FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix filename) then ParsedInput.SigFile( ParsedSigFileInput( filename, @@ -432,9 +427,7 @@ let ParseOneInputLexbuf (tcConfig: TcConfig, lexResourceManager, lexbuf, filenam let ValidSuffixes = FSharpSigFileSuffixes@FSharpImplFileSuffixes let checkInputFile (tcConfig: TcConfig) filename = - let lower = String.lowercase filename - - if List.exists (FileSystemUtils.checkSuffix lower) ValidSuffixes then + if List.exists (FileSystemUtils.checkSuffix filename) ValidSuffixes then if not(FileSystem.FileExistsShim filename) then error(Error(FSComp.SR.buildCouldNotFindSourceFile filename, rangeStartup)) else diff --git a/src/fsharp/XmlDocFileWriter.fs b/src/fsharp/XmlDocFileWriter.fs index e9757567ff11e85267f17da46769c373a927def4..0402df55ff84b8fd4bb17613c4de7f7d6ecc108d 100644 --- a/src/fsharp/XmlDocFileWriter.fs +++ b/src/fsharp/XmlDocFileWriter.fs @@ -80,7 +80,7 @@ module XmlDocWriter = doModuleSig None generatedCcu.Contents let WriteXmlDocFile (g, assemblyName, generatedCcu: CcuThunk, xmlfile) = - if not (FileSystemUtils.hasSuffixCaseInsensitive "xml" xmlfile ) then + if not (FileSystemUtils.checkSuffix xmlfile "xml" ) then error(Error(FSComp.SR.docfileNoXmlSuffix(), Range.rangeStartup)) let mutable members = [] diff --git a/src/fsharp/absil/illib.fs b/src/fsharp/absil/illib.fs index 999c677859b10fdc3505c7845ff4da55353af36f..ad1034b0666a0689a93ca15fb1e7d2b750630eb7 100644 --- a/src/fsharp/absil/illib.fs +++ b/src/fsharp/absil/illib.fs @@ -77,6 +77,9 @@ module internal PervasiveAutoOpens = member inline x.EndsWithOrdinal value = x.EndsWith(value, StringComparison.Ordinal) + member inline x.EndsWithOrdinalIgnoreCase value = + x.EndsWith(value, StringComparison.OrdinalIgnoreCase) + /// Get an initialization hole let getHole (r: _ ref) = match r.Value with None -> failwith "getHole" | Some x -> x diff --git a/src/fsharp/absil/illib.fsi b/src/fsharp/absil/illib.fsi index b9f86798fd2c24e09535945534a9a87f7fa0d022..02f76edc27678b52fc5bff094cc293a912e069bd 100644 --- a/src/fsharp/absil/illib.fsi +++ b/src/fsharp/absil/illib.fsi @@ -61,6 +61,8 @@ module internal PervasiveAutoOpens = member inline EndsWithOrdinal: value:string -> bool + member inline EndsWithOrdinalIgnoreCase: value:string -> bool + type Async with /// Runs the computation synchronously, always starting on the current thread. static member RunImmediate: computation: Async<'T> * ?cancellationToken: CancellationToken -> 'T diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index a2c585ee659e7fed2d5798a460ebaf54b69d58a5..0a635bf959ba72229b79bf61cdcf918b3a35f035 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -265,8 +265,7 @@ let SetProcessThreadLocals tcConfigB = let ProcessCommandLineFlags (tcConfigB: TcConfigBuilder, lcidFromCodePage, argv) = let mutable inputFilesRef = [] let collect name = - let lower = String.lowercase name - if List.exists (FileSystemUtils.checkSuffix lower) [".resx"] then + if List.exists (FileSystemUtils.checkSuffix name) [".resx"] then error(Error(FSComp.SR.fscResxSourceFileDeprecated name, rangeStartup)) else inputFilesRef <- name :: inputFilesRef diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index 407777f6664a7bb43ad8a1a121422c8c782a490b..c097064a6726f8b8b267ecc35da8bb1d4f652c22 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -1643,8 +1643,7 @@ module internal ParseAndCheckFile = member _.AnyErrors = errorCount > 0 let getLightSyntaxStatus fileName options = - let lower = String.lowercase fileName - let lightOnByDefault = List.exists (FileSystemUtils.checkSuffix lower) FSharpLightSyntaxFileSuffixes + let lightOnByDefault = List.exists (FileSystemUtils.checkSuffix fileName) FSharpLightSyntaxFileSuffixes let lightStatus = if lightOnByDefault then (options.LightSyntax <> Some false) else (options.LightSyntax = Some true) LightSyntaxStatus(lightStatus, true) diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index dfc0668b26f5a673b05a116426a0bb883c1bd5a4..d27d85a0100745420b7e0c6e3c9ff705cd0e76e3 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -115,8 +115,7 @@ module IncrementalBuildSyntaxTree = try IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBEParsed filename) - let lower = String.lowercase filename - let canSkip = sigNameOpt.IsSome && FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix lower) + let canSkip = sigNameOpt.IsSome && FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix filename) let input = if canSkip then ParsedInput.ImplFile( diff --git a/src/fsharp/utils/FileSystem.fs b/src/fsharp/utils/FileSystem.fs index a204177d517e65a7495a473e9beed3545b9ee201..b3519f27417a8235212f0e2f1e1e48c58cbd9f5d 100644 --- a/src/fsharp/utils/FileSystem.fs +++ b/src/fsharp/utils/FileSystem.fs @@ -386,7 +386,7 @@ module internal FileSystemUtils = for c in path do if chars.Contains c then raise(IllegalFileNameChar(path, c))) - let checkSuffix (x:string) (y:string) = x.EndsWithOrdinal(y) + let checkSuffix (x:string) (y:string) = x.EndsWithOrdinalIgnoreCase(y) let hasExtensionWithValidate (validate:bool) (s:string) = if validate then (checkPathForIllegalChars s) @@ -416,10 +416,7 @@ module internal FileSystemUtils = let trimQuotes (s:string) = s.Trim( [|' '; '\"'|] ) - let hasSuffixCaseInsensitive suffix filename = (* case-insensitive *) - checkSuffix (String.lowercase filename) (String.lowercase suffix) - - let isDll file = hasSuffixCaseInsensitive ".dll" file + let isDll file = checkSuffix file ".dll" [] type IAssemblyLoader = diff --git a/src/fsharp/utils/FileSystem.fsi b/src/fsharp/utils/FileSystem.fsi index 8fdeb9163ecf4199687e1975cd19d0e11c03ed83..54d2c77f4f0c8d095a827a8b3d51fa9525a26ac3 100644 --- a/src/fsharp/utils/FileSystem.fsi +++ b/src/fsharp/utils/FileSystem.fsi @@ -106,6 +106,7 @@ module internal FileSystemUtils = /// checkSuffix f s returns True if filename "f" ends in suffix "s", /// e.g. checkSuffix "abc.fs" ".fs" returns true. + /// Disregards casing, e.g. checkSuffix "abc.Fs" ".fs" returns true. val checkSuffix: string -> string -> bool /// chopExtension f removes the extension from the given @@ -125,9 +126,6 @@ module internal FileSystemUtils = /// Trim the quotes and spaces from either end of a string val trimQuotes: string -> string - /// Checks whether filename ends in suffix, ignoring case. - val hasSuffixCaseInsensitive: string -> string -> bool - /// Checks whether file is dll (ends in .dll) val isDll: string -> bool