@@ -1004,10 +1004,22 @@ and SolveDimensionlessNumericType (csenv:ConstraintSolverEnv) ndeep m2 trace ty
10041004 | None ->
10051005 CompleteD
10061006
1007- /// We do a bunch of fakery to pretend that primitive types have certain members.
1008- /// We pretend int and other types support a number of operators. In the actual IL for mscorlib they
1009- /// don't, however the type-directed static optimization rules in the library code that makes use of this
1010- /// will deal with the problem.
1007+ /// Attempt to solve a statically resolved member constraint.
1008+ ///
1009+ /// 1 . We do a bunch of fakery to pretend that primitive types have certain members.
1010+ /// We pretend int and other types support a number of operators. In the actual IL for mscorlib they
1011+ /// don't. The type-directed static optimization rules in the library code that makes use of this
1012+ /// will deal with the problem.
1013+ ///
1014+ /// 2 . Some additional solutions are forced prior to generalization (permitWeakResolution=true). These are, roughly speaking, rules
1015+ /// for binary-operand constraints arising from constructs such as "1.0 + x" where "x" is an unknown type. THe constraint here
1016+ /// involves two type parameters - one for the left, and one for the right. The left is already known to be Double.
1017+ /// In this situation (and in the absence of other evidence prior to generalization), constraint solving forces an assumption that
1018+ /// the right is also Double - this is "weak" because there is only weak evidence for it.
1019+ ///
1020+ /// permitWeakResolution also applies to resolutions of multi-type-variable constraints via method overloads. Method overloading gets applied even if
1021+ /// only one of the two type variables is known
1022+ ///
10111023and SolveMemberConstraint ( csenv : ConstraintSolverEnv ) ignoreUnresolvedOverload permitWeakResolution ndeep m2 trace ( TTrait ( tys , nm , memFlags , argtys , rty , sln )): OperationResult < bool > = trackErrors {
10121024 // Do not re-solve if already solved
10131025 if sln.Value.IsSome then return true else
@@ -1065,7 +1077,7 @@ and SolveMemberConstraint (csenv:ConstraintSolverEnv) ignoreUnresolvedOverload p
10651077 // The rule is triggered by these sorts of inputs when permitWeakResolution=true
10661078 // float * 'a
10671079 // 'a * float
1068- // decimal<'u> * 'a <---
1080+ // decimal<'u> * 'a
10691081 ( let checkRuleAppliesInPreferenceToMethods argty1 argty2 =
10701082 // Check that at least one of the argument types is numeric
10711083 ( IsNumericOrIntegralEnumType g argty1) &&
@@ -1314,7 +1326,7 @@ and SolveMemberConstraint (csenv:ConstraintSolverEnv) ignoreUnresolvedOverload p
13141326
13151327 // Now check if there are no feasible solutions at all
13161328 match minfos, recdPropSearch, anonRecdPropSearch with
1317- | [], None, None when not ( tys |> List.exists ( isAnyParTy g )) ->
1329+ | [], None, None when MemberConstraintIsReadyForStrongResolution csenv traitInfo ->
13181330 if tys |> List.exists ( isFunTy g) then
13191331 return ! ErrorD ( ConstraintSolverError( FSComp.SR.csExpectTypeWithOperatorButGivenFunction( DecompileOpName nm), m, m2))
13201332 elif tys |> List.exists ( isAnyTupleTy g) then
@@ -1387,14 +1399,21 @@ and SolveMemberConstraint (csenv:ConstraintSolverEnv) ignoreUnresolvedOverload p
13871399 | _ ->
13881400 let support = GetSupportOfMemberConstraint csenv traitInfo
13891401 let frees = GetFreeTyparsOfMemberConstraint csenv traitInfo
1390- // If there's nothing left to learn then raise the errors
1391- if ( permitWeakResolution && isNil support) || isNil frees then do ! errors
1402+
1403+ // If there's nothing left to learn then raise the errors.
1404+ // Note: we should likely call MemberConstraintIsReadyForResolution here when permitWeakResolution=false but for stability
1405+ // reasons we use the more restrictive isNil frees.
1406+ if ( permitWeakResolution && MemberConstraintIsReadyForWeakResolution csenv traitInfo) || isNil frees then
1407+ do ! errors
13921408 // Otherwise re-record the trait waiting for canonicalization
1393- else do ! AddMemberConstraint csenv ndeep m2 trace traitInfo support frees
1394- return !
1395- match errors with
1396- | ErrorResult (_, UnresolvedOverloading _) when not ignoreUnresolvedOverload && ( not ( nm = " op_Explicit" || nm = " op_Implicit" )) -> ErrorD LocallyAbortOperationThatFailsToResolveOverload
1397- | _ -> ResultD TTraitUnsolved
1409+ else
1410+ do ! AddMemberConstraint csenv ndeep m2 trace traitInfo support frees
1411+
1412+ match errors with
1413+ | ErrorResult (_, UnresolvedOverloading _) when not ignoreUnresolvedOverload && ( not ( nm = " op_Explicit" || nm = " op_Implicit" )) ->
1414+ return ! ErrorD LocallyAbortOperationThatFailsToResolveOverload
1415+ | _ ->
1416+ return TTraitUnsolved
13981417 }
13991418 return ! RecordMemberConstraintSolution csenv.SolverState m trace traitInfo res
14001419 }
@@ -1475,21 +1494,17 @@ and TransactMemberConstraintSolution traitInfo (trace:OptionalTrace) sln =
14751494/// That is, don't perform resolution if more nominal information may influence the set of available overloads
14761495and GetRelevantMethodsForTrait ( csenv : ConstraintSolverEnv ) permitWeakResolution nm ( TTrait ( tys , _ , memFlags , argtys , rty , soln ) as traitInfo ): MethInfo list =
14771496 let results =
1478- if permitWeakResolution || isNil ( GetSupportOfMemberConstraint csenv traitInfo) then
1497+ if permitWeakResolution || MemberConstraintSupportIsReadyForDeterminingOverloads csenv traitInfo then
14791498 let m = csenv.m
14801499 let minfos =
14811500 match memFlags.MemberKind with
14821501 | MemberKind.Constructor ->
14831502 tys |> List.map ( GetIntrinsicConstructorInfosOfType csenv.SolverState.InfoReader m)
14841503 | _ ->
14851504 tys |> List.map ( GetIntrinsicMethInfosOfType csenv.SolverState.InfoReader ( Some nm, AccessibleFromSomeFSharpCode, AllowMultiIntfInstantiations.Yes) IgnoreOverrides m)
1486- /// Merge the sets so we don't get the same minfo from each side
1487- /// We merge based on whether minfos use identical metadata or not.
14881505
1489- /// REVIEW: Consider the pathological cases where this may cause a loss of distinction
1490- /// between potential overloads because a generic instantiation derived from the left hand type differs
1491- /// to a generic instantiation for an operator based on the right hand type.
1492-
1506+ // Merge the sets so we don't get the same minfo from each side
1507+ // We merge based on whether minfos use identical metadata or not.
14931508 let minfos = List.reduce ( ListSet.unionFavourLeft MethInfo.MethInfosUseIdenticalDefinitions) minfos
14941509
14951510 /// Check that the available members aren't hiding a member from the parent (depth 1 only)
@@ -1503,7 +1518,7 @@ and GetRelevantMethodsForTrait (csenv:ConstraintSolverEnv) permitWeakResolution
15031518 []
15041519 // The trait name "op_Explicit" also covers "op_Implicit", so look for that one too.
15051520 if nm = " op_Explicit" then
1506- results @ GetRelevantMethodsForTrait ( csenv: ConstraintSolverEnv ) permitWeakResolution " op_Implicit" ( TTrait( tys, " op_Implicit" , memFlags, argtys, rty, soln))
1521+ results @ GetRelevantMethodsForTrait csenv permitWeakResolution " op_Implicit" ( TTrait( tys, " op_Implicit" , memFlags, argtys, rty, soln))
15071522 else
15081523 results
15091524
@@ -1512,10 +1527,28 @@ and GetRelevantMethodsForTrait (csenv:ConstraintSolverEnv) permitWeakResolution
15121527and GetSupportOfMemberConstraint ( csenv : ConstraintSolverEnv ) ( TTrait ( tys , _ , _ , _ , _ , _ )) =
15131528 tys |> List.choose ( tryAnyParTyOption csenv.g)
15141529
1515- /// All the typars relevant to the member constraint * )
1530+ /// Check if the support is fully solved.
1531+ and SupportOfMemberConstraintIsFullySolved ( csenv : ConstraintSolverEnv ) ( TTrait ( tys , _ , _ , _ , _ , _ )) =
1532+ tys |> List.forall ( isAnyParTy csenv.g >> not )
1533+
1534+ // This may be relevant to future bug fixes, see https://github.com/Microsoft/visualfsharp/issues/3814
1535+ // /// Check if some part of the support is solved.
1536+ // and SupportOfMemberConstraintIsPartiallySolved (csenv:ConstraintSolverEnv) (TTrait(tys, _, _, _, _, _)) =
1537+ // tys |> List.exists (isAnyParTy csenv.g >> not)
1538+
1539+ /// Get all the unsolved typars (statically resolved or not) relevant to the member constraint
15161540and GetFreeTyparsOfMemberConstraint ( csenv : ConstraintSolverEnv ) ( TTrait ( tys , _ , _ , argtys , rty , _ )) =
15171541 freeInTypesLeftToRightSkippingConstraints csenv.g ( tys@ argtys@ Option.toList rty)
15181542
1543+ and MemberConstraintIsReadyForWeakResolution csenv traitInfo =
1544+ SupportOfMemberConstraintIsFullySolved csenv traitInfo
1545+
1546+ and MemberConstraintIsReadyForStrongResolution csenv traitInfo =
1547+ SupportOfMemberConstraintIsFullySolved csenv traitInfo
1548+
1549+ and MemberConstraintSupportIsReadyForDeterminingOverloads csenv traitInfo =
1550+ SupportOfMemberConstraintIsFullySolved csenv traitInfo
1551+
15191552/// Re-solve the global constraints involving any of the given type variables.
15201553/// Trait constraints can't always be solved using the pessimistic rules. We only canonicalize
15211554/// them forcefully (permitWeakResolution=true) prior to generalization.
0 commit comments