From 6f2cb0d14fa61bde92c12a0dbfae0b7f421c5c46 Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Mon, 1 Oct 2018 15:55:19 +0200 Subject: [PATCH 1/2] We only need to check for mangledGenericTypeNameSym once (#5633) * We only need to check for mangledGenericTypeNameSym once * ShortCut name checking * Reduce number of LastIndexOf calls * Reduce number of LastIndexOf calls * Reduce number of LastIndexOf calls * Incorporate feedback * Use PrettyNaming.DemangleGenericTypeName instead of ungenericizeTypeName * Remove couple of double checks * Update illib.fs --- src/absil/il.fs | 28 ++++------------------ src/absil/il.fsi | 3 --- src/absil/illib.fs | 12 +--------- src/fsharp/CompileOps.fs | 10 ++++---- src/fsharp/NameResolution.fs | 32 ++++++++++++++----------- src/fsharp/NicePrint.fs | 6 ++--- src/fsharp/PrettyNaming.fs | 46 ++++++++++++++++++++---------------- src/fsharp/tast.fs | 7 +++--- 8 files changed, 62 insertions(+), 82 deletions(-) diff --git a/src/absil/il.fs b/src/absil/il.fs index c2314418fe4..b1bf2fdf920 100644 --- a/src/absil/il.fs +++ b/src/absil/il.fs @@ -154,12 +154,11 @@ let unsplitTypeName (ns, n) = | [] -> String.concat "." ns + "." + n | _ -> n -let splitTypeNameRightAux nm = - if String.contains nm '.' then - let idx = String.rindex nm '.' - let s1, s2 = splitNameAt nm idx - Some s1, s2 - else None, nm +let splitTypeNameRightAux (nm:string) = + let idx = nm.LastIndexOf '.' + if idx = -1 then None, nm else + let s1, s2 = splitNameAt nm idx + Some s1, s2 let splitTypeNameRight nm = memoizeNamespaceRightTable.GetOrAdd(nm, splitTypeNameRightAux) @@ -4189,23 +4188,6 @@ let resolveILMethodRef td mref = resolveILMethodRefWithRescope id td mref let mkRefToILModule m = ILModuleRef.Create(m.Name, true, None) - -let ungenericizeTypeName n = - let sym = '`' - if - String.contains n sym && - (* check what comes after the symbol is a number *) - (let m = String.rindex n sym - let res = ref (m < n.Length - 1) - for i = m + 1 to n.Length - 1 do - res := !res && n.[i] >= '0' && n.[i] <= '9' - !res) - then - let pos = String.rindex n sym - String.sub n 0 pos - else n - - type ILEventRef = { erA: ILTypeRef; erB: string } static member Create(a, b) = {erA=a;erB=b} diff --git a/src/absil/il.fsi b/src/absil/il.fsi index 6ed4d42aa33..3362f53d619 100644 --- a/src/absil/il.fsi +++ b/src/absil/il.fsi @@ -1540,9 +1540,6 @@ val typeNameForGlobalFunctions: string val isTypeNameForGlobalFunctions: string -> bool -val ungenericizeTypeName: string -> string (* e.g. List`1 --> List *) - - // ==================================================================== // PART 2 // diff --git a/src/absil/illib.fs b/src/absil/illib.fs index c628700af21..b9ec8eaee68 100644 --- a/src/absil/illib.fs +++ b/src/absil/illib.fs @@ -452,23 +452,13 @@ type String with member inline x.EndsWithOrdinal(value) = x.EndsWith(value, StringComparison.Ordinal) -module String = - let indexNotFound() = raise (new KeyNotFoundException("An index for the character was not found in the string")) - +module String = let make (n: int) (c: char) : string = new String(c, n) let get (str:string) i = str.[i] let sub (s:string) (start:int) (len:int) = s.Substring(start,len) - let index (s:string) (c:char) = - let r = s.IndexOf(c) - if r = -1 then indexNotFound() else r - - let rindex (s:string) (c:char) = - let r = s.LastIndexOf(c) - if r = -1 then indexNotFound() else r - let contains (s:string) (c:char) = s.IndexOf(c) <> -1 let order = LanguagePrimitives.FastGenericComparer diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index d54373c5548..3517d044284 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -2609,13 +2609,13 @@ type TcConfigBuilder = member tcConfigB.RemoveReferencedAssemblyByPath (m, path) = tcConfigB.referencedDLLs <- tcConfigB.referencedDLLs |> List.filter (fun ar-> ar.Range <> m || ar.Text <> path) - static member SplitCommandLineResourceInfo ri = - if String.contains ri ',' then - let p = String.index ri ',' + static member SplitCommandLineResourceInfo (ri:string) = + let p = ri.IndexOf ',' + if p <> -1 then let file = String.sub ri 0 p let rest = String.sub ri (p+1) (String.length ri - p - 1) - if String.contains rest ',' then - let p = String.index rest ',' + let p = rest.IndexOf ',' + if p <> -1 then let name = String.sub rest 0 p+".resources" let pubpri = String.sub rest (p+1) (rest.Length - p - 1) if pubpri = "public" then file, name, ILResourceAccess.Public diff --git a/src/fsharp/NameResolution.fs b/src/fsharp/NameResolution.fs index a4cbd0279de..43f7c297ca6 100644 --- a/src/fsharp/NameResolution.fs +++ b/src/fsharp/NameResolution.fs @@ -985,10 +985,8 @@ type TypeNameResolutionStaticArgsInfo = // Get the first possible mangled name of the type, assuming the args are generic args member x.MangledNameForType nm = - if IsMangledGenericName nm || x.NumStaticArgs = 0 then nm - else nm+"`"+string x.NumStaticArgs - - + if x.NumStaticArgs = 0 || TryDemangleGenericNameAndPos nm <> ValueNone then nm + else nm + "`" + string x.NumStaticArgs [] /// Represents information which guides name resolution of types. @@ -1018,7 +1016,11 @@ let LookupTypeNameInEntityHaveArity nm (staticResInfo: TypeNameResolutionStaticA /// Unqualified lookups of type names where the number of generic arguments is known /// from context, e.g. List. Rebindings due to 'open' may have rebound identifiers. let LookupTypeNameInEnvHaveArity fq nm numTyArgs (nenv:NameResolutionEnv) = - let key = if IsMangledGenericName nm then DecodeGenericTypeName nm else NameArityPair(nm,numTyArgs) + let key = + match TryDemangleGenericNameAndPos nm with + | ValueSome pos -> DecodeGenericTypeName pos nm + | _ -> NameArityPair(nm,numTyArgs) + match nenv.TyconsByDemangledNameAndArity(fq).TryFind(key) with | Some res -> Some res | None -> nenv.TyconsByAccessNames(fq).TryFind nm |> Option.map List.head @@ -1041,15 +1043,17 @@ let LookupTypeNameInEnvHaveArity fq nm numTyArgs (nenv:NameResolutionEnv) = // also be used to qualify access if needed, though this is almost never needed. let LookupTypeNameNoArity nm (byDemangledNameAndArity: LayeredMap) (byAccessNames: LayeredMultiMap) = - if IsMangledGenericName nm then - match byDemangledNameAndArity.TryFind (DecodeGenericTypeName nm) with - | Some res -> [res] - | None -> - match byAccessNames.TryFind nm with - | Some res -> res - | None -> [] - else - byAccessNames.[nm] + match TryDemangleGenericNameAndPos nm with + | ValueSome pos -> + let demangled = DecodeGenericTypeName pos nm + match byDemangledNameAndArity.TryFind demangled with + | Some res -> [res] + | None -> + match byAccessNames.TryFind nm with + | Some res -> res + | None -> [] + | _ -> + byAccessNames.[nm] /// Qualified lookup of type names in the environment let LookupTypeNameInEnvNoArity fq nm (nenv: NameResolutionEnv) = diff --git a/src/fsharp/NicePrint.fs b/src/fsharp/NicePrint.fs index ca5fd8c674c..c4ed19f1ee0 100755 --- a/src/fsharp/NicePrint.fs +++ b/src/fsharp/NicePrint.fs @@ -102,7 +102,7 @@ module private PrintIL = open Microsoft.FSharp.Compiler.AbstractIL.IL let fullySplitILTypeRef (tref:ILTypeRef) = - (List.collect IL.splitNamespace (tref.Enclosing @ [IL.ungenericizeTypeName tref.Name])) + (List.collect IL.splitNamespace (tref.Enclosing @ [PrettyNaming.DemangleGenericTypeName tref.Name])) let layoutILTypeRefName denv path = let path = @@ -193,7 +193,7 @@ module private PrintIL = let args = signatur.ArgTypes |> List.map (layoutILType denv ilTyparSubst) let res = match cons with - | Some className -> layoutILTypeRefName denv (SplitNamesForILPath (ungenericizeTypeName className)) ^^ (pruneParms className ilTyparSubst |> paramsL) // special case for constructor return-type (viz., the class itself) + | Some className -> layoutILTypeRefName denv (SplitNamesForILPath (PrettyNaming.DemangleGenericTypeName className)) ^^ (pruneParms className ilTyparSubst |> paramsL) // special case for constructor return-type (viz., the class itself) | None -> signatur.ReturnType |> layoutILType denv ilTyparSubst match args with | [] -> WordL.structUnit ^^ WordL.arrow ^^ res @@ -226,7 +226,7 @@ module private PrintIL = // return type be passed along as the `cons` parameter.) let res = match cons with - | Some className -> layoutILTypeRefName denv (SplitNamesForILPath (ungenericizeTypeName className)) ^^ (pruneParms className ilTyparSubst |> paramsL) // special case for constructor return-type (viz., the class itself) + | Some className -> layoutILTypeRefName denv (SplitNamesForILPath (PrettyNaming.DemangleGenericTypeName className)) ^^ (pruneParms className ilTyparSubst |> paramsL) // special case for constructor return-type (viz., the class itself) | None -> retType |> layoutILType denv ilTyparSubst match parameters with | [] -> WordL.structUnit ^^ WordL.arrow ^^ res diff --git a/src/fsharp/PrettyNaming.fs b/src/fsharp/PrettyNaming.fs index 4756eddc5f6..923be2ccea3 100755 --- a/src/fsharp/PrettyNaming.fs +++ b/src/fsharp/PrettyNaming.fs @@ -484,30 +484,36 @@ module public Microsoft.FSharp.Compiler.PrettyNaming let [] private mangledGenericTypeNameSym = '`' - let IsMangledGenericName (n:string) = - n.IndexOf mangledGenericTypeNameSym <> -1 && + let TryDemangleGenericNameAndPos (n:string) = (* check what comes after the symbol is a number *) - let m = n.LastIndexOf mangledGenericTypeNameSym - let mutable res = m < n.Length - 1 - for i = m + 1 to n.Length - 1 do - res <- res && n.[i] >= '0' && n.[i] <= '9' - res + let pos = n.LastIndexOf mangledGenericTypeNameSym + if pos = -1 then ValueNone else + let mutable res = pos < n.Length - 1 + let mutable i = pos + 1 + while res && i < n.Length do + let char = n.[i] + if not (char >= '0' && char <= '9') then + res <- false + i <- i + 1 + if res then + ValueSome pos + else + ValueNone type NameArityPair = NameArityPair of string * int - let DecodeGenericTypeName n = - if IsMangledGenericName n then - let pos = n.LastIndexOf mangledGenericTypeNameSym - let res = n.Substring(0,pos) - let num = n.Substring(pos+1,n.Length - pos - 1) - NameArityPair(res, int32 num) - else NameArityPair(n,0) - - let DemangleGenericTypeName n = - if IsMangledGenericName n then - let pos = n.LastIndexOf mangledGenericTypeNameSym - n.Substring(0,pos) - else n + let DecodeGenericTypeName pos (mangledName:string) = + let res = mangledName.Substring(0,pos) + let num = mangledName.Substring(pos+1,mangledName.Length - pos - 1) + NameArityPair(res, int32 num) + + let DemangleGenericTypeNameWithPos pos (mangledName:string) = + mangledName.Substring(0,pos) + + let DemangleGenericTypeName (mangledName:string) = + match TryDemangleGenericNameAndPos mangledName with + | ValueSome pos -> DemangleGenericTypeNameWithPos pos mangledName + | _ -> mangledName let private chopStringTo (s:string) (c:char) = match s.IndexOf c with diff --git a/src/fsharp/tast.fs b/src/fsharp/tast.fs index 53b253b1ab7..726d4d1ee04 100644 --- a/src/fsharp/tast.fs +++ b/src/fsharp/tast.fs @@ -480,10 +480,11 @@ let KeyTyconByDemangledNameAndArity nm (typars: _ list) x = /// Generic types can be accessed either by 'List' or 'List`1'. This lists both keys. The second form should really be deprecated. let KeyTyconByAccessNames nm x = - if IsMangledGenericName nm then - let dnm = DemangleGenericTypeName nm + match TryDemangleGenericNameAndPos nm with + | ValueSome pos -> + let dnm = DemangleGenericTypeNameWithPos pos nm [| KeyValuePair(nm,x); KeyValuePair(dnm,x) |] - else + | _ -> [| KeyValuePair(nm,x) |] type ModuleOrNamespaceKind = From ede79027d1acc62d65c83566d45fe217cb08af23 Mon Sep 17 00:00:00 2001 From: Theodore Tsirpanis <12659251+teo-tsirpanis@users.noreply.github.com> Date: Mon, 1 Oct 2018 17:36:42 +0300 Subject: [PATCH 2/2] Add uint16's literal suffix as a valid numeric literal in a compiler error (#5712) --- src/buildfromsource/FSharp.Compiler.Private/FSComp.resx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/buildfromsource/FSharp.Compiler.Private/FSComp.resx b/src/buildfromsource/FSharp.Compiler.Private/FSComp.resx index be8589241b4..a56052a1e9d 100644 --- a/src/buildfromsource/FSharp.Compiler.Private/FSComp.resx +++ b/src/buildfromsource/FSharp.Compiler.Private/FSComp.resx @@ -3082,7 +3082,7 @@ This number is outside the allowable range for 32-bit floats - This is not a valid numeric literal. Valid numeric literals include 1, 0x1, 0b0001 (int), 1u (uint32), 1L (int64), 1UL (uint64), 1s (int16), 1y (sbyte), 1uy (byte), 1.0 (float), 1.0f (float32), 1.0m (decimal), 1I (BigInteger). + This is not a valid numeric literal. Valid numeric literals include 1, 0x1, 0b0001 (int), 1u (uint32), 1L (int64), 1UL (uint64), 1s (int16), 1us (uint16), 1y (sbyte), 1uy (byte), 1.0 (float), 1.0f (float32), 1.0m (decimal), 1I (BigInteger). This is not a valid byte literal @@ -4360,4 +4360,4 @@ This type does not inherit Attribute, it will not work correctly with other .NET languages. - \ No newline at end of file +