diff --git a/src/fsharp/ErrorLogger.fs b/src/fsharp/ErrorLogger.fs index 680e7c57967..5760aef8a2a 100755 --- a/src/fsharp/ErrorLogger.fs +++ b/src/fsharp/ErrorLogger.fs @@ -671,7 +671,7 @@ type public FSharpErrorSeverityOptions = // See https://github.com/Microsoft/visualfsharp/issues/6417, if a compile of the FSharp.Compiler.Services.dll or other compiler -// binary produces exactly 65536 methods then older versions of the compiler raise a bug. If you hit this bug again then try removing -// this. -let dummyMethodFOrBug6417A() = () -let dummyMethodFOrBug6417B() = () +// binary produces exactly 65536 methods then older versions of the compiler raise a bug. If you hit this bug again then try adding +// this back in. +// let dummyMethodFOrBug6417A() = () +// let dummyMethodFOrBug6417B() = () diff --git a/src/fsharp/ExtensionTyping.fs b/src/fsharp/ExtensionTyping.fs index 0c880dd9da3..c075e0dbe96 100755 --- a/src/fsharp/ExtensionTyping.fs +++ b/src/fsharp/ExtensionTyping.fs @@ -415,6 +415,7 @@ module internal ExtensionTyping = member __.IsEnum = x.IsEnum member __.IsClass = x.IsClass member __.IsSealed = x.IsSealed + member __.IsAbstract = x.IsAbstract member __.IsInterface = x.IsInterface member __.GetArrayRank() = x.GetArrayRank() member __.GenericParameterPosition = x.GenericParameterPosition diff --git a/src/fsharp/ExtensionTyping.fsi b/src/fsharp/ExtensionTyping.fsi index 5049fffa778..5c679fe69e1 100755 --- a/src/fsharp/ExtensionTyping.fsi +++ b/src/fsharp/ExtensionTyping.fsi @@ -120,6 +120,7 @@ module internal ExtensionTyping = member IsInterface : bool member IsClass : bool member IsSealed : bool + member IsAbstract : bool member IsPublic : bool member IsNestedPublic : bool member GenericParameterPosition : int diff --git a/src/fsharp/NameResolution.fs b/src/fsharp/NameResolution.fs index baaed61c531..00110213773 100644 --- a/src/fsharp/NameResolution.fs +++ b/src/fsharp/NameResolution.fs @@ -78,7 +78,6 @@ let ActivePatternElemsOfValRef vref = | Some apinfo -> apinfo.ActiveTags |> List.mapi (fun i _ -> APElemRef(apinfo, vref, i)) | None -> [] - /// Try to make a reference to a value in a module. // // mkNestedValRef may fail if the assembly load set is @@ -314,6 +313,7 @@ type FullyQualifiedFlag = | OpenQualified +type UnqualifiedItems = LayeredMap [] /// The environment of information used to resolve names @@ -321,8 +321,8 @@ type NameResolutionEnv = { /// Display environment information for output eDisplayEnv: DisplayEnv - /// Values and Data Tags available by unqualified name - eUnqualifiedItems: LayeredMap + /// Values, functions, methods and other items available by unqualified name + eUnqualifiedItems: UnqualifiedItems /// Data Tags and Active Pattern Tags available by unqualified name ePatItems: NameMap @@ -417,6 +417,12 @@ type NameResolutionEnv = // Helpers to do with extension members //------------------------------------------------------------------------- +/// Indicates if we only need one result or all possible results from a resolution. +[] +type ResultCollectionSettings = + | AllResults + | AtMostOneResult + /// Allocate the next extension method priority. This is an incrementing sequence of integers /// during type checking. let NextExtensionMethodPriority() = uint64 (newStamp()) @@ -488,6 +494,125 @@ let private GetCSharpStyleIndexedExtensionMembersForTyconRef (amap: Import.Impor [] +/// Query the declared properties of a type (including inherited properties) +let IntrinsicPropInfosOfTypeInScope (infoReader: InfoReader) optFilter ad findFlag m ty = + let g = infoReader.g + let amap = infoReader.amap + let pinfos = GetIntrinsicPropInfoSetsOfType infoReader optFilter ad AllowMultiIntfInstantiations.Yes findFlag m ty + let pinfos = pinfos |> ExcludeHiddenOfPropInfos g amap m + pinfos + +/// Select from a list of extension properties +let SelectPropInfosFromExtMembers (infoReader: InfoReader) ad optFilter declaringTy m extMemInfos = + let g = infoReader.g + let amap = infoReader.amap + // NOTE: multiple "open"'s push multiple duplicate values into eIndexedExtensionMembers, hence use a set. + let seen = HashSet(ExtensionMember.Comparer g) + let propCollector = new PropertyCollector(g, amap, m, declaringTy, optFilter, ad) + for emem in extMemInfos do + if seen.Add emem then + match emem with + | FSExtMem (vref, _pri) -> + match vref.MemberInfo with + | None -> () + | Some membInfo -> propCollector.Collect(membInfo, vref) + | ILExtMem _ -> + // No extension properties coming from .NET + () + propCollector.Close() + +/// Query the available extension properties of a type (including extension properties for inherited types) +let ExtensionPropInfosOfTypeInScope collectionSettings (infoReader:InfoReader) (nenv: NameResolutionEnv) optFilter ad m ty = + let g = infoReader.g + + let extMemsDangling = SelectPropInfosFromExtMembers infoReader ad optFilter ty m nenv.eUnindexedExtensionMembers + + if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil extMemsDangling) then + extMemsDangling + else + let extMemsFromHierarchy = + infoReader.GetEntireTypeHierachy(AllowMultiIntfInstantiations.Yes, m, ty) + |> List.collect (fun ty -> + if isAppTy g ty then + let tcref = tcrefOfAppTy g ty + let extMemInfos = nenv.eIndexedExtensionMembers.Find tcref + SelectPropInfosFromExtMembers infoReader ad optFilter ty m extMemInfos + else []) + + extMemsDangling @ extMemsFromHierarchy + +/// Get all the available properties of a type (both intrinsic and extension) +let AllPropInfosOfTypeInScope collectionSettings infoReader nenv optFilter ad findFlag m ty = + IntrinsicPropInfosOfTypeInScope infoReader optFilter ad findFlag m ty + @ ExtensionPropInfosOfTypeInScope collectionSettings infoReader nenv optFilter ad m ty + +/// Get the available methods of a type (both declared and inherited) +let IntrinsicMethInfosOfType (infoReader:InfoReader) optFilter ad allowMultiIntfInst findFlag m ty = + let g = infoReader.g + let amap = infoReader.amap + let minfos = GetIntrinsicMethInfoSetsOfType infoReader optFilter ad allowMultiIntfInst findFlag m ty + let minfos = minfos |> ExcludeHiddenOfMethInfos g amap m + minfos + +/// Select from a list of extension methods +let SelectMethInfosFromExtMembers (infoReader:InfoReader) optFilter apparentTy m extMemInfos = + let g = infoReader.g + // NOTE: multiple "open"'s push multiple duplicate values into eIndexedExtensionMembers + let seen = HashSet(ExtensionMember.Comparer g) + [ + for emem in extMemInfos do + if seen.Add emem then + match emem with + | FSExtMem (vref, pri) -> + match vref.MemberInfo with + | None -> () + | Some membInfo -> + match TrySelectMemberVal g optFilter apparentTy (Some pri) membInfo vref with + | Some m -> yield m + | _ -> () + | ILExtMem (actualParent, minfo, pri) when (match optFilter with None -> true | Some nm -> nm = minfo.LogicalName) -> + // Make a reference to the type containing the extension members + match minfo with + | ILMeth(_, ilminfo, _) -> + yield (MethInfo.CreateILExtensionMeth (infoReader.amap, m, apparentTy, actualParent, Some pri, ilminfo.RawMetadata)) + // F#-defined IL-style extension methods are not seen as extension methods in F# code + | FSMeth(g, _, vref, _) -> + yield (FSMeth(g, apparentTy, vref, Some pri)) +#if !NO_EXTENSIONTYPING + // // Provided extension methods are not yet supported + | ProvidedMeth(amap, providedMeth, _, m) -> + yield (ProvidedMeth(amap, providedMeth, Some pri, m)) +#endif + | DefaultStructCtor _ -> + () + | _ -> () + ] + +/// Query the available extension properties of a methods (including extension methods for inherited types) +let ExtensionMethInfosOfTypeInScope (collectionSettings:ResultCollectionSettings) (infoReader:InfoReader) (nenv: NameResolutionEnv) optFilter m ty = + let extMemsDangling = SelectMethInfosFromExtMembers infoReader optFilter ty m nenv.eUnindexedExtensionMembers + if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil extMemsDangling) then + extMemsDangling + else + let extMemsFromHierarchy = + infoReader.GetEntireTypeHierachy(AllowMultiIntfInstantiations.Yes, m, ty) + |> List.collect (fun ty -> + let g = infoReader.g + if isAppTy g ty then + let tcref = tcrefOfAppTy g ty + let extValRefs = nenv.eIndexedExtensionMembers.Find tcref + SelectMethInfosFromExtMembers infoReader optFilter ty m extValRefs + else []) + extMemsDangling @ extMemsFromHierarchy + +/// Get all the available methods of a type (both intrinsic and extension) +let AllMethInfosOfTypeInScope collectionSettings infoReader nenv optFilter ad findFlag m ty = + let intrinsic = IntrinsicMethInfosOfType infoReader optFilter ad AllowMultiIntfInstantiations.Yes findFlag m ty + if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil intrinsic) then + intrinsic + else + intrinsic @ ExtensionMethInfosOfTypeInScope collectionSettings infoReader nenv optFilter m ty + //------------------------------------------------------------------------- // Helpers to do with building environments //------------------------------------------------------------------------- @@ -504,7 +629,7 @@ type BulkAdd = Yes | No /// bulkAddMode: true when adding the values from the 'open' of a namespace /// or module, when we collapse the value table down to a dictionary. -let AddValRefsToItems (bulkAddMode: BulkAdd) (eUnqualifiedItems: LayeredMap<_, _>) (vrefs: ValRef[]) = +let AddValRefsToItems (bulkAddMode: BulkAdd) (eUnqualifiedItems: UnqualifiedItems) (vrefs: ValRef[]) = // Object model members are not added to the unqualified name resolution environment let vrefs = vrefs |> Array.filter (fun vref -> not vref.IsMember) @@ -616,7 +741,7 @@ let AddUnionCases1 (tab: Map<_, _>) (ucrefs: UnionCaseRef list) = acc.Add (ucref.CaseName, item)) /// Add a set of union cases to the corresponding sub-table of the environment -let AddUnionCases2 bulkAddMode (eUnqualifiedItems: LayeredMap<_, _>) (ucrefs: UnionCaseRef list) = +let AddUnionCases2 bulkAddMode (eUnqualifiedItems: UnqualifiedItems) (ucrefs: UnionCaseRef list) = match bulkAddMode with | BulkAdd.Yes -> let items = @@ -630,6 +755,30 @@ let AddUnionCases2 bulkAddMode (eUnqualifiedItems: LayeredMap<_, _>) (ucrefs: Un let item = Item.UnionCase(GeneralizeUnionCaseRef ucref, false) acc.Add (ucref.CaseName, item)) +let AddStaticContentOfTyconRefToNameEnv (g:TcGlobals) (amap: Import.ImportMap) m (nenv: NameResolutionEnv) (tcref:TyconRef) = + let ty = generalizedTyconRef tcref + let infoReader = InfoReader(g,amap) + let items = + [| let methGroups = + AllMethInfosOfTypeInScope ResultCollectionSettings.AllResults infoReader nenv None AccessorDomain.AccessibleFromSomeFSharpCode 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 AccessorDomain.AccessibleFromSomeFSharpCode 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])) |] + + { nenv with eUnqualifiedItems = nenv.eUnqualifiedItems.AddAndMarkAsCollapsible items } + /// Add any implied contents of a type definition to the environment. let private AddPartsOfTyconRefToNameEnv bulkAddMode ownDefinition (g: TcGlobals) amap m nenv (tcref: TyconRef) = @@ -679,10 +828,14 @@ let private AddPartsOfTyconRefToNameEnv bulkAddMode ownDefinition (g: TcGlobals) | _ -> Item.UnqualifiedType [tcref])) else tab - if isILOrRequiredQualifiedAccess || List.isEmpty ucrefs then - tab - else - AddUnionCases2 bulkAddMode tab ucrefs + + let tab = + if isILOrRequiredQualifiedAccess || List.isEmpty ucrefs then + tab + else + AddUnionCases2 bulkAddMode tab ucrefs + + tab let ePatItems = if isILOrRequiredQualifiedAccess || List.isEmpty ucrefs then @@ -690,12 +843,21 @@ let private AddPartsOfTyconRefToNameEnv bulkAddMode ownDefinition (g: TcGlobals) else AddUnionCases1 nenv.ePatItems ucrefs - { nenv with - eFieldLabels = eFieldLabels - eUnqualifiedItems = eUnqualifiedItems - ePatItems = ePatItems - eIndexedExtensionMembers = eIndexedExtensionMembers - eUnindexedExtensionMembers = eUnindexedExtensionMembers } + let nenv = + { nenv with + eFieldLabels = eFieldLabels + eUnqualifiedItems = eUnqualifiedItems + ePatItems = ePatItems + eIndexedExtensionMembers = eIndexedExtensionMembers + eUnindexedExtensionMembers = eUnindexedExtensionMembers } + + let nenv = + if TryFindFSharpBoolAttribute g g.attrib_AutoOpenAttribute tcref.Attribs = Some true && isStaticClass g tcref then + AddStaticContentOfTyconRefToNameEnv g amap m nenv tcref + else + nenv + + nenv /// Add a set of type definitions to the name resolution environment let AddTyconRefsToNameEnv bulkAddMode ownDefinition g amap m root nenv tcrefs = @@ -817,8 +979,14 @@ and AddModuleOrNamespaceContentsToNameEnv (g: TcGlobals) amap (ad: AccessorDomai // open M1 // // The list contains [M1b; M1a] -and AddModulesAndNamespacesContentsToNameEnv g amap ad m root nenv modrefs = - (modrefs, nenv) ||> List.foldBack (fun modref acc -> AddModuleOrNamespaceContentsToNameEnv g amap ad m root acc modref) +and AddEntitiesContentsToNameEnv g amap ad m root nenv modrefs = + (modrefs, nenv) ||> List.foldBack (fun modref acc -> AddEntityContentsToNameEnv g amap ad m root acc modref) + +and AddEntityContentsToNameEnv g amap ad m root nenv (modref: EntityRef) = + if modref.IsModuleOrNamespace then + AddModuleOrNamespaceContentsToNameEnv g amap ad m root nenv modref + else + AddStaticContentOfTyconRefToNameEnv g amap m nenv modref /// Add a single modules or namespace to the name resolution environment let AddModuleOrNamespaceRefToNameEnv g amap m root ad nenv (modref: EntityRef) = @@ -910,18 +1078,13 @@ let AddResults res1 res2 = let NoResultsOrUsefulErrors = Result [] -/// Indicates if we only need one result or all possible results from a resolution. -[] -type ResultCollectionSettings = -| AllResults -| AtMostOneResult - let rec CollectResults f = function | [] -> NoResultsOrUsefulErrors | [h] -> OneResult (f h) | h :: t -> AddResults (OneResult (f h)) (CollectResults f t) -let rec CollectAtMostOneResult f = function +let rec CollectAtMostOneResult f inputs = + match inputs with | [] -> NoResultsOrUsefulErrors | [h] -> OneResult (f h) | h :: t -> @@ -1828,13 +1991,13 @@ let CheckForTypeLegitimacyAndMultipleGenericTypeAmbiguities //------------------------------------------------------------------------- /// Perform name resolution for an identifier which must resolve to be a namespace or module. -let rec ResolveLongIndentAsModuleOrNamespace sink atMostOne amap m first fullyQualified (nenv: NameResolutionEnv) ad (id: Ident) (rest: Ident list) isOpenDecl = +let rec ResolveLongIndentAsModuleOrNamespaceOrStaticClass sink (atMostOne: ResultCollectionSettings) amap m allowStaticClasses first fullyQualified (nenv: NameResolutionEnv) ad (id:Ident) (rest: Ident list) isOpenDecl = if first && id.idText = MangledGlobalName then match rest with | [] -> error (Error(FSComp.SR.nrGlobalUsedOnlyAsFirstName(), id.idRange)) | id2 :: rest2 -> - ResolveLongIndentAsModuleOrNamespace sink atMostOne amap m false FullyQualified nenv ad id2 rest2 isOpenDecl + ResolveLongIndentAsModuleOrNamespaceOrStaticClass sink atMostOne amap m allowStaticClasses false FullyQualified nenv ad id2 rest2 isOpenDecl else let moduleOrNamespaces = nenv.ModulesAndNamespaces fullyQualified let namespaceNotFound = lazy( @@ -1847,6 +2010,8 @@ let rec ResolveLongIndentAsModuleOrNamespace sink atMostOne amap m first fullyQu UndefinedName(0, FSComp.SR.undefinedNameNamespaceOrModule, id, suggestModulesAndNamespaces)) + // Avoid generating the same error and name suggestion thunk twice It's not clear this is necessary + // since it's just saving an allocation. let mutable moduleNotFoundErrorCache = None let moduleNotFound (modref: ModuleOrNamespaceRef) (mty: ModuleOrNamespaceType) (id: Ident) depth = match moduleNotFoundErrorCache with @@ -1867,35 +2032,68 @@ let rec ResolveLongIndentAsModuleOrNamespace sink atMostOne amap m first fullyQu let occurence = if isOpenDecl then ItemOccurence.Open else ItemOccurence.Use CallNameResolutionSink sink (m, nenv, item, item, emptyTyparInst, occurence, nenv.DisplayEnv, ad) - match moduleOrNamespaces.TryGetValue id.idText with - | true, modrefs -> + let erefs = + let modrefs = + match moduleOrNamespaces.TryGetValue id.idText with + | true, modrefs -> modrefs + | _ -> [] + + let tcrefs = + if allowStaticClasses then + LookupTypeNameInEnvNoArity fullyQualified id.idText nenv |> List.filter (isStaticClass amap.g) + else [] + + modrefs @ tcrefs + + if not erefs.IsEmpty then /// Look through the sub-namespaces and/or modules - let rec look depth (modref: ModuleOrNamespaceRef) (mty: ModuleOrNamespaceType) (lid: Ident list) = + let rec look depth allowStaticClasses (modref: ModuleOrNamespaceRef) (lid: Ident list) = + let mty = modref.ModuleOrNamespaceType match lid with - | [] -> success (depth, modref, mty) - | id :: rest -> - match mty.ModulesAndNamespacesByDemangledName.TryGetValue id.idText with - | true, mspec -> - let subref = modref.NestedTyconRef mspec - if IsEntityAccessible amap m ad subref then - notifyNameResolution subref id.idRange - look (depth+1) subref mspec.ModuleOrNamespaceType rest - else - moduleNotFound modref mty id depth - | _ -> moduleNotFound modref mty id depth - + | [] -> + success [ (depth, modref, mty) ] - modrefs |> CollectResults2 atMostOne (fun modref -> - if IsEntityAccessible amap m ad modref then - notifyNameResolution modref id.idRange - look 1 modref modref.ModuleOrNamespaceType rest + | id :: rest -> + let especs = + let mspecs = + match mty.ModulesAndNamespacesByDemangledName.TryGetValue id.idText with + | true, res -> [res] + | _ -> [] + let tspecs = + if allowStaticClasses then + LookupTypeNameInEntityNoArity id.idRange id.idText mty + |> List.filter (modref.NestedTyconRef >> isStaticClass amap.g) + else [] + mspecs @ tspecs + + if not especs.IsEmpty then + especs + |> List.map (fun espec -> + let subref = modref.NestedTyconRef espec + if IsEntityAccessible amap m ad subref then + notifyNameResolution subref id.idRange + let allowStaticClasses = allowStaticClasses && (subref.IsModuleOrNamespace || isStaticClass amap.g subref) + look (depth+1) allowStaticClasses subref rest + else + moduleNotFound modref mty id depth) + |> List.reduce AddResults + else + moduleNotFound modref mty id depth + + erefs + |> List.map (fun eref -> + if IsEntityAccessible amap m ad eref then + notifyNameResolution eref id.idRange + let allowStaticClasses = allowStaticClasses && (eref.IsModuleOrNamespace || isStaticClass amap.g eref) + look 1 allowStaticClasses eref rest else raze (namespaceNotFound.Force())) - | _ -> raze (namespaceNotFound.Force()) - + |> List.reduce AddResults + else + raze (namespaceNotFound.Force()) let ResolveLongIndentAsModuleOrNamespaceThen sink atMostOne amap m fullyQualified (nenv: NameResolutionEnv) ad id rest isOpenDecl f = - match ResolveLongIndentAsModuleOrNamespace sink ResultCollectionSettings.AllResults amap m true fullyQualified nenv ad id [] isOpenDecl with + match ResolveLongIndentAsModuleOrNamespaceOrStaticClass sink ResultCollectionSettings.AllResults amap m false true fullyQualified nenv ad id [] isOpenDecl with | Result modrefs -> match rest with | [] -> error(Error(FSComp.SR.nrUnexpectedEmptyLongId(), id.idRange)) @@ -1943,126 +2141,6 @@ let ResolveObjectConstructor (ncenv: NameResolver) edenv m ad ty = // Bind the "." notation (member lookup or lookup in a type) //------------------------------------------------------------------------- -/// Query the declared properties of a type (including inherited properties) -let IntrinsicPropInfosOfTypeInScope (infoReader:InfoReader) optFilter ad findFlag m ty = - let g = infoReader.g - let amap = infoReader.amap - let pinfos = GetIntrinsicPropInfoSetsOfType infoReader optFilter ad AllowMultiIntfInstantiations.Yes findFlag m ty - let pinfos = pinfos |> ExcludeHiddenOfPropInfos g amap m - pinfos - -/// Select from a list of extension properties -let SelectPropInfosFromExtMembers (infoReader:InfoReader) ad optFilter declaringTy m extMemInfos = - let g = infoReader.g - let amap = infoReader.amap - // NOTE: multiple "open"'s push multiple duplicate values into eIndexedExtensionMembers, hence setify. - let seen = HashSet(ExtensionMember.Comparer g) - let propCollector = new PropertyCollector(g, amap, m, declaringTy, optFilter, ad) - for emem in extMemInfos do - if seen.Add emem then - match emem with - | FSExtMem (vref, _pri) -> - match vref.MemberInfo with - | None -> () - | Some membInfo -> propCollector.Collect(membInfo, vref) - | ILExtMem _ -> - // No extension properties coming from .NET - () - propCollector.Close() - -/// Query the available extension properties of a type (including extension properties for inherited types) -let ExtensionPropInfosOfTypeInScope collectionSettings (infoReader:InfoReader) (nenv: NameResolutionEnv) optFilter ad m ty = - let g = infoReader.g - - let extMemsDangling = SelectPropInfosFromExtMembers infoReader ad optFilter ty m nenv.eUnindexedExtensionMembers - - if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil extMemsDangling) then - extMemsDangling - else - let extMemsFromHierarchy = - infoReader.GetEntireTypeHierachy(AllowMultiIntfInstantiations.Yes,m,ty) - |> List.collect (fun ty -> - if isAppTy g ty then - let tcref = tcrefOfAppTy g ty - let extMemInfos = nenv.eIndexedExtensionMembers.Find tcref - SelectPropInfosFromExtMembers infoReader ad optFilter ty m extMemInfos - else []) - - extMemsDangling @ extMemsFromHierarchy - -/// Get all the available properties of a type (both intrinsic and extension) -let AllPropInfosOfTypeInScope collectionSettings infoReader nenv optFilter ad findFlag m ty = - IntrinsicPropInfosOfTypeInScope infoReader optFilter ad findFlag m ty - @ ExtensionPropInfosOfTypeInScope collectionSettings infoReader nenv optFilter ad m ty - -/// Get the available methods of a type (both declared and inherited) -let IntrinsicMethInfosOfType (infoReader:InfoReader) optFilter ad allowMultiIntfInst findFlag m ty = - let g = infoReader.g - let amap = infoReader.amap - let minfos = GetIntrinsicMethInfoSetsOfType infoReader optFilter ad allowMultiIntfInst findFlag m ty - let minfos = minfos |> ExcludeHiddenOfMethInfos g amap m - minfos - -/// Select from a list of extension methods -let SelectMethInfosFromExtMembers (infoReader: InfoReader) optFilter apparentTy m extMemInfos = - let g = infoReader.g - // NOTE: multiple "open"'s push multiple duplicate values into eIndexedExtensionMembers - let seen = HashSet(ExtensionMember.Comparer g) - [ - for emem in extMemInfos do - if seen.Add emem then - match emem with - | FSExtMem (vref, pri) -> - match vref.MemberInfo with - | None -> () - | Some membInfo -> - match TrySelectMemberVal g optFilter apparentTy (Some pri) membInfo vref with - | Some m -> yield m - | _ -> () - | ILExtMem (actualParent, minfo, pri) when (match optFilter with None -> true | Some nm -> nm = minfo.LogicalName) -> - // Make a reference to the type containing the extension members - match minfo with - | ILMeth(_, ilminfo, _) -> - yield (MethInfo.CreateILExtensionMeth (infoReader.amap, m, apparentTy, actualParent, Some pri, ilminfo.RawMetadata)) - // F#-defined IL-style extension methods are not seen as extension methods in F# code - | FSMeth(g, _, vref, _) -> - yield (FSMeth(g, apparentTy, vref, Some pri)) -#if !NO_EXTENSIONTYPING - // // Provided extension methods are not yet supported - | ProvidedMeth(amap, providedMeth, _, m) -> - yield (ProvidedMeth(amap, providedMeth, Some pri, m)) -#endif - | DefaultStructCtor _ -> - () - | _ -> () - ] - -/// Query the available extension properties of a methods (including extension methods for inherited types) -let ExtensionMethInfosOfTypeInScope (collectionSettings:ResultCollectionSettings) (infoReader:InfoReader) (nenv: NameResolutionEnv) optFilter m ty = - let extMemsDangling = SelectMethInfosFromExtMembers infoReader optFilter ty m nenv.eUnindexedExtensionMembers - if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil extMemsDangling) then - extMemsDangling - else - let extMemsFromHierarchy = - infoReader.GetEntireTypeHierachy(AllowMultiIntfInstantiations.Yes,m,ty) - |> List.collect (fun ty -> - let g = infoReader.g - if isAppTy g ty then - let tcref = tcrefOfAppTy g ty - let extValRefs = nenv.eIndexedExtensionMembers.Find tcref - SelectMethInfosFromExtMembers infoReader optFilter ty m extValRefs - else []) - extMemsDangling @ extMemsFromHierarchy - -/// Get all the available methods of a type (both intrinsic and extension) -let AllMethInfosOfTypeInScope collectionSettings infoReader nenv optFilter ad findFlag m ty = - let intrinsic = IntrinsicMethInfosOfType infoReader optFilter ad AllowMultiIntfInstantiations.Yes findFlag m ty - if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil intrinsic) then - intrinsic - else - intrinsic @ ExtensionMethInfosOfTypeInScope collectionSettings infoReader nenv optFilter m ty - - /// Used to report an error condition where name resolution failed due to an indeterminate type exception IndeterminateType of range @@ -3970,6 +4048,7 @@ let rec ResolvePartialLongIdentPrim (ncenv: NameResolver) (nenv: NameResolutionE ResolvePartialLongIdentInModuleOrNamespace ncenv nenv isApplicableMeth m ad modref rest allowObsolete else []) + // Look for values called 'id' that accept the dot-notation let values, isItemVal = (match nenv.eUnqualifiedItems.TryGetValue id with @@ -4130,6 +4209,7 @@ and ResolvePartialLongIdentToClassOrRecdFieldsImpl (ncenv: NameResolver) (nenv: ResolvePartialLongIdentInModuleOrNamespaceForRecordFields ncenv nenv m ad modref rest allowObsolete else []) + let qualifiedFields = match rest with | [] -> diff --git a/src/fsharp/NameResolution.fsi b/src/fsharp/NameResolution.fsi index 8ec9caedc76..4d809d435a3 100755 --- a/src/fsharp/NameResolution.fsi +++ b/src/fsharp/NameResolution.fsi @@ -201,7 +201,7 @@ val internal AddModuleOrNamespaceRefsToNameEnv : TcGlobals -> val internal AddModuleOrNamespaceRefToNameEnv : TcGlobals -> ImportMap -> range -> bool -> AccessorDomain -> NameResolutionEnv -> ModuleOrNamespaceRef -> NameResolutionEnv /// Add a list of modules or namespaces to the name resolution environment -val internal AddModulesAndNamespacesContentsToNameEnv : TcGlobals -> ImportMap -> AccessorDomain -> range -> bool -> NameResolutionEnv -> ModuleOrNamespaceRef list -> NameResolutionEnv +val internal AddEntitiesContentsToNameEnv : TcGlobals -> ImportMap -> AccessorDomain -> range -> bool -> NameResolutionEnv -> ModuleOrNamespaceRef list -> NameResolutionEnv /// A flag which indicates if it is an error to have two declared type parameters with identical names /// in the name resolution environment. @@ -468,8 +468,8 @@ type PermitDirectReferenceToGeneratedType = | Yes | No -/// Resolve a long identifier to a namespace or module. -val internal ResolveLongIndentAsModuleOrNamespace : TcResultsSink -> ResultCollectionSettings -> Import.ImportMap -> range -> bool -> FullyQualifiedFlag -> NameResolutionEnv -> AccessorDomain -> Ident -> Ident list -> isOpenDecl: bool -> ResultOrException<(int * ModuleOrNamespaceRef * ModuleOrNamespaceType) list > +/// Resolve a long identifier to a namespace, module or static class. +val internal ResolveLongIndentAsModuleOrNamespaceOrStaticClass : TcResultsSink -> ResultCollectionSettings -> Import.ImportMap -> range -> allowStaticClasses: bool -> first: bool -> FullyQualifiedFlag -> NameResolutionEnv -> AccessorDomain -> Ident -> Ident list -> isOpenDecl: bool -> ResultOrException<(int * ModuleOrNamespaceRef * ModuleOrNamespaceType) list > /// Resolve a long identifier to an object constructor. val internal ResolveObjectConstructor : NameResolver -> DisplayEnv -> range -> AccessorDomain -> TType -> ResultOrException diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs index 55436c91843..90a833da230 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -8940,3 +8940,19 @@ let isThreadOrContextStatic g attrs = let mkUnitDelayLambda (g: TcGlobals) m e = let uv, _ = mkCompGenLocal m "unitVar" g.unit_ty mkLambda m uv (e, tyOfExpr g e) + + +let isStaticClass (g:TcGlobals) (x: EntityRef) = + not x.IsModuleOrNamespace && + x.TyparsNoRange.IsEmpty && + ((x.IsILTycon && + x.ILTyconRawMetadata.IsSealed && + x.ILTyconRawMetadata.IsAbstract) +#if !NO_EXTENSIONTYPING + || (x.IsProvided && + match x.TypeReprInfo with + | TProvidedTypeExtensionPoint info -> info.IsSealed && info.IsAbstract + | _ -> false) +#endif + || (not x.IsILTycon && not x.IsProvided && HasFSharpAttribute g g.attrib_AbstractClassAttribute x.Attribs)) && + not (HasFSharpAttribute g g.attrib_RequireQualifiedAccessAttribute x.Attribs) diff --git a/src/fsharp/TastOps.fsi b/src/fsharp/TastOps.fsi index 46088de6bd2..01e2070c419 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -2295,3 +2295,4 @@ val isThreadOrContextStatic: TcGlobals -> Attrib list -> bool val mkUnitDelayLambda: TcGlobals -> range -> Expr -> Expr +val isStaticClass: g: TcGlobals -> tcref: TyconRef -> bool \ No newline at end of file diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 2a1df70149b..d39a5b9219c 100644 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -370,11 +370,11 @@ let AddLocalTyconsAndReport tcSink scopem g amap m tycons env = CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights) env -/// Adjust the TcEnv to account for opening the set of modules and namespaces implied by an `open` declaration -let OpenModulesOrNamespaces tcSink g amap scopem root env mvvs openDeclaration = +/// Adjust the TcEnv to account for opening the set of modules, namespaces or static classes implied by an `open` declaration +let OpenEntities tcSink g amap scopem root env mvvs openDeclaration = let env = if isNil mvvs then env else - { env with eNameResEnv = AddModulesAndNamespacesContentsToNameEnv g amap env.eAccessRights scopem root env.eNameResEnv mvvs } + { env with eNameResEnv = AddEntitiesContentsToNameEnv g amap env.eAccessRights scopem root env.eNameResEnv mvvs } CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights) CallOpenDeclarationSink tcSink openDeclaration env @@ -644,11 +644,11 @@ let ImplicitlyOpenOwnNamespace tcSink g amap scopem enclosingNamespacePath env = match enclosingNamespacePathToOpen with | id :: rest -> let ad = env.eAccessRights - match ResolveLongIndentAsModuleOrNamespace tcSink ResultCollectionSettings.AllResults amap scopem true OpenQualified env.eNameResEnv ad id rest true with + match ResolveLongIndentAsModuleOrNamespaceOrStaticClass tcSink ResultCollectionSettings.AllResults amap scopem true true OpenQualified env.eNameResEnv ad id rest true with | Result modrefs -> let modrefs = List.map p23 modrefs let openDecl = OpenDeclaration.Create (enclosingNamespacePathToOpen, modrefs, scopem, true) - OpenModulesOrNamespaces tcSink g amap scopem false env modrefs openDecl + OpenEntities tcSink g amap scopem false env modrefs openDecl | Exception _ -> env | _ -> env @@ -6892,7 +6892,7 @@ and TcConstExpr cenv overallTy env m tpenv c = let expr = let modName = "NumericLiteral" + suffix let ad = env.eAccessRights - match ResolveLongIndentAsModuleOrNamespace cenv.tcSink ResultCollectionSettings.AtMostOneResult cenv.amap m true OpenQualified env.eNameResEnv ad (ident (modName, m)) [] false with + match ResolveLongIndentAsModuleOrNamespaceOrStaticClass cenv.tcSink ResultCollectionSettings.AtMostOneResult cenv.amap m true true OpenQualified env.eNameResEnv ad (ident (modName, m)) [] false with | Result [] | Exception _ -> error(Error(FSComp.SR.tcNumericLiteralRequiresModule modName, m)) | Result ((_, mref, _) :: _) -> @@ -8719,7 +8719,7 @@ and TcNameOfExpr cenv env tpenv (synArg: SynExpr) = | LongOrSingleIdent (false, (LongIdentWithDots(longId, _) as lidd), _, _) when longId.Length > 0 -> let ad = env.eAccessRights let id, rest = List.headAndTail longId - match ResolveLongIndentAsModuleOrNamespace cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m true OpenQualified env.eNameResEnv ad id rest true with + match ResolveLongIndentAsModuleOrNamespaceOrStaticClass cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m false true OpenQualified env.eNameResEnv ad id rest true with | Result modref when delayed.IsEmpty && modref |> List.exists (p23 >> IsEntityAccessible cenv.amap m ad) -> () // resolved to a module or namespace, done with checks | _ -> @@ -12586,19 +12586,19 @@ let TcTyconMemberSpecs cenv env containerInfo declKind tpenv (augSpfn: SynMember // Bind 'open' declarations //------------------------------------------------------------------------- -let TcModuleOrNamespaceLidAndPermitAutoResolve tcSink env amap (longId: Ident list) = +let TcOpenLidAndPermitAutoResolve tcSink env amap (longId : Ident list) = let ad = env.eAccessRights match longId with | [] -> [] | id :: rest -> let m = longId |> List.map (fun id -> id.idRange) |> List.reduce unionRanges - match ResolveLongIndentAsModuleOrNamespace tcSink ResultCollectionSettings.AllResults amap m true OpenQualified env.eNameResEnv ad id rest true with + match ResolveLongIndentAsModuleOrNamespaceOrStaticClass tcSink ResultCollectionSettings.AllResults amap m true true OpenQualified env.eNameResEnv ad id rest true with | Result res -> res | Exception err -> errorR(err); [] let TcOpenDecl tcSink (g: TcGlobals) amap m scopem env (longId: Ident list) = - match TcModuleOrNamespaceLidAndPermitAutoResolve tcSink env amap longId with + match TcOpenLidAndPermitAutoResolve tcSink env amap longId with | [] -> env | modrefs -> @@ -12650,7 +12650,7 @@ let TcOpenDecl tcSink (g: TcGlobals) amap m scopem env (longId: Ident list) = modrefs |> List.iter (fun modref -> CheckEntityAttributes g modref m |> CommitOperationResult) let openDecl = OpenDeclaration.Create (longId, modrefs, scopem, false) - let env = OpenModulesOrNamespaces tcSink g amap scopem false env modrefs openDecl + let env = OpenEntities tcSink g amap scopem false env modrefs openDecl env @@ -14125,7 +14125,7 @@ module MutRecBindingChecking = let resolved = match p with | [] -> Result [] - | id :: rest -> ResolveLongIndentAsModuleOrNamespace cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m true OpenQualified env.eNameResEnv ad id rest false + | id :: rest -> ResolveLongIndentAsModuleOrNamespaceOrStaticClass cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m false true OpenQualified env.eNameResEnv ad id rest false let mvvs = ForceRaise resolved if isNil mvvs then env else let modrefs = mvvs |> List.map p23 @@ -16952,7 +16952,7 @@ let rec TcSignatureElementNonMutRec cenv parent typeNames endm (env: TcEnv) synS let resolved = match p with | [] -> Result [] - | id :: rest -> ResolveLongIndentAsModuleOrNamespace cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m true OpenQualified env.eNameResEnv ad id rest false + | id :: rest -> ResolveLongIndentAsModuleOrNamespaceOrStaticClass cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m false true OpenQualified env.eNameResEnv ad id rest false let mvvs = ForceRaise resolved let scopem = unionRanges m endm let unfilteredModrefs = mvvs |> List.map p23 @@ -17506,7 +17506,7 @@ let ApplyAssemblyLevelAutoOpenAttributeToTcEnv g amap (ccu: CcuThunk) scopem env | ValueNone -> warn() | ValueSome _ -> let openDecl = OpenDeclaration.Create ([], [modref], scopem, false) - OpenModulesOrNamespaces TcResultsSink.NoSink g amap scopem root env [modref] openDecl + OpenEntities TcResultsSink.NoSink g amap scopem root env [modref] openDecl // Add the CCU and apply the "AutoOpen" attributes let AddCcuToTcEnv(g, amap, scopem, env, assemblyName, ccu, autoOpens, internalsVisible) = diff --git a/src/fsharp/tast.fs b/src/fsharp/tast.fs index dd8f0506f70..d59c33f700f 100644 --- a/src/fsharp/tast.fs +++ b/src/fsharp/tast.fs @@ -1446,7 +1446,10 @@ and IsSealed: bool /// A flag read eagerly from the provided type and used to compute basic properties of the type definition. - IsInterface: bool + IsAbstract: bool + + /// A flag read eagerly from the provided type and used to compute basic properties of the type definition. + IsInterface: bool /// A flag read eagerly from the provided type and used to compute basic properties of the type definition. IsStructOrEnum: bool @@ -2009,6 +2012,7 @@ and Construct = IsStructOrEnum = st.PUntaint((fun st -> st.IsValueType || st.IsEnum), m) IsInterface = st.PUntaint((fun st -> st.IsInterface), m) IsSealed = st.PUntaint((fun st -> st.IsSealed), m) + IsAbstract = st.PUntaint((fun st -> st.IsAbstract), m) IsClass = st.PUntaint((fun st -> st.IsClass), m) IsErased = isErased IsSuppressRelocate = isSuppressRelocate } diff --git a/tests/EndToEndBuildTests/ProvidedTypes/ProvidedTypes.fs b/tests/EndToEndBuildTests/ProvidedTypes/ProvidedTypes.fs index 45974519909..e7a924bcfaa 100644 --- a/tests/EndToEndBuildTests/ProvidedTypes/ProvidedTypes.fs +++ b/tests/EndToEndBuildTests/ProvidedTypes/ProvidedTypes.fs @@ -4026,7 +4026,7 @@ namespace ProviderImplementation.ProvidedTypes.AssemblyReader // Emit compressed untagged integer member buf.EmitZUntaggedIndex big idx = if big then buf.EmitInt32 idx - elif idx > 0xffff then failwith "EmitZUntaggedIndex: too big for small address or simple index" + elif idx > 0xffff then failwithf "EmitZUntaggedIndex: too big for small address or simple index, idx = %d, big = %A, stack = %s" idx big ((new System.Diagnostics.StackTrace()).ToString()) else buf.EmitInt32AsUInt16 idx // Emit compressed tagged integer diff --git a/tests/fsharp/core/longnames/test.fsx b/tests/fsharp/core/longnames/test.fsx index 577dc547a6d..3692043c7dd 100644 --- a/tests/fsharp/core/longnames/test.fsx +++ b/tests/fsharp/core/longnames/test.fsx @@ -688,6 +688,66 @@ module rec Ok23 = test "lkneecec09iew23" (typeof.FullName.Contains("AModule") ) + +[] +type MyMath() = + static member Min(a: double, b: double) = System.Math.Min(a, b) + static member Min(a: int, b: int) = System.Math.Min(a, b) + +[] +type AutoOpenMyMath() = + static member AutoMin(a: double, b: double) = System.Math.Min(a, b) + static member AutoMin(a: int, b: int) = System.Math.Min(a, b) + +[] +type NotAllowedToOpen() = + static member QualifiedMin(a: double, b: double) = System.Math.Min(a, b) + static member QualifiedMin(a: int, b: int) = System.Math.Min(a, b) + +module OpenSystemMathOnce = + + open System.Math + let x = Min(1.0, 2.0) + test "vwejhweoiu" (x = 1.0) + + +module OpenSystemMathTwice = + + open System.Math + let x = Min(1.0, 2.0) + + open System.Math + let x2 = Min(2.0, 1.0) + + test "vwejhweoiu2" (x2 = 1.0) + +module OpenMyMathOnce = + + open MyMath + let x = Min(1.0, 2.0) + let x2 = Min(1, 2) + + test "vwejhweoiu2" (x = 1.0) + test "vwejhweoiu3" (x2 = 1) + +module DontOpenAutoMath = + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2) + + test "vwejhweoiu2" (x = 1.0) + test "vwejhweoiu3" (x2 = 1) + +module OpenAutoMath = + open AutoOpenMyMath + //open NotAllowedToOpen + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2) + + test "vwejhweoiu2" (x = 1.0) + test "vwejhweoiu3" (x2 = 1) + #if TESTS_AS_APP let RUN() = !failures #else diff --git a/tests/service/EditorTests.fs b/tests/service/EditorTests.fs index 63406f09cb4..69b9e407645 100644 --- a/tests/service/EditorTests.fs +++ b/tests/service/EditorTests.fs @@ -1288,16 +1288,6 @@ let ``Test TPProject param info`` () = #endif // TEST_TP_PROJECTS -#if EXE - -``Intro test`` () -//``Test TPProject all symbols`` () -//``Test TPProject errors`` () -//``Test TPProject quick info`` () -//``Test TPProject param info`` () -``Basic cancellation test`` () -``Intro test`` () -#endif [] let ``FSharpField.IsNameGenerated`` () = diff --git a/vsintegration/tests/UnitTests/CompletionProviderTests.fs b/vsintegration/tests/UnitTests/CompletionProviderTests.fs index 91339ffde4a..97ea7cbeff8 100644 --- a/vsintegration/tests/UnitTests/CompletionProviderTests.fs +++ b/vsintegration/tests/UnitTests/CompletionProviderTests.fs @@ -444,6 +444,14 @@ List(). "ExtensionMeth"] VerifyCompletionListExactly(fileContents, "List().", expected) +[] +let ``Completion for open contains namespaces and static types``() = + let fileContents = """ +open System.Ma +""" + let expected = ["Management"; "Math"] // both namespace and static type + VerifyCompletionList(fileContents, "System.Ma", expected, []) + [] let ``No completion on type name at declaration site``() = let fileContents = """ diff --git a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs index 9e58d24c1f1..a1ea76e7172 100644 --- a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs +++ b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs @@ -3639,8 +3639,8 @@ let x = query { for bbbb in abbbbc(*D0*) do AssertAutoCompleteContains [ "open System." ] "." // marker - [ "Collections" ] // should contain (namespace) - [ "Console" ] // should not contain (type) + [ "Collections"; "Console" ] // should contain (namespace, static type) + [ "Int32" ] // should not contain (non-static type) [] member public this.``OpenNamespaceOrModule.CompletionOnlyContainsNamespaceOrModule.Case2``() =