@@ -385,6 +385,7 @@ module HashTastMemberOrVals =
385385///
386386/// </summary>
387387module StructuralUtilities =
388+ open Internal.Utilities .Library .Extras
388389
389390 [<Struct; NoComparison; RequireQualifiedAccess>]
390391 type TypeToken =
@@ -399,17 +400,23 @@ module StructuralUtilities =
399400 | Unsolved of int
400401 | Rigid of int
401402
402- type TypeStructure = TypeStructure of TypeToken []
403+ type TypeStructure =
404+ | Stable of TypeToken []
405+ | Unstable of TypeToken []
406+ | PossiblyInfinite
403407
404408 type private EmitContext =
405409 {
406410 typarMap: System .Collections .Generic .Dictionary < Stamp , int >
411+ mutable stable: bool
407412 }
408413
409- let inline emitNullness ( n : Nullness ) =
414+ let private emitNullness env ( n : Nullness ) =
410415 match n.TryEvaluate() with
411416 | ValueSome k -> TypeToken.Nullness k
412- | ValueNone -> TypeToken.NullnessUnsolved
417+ | ValueNone ->
418+ env.stable <- false
419+ TypeToken.NullnessUnsolved
413420
414421 let rec private emitMeasure ( m : Measure ) =
415422 seq {
@@ -438,7 +445,7 @@ module StructuralUtilities =
438445
439446 | TType_ app( tcref, tinst, n) ->
440447 TypeToken.Stamp tcref.Stamp
441- emitNullness n
448+ emitNullness env n
442449
443450 for arg in tinst do
444451 yield ! emitTType env arg
@@ -466,10 +473,10 @@ module StructuralUtilities =
466473 | TType_ fun( d, r, n) ->
467474 yield ! emitTType env d
468475 yield ! emitTType env r
469- emitNullness n
476+ emitNullness env n
470477
471478 | TType_ var( r, n) ->
472- emitNullness n
479+ emitNullness env n
473480
474481 let typarId =
475482 match env.typarMap.TryGetValue r.Stamp with
@@ -480,21 +487,22 @@ module StructuralUtilities =
480487 idx
481488
482489 match r.Solution with
483- | Some ty ->
484- yield ! emitTType env ty
490+ | Some ty -> yield ! emitTType env ty
485491 | None ->
486492 if r.Rigidity = TyparRigidity.Rigid then
487493 TypeToken.Rigid typarId
488494 else
495+ env.stable <- false
489496 TypeToken.Unsolved typarId
490497 | TType_ measure m -> yield ! emitMeasure m
491498 }
492499
493- let tryGetTypeStructureOfStrippedType ( ty : TType ) =
500+ let private getTypeStructureOfStrippedType ( ty : TType ) =
494501
495502 let env =
496503 {
497504 typarMap = System.Collections.Generic.Dictionary< Stamp, int>()
505+ stable = true
498506 }
499507
500508 let tokens =
@@ -504,7 +512,19 @@ module StructuralUtilities =
504512 |> Seq.toArray
505513
506514 // If the sequence got too long, just drop it, we could be dealing with an infinite type.
507- if tokens.Length = 256 then
508- ValueNone
509- else
510- ValueSome( TypeStructure tokens)
515+ if tokens.Length = 256 then PossiblyInfinite
516+ elif not env.stable then Unstable tokens
517+ else Stable tokens
518+
519+ let tryGetTypeStructureOfStrippedType ty =
520+ // Speed up repeated calls by memoizing results for types that yield a stable structure.
521+ let memoize =
522+ WeakMap.cacheConditionally
523+ ( function
524+ | Stable _ -> true
525+ | _ -> false )
526+ getTypeStructureOfStrippedType
527+
528+ match memoize ty with
529+ | PossiblyInfinite -> ValueNone
530+ | ts -> ValueSome ts
0 commit comments