Skip to content

Commit e0933b4

Browse files
vasily-kirichenkoKevinRansom
authored andcommitted
Use HashSet instead of Set in the type suggestion algorithm (#3883)
* use HashSet instead of Set in the type suggestion algorithm * fix tests * optimize jaro * reduce allocations * fix * use Stack * back to ResizeArray, no rev * refactor GetRecordLabelsForType * use imperative loop instead of seq
1 parent 46a1e68 commit e0933b4

File tree

7 files changed

+125
-147
lines changed

7 files changed

+125
-147
lines changed

src/fsharp/ConstraintSolver.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2050,7 +2050,7 @@ and ReportNoCandidatesError (csenv:ConstraintSolverEnv) (nUnnamedCallerArgs, nNa
20502050
let predictFields() =
20512051
minfo.DeclaringEntityRef.AllInstanceFieldsAsList
20522052
|> List.map (fun p -> p.Name.Replace("@", ""))
2053-
|> Set.ofList
2053+
|> System.Collections.Generic.HashSet
20542054

20552055
ErrorWithSuggestions((msgNum, FSComp.SR.csCtorHasNoArgumentOrReturnProperty(methodName, id.idText, msgText)), id.idRange, id.idText, predictFields)
20562056
else

src/fsharp/ErrorLogger.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ let rec findOriginalException err =
5454
| WrappedError(err, _) -> findOriginalException err
5555
| _ -> err
5656

57-
type Suggestions = unit -> Set<string>
57+
type Suggestions = unit -> Collections.Generic.HashSet<string>
5858

59-
let NoSuggestions : Suggestions = fun () -> Set.empty
59+
let NoSuggestions : Suggestions = fun () -> Collections.Generic.HashSet()
6060

6161
/// Thrown when we stop processing the F# Interactive entry or #load.
6262
exception StopProcessingExn of exn option with

src/fsharp/NameResolution.fs

Lines changed: 77 additions & 87 deletions
Large diffs are not rendered by default.

src/fsharp/TypeChecker.fs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4458,16 +4458,16 @@ and TcTyparOrMeasurePar optKind cenv (env:TcEnv) newOk tpenv (Typar(id, _, _) as
44584458
let predictions1 =
44594459
env.eNameResEnv.eTypars
44604460
|> Seq.map (fun p -> "'" + p.Key)
4461-
|> Set.ofSeq
44624461

44634462
let predictions2 =
44644463
match tpenv with
44654464
| UnscopedTyparEnv elements ->
44664465
elements
44674466
|> Seq.map (fun p -> "'" + p.Key)
4468-
|> Set.ofSeq
44694467

4470-
Set.union predictions1 predictions2
4468+
[ yield! predictions1
4469+
yield! predictions2 ]
4470+
|> HashSet
44714471

44724472
let reportedId = Ident("'" + id.idText, id.idRange)
44734473
error (UndefinedName(0, FSComp.SR.undefinedNameTypeParameter, reportedId, predictTypeParameters))
@@ -6440,7 +6440,7 @@ and FreshenObjExprAbstractSlot cenv (env: TcEnv) (implty:TType) virtNameAndArity
64406440
let suggestVirtualMembers() =
64416441
virtNameAndArityPairs
64426442
|> List.map (fst >> fst)
6443-
|> Set.ofList
6443+
|> HashSet
64446444

64456445
if containsNonAbstractMemberWithSameName then
64466446
errorR(ErrorWithSuggestions(FSComp.SR.tcMemberFoundIsNotAbstractOrVirtual(tcref.DisplayName, bindName), mBinding, bindName, suggestVirtualMembers))

src/utils/EditDistance.fs

Lines changed: 37 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,73 +3,61 @@
33
/// Functions to compute the edit distance between two strings
44
module internal Internal.Utilities.EditDistance
55

6-
/// Given an offset and a radius from that offset,
7-
/// does mChar exist in that part of str?
8-
let inline existsInWin (mChar: char) (str: string) offset rad =
9-
let startAt = max 0 (offset - rad)
10-
let endAt = min (offset + rad) (String.length str - 1)
6+
open System
7+
open System.Collections.Generic
8+
9+
/// Given an offset and a radius from that offset, does mChar exist in that part of str?
10+
let inline existsInWin (mChar: char) (str: string) (offset: int) (rad: int) =
11+
let startAt = Math.Max(0, offset - rad)
12+
let endAt = Math.Min(offset + rad, str.Length - 1)
1113
if endAt - startAt < 0 then false
1214
else
1315
let rec exists index =
1416
if str.[index] = mChar then true
1517
elif index = endAt then false
1618
else exists (index + 1)
1719
exists startAt
18-
19-
/// The jaro distance between s1 and s2
20-
let jaro s1 s2 =
21-
// The radius is half of the lesser
22-
// of the two string lengths rounded up.
20+
21+
let jaro (s1: string) (s2: string) =
22+
// The radius is half of the lesser of the two string lengths rounded up.
2323
let matchRadius =
24-
let minLen =
25-
min (String.length s1) (String.length s2) in
26-
minLen / 2 + minLen % 2
27-
24+
let minLen = Math.Min(s1.Length, s2.Length)
25+
minLen / 2 + minLen % 2
26+
2827
// An inner function which recursively finds the number
2928
// of matched characters within the radius.
3029
let commonChars (chars1: string) (chars2: string) =
31-
let rec inner i result =
32-
match i with
33-
| -1 -> result
34-
| _ -> if existsInWin chars1.[i] chars2 i matchRadius
35-
then inner (i - 1) (chars1.[i] :: result)
36-
else inner (i - 1) result
37-
inner (chars1.Length - 1) []
38-
30+
let result = ResizeArray(chars1.Length)
31+
for i = 0 to chars1.Length - 1 do
32+
let c = chars1.[i]
33+
if existsInWin c chars2 i matchRadius then
34+
result.Add c
35+
result
36+
3937
// The sets of common characters and their lengths as floats
4038
let c1 = commonChars s1 s2
4139
let c2 = commonChars s2 s1
42-
let c1length = float (List.length c1)
43-
let c2length = float (List.length c2)
44-
45-
// The number of transpositions within
46-
// the sets of common characters.
47-
let transpositions =
48-
let rec inner cl1 cl2 result =
49-
match cl1, cl2 with
50-
| [], _ | _, [] -> result
51-
| c1h :: c1t, c2h :: c2t ->
52-
if c1h <> c2h
53-
then inner c1t c2t (result + 1.0)
54-
else inner c1t c2t result
55-
let mismatches = inner c1 c2 0.0
40+
let c1length = float c1.Count
41+
let c2length = float c2.Count
42+
43+
// The number of transpositions within the sets of common characters.
44+
let transpositions =
45+
let mutable mismatches = 0.0
46+
for i = 0 to (Math.Min(c1.Count, c2.Count)) - 1 do
47+
if c1.[i] <> c2.[i] then
48+
mismatches <- mismatches + 1.0
49+
5650
// If one common string is longer than the other
5751
// each additional char counts as half a transposition
5852
(mismatches + abs (c1length - c2length)) / 2.0
59-
60-
let s1length = float (String.length s1)
61-
let s2length = float (String.length s2)
62-
let tLength = max c1length c2length
63-
64-
// The jaro distance as given by
65-
// 1/3 ( m2/|s1| + m1/|s2| + (mc-t)/mc )
66-
let result = (c1length / s1length +
67-
c2length / s2length +
68-
(tLength - transpositions) / tLength)
69-
/ 3.0
70-
53+
54+
let tLength = Math.Max(c1length, c2length)
55+
56+
// The jaro distance as given by 1/3 ( m2/|s1| + m1/|s2| + (mc-t)/mc )
57+
let result = (c1length / float s1.Length + c2length / float s2.Length + (tLength - transpositions) / tLength) / 3.0
58+
7159
// This is for cases where |s1|, |s2| or m are zero
72-
if System.Double.IsNaN result then 0.0 else result
60+
if Double.IsNaN result then 0.0 else result
7361

7462
/// Calculates the Jaro-Winkler edit distance between two strings.
7563
/// The edit distance is a metric that allows to measure the amount of similarity between two strings.

tests/fsharp/typecheck/sigs/neg01.bsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ neg01a.fs(22,8,23,7): typecheck error FS0913: Types cannot contain nested type d
55

66
neg01b.fs(2,13,2,14): typecheck error FS0039: The value, constructor, namespace or type 'X' is not defined. Maybe you want one of the following:
77

8+
z
9+
810
A
911

1012
B
11-
12-
z

tests/fsharp/typecheck/sigs/neg14.bsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ neg14a.fs(9,6,9,33): typecheck error FS0343: The type 'missingInterfaceInSignatu
33

44
neg14b.fs(2,13,2,14): typecheck error FS0039: The value, constructor, namespace or type 'X' is not defined. Maybe you want one of the following:
55

6+
z
7+
68
A
79

810
B
9-
10-
z

0 commit comments

Comments
 (0)