Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[fsharp] Source update a29233c → df0e609
  • Loading branch information
dotnet-maestro[bot] committed Sep 5, 2026
commit 9dd7bdf8dd00cff4ca3f62019d27098e03d5c9cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ type ComputationExpressionContext<'a> =
tpenv: UnscopedTyparEnv
customOperationMethodsIndexedByKeyword:
IDictionary<string, list<string * bool * bool * bool * bool * bool * bool * option<string> * MethInfo>>
customOperationMethodsIndexedByMethodName:
IDictionary<string, list<string * bool * bool * bool * bool * bool * bool * option<string> * MethInfo>>
sourceMethInfo: 'a list
builderValName: string
ad: AccessorDomain
Expand Down Expand Up @@ -271,14 +269,8 @@ let getCustomOperationMethods (cenv: TcFileState) (env: TcEnv) ad mBuilderVal bu

/// Decide if the identifier represents a use of a custom query operator
let tryGetDataForCustomOperation (nm: Ident) ceenv =
let isOpDataCountAllowed opDatas =
match opDatas with
| [ _ ] -> true
| _ :: _ -> ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations
| _ -> false

match ceenv.customOperationMethodsIndexedByKeyword.TryGetValue nm.idText with
| true, opDatas when isOpDataCountAllowed opDatas ->
| true, opDatas ->
for opData in opDatas do
let (opName,
maintainsVarSpaceUsingBind,
Expand All @@ -288,7 +280,7 @@ let tryGetDataForCustomOperation (nm: Ident) ceenv =
isLikeJoin,
isLikeGroupJoin,
_joinConditionWord,
methInfo) =
_methInfo) =
opData

if
Expand All @@ -299,15 +291,7 @@ let tryGetDataForCustomOperation (nm: Ident) ceenv =
then
errorR (Error(FSComp.SR.tcCustomOperationInvalid (RichText.mkMethod opName), nm.idRange))

if not (ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations) then
match ceenv.customOperationMethodsIndexedByMethodName.TryGetValue methInfo.LogicalName with
| true, [ _ ] -> ()
| _ -> errorR (Error(FSComp.SR.tcCustomOperationMayNotBeOverloaded (RichText.mkMethod nm.idText), nm.idRange))

Some opDatas
| true, opData :: _ ->
errorR (Error(FSComp.SR.tcCustomOperationMayNotBeOverloaded (RichText.mkMethod nm.idText), nm.idRange))
Some [ opData ]
| _ -> None

let isCustomOperation ceenv nm =
Expand Down Expand Up @@ -551,22 +535,15 @@ let tryExpectedArgCountForCustomOperator ceenv (nm: Ident) =
| None -> -1
| Some argInfos -> List.length argInfos)

// Prior to 'OverloadsForCustomOperations' we count exact arguments.
//
// With 'OverloadsForCustomOperations' we don't compute an exact expected argument count
// if any arguments are optional, out or ParamArray.
let isSpecial =
if ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations then
argInfosForOverloads
|> List.exists (fun info ->
match info with
| None -> false
| Some args ->
args
|> List.exists (fun (ParamAttribs(isParamArrayArg, _isInArg, isOutArg, optArgInfo, _callerInfo, _reflArgInfo)) ->
isParamArrayArg || isOutArg || optArgInfo.IsOptional))
else
false
argInfosForOverloads
|> List.exists (fun info ->
match info with
| None -> false
| Some args ->
args
|> List.exists (fun (ParamAttribs(isParamArrayArg, _isInArg, isOutArg, optArgInfo, _callerInfo, _reflArgInfo)) ->
isParamArrayArg || isOutArg || optArgInfo.IsOptional))

if not isSpecial && nums |> List.forall (fun v -> v >= 0 && v = nums[0]) then
Some(max (nums[0] - 1) 0) // drop the computation context argument
Expand Down Expand Up @@ -2558,7 +2535,7 @@ and ConsumeCustomOpClauses
let argCountsMatch =
match expectedArgCount with
| Some n -> n = args.Length
| None -> ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations
| None -> true

