@@ -106,6 +106,9 @@ let mkEqualsTy g ty =
106106let mkEqualsWithComparerTy g ty =
107107 mkFunTy g ( mkThisTy g ty) ( mkFunTy g ( mkRefTupledTy g [ g.obj_ ty; g.IEqualityComparer_ ty ]) g.bool_ ty)
108108
109+ let mkEqualsWithComparerTyExact g ty =
110+ mkFunTy g ( mkThisTy g ty) ( mkFunTy g ( mkRefTupledTy g [ ty; g.IEqualityComparer_ ty ]) g.bool_ ty)
111+
109112let mkHashTy g ty =
110113 mkFunTy g ( mkThisTy g ty) ( mkFunTy g g.unit_ ty g.int_ ty)
111114
@@ -361,7 +364,7 @@ let mkRecdEquality g tcref (tycon: Tycon) =
361364 thisv, thatv, expr
362365
363366/// Build the equality implementation for a record type when parameterized by a comparer
364- let mkRecdEqualityWithComparer g tcref ( tycon : Tycon ) ( _thisv , thise ) thatobje ( thatv , thate ) compe =
367+ let mkRecdEqualityWithComparer g tcref ( tycon : Tycon ) thise thatobje ( thatv , thate ) compe isexact =
365368 let m = tycon.Range
366369 let fields = tycon.AllInstanceFieldsAsList
367370 let tinst , ty = mkMinimalTy g tcref
@@ -382,14 +385,21 @@ let mkRecdEqualityWithComparer g tcref (tycon: Tycon) (_thisv, thise) thatobje (
382385 let expr = mkEqualsTestConjuncts g m ( List.map mkTest fields)
383386
384387 let expr = mkBindThatAddr g m ty thataddrv thatv thate expr
385- // will be optimized away if not necessary
386- let expr = mkIsInstConditional g m ty thatobje thatv expr ( mkFalse g m)
388+
389+ let expr =
390+ if isexact then
391+ expr
392+ else
393+ mkIsInstConditional g m ty thatobje thatv expr ( mkFalse g m)
387394
388395 let expr =
389396 if tycon.IsStructOrEnumTycon then
390397 expr
391398 else
392- mkBindThisNullEquals g m thise thatobje expr
399+ if isexact then
400+ mkBindThatNullEquals g m thise thate expr
401+ else
402+ mkBindThisNullEquals g m thise thatobje expr
393403
394404 expr
395405
@@ -425,7 +435,7 @@ let mkExnEquality (g: TcGlobals) exnref (exnc: Tycon) =
425435 thisv, thatv, expr
426436
427437/// Build the equality implementation for an exception definition when parameterized by a comparer
428- let mkExnEqualityWithComparer g exnref ( exnc : Tycon ) ( _thisv , thise ) thatobje ( thatv , thate ) compe =
438+ let mkExnEqualityWithComparer g exnref ( exnc : Tycon ) thise thatobje ( thatv , thate ) compe isexact =
429439 let m = exnc.Range
430440 let thataddrv , thataddre = mkThatAddrLocal g m g.exn_ ty
431441
@@ -453,13 +463,21 @@ let mkExnEqualityWithComparer g exnref (exnc: Tycon) (_thisv, thise) thatobje (t
453463 mbuilder.Close( dtree, m, g.bool_ ty)
454464
455465 let expr = mkBindThatAddr g m g.exn_ ty thataddrv thatv thate expr
456- let expr = mkIsInstConditional g m g.exn_ ty thatobje thatv expr ( mkFalse g m)
466+
467+ let expr =
468+ if isexact then
469+ expr
470+ else
471+ mkIsInstConditional g m g.exn_ ty thatobje thatv expr ( mkFalse g m)
457472
458473 let expr =
459474 if exnc.IsStructOrEnumTycon then
460475 expr
461476 else
462- mkBindThisNullEquals g m thise thatobje expr
477+ if isexact then
478+ mkBindThatNullEquals g m thise thate expr
479+ else
480+ mkBindThisNullEquals g m thise thatobje expr
463481
464482 expr
465483
@@ -758,7 +776,7 @@ let mkUnionEquality g tcref (tycon: Tycon) =
758776 thisv, thatv, expr
759777
760778/// Build the equality implementation for a union type when parameterized by a comparer
761- let mkUnionEqualityWithComparer g tcref ( tycon : Tycon ) ( _thisv , thise ) thatobje ( thatv , thate ) compe =
779+ let mkUnionEqualityWithComparer g tcref ( tycon : Tycon ) thise thatobje ( thatv , thate ) compe isexact =
762780 let m = tycon.Range
763781 let ucases = tycon.UnionCasesAsList
764782 let tinst , ty = mkMinimalTy g tcref
@@ -846,13 +864,21 @@ let mkUnionEqualityWithComparer g tcref (tycon: Tycon) (_thisv, thise) thatobje
846864 ( mkCompGenLet m thattagv ( mkUnionCaseTagGetViaExprAddr ( thataddre, tcref, tinst, m)) tagsEqTested)
847865
848866 let expr = mkBindThatAddr g m ty thataddrv thatv thate expr
849- let expr = mkIsInstConditional g m ty thatobje thatv expr ( mkFalse g m)
867+
868+ let expr =
869+ if isexact then
870+ expr
871+ else
872+ mkIsInstConditional g m ty thatobje thatv expr ( mkFalse g m)
850873
851874 let expr =
852875 if tycon.IsStructOrEnumTycon then
853876 expr
854877 else
855- mkBindThisNullEquals g m thise thatobje expr
878+ if isexact then
879+ mkBindThatNullEquals g m thise thate expr
880+ else
881+ mkBindThisNullEquals g m thise thatobje expr
856882
857883 expr
858884
@@ -1014,6 +1040,15 @@ let getAugmentationAttribs g (tycon: Tycon) =
10141040 TryFindFSharpBoolAttribute g g.attrib_ CustomComparisonAttribute tycon.Attribs,
10151041 TryFindFSharpBoolAttribute g g.attrib_ StructuralComparisonAttribute tycon.Attribs
10161042
1043+ [<NoEquality; NoComparison; StructuredFormatDisplay( " {DebugText}" ) >]
1044+ type EqualityWithComparerAugmentation =
1045+ {
1046+ GetHashCode: Val
1047+ GetHashCodeWithComparer: Val
1048+ EqualsWithComparer: Val
1049+ EqualsExactWithComparer: Val
1050+ }
1051+
10171052let CheckAugmentationAttribs isImplementation g amap ( tycon : Tycon ) =
10181053 let m = tycon.Range
10191054 let attribs = getAugmentationAttribs g tycon
@@ -1333,7 +1368,25 @@ let MakeValsForEqualityWithComparerAugmentation g (tcref: TyconRef) =
13331368 let withcEqualsVal =
13341369 mkValSpec g tcref ty vis ( Some( mkIStructuralEquatableEqualsSlotSig g)) " Equals" ( tps + -> ( mkEqualsWithComparerTy g ty)) tupArg false
13351370
1336- objGetHashCodeVal, withcGetHashCodeVal, withcEqualsVal
1371+ let withcEqualsValExact =
1372+ mkValSpec
1373+ g
1374+ tcref
1375+ ty
1376+ vis
1377+ // This doesn't implement any interface.
1378+ None
1379+ " Equals"
1380+ ( tps + -> ( mkEqualsWithComparerTyExact g ty))
1381+ tupArg
1382+ false
1383+
1384+ {
1385+ GetHashCode = objGetHashCodeVal
1386+ GetHashCodeWithComparer = withcGetHashCodeVal
1387+ EqualsWithComparer = withcEqualsVal
1388+ EqualsExactWithComparer = withcEqualsValExact
1389+ }
13371390
13381391let MakeBindingsForCompareAugmentation g ( tycon : Tycon ) =
13391392 let tcref = mkLocalTyconRef tycon
@@ -1419,7 +1472,7 @@ let MakeBindingsForEqualityWithComparerAugmentation (g: TcGlobals) (tycon: Tycon
14191472 let mkStructuralEquatable hashf equalsf =
14201473 match tycon.GeneratedHashAndEqualsWithComparerValues with
14211474 | None -> []
1422- | Some( objGetHashCodeVal, withcGetHashCodeVal, withcEqualsVal) ->
1475+ | Some( objGetHashCodeVal, withcGetHashCodeVal, withcEqualsVal, withcEqualsExactValOption ) ->
14231476
14241477 // build the hash rhs
14251478 let withcGetHashCodeExpr =
@@ -1451,12 +1504,33 @@ let MakeBindingsForEqualityWithComparerAugmentation (g: TcGlobals) (tycon: Tycon
14511504
14521505 // build the equals rhs
14531506 let withcEqualsExpr =
1454- let _tinst , ty = mkMinimalTy g tcref
1507+ let tinst , ty = mkMinimalTy g tcref
14551508 let thisv , thise = mkThisVar g m ty
14561509 let thatobjv , thatobje = mkCompGenLocal m " obj" g.obj_ ty
14571510 let thatv , thate = mkCompGenLocal m " that" ty
14581511 let compv , compe = mkCompGenLocal m " comp" g.IEqualityComparer_ ty
1459- let equalse = equalsf g tcref tycon ( thisv, thise) thatobje ( thatv, thate) compe
1512+
1513+ // if the new overload is available, use it
1514+ // otherwise, generate the whole equals thing
1515+ let equalse =
1516+ match withcEqualsExactValOption with
1517+ | Some withcEqualsExactVal ->
1518+ mkIsInstConditional
1519+ g
1520+ m
1521+ ty
1522+ thatobje
1523+ thatv
1524+ ( mkApps
1525+ g
1526+ (( exprForValRef m withcEqualsExactVal, withcEqualsExactVal.Type),
1527+ ( if isNil tinst then [] else [ tinst ]),
1528+ [ thise; mkRefTupled g m [ thate; compe ] [ ty; g.IEqualityComparer_ ty ] ],
1529+ m))
1530+ ( mkFalse g m)
1531+ | None ->
1532+ equalsf g tcref tycon thise thatobje ( thatv, thate) compe false
1533+
14601534 mkMultiLambdas g m tps [ [ thisv ]; [ thatobjv; compv ] ] ( equalse, g.bool_ ty)
14611535
14621536 let objGetHashCodeExpr =
@@ -1481,9 +1555,22 @@ let MakeBindingsForEqualityWithComparerAugmentation (g: TcGlobals) (tycon: Tycon
14811555
14821556 mkLambdas g m tps [ thisv; unitv ] ( hashe, g.int_ ty)
14831557
1558+ let withcEqualsExactExpr =
1559+ let _tinst , ty = mkMinimalTy g tcref
1560+ let thisv , thise = mkThisVar g m ty
1561+ let thatv , thate = mkCompGenLocal m " obj" ty
1562+ let compv , compe = mkCompGenLocal m " comp" g.IEqualityComparer_ ty
1563+
1564+ let equalse = equalsf g tcref tycon thise thate ( thatv, thate) compe true
1565+
1566+ mkMultiLambdas g m tps [ [ thisv ]; [ thatv; compv ] ] ( equalse, g.bool_ ty)
1567+
14841568 [
14851569 ( mkCompGenBind withcGetHashCodeVal.Deref withcGetHashCodeExpr)
14861570 ( mkCompGenBind objGetHashCodeVal.Deref objGetHashCodeExpr)
1571+ match withcEqualsExactValOption with
1572+ | Some withcEqualsExactVal -> mkCompGenBind withcEqualsExactVal.Deref withcEqualsExactExpr
1573+ | None -> ()
14871574 ( mkCompGenBind withcEqualsVal.Deref withcEqualsExpr)
14881575 ]
14891576
0 commit comments