11module internal Internal.Utilities.TypeHashing
22
33open Internal.Utilities .Rational
4- open Internal.Utilities .Library
54open FSharp.Compiler .AbstractIL .IL
65open FSharp.Compiler .Syntax
76open FSharp.Compiler .TcGlobals
87open FSharp.Compiler .Text
98open FSharp.Compiler .TypedTree
109open FSharp.Compiler .TypedTreeBasics
1110open FSharp.Compiler .TypedTreeOps
12- open System.Collections .Immutable
1311
1412type ObserverVisibility =
1513 | PublicOnly
@@ -126,7 +124,6 @@ module HashAccessibility =
126124 | _ -> true
127125
128126module rec HashTypes =
129- open Microsoft.FSharp .Core .LanguagePrimitives
130127
131128 /// Hash a reference to a type
132129 let hashTyconRef tcref = hashTyconRefImpl tcref
@@ -371,7 +368,7 @@ module HashTastMemberOrVals =
371368/// * Uses per-compilation stamps (entities, typars, anon records, measures).
372369/// * Emits shape for union cases (declaring type stamp + case name), tuple structness,
373370/// function arrows, forall binders, nullness, measures, generic arguments.
374- /// * Unknown/variable nullness => NeverEqual token to force inequality (avoid unsound hits) .
371+ /// * Does not include type constraints .
375372///
376373/// Non-goals:
377374/// * Cross-compilation stability.
@@ -385,117 +382,120 @@ module StructuralUtilities =
385382 | Stamp of stamp : Stamp
386383 | UCase of name : string
387384 | Nullness of nullness : NullnessInfo
385+ | NullnessUnsolved
388386 | TupInfo of b : bool
387+ | Forall of int
389388 | MeasureOne
390389 | MeasureRational of int * int
391- | UnconstrainedVar
392- | Unsolved
390+ | Unsolved of int
391+ | Rigid of int
393392
394- type TypeStructure =
395- | TypeStructure of TypeToken []
396- | UnsolvedTypeStructure of TypeToken []
397- | PossiblyInfinite
393+ type TypeStructure = TypeStructure of TypeToken []
398394
399- let inline toNullnessToken ( n : Nullness ) =
395+ type private EmitContext =
396+ {
397+ typarMap: System .Collections .Generic .Dictionary < Stamp , int >
398+ }
399+
400+ let inline emitNullness ( n : Nullness ) =
400401 match n.TryEvaluate() with
401402 | ValueSome k -> TypeToken.Nullness k
402- | _ -> TypeToken.Unsolved
403+ | ValueNone -> TypeToken.NullnessUnsolved
403404
404- let rec private accumulateMeasure ( m : Measure ) =
405+ let rec private emitMeasure ( m : Measure ) =
405406 seq {
406407 match m with
407408 | Measure.Var mv -> TypeToken.Stamp mv.Stamp
408409 | Measure.Const( tcref, _) -> TypeToken.Stamp tcref.Stamp
409410 | Measure.Prod( m1, m2, _) ->
410- yield ! accumulateMeasure m1
411- yield ! accumulateMeasure m2
412- | Measure.Inv m1 -> yield ! accumulateMeasure m1
411+ yield ! emitMeasure m1
412+ yield ! emitMeasure m2
413+ | Measure.Inv m1 -> yield ! emitMeasure m1
413414 | Measure.One _ -> TypeToken.MeasureOne
414415 | Measure.RationalPower( m1, r) ->
415- yield ! accumulateMeasure m1
416+ yield ! emitMeasure m1
416417 TypeToken.MeasureRational( GetNumerator r, GetDenominator r)
417418 }
418419
419- let rec private accumulateTypar ( typar : Typar ) =
420- seq {
421- match typar.Solution with
422- | Some ty -> yield ! accumulateTType ty
423- | None ->
424- if typar.Rigidity <> TyparRigidity.Rigid then
425- TypeToken.Unsolved
426-
427- // We don't emit details of the constraints, just the stamp to avoid collisions.
428- if typar.Constraints.Length > 0 then
429- TypeToken.Stamp typar.Stamp
430- else
431- TypeToken.UnconstrainedVar
432- }
433-
434- and private accumulateTType ( ty : TType ) =
420+ and private emitTType ( env : EmitContext ) ( ty : TType ) =
435421 seq {
436422 match ty with
437423 | TType_ ucase( u, tinst) ->
438424 TypeToken.Stamp u.TyconRef.Stamp
439425 TypeToken.UCase u.CaseName
440426
441427 for arg in tinst do
442- yield ! accumulateTType arg
428+ yield ! emitTType env arg
443429
444430 | TType_ app( tcref, tinst, n) ->
445431 TypeToken.Stamp tcref.Stamp
446- toNullnessToken n
432+ emitNullness n
447433
448434 for arg in tinst do
449- yield ! accumulateTType arg
435+ yield ! emitTType env arg
450436
451437 | TType_ anon( info, tys) ->
452438 TypeToken.Stamp info.Stamp
453439
454440 for arg in tys do
455- yield ! accumulateTType arg
441+ yield ! emitTType env arg
456442
457443 | TType_ tuple( tupInfo, tys) ->
458444 TypeToken.TupInfo( evalTupInfoIsStruct tupInfo)
459445
460446 for arg in tys do
461- yield ! accumulateTType arg
447+ yield ! emitTType env arg
462448
463449 | TType_ forall( tps, tau) ->
464450 for tp in tps do
465- yield ! accumulateTypar tp
451+ env.typarMap .[ tp.Stamp ] <- env.typarMap.Count
466452
467- yield ! accumulateTType tau
453+ TypeToken.Forall tps.Length
454+
455+ yield ! emitTType env tau
468456
469457 | TType_ fun( d, r, n) ->
470- yield ! accumulateTType d
471- yield ! accumulateTType r
472- toNullnessToken n
458+ yield ! emitTType env d
459+ yield ! emitTType env r
460+ emitNullness n
473461
474462 | TType_ var( r, n) ->
475- toNullnessToken n
476- yield ! accumulateTypar r
477-
478- | TType_ measure m -> yield ! accumulateMeasure m
463+ emitNullness n
464+
465+ let typarId =
466+ match env.typarMap.TryGetValue r.Stamp with
467+ | true , idx -> idx
468+ | _ ->
469+ let idx = env.typarMap.Count
470+ env.typarMap.[ r.Stamp] <- idx
471+ idx
472+
473+ match r.Solution with
474+ | Some ty ->
475+ yield ! emitTType env ty
476+ | None ->
477+ if r.Rigidity = TyparRigidity.Rigid then
478+ TypeToken.Rigid typarId
479+ else
480+ TypeToken.Unsolved typarId
481+ | TType_ measure m -> yield ! emitMeasure m
479482 }
480483
481- // If the sequence got too long, just drop it, we could be dealing with an infinite type.
482- let private toTypeStructure ( tokens : TypeToken seq ) =
483- let tokens = tokens |> Seq.truncate 256 |> Seq.toArray
484+ let tryGetTypeStructureOfStrippedType ( ty : TType ) =
485+
486+ let env =
487+ {
488+ typarMap = System.Collections.Generic.Dictionary< Stamp, int>()
489+ }
490+
491+ let tokens =
492+ emitTType env ty
493+ |> Seq.filter ( fun t -> t <> TypeToken.Nullness NullnessInfo.WithoutNull)
494+ |> Seq.truncate 256
495+ |> Seq.toArray
484496
497+ // If the sequence got too long, just drop it, we could be dealing with an infinite type.
485498 if tokens.Length = 256 then
486- PossiblyInfinite
487- elif tokens |> Array.exists _. IsUnsolved then
488- UnsolvedTypeStructure tokens
499+ ValueNone
489500 else
490- TypeStructure tokens
491-
492- /// Get the full structure of a type as a sequence of tokens, suitable for equality
493- let getTypeStructure =
494- let shouldCache =
495- function
496- | PossiblyInfinite
497- | UnsolvedTypeStructure _ -> false
498- | _ -> true
499-
500- // Speed up repeated calls by memoizing results for types that yield a stable structure.
501- Extras.WeakMap.cacheConditionally shouldCache ( fun ty -> accumulateTType ty |> toTypeStructure)
501+ ValueSome( TypeStructure tokens)
0 commit comments