if argCountsMatch then
// Check for the [<ProjectionParameter>] attribute on each argument position
Expand Down Expand Up @@ -3037,26 +3014,9 @@ let TcComputationExpression (cenv: TcFileState) env (overallTy: OverallTy) tpenv
| _ -> CustomOperationsMode.Allowed

let customOperationMethodsIndexedByKeyword =
if cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations then
customOperationMethods
|> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm)
|> Seq.map (fun (nm, group) -> (nm, Seq.toList group))
else
customOperationMethods
|> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm)
|> Seq.map (fun (nm, group) -> (nm, Seq.toList group))
|> dict

// Check for duplicates by method name (keywords and method names must be 1:1)
let customOperationMethodsIndexedByMethodName =
if cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations then
customOperationMethods
|> Seq.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName)
|> Seq.map (fun (nm, group) -> (nm, Seq.toList group))
else
customOperationMethods
|> Seq.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName)
|> Seq.map (fun (nm, group) -> (nm, Seq.toList group))
customOperationMethods
|> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm)
|> Seq.map (fun (nm, group) -> (nm, Seq.toList group))
|> dict

// If there are no 'yield' in the computation expression, and the builder supports 'Yield',
Expand All @@ -3078,7 +3038,6 @@ let TcComputationExpression (cenv: TcFileState) env (overallTy: OverallTy) tpenv
env = env
tpenv = tpenv
customOperationMethodsIndexedByKeyword = customOperationMethodsIndexedByKeyword
customOperationMethodsIndexedByMethodName = customOperationMethodsIndexedByMethodName
sourceMethInfo = sourceMethInfo
builderValName = builderValName
ad = ad
Expand Down
19 changes: 0 additions & 19 deletions src/fsharp/src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11315,8 +11315,6 @@ and TcAndBuildFixedExpr (cenv: cenv) env (overallPatTy, fixedExpr, overallExprTy

match getPinnableReferenceMInfo with
| Some mInfo ->
checkLanguageFeatureAndRecover g.langVersion LanguageFeature.ExtendedFixedBindings mBinding

let mInst = FreshenMethInfo g env.TraitContext mBinding mInfo
let pinnableReference, actualRetTy = BuildPossiblyConditionalMethodCall cenv env NeverMutates mBinding false mInfo NormalValUse mInst [ fixedExpr ] [] None

Expand Down Expand Up @@ -11352,23 +11350,6 @@ and TcAndBuildFixedExpr (cenv: cenv) env (overallPatTy, fixedExpr, overallExprTy

match overallExprTy with
| ty when isByrefTy g ty ->
// Feature ExtendedFixedBindings allows *any* byref to be used with fixed bindings, whereas the old logic only allowed a specific
// subset. This preserves the old logic when the feature is turned off.
if not (g.langVersion.SupportsFeature LanguageFeature.ExtendedFixedBindings) then
let okByRef =
match stripDebugPoints (stripExpr fixedExpr) with
| Expr.Op (op, tyargs, args, _) ->
match op, tyargs, args with
| TOp.ValFieldGetAddr (rfref, _), _, [_] -> not rfref.Tycon.IsStructOrEnumTycon
| TOp.ILAsm ([ I_ldflda fspec], _), _, _ -> fspec.DeclaringType.Boxity = ILBoxity.AsObject
| TOp.ILAsm ([ I_ldelema _], _), _, _ -> true
| TOp.RefAddrGet _, _, _ -> true
| _ -> false
| _ -> false

if not okByRef then
errorR (languageFeatureError g.langVersion LanguageFeature.ExtendedFixedBindings mBinding)

let elemTy = destByrefTy g overallExprTy
UnifyTypes cenv env mBinding (mkNativePtrTy g elemTy) overallPatTy
mkCompGenLetIn mBinding "pinnedByref" ty fixedExpr (fun (v, ve) ->
Expand Down
14 changes: 8 additions & 6 deletions src/fsharp/src/Compiler/Checking/TypeHierarchy.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

module internal FSharp.Compiler.TypeHierarchy

open Internal.Utilities.Library
open Internal.Utilities.Library.Extras
open FSharp.Compiler.Text
open FSharp.Compiler.AbstractIL.IL
Expand Down Expand Up @@ -241,7 +242,7 @@ let FoldHierarchyOfTypeAux followInterfaces allowMultiIntfInst skipUnref visitor
| _ -> false

// Do not visit the same type twice. Could only be doing this if we've seen this tycon
if seenThisTycon && (match tcrefOpt with ValueSome tcref -> List.exists (typeEquiv g ty) (visited.Find tcref) | ValueNone -> false) then state else
if seenThisTycon && (match tcrefOpt with ValueSome tcref -> ListInline.exists (typeEquiv g ty) (visited.Find tcref) | ValueNone -> false) then state else

// Do not visit the same tycon twice, e.g. I<int> and I<string>, collect I<int> only, unless directed to allow this
if seenThisTycon && allowMultiIntfInst = AllowMultiIntfInstantiations.No then state else
Expand All @@ -255,10 +256,11 @@ let FoldHierarchyOfTypeAux followInterfaces allowMultiIntfInst skipUnref visitor
state

if ndeep > 100 then (errorR(Error((FSComp.SR.recursiveClassHierarchy (RichText.mkText (showType ty))), m)); (visitedTycon, visited, acc)) else
// Local 'loop' is passed as a lambda, not 'loop (ndeep+1)': InlineIfLambda then inlines it instead of allocating it as a closure.
let visitedTycon, visited, acc =
if isInterfaceTy g ty then
List.foldBack
(loop (ndeep+1))
ListInline.foldBack
(fun ity st -> loop (ndeep+1) ity st)
(GetImmediateInterfacesOfType skipUnref g amap m ty)
(loop ndeep g.obj_ty_noNulls state)
else
Expand Down Expand Up @@ -289,15 +291,15 @@ let FoldHierarchyOfTypeAux followInterfaces allowMultiIntfInst skipUnref visitor
| _ ->
let state =
if followInterfaces then
List.foldBack
(loop (ndeep+1))
ListInline.foldBack
(fun ity st -> loop (ndeep+1) ity st)
(GetImmediateInterfacesOfType skipUnref g amap m ty)
state
else
state
let state =
Option.foldBack
(loop (ndeep+1))
(fun sty st -> loop (ndeep+1) sty st)
(GetSuperTypeOfType g amap m ty)
state
state
Expand Down
87 changes: 55 additions & 32 deletions src/fsharp/src/Compiler/Checking/infos.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module internal FSharp.Compiler.Infos

open System
open System.Collections.Generic
open System.Runtime.CompilerServices
open Internal.Utilities.Library
open Internal.Utilities.Library.Extras
open FSharp.Compiler
Expand Down Expand Up @@ -656,6 +658,56 @@ type ILMethInfo =
|> GetFSharpViewOfReturnType amap.g


// Module-level, not a local closure, so cache hits in GetParamAttribs allocate nothing.
let private ComputeILMethodParamAttribs g (ilMethInfo: ILMethInfo) amap m =
[ [ for p in ilMethInfo.ParamMetadata do
let attrs = p.CustomAttrs
let isParamArrayArg = p.CustomAttrsStored.HasWellKnownAttribute(g, WellKnownILAttributes.ParamArrayAttribute)
let reflArgInfo =
match attrs with
| ILAttribDecoded WellKnownILAttributes.ReflectedDefinitionAttribute ([ILAttribElem.Bool b ], _) -> ReflectedArgInfo.Quote b
| ILAttribDecoded WellKnownILAttributes.ReflectedDefinitionAttribute _ -> ReflectedArgInfo.Quote false
| _ -> ReflectedArgInfo.None
let isOutArg = (p.IsOut && not p.IsIn)
let isInArg = (p.IsIn && not p.IsOut)
// Note: we get default argument values from VB and other .NET language metadata
let optArgInfo = OptionalArgInfo.FromILParameter g amap m ilMethInfo.MetadataScope ilMethInfo.DeclaringTypeInst p

let isCallerLineNumberArg = p.CustomAttrsStored.HasWellKnownAttribute(g, WellKnownILAttributes.CallerLineNumberAttribute)
let isCallerFilePathArg = p.CustomAttrsStored.HasWellKnownAttribute(g, WellKnownILAttributes.CallerFilePathAttribute)
let isCallerMemberNameArg = p.CustomAttrsStored.HasWellKnownAttribute(g, WellKnownILAttributes.CallerMemberNameAttribute)

let callerInfo =
match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg with
| false, false, false -> NoCallerInfo
| true, false, false -> CallerLineNumber
| false, true, false -> CallerFilePath
| false, false, true -> CallerMemberName
| _, _, _ ->
// if multiple caller info attributes are specified, pick the "wrong" one here
// so that we get an error later
if p.Type.TypeRef.FullName = "System.Int32" then CallerFilePath
else CallerLineNumber

ParamAttribs(isParamArrayArg, isInArg, isOutArg, optArgInfo, callerInfo, reflArgInfo) ] ]

// Extension view drops the object arg from ParamMetadata, so IsILExtensionMethod is part of the key.
let private getILMethodParamAttribsTable =
WeakMap.getOrCreate (fun (amap: ImportMap) ->
MemoizationTable(
"ilMethodParamAttribs",
(fun (struct (ilMethInfo: ILMethInfo, m)) -> ComputeILMethodParamAttribs amap.g ilMethInfo amap m),
keyComparer =
{ new IEqualityComparer<struct (ILMethInfo * range)> with
member _.GetHashCode(struct (mi, _)) =
RuntimeHelpers.GetHashCode mi.RawMetadata ^^^ (if mi.IsILExtensionMethod then 1 else 0)

member _.Equals(struct (mi1, _), struct (mi2, _)) =
mi1.IsILExtensionMethod = mi2.IsILExtensionMethod
&& mi1.RawMetadata === mi2.RawMetadata },
canMemoize = fun (struct (mi, _)) -> mi.DeclaringTypeInst.IsEmpty))


/// Describes an F# use of a method
[<System.Diagnostics.DebuggerDisplay("{DebuggerDisplayName}")>]
[<NoComparison; NoEquality>]
Expand Down Expand Up @@ -1333,39 +1385,10 @@ type MethInfo =
#endif

/// Get the parameter attributes of a method info, which get combined with the parameter names and types
member x.GetParamAttribs(amap, m) =
member x.GetParamAttribs(amap: ImportMap, m) =
match x with
| ILMeth(g, ilMethInfo, _) ->
[ [ for p in ilMethInfo.ParamMetadata do
let attrs = p.CustomAttrs
let isParamArrayArg = p.CustomAttrsStored.HasWellKnownAttribute(g, WellKnownILAttributes.ParamArrayAttribute)
let reflArgInfo =
match attrs with
| ILAttribDecoded WellKnownILAttributes.ReflectedDefinitionAttribute ([ILAttribElem.Bool b ], _) -> ReflectedArgInfo.Quote b
| ILAttribDecoded WellKnownILAttributes.ReflectedDefinitionAttribute _ -> ReflectedArgInfo.Quote false
| _ -> ReflectedArgInfo.None
let isOutArg = (p.IsOut && not p.IsIn)
let isInArg = (p.IsIn && not p.IsOut)
// Note: we get default argument values from VB and other .NET language metadata
let optArgInfo = OptionalArgInfo.FromILParameter g amap m ilMethInfo.MetadataScope ilMethInfo.DeclaringTypeInst p

let isCallerLineNumberArg = p.CustomAttrsStored.HasWellKnownAttribute(g, WellKnownILAttributes.CallerLineNumberAttribute)
let isCallerFilePathArg = p.CustomAttrsStored.HasWellKnownAttribute(g, WellKnownILAttributes.CallerFilePathAttribute)
let isCallerMemberNameArg = p.CustomAttrsStored.HasWellKnownAttribute(g, WellKnownILAttributes.CallerMemberNameAttribute)

let callerInfo =
match isCallerLineNumberArg, isCallerFilePathArg, isCallerMemberNameArg with
| false, false, false -> NoCallerInfo
| true, false, false -> CallerLineNumber
| false, true, false -> CallerFilePath
| false, false, true -> CallerMemberName
| _, _, _ ->
// if multiple caller info attributes are specified, pick the "wrong" one here
// so that we get an error later
if p.Type.TypeRef.FullName = "System.Int32" then CallerFilePath
else CallerLineNumber

ParamAttribs(isParamArrayArg, isInArg, isOutArg, optArgInfo, callerInfo, reflArgInfo) ] ]
| ILMeth(_, ilMethInfo, _) ->
(getILMethodParamAttribsTable amap).Apply(struct (ilMethInfo, m))

| FSMeth(g, _, vref, _) ->
GetArgInfosOfMember x.IsCSharpStyleExtensionMember g vref
Expand Down
3 changes: 0 additions & 3 deletions src/fsharp/src/Compiler/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1246,7 +1246,6 @@ invalidFullNameForProvidedType,"invalid full name for provided type"
3085,tcCustomOperationMayNotBeUsedInConjunctionWithNonSimpleLetBindings,"A custom operation may not be used in conjunction with a non-value or recursive 'let' binding in another part of this computation expression"
3086,tcCustomOperationMayNotBeUsedHere,"A custom operation may not be used in conjunction with 'use', 'try/with', 'try/finally', 'if/then/else' or 'match' operators within this computation expression"
3087,tcCustomOperationMayNotBeOverloaded,"The custom operation '%s' refers to a method which is overloaded. The implementations of custom operations may not be overloaded."
featureOverloadsForCustomOperations,"overloads for custom operations"
featureExpandedMeasurables,"more types support units of measure"
featureRefCellNotationInformationals,"informational messages related to reference cells"
featureNonVariablePatternsToRightOfAsPatterns,"non-variable patterns to the right of 'as' patterns"
Expand Down Expand Up @@ -1575,15 +1574,13 @@ featureRequiredProperties,"support for required properties"
featureMatchNotAllowedForUnionCaseWithNoData,"Pattern match discard is not allowed for union case that takes no data."
featureCSharpExtensionAttributeNotRequired,"Allow implicit Extension attribute on declaring types, modules"
featureErrorForNonVirtualMembersOverrides,"Raises errors for non-virtual members overrides"
featureArithmeticInLiterals,"Arithmetic and logical operations in literals, enum definitions and attributes"
featureErrorReportingOnStaticClasses,"Error reporting on static classes"
featureWarningWhenCopyAndUpdateRecordChangesAllFields,"Raises warnings when an copy-and-update record expression changes all fields of a record."
featureNonInlineLiteralsAsPrintfFormat,"String values marked as literals and IL constants as printf format"
featureExtendedStringInterpolation,"Extended string interpolation similar to C# raw string literals."
featureWarningWhenMultipleRecdTypeChoice,"Raises warnings when multiple record type matches were found during name resolution because of overlapping field names."
featureConstraintIntersectionOnFlexibleTypes,"Constraint intersection on flexible types"
featureChkNotTailRecursive,"Raises warnings if a member or function has the 'TailCall' attribute, but is not being used in a tail recursive way."
featureExtendedFixedBindings,"extended fixed bindings for byref and GetPinnableReference"
featurePreferExtensionMethodOverPlainProperty,"prefer extension method over plain property"
featureWarningIndexedPropertiesGetSetSameType,"Indexed properties getter and setter must have the same type"
featureChkTailCallAttrOnNonRec,"Raises warnings if the 'TailCall' attribute is used on non-recursive functions."
Expand Down
Loading
Loading