Skip to content

Commit b4b951c

Browse files
committed
for unsolved always recompute TypeStructure
1 parent aec47e7 commit b4b951c

File tree

3 files changed

+51
-22
lines changed

3 files changed

+51
-22
lines changed

src/Compiler/Utilities/TypeHashing.fs

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -379,17 +379,6 @@ module HashTastMemberOrVals =
379379
///
380380
/// </summary>
381381
module StructuralUtilities =
382-
[<Struct; CustomEquality; NoComparison>]
383-
type NeverEqual =
384-
struct
385-
interface System.IEquatable<NeverEqual> with
386-
member _.Equals _ = false
387-
388-
override _.Equals _ = false
389-
override _.GetHashCode() = 0
390-
end
391-
392-
static member Singleton = NeverEqual()
393382

394383
[<Struct; NoComparison; RequireQualifiedAccess>]
395384
type TypeToken =
@@ -399,16 +388,17 @@ module StructuralUtilities =
399388
| TupInfo of b: bool
400389
| MeasureOne
401390
| MeasureRational of int * int
402-
| NeverEqual of never: NeverEqual
391+
| Unsolved
403392

404393
type TypeStructure =
405394
| TypeStructure of TypeToken[]
406-
| PossiblyInfinite of never: NeverEqual
395+
| UnsolvedTypeStructure of TypeToken[]
396+
| PossiblyInfinite
407397

408398
let inline toNullnessToken (n: Nullness) =
409399
match n.TryEvaluate() with
410400
| ValueSome k -> TypeToken.Nullness k
411-
| _ -> TypeToken.NeverEqual NeverEqual.Singleton
401+
| _ -> TypeToken.Unsolved
412402

413403
let rec private accumulateMeasure (m: Measure) =
414404
seq {
@@ -425,7 +415,14 @@ module StructuralUtilities =
425415
TypeToken.MeasureRational(GetNumerator r, GetDenominator r)
426416
}
427417

428-
let rec private accumulateTType (ty: TType) =
418+
let rec private accumulateTypar (typar: Typar) =
419+
seq {
420+
match typar.Solution with
421+
| Some ty -> yield! accumulateTType ty
422+
| None -> TypeToken.Unsolved
423+
}
424+
425+
and private accumulateTType (ty: TType) =
429426
seq {
430427
match ty with
431428
| TType_ucase(u, tinst) ->
@@ -441,40 +438,55 @@ module StructuralUtilities =
441438

442439
for arg in tinst do
443440
yield! accumulateTType arg
441+
444442
| TType_anon(info, tys) ->
445443
TypeToken.Stamp info.Stamp
446444

447445
for arg in tys do
448446
yield! accumulateTType arg
447+
449448
| TType_tuple(tupInfo, tys) ->
450449
TypeToken.TupInfo(evalTupInfoIsStruct tupInfo)
451450

452451
for arg in tys do
453452
yield! accumulateTType arg
453+
454454
| TType_forall(tps, tau) ->
455455
for tp in tps do
456-
TypeToken.Stamp tp.Stamp
456+
yield! accumulateTypar tp
457457

458458
yield! accumulateTType tau
459+
459460
| TType_fun(d, r, n) ->
460461
yield! accumulateTType d
461462
yield! accumulateTType r
462463
toNullnessToken n
464+
463465
| TType_var(r, n) ->
464-
TypeToken.Stamp r.Stamp
465466
toNullnessToken n
467+
yield! accumulateTypar r
468+
466469
| TType_measure m -> yield! accumulateMeasure m
467470
}
468471

469472
// If the sequence got too long, just drop it, we could be dealing with an infinite type.
470-
let private toTypeStructure tokens =
471-
let tokens = tokens |> Seq.truncate 256 |> Array.ofSeq
473+
let private toTypeStructure (tokens: TypeToken seq) =
474+
let tokens = tokens |> Seq.truncate 256 |> Seq.toArray
472475

473-
if tokens.Length = 256 then
474-
PossiblyInfinite NeverEqual.Singleton
476+
if Seq.length tokens = 256 then
477+
PossiblyInfinite
478+
elif tokens |> Array.exists _.IsUnsolved then
479+
UnsolvedTypeStructure tokens
475480
else
476481
TypeStructure tokens
477482

478483
/// Get the full structure of a type as a sequence of tokens, suitable for equality
479484
let getTypeStructure =
480-
Extras.WeakMap.getOrCreate (fun ty -> accumulateTType ty |> toTypeStructure)
485+
let shouldCache =
486+
function
487+
| PossiblyInfinite
488+
| UnsolvedTypeStructure _ -> false
489+
| _ -> true
490+
491+
// Speed up repeated calls by caching results for types that yield a stable structure.
492+
Extras.WeakMap.cacheConditionally shouldCache (fun ty -> accumulateTType ty |> toTypeStructure)

src/Compiler/Utilities/lib.fs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,3 +473,15 @@ module WeakMap =
473473
// Cached factory to avoid allocating a new lambda per lookup.
474474
let factory = ConditionalWeakTable.CreateValueCallback(fun k -> valueFactory k)
475475
fun (key: 'Key when 'Key: not null) -> table.GetValue(key, factory)
476+
477+
/// Like getOrCreate, but only cache the value if it satisfies the given predicate.
478+
let cacheConditionally shouldCache valueFactory =
479+
let table = ConditionalWeakTable<_, _>()
480+
fun (key: 'Key when 'Key: not null) ->
481+
match table.TryGetValue key with
482+
| true, value -> value
483+
| false, _ ->
484+
let value = valueFactory key
485+
if shouldCache value then
486+
try table.Add(key, value) with _ -> ()
487+
value

src/Compiler/Utilities/lib.fsi

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,8 @@ module internal WeakMap =
307307
val internal getOrCreate:
308308
valueFactory: ('Key -> 'Value) -> ('Key -> 'Value)
309309
when 'Key: not struct and 'Key: not null and 'Value: not struct
310+
311+
/// Like getOrCreate, but only cache the value if it satisfies the given predicate.
312+
val cacheConditionally:
313+
shouldCache: ('Value -> bool) -> valueFactory: ('Key -> 'Value) -> ('Key -> 'Value)
314+
when 'Key: not struct and 'Key: not null and 'Value: not struct

0 commit comments

Comments
 (0)