@@ -8,6 +8,7 @@ open FSharp.Compiler.Text
88open FSharp.Compiler .TypedTree
99open FSharp.Compiler .TypedTreeBasics
1010open FSharp.Compiler .TypedTreeOps
11+ open System.Collections .Immutable
1112
1213type ObserverVisibility =
1314 | PublicOnly
@@ -357,165 +358,96 @@ module HashTastMemberOrVals =
357358 hashNonMemberVal ( g, obs) ( tps, vref.Deref, tau, cxs)
358359 | Some _ -> hashMember ( g, obs) emptyTyparInst vref.Deref
359360
360- /// Practical TType comparer strictly for the use with cache keys.
361- module HashStamps =
362- let rec typeInstStampsEqual ( tys1 : TypeInst ) ( tys2 : TypeInst ) =
363- tys1.Length = tys2.Length && ( tys1, tys2) ||> Seq.forall2 stampEquals
364-
365- and inline typarStampEquals ( t1 : Typar ) ( t2 : Typar ) = t1.Stamp = t2.Stamp
366-
367- and typarsStampsEqual ( tps1 : Typars ) ( tps2 : Typars ) =
368- tps1.Length = tps2.Length && ( tps1, tps2) ||> Seq.forall2 typarStampEquals
369-
370- and measureStampEquals ( m1 : Measure ) ( m2 : Measure ) =
371- match m1, m2 with
372- | Measure.Var( mv1), Measure.Var( mv2) -> mv1.Stamp = mv2.Stamp
373- | Measure.Const( t1, _), Measure.Const( t2, _) -> t1.Stamp = t2.Stamp
374- | Measure.Prod( m1, m2, _), Measure.Prod( m3, m4, _) -> measureStampEquals m1 m3 && measureStampEquals m2 m4
375- | Measure.Inv m1, Measure.Inv m2 -> measureStampEquals m1 m2
376- | Measure.One _, Measure.One _ -> true
377- | Measure.RationalPower( m1, r1), Measure.RationalPower( m2, r2) -> r1 = r2 && measureStampEquals m1 m2
378- | _ -> false
379-
380- and nullnessEquals ( n1 : Nullness ) ( n2 : Nullness ) =
381- match n1, n2 with
382- | Nullness.Known k1, Nullness.Known k2 -> k1 = k2
383- | Nullness.Variable _, Nullness.Variable _ -> true
384- | _ -> false
385-
386- and stampEquals ty1 ty2 =
387- match ty1, ty2 with
388- | TType_ ucase( u, tys1), TType_ ucase( v, tys2) -> u.CaseName = v.CaseName && typeInstStampsEqual tys1 tys2
389- | TType_ app( tcref1, tinst1, n1), TType_ app( tcref2, tinst2, n2) ->
390- tcref1.Stamp = tcref2.Stamp
391- && nullnessEquals n1 n2
392- && typeInstStampsEqual tinst1 tinst2
393- | TType_ anon( info1, tys1), TType_ anon( info2, tys2) -> info1.Stamp = info2.Stamp && typeInstStampsEqual tys1 tys2
394- | TType_ tuple( c1, tys1), TType_ tuple( c2, tys2) -> c1 = c2 && typeInstStampsEqual tys1 tys2
395- | TType_ forall( tps1, tau1), TType_ forall( tps2, tau2) -> stampEquals tau1 tau2 && typarsStampsEqual tps1 tps2
396- | TType_ var( r1, n1), TType_ var( r2, n2) -> r1.Stamp = r2.Stamp && nullnessEquals n1 n2
397- | TType_ measure m1, TType_ measure m2 -> measureStampEquals m1 m2
398- | _ -> false
399-
400- let inline hashStamp ( x : Stamp ) : Hash = uint x * 2654435761 u |> int
401-
402- // The idea is to keep the illusion of immutability of TType.
403- // This hash must be stable during compilation, otherwise we won't be able to find keys or evict from the cache.
404- let rec hashTType ty : Hash =
405- match ty with
406- | TType_ ucase( u, tinst) -> tinst |> hashListOrderMatters ( hashTType) |> pipeToHash ( hash u.CaseName)
407- | TType_ app( tcref, tinst, Nullness.Known n) ->
408- tinst
409- |> hashListOrderMatters ( hashTType)
410- |> pipeToHash ( hashStamp tcref.Stamp)
411- |> pipeToHash ( hash n)
412- | TType_ app( tcref, tinst, Nullness.Variable _) -> tinst |> hashListOrderMatters ( hashTType) |> pipeToHash ( hashStamp tcref.Stamp)
413- | TType_ anon( info, tys) -> tys |> hashListOrderMatters ( hashTType) |> pipeToHash ( hashStamp info.Stamp)
414- | TType_ tuple( c, tys) -> tys |> hashListOrderMatters ( hashTType) |> pipeToHash ( hash c)
415- | TType_ forall( tps, tau) ->
416- tps
417- |> Seq.map _. Stamp
418- |> hashListOrderMatters ( hashStamp)
419- |> pipeToHash ( hashTType tau)
420- | TType_ fun( d, r, Nullness.Known n) -> hashTType d |> pipeToHash ( hashTType r) |> pipeToHash ( hash n)
421- | TType_ fun( d, r, Nullness.Variable _) -> hashTType d |> pipeToHash ( hashTType r)
422- | TType_ var( r, Nullness.Known n) -> hashStamp r.Stamp |> pipeToHash ( hash n)
423- | TType_ var( r, Nullness.Variable _) -> hashStamp r.Stamp
424- | TType_ measure _ -> 0
425-
426- /// Lossless accumulation of TType structure (parallel to HashStamps.hashTType but retaining full shape tokens)
427- module AccumulateTypes =
361+ /// Lossless accumulation of TType structure
362+ module TypeStructural =
363+ // Helper struct whose instances are never equal (even to themselves).
364+ [<Struct; CustomEquality; NoComparison>]
365+ type NeverEqual =
366+ struct
367+ interface System.IEquatable< NeverEqual> with
368+ member _.Equals _ = false
369+
370+ override _.Equals ( _ ) = false
371+ override _.GetHashCode () = 0
372+ end
373+
374+ [<Struct; NoComparison>]
428375 type NullnessToken =
429- | Known of NullnessInfo
430- | Variable
376+ | Known of info : NullnessInfo
377+ | Variable of never : NeverEqual
431378 | Absent
432379
433380 /// Convert compiler Nullness info to token form
434381 let inline toNullnessToken ( n : Nullness ) =
435382 match n with
436383 | Nullness.Known k -> NullnessToken.Known k
437- | Nullness.Variable _ -> NullnessToken.Variable
384+ | Nullness.Variable _ -> NullnessToken.Variable( NeverEqual ())
438385
439386 /// Tokens capturing a lossless, structural representation of TType needed for deterministic keys.
387+ [<Struct; NoComparison>]
440388 type TypeToken =
441- | UCase of string * TypeToken list
442- | App of Stamp * NullnessToken * TypeToken list
443- | Anon of Stamp * TypeToken list
444- | Tuple of bool * TypeToken list
445- | Forall of Stamp list * TypeToken
446- | Fun of TypeToken * TypeToken * NullnessToken
447- | Var of Stamp * NullnessToken
448- | Measure of MeasureToken
449- and MeasureToken =
450- | MVar of Stamp
451- | MConst of Stamp
452- | MProd of MeasureToken * MeasureToken
453- | MInv of MeasureToken
454- | MOne
455- | MRationalPower of MeasureToken * Rational
389+ | Stamp of stamp : Stamp
390+ | UCase of name : string
391+ | Nullness of nullness : NullnessToken
392+ | TupInfo of b : bool
393+ | MeasureOne
394+ | MeasureRational of rational : Rational
395+
396+ type TypeStructure = TypeToken[]
456397
457398 /// Accumulate Measure to MeasureToken
458- let rec private accumulateMeasure m =
399+ let rec private accumulateMeasure m acc =
459400 match m with
460- | Measure.Var mv -> MVar mv.Stamp
461- | Measure.Const( tcref, _) -> MConst tcref.Stamp
462- | Measure.Prod( m1, m2, _) -> MProd( accumulateMeasure m1, accumulateMeasure m2)
463- | Measure.Inv m1 -> MInv ( accumulateMeasure m1)
464- | Measure.One _ -> MOne
465- | Measure.RationalPower( m1, r) -> MRationalPower( accumulateMeasure m1, r)
466-
467- /// Accumulate a TType into a lossless token tree. Uses stamps for identity where appropriate (matching hashTType logic).
468- let rec accumulateTType ( ty : TType ) : TypeToken =
401+ | Measure.Var mv -> acc ( Stamp mv.Stamp)
402+ | Measure.Const( tcref, _) -> acc ( Stamp tcref.Stamp)
403+ | Measure.Prod( m1, m2, _) ->
404+ accumulateMeasure m1 acc
405+ accumulateMeasure m2 acc
406+ | Measure.Inv m1 -> accumulateMeasure m1 acc
407+ | Measure.One _ -> acc MeasureOne
408+ | Measure.RationalPower( m1, r) ->
409+ accumulateMeasure m1 acc
410+ acc ( MeasureRational r)
411+
412+ /// Accumulate a TType into a lossless token list. Uses stamps for identity where appropriate (matching hashTType logic).
413+ let rec private accumulateTType ( ty : TType ) acc =
469414 match ty with
470415 | TType_ ucase( u, tinst) ->
471- let args = tinst |> List.map accumulateTType
472- UCase( u.CaseName, args)
416+ acc ( UCase u.CaseName)
417+
418+ for arg in tinst do
419+ accumulateTType arg acc
473420 | TType_ app( tcref, tinst, n) ->
474- let args = tinst |> List.map accumulateTType
475- App( tcref.Stamp, toNullnessToken n, args)
421+ acc ( Stamp tcref.Stamp)
422+ acc ( Nullness( toNullnessToken n))
423+
424+ for arg in tinst do
425+ accumulateTType arg acc
476426 | TType_ anon( info, tys) ->
477- let args = tys |> List.map accumulateTType
478- Anon( info.Stamp, args)
427+ acc ( Stamp info.Stamp)
428+
429+ for arg in tys do
430+ accumulateTType arg acc
479431 | TType_ tuple( tupInfo, tys) ->
480- let elems = tys |> List.map accumulateTType
481- let isStruct = evalTupInfoIsStruct tupInfo
482- Tuple( isStruct, elems)
432+ acc ( TupInfo( evalTupInfoIsStruct tupInfo))
433+
434+ for arg in tys do
435+ accumulateTType arg acc
483436 | TType_ forall( tps, tau) ->
484- let stamps = tps |> List.map ( fun tp -> tp.Stamp)
485- let body = accumulateTType tau
486- Forall( stamps, body)
437+ for tp in tps do
438+ acc ( Stamp tp.Stamp)
439+
440+ accumulateTType tau acc
487441 | TType_ fun( d, r, n) ->
488- Fun( accumulateTType d, accumulateTType r, toNullnessToken n)
442+ accumulateTType d acc
443+ accumulateTType r acc
444+ acc ( Nullness( toNullnessToken n))
489445 | TType_ var( r, n) ->
490- Var( r.Stamp, toNullnessToken n)
491- | TType_ measure m -> Measure ( accumulateMeasure m)
492-
493- // /// Flatten accumulated token tree to a sequence of simple discriminators and payload (useful for generic hashing/serialization)
494- //let flatten (root: TypeToken) : obj list =
495- // let res = System.Collections.Generic.List<obj>()
496- // let rec loop tt =
497- // match tt with
498- // | UCase(name, args) ->
499- // res.Add "UCASE"; res.Add name; res.Add args.Length; args |> List.iter loop
500- // | App(stamp, nTok, args) ->
501- // res.Add "APP"; res.Add stamp; res.Add (match nTok with | Known k -> box k | Variable -> box "VAR" | Absent -> box null);
502- // res.Add args.Length; args |> List.iter loop
503- // | Anon(stamp, args) -> res.Add "ANON"; res.Add stamp; res.Add args.Length; args |> List.iter loop
504- // | Tuple(isStruct, elems) -> res.Add "TUP"; res.Add isStruct; res.Add elems.Length; elems |> List.iter loop
505- // | Forall(stamps, body) -> res.Add "FORALL"; res.Add stamps.Length; stamps |> List.iter (fun s -> res.Add s); loop body
506- // | Fun(d, r, nTok) ->
507- // res.Add "FUN"; res.Add (match nTok with | Known k -> box k | Variable -> box "VAR" | Absent -> box null); loop d; loop r
508- // | Var(stamp, nTok) -> res.Add "VAR"; res.Add stamp; res.Add (match nTok with | Known k -> box k | Variable -> box "VAR" | Absent -> box null)
509- // | Measure m ->
510- // res.Add "MEASURE"
511- // let rec loopM mt =
512- // match mt with
513- // | MVar s -> res.Add "MVAR"; res.Add s
514- // | MConst s -> res.Add "MCONST"; res.Add s
515- // | MProd(a, b) -> res.Add "MPROD"; loopM a; loopM b
516- // | MInv x -> res.Add "MINV"; loopM x
517- // | MOne -> res.Add "MONE"
518- // | MRationalPower(x, r) -> res.Add "MRAT"; res.Add (box r); loopM x
519- // loopM m
520- // loop root
521- // res |> Seq.toList
446+ acc ( Stamp r.Stamp)
447+ acc ( Nullness( toNullnessToken n))
448+ | TType_ measure m -> accumulateMeasure m acc
449+
450+ let getTypeStructure ty =
451+ let tokens = ResizeArray()
452+ accumulateTType ty tokens.Add
453+ tokens.ToArray()
0 commit comments