Skip to content
Closed
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
122 changes: 97 additions & 25 deletions src/fsharp/NameResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -775,36 +775,108 @@ let AddStaticContentOfTyconRefToNameEnv (g:TcGlobals) (amap: Import.ImportMap) a
if amap.g.langVersion.SupportsFeature LanguageFeature.OpenStaticClasses then
let ty = generalizedTyconRef tcref
let infoReader = InfoReader(g,amap)
let items =
[| let methGroups =
AllMethInfosOfTypeInScope ResultCollectionSettings.AllResults infoReader nenv None ad PreferOverrides m ty
|> List.groupBy (fun m -> m.LogicalName)

for (methName, methGroup) in methGroups do
let methGroup = methGroup |> List.filter (fun m -> not m.IsInstance && not m.IsClassConstructor)
if not methGroup.IsEmpty then
yield KeyValuePair(methName, Item.MethodGroup(methName, methGroup, None))

let propInfos =
AllPropInfosOfTypeInScope ResultCollectionSettings.AllResults infoReader nenv None ad PreferOverrides m ty
|> List.groupBy (fun m -> m.PropertyName)

for (propName, propInfos) in propInfos do
let propInfos = propInfos |> List.filter (fun m -> m.IsStatic)
for propInfo in propInfos do
yield KeyValuePair(propName , Item.Property(propName,[propInfo]))

let getMethItems () =
[ let methGroups =
AllMethInfosOfTypeInScope ResultCollectionSettings.AllResults infoReader nenv None AccessorDomain.AccessibleFromSomeFSharpCode PreferOverrides m ty
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to pass ad here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoops

|> List.groupBy (fun m -> m.LogicalName)

for (methName, methGroup) in methGroups do
let methGroup = methGroup |> List.filter (fun m -> not m.IsInstance && not m.IsClassConstructor)
if not methGroup.IsEmpty then
yield KeyValuePair(methName, Item.MethodGroup(methName, methGroup, None))
]

let getPropItems () =
[ let propInfos =
AllPropInfosOfTypeInScope ResultCollectionSettings.AllResults infoReader nenv None AccessorDomain.AccessibleFromSomeFSharpCode PreferOverrides m ty
|> List.groupBy (fun m -> m.PropertyName)

let fields =
for (propName, propInfos) in propInfos do
let propInfos = propInfos |> List.filter (fun m -> m.IsStatic)
for propInfo in propInfos do
yield KeyValuePair(propName , Item.Property(propName,[propInfo]))
]

let getFieldItems () =
[ let fields =
infoReader.GetILFieldInfosOfType(None, ad, m, ty)
|> List.groupBy (fun f -> f.FieldName)

for (fieldName, fieldInfos) in fields do
let fieldInfos = fieldInfos |> List.filter (fun fi -> fi.IsStatic)
for fieldInfo in fieldInfos do
yield KeyValuePair(fieldName, Item.ILField(fieldInfo))
|]
for (fieldName, fieldInfos) in fields do
let fieldInfos = fieldInfos |> List.filter (fun fi -> fi.IsStatic)
for fieldInfo in fieldInfos do
yield KeyValuePair(fieldName, Item.ILField(fieldInfo))
]

let getEventItems () =
[ let events =
infoReader.GetEventInfosOfType(None, ad, m, ty)
|> List.groupBy (fun e -> e.EventName)

{ nenv with eUnqualifiedItems = nenv.eUnqualifiedItems.AddAndMarkAsCollapsible items }
for (eventName, eventInfos) in events do
let eventInfos = eventInfos |> List.filter (fun e -> e.IsStatic)
for eventInfo in eventInfos do
yield KeyValuePair(eventName, Item.Event(eventInfo))
]

let items =
[
let propAndMethGroups =
getPropItems () @ getMethItems ()
|> List.groupBy (fun pair -> pair.Key)

for (_, items) in propAndMethGroups do
// This is to handle the current behavior with qualified extension members:
// Extension properties will shadow all extension methods that share the same name no matter the order in which the extensions are opened from modules.
// TODO: What happens with CSharp-style extension methods?
let sortedItems =
items
|> List.sortBy (fun pair ->
match pair.Value with
| Item.Property (_, [propInfo]) -> not propInfo.IsExtensionMember
| Item.MethodGroup (_, methGroup, _) -> methGroup |> List.exists (fun x -> not x.IsExtensionMember)
| _ -> false)
match sortedItems with
| item :: _ -> yield item
| _ -> ()

yield! getFieldItems ()
yield! getEventItems ()
]

{ nenv with
eUnqualifiedItems =
(nenv.eUnqualifiedItems, items)
||> List.fold (fun x (KeyValue(k, v)) ->
match x.TryGetValue k with
| true, existingItem ->
match existingItem, v with

// Combine methods groups. This allows overloading on methods from different classes. Mimics C# behavior.
| Item.MethodGroup (_, minfosCurrent, None), Item.MethodGroup (_, minfosNew, None) ->
let minfos =
(minfosNew, minfosCurrent)
||> List.fold (fun minfos minfo1 ->
// Shadow methods with the same signature.
// F# specific behavior; the order of opening is significant and ambiguities are shadowed.
// In C#, an error would occur and asks the developer to resolve the ambiguity.
// We allow UoM (units of measure) to be significant in overloading here.
if minfosCurrent |> List.exists (fun minfo2 -> MethInfosEquivByNameAndSig Erasure.EraseNone true g amap m minfo1 minfo2) then
minfos
else
minfo1 :: minfos
)
x.Add(k, Item.MethodGroup (k, minfos, None))

// Methods will always shadow properties, events, and fields with the same name; order of opening does not matter in this case.
// This is to mimic the C# behavior of opening multiple static classes.
| Item.MethodGroup _, Item.Property _
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fine, will need test cases and RFC update

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, for sure. This is to mimic opening multiple static classes in C# and what their behavior is.

| Item.MethodGroup _, Item.Event _
| Item.MethodGroup _, Item.ILField _ -> x
| _ -> x.Add(k, v)
| _ -> x.Add(k, v))
}
else
nenv

Expand Down