Skip to content

Commit

Permalink
Merge branch 'main' into fix-16343
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarfgp authored Jan 24, 2025
2 parents 0b664a9 + c4d36d6 commit cddbb7a
Show file tree
Hide file tree
Showing 40 changed files with 800 additions and 220 deletions.
6 changes: 3 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
{
"name": "F#",
"image": "mcr.microsoft.com/dotnet/sdk:9.0.100",
"image": "mcr.microsoft.com/dotnet/sdk:9.0.102",
"features": {
"ghcr.io/devcontainers/features/common-utils:2.5.1": {},
"ghcr.io/devcontainers/features/common-utils:2.5.2": {},
"ghcr.io/devcontainers/features/git:1.3.2": {},
"ghcr.io/devcontainers/features/github-cli:1.0.13": {},
"ghcr.io/devcontainers/features/dotnet:2.1.3": {}
"ghcr.io/devcontainers/features/dotnet:2.2.0": {}
},
"hostRequirements": {
"cpus": 2,
Expand Down
7 changes: 4 additions & 3 deletions docs/release-notes/.FSharp.Compiler.Service/9.0.300.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
### Fixed

* Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877))
* Fix internal error when missing measure attribute in an unsolved measure typar. ([Issue #7491](https://github.com/dotnet/fsharp/issues/7491), [PR #18234](https://github.com/dotnet/fsharp/pull/18234)==
* Set `Cancellable.token` from async computation ([Issue #18235](https://github.com/dotnet/fsharp/issues/18235), [PR #18238](https://github.com/dotnet/fsharp/pull/18238))

### Added

* Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241))

### Changed

* FSharpCheckFileResults.ProjectContext.ProjectOptions will not be available when using the experimental Transparent Compiler feature. ([PR #18205](https://github.com/dotnet/fsharp/pull/18205))
* Update `Obsolete` attribute checking to account for `DiagnosticId` and `UrlFormat` properties. ([PR #18224](https://github.com/dotnet/fsharp/pull/18224))

### Breaking Changes

3 changes: 2 additions & 1 deletion eng/DotNetBuild.props
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<PropertyGroup>
<SourceBuildBootstrapTfmArg Condition="$(SourceBuildBootstrapTfm) != ''">--tfm $(SourceBuildBootstrapTfm)</SourceBuildBootstrapTfmArg>
<DotNetBuildUseMonoRuntime Condition="'$(DotNetBuildUseMonoRuntime)' == ''">false</DotNetBuildUseMonoRuntime>
<SourceBuildBootstrapRestoreConfigFileArg Condition="'$(RestoreConfigFile)' != ''" >/p:RestoreConfigFile=$(RestoreConfigFile)</SourceBuildBootstrapRestoreConfigFileArg>
</PropertyGroup>

<!-- this runs the source-build bootstrap path as described in https://github.com/dotnet/fsharp/blob/95df49e380ea8dbf33653fa4209f89dba29413f5/eng/build.sh#L247
Expand All @@ -41,7 +42,7 @@
-bl enables the binlogs for the tools and Proto builds, which make debugging failures here easier
-->
<Exec
Command="./build.sh --bootstrap --skipBuild -bl $(SourceBuildBootstrapTfmArg) /p:DotNetBuildUseMonoRuntime=$(DotNetBuildUseMonoRuntime) /p:DotNetBuildSourceOnly=true /p:DotNetBuildInnerRepo=true /p:DotNetBuildRepo=true /p:DotNetBuildOrchestrator=$(DotNetBuildOrchestrator)"
Command="./build.sh --bootstrap --skipBuild -bl $(SourceBuildBootstrapTfmArg) $(SourceBuildBootstrapRestoreConfigFileArg) /p:DotNetBuildUseMonoRuntime=$(DotNetBuildUseMonoRuntime) /p:DotNetBuildSourceOnly=true /p:DotNetBuildInnerRepo=true /p:DotNetBuildRepo=true /p:DotNetBuildOrchestrator=$(DotNetBuildOrchestrator)"
WorkingDirectory="$(InnerSourceBuildRepoRoot)"
EnvironmentVariables="@(InnerBuildEnv)" />
</Target>
Expand Down
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<FSharpLibrariesChangelogVersion>$(FSMajorVersion).$(FSMinorVersion).$(FSBuildVersion)</FSharpLibrariesChangelogVersion>
<!-- -->
<!-- The current published nuget package -->
<FSharpCoreShippedPackageVersionValue>9.0.100</FSharpCoreShippedPackageVersionValue>
<FSharpCoreShippedPackageVersionValue>9.0.101</FSharpCoreShippedPackageVersionValue>
<!-- -->
<!-- The pattern for specifying the preview package -->
<FSharpCorePreviewPackageVersionValue>$(FSCorePackageVersionValue)-$(PreReleaseVersionLabel).*</FSharpCorePreviewPackageVersionValue>
Expand Down
230 changes: 153 additions & 77 deletions src/Compiler/Checking/AttributeChecking.fs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ open FSharp.Compiler.TypeProviders
open FSharp.Core.CompilerServices
#endif

exception ObsoleteWarning of string * range
exception ObsoleteError of string * range
exception ObsoleteDiagnostic of
isError: bool *
diagnosticId: string *
message: string *
urlFormat: string *
range: range

let fail() = failwith "This custom attribute has an argument that cannot yet be converted using this API"

Expand Down Expand Up @@ -234,7 +238,6 @@ let MethInfoHasAttribute g m attribSpec minfo =
(fun _ -> Some ())
|> Option.isSome


let private CheckCompilerFeatureRequiredAttribute (g: TcGlobals) cattrs msg m =
// In some cases C# will generate both ObsoleteAttribute and CompilerFeatureRequiredAttribute.
// Specifically, when default constructor is generated for class with any required members in them.
Expand All @@ -244,104 +247,177 @@ let private CheckCompilerFeatureRequiredAttribute (g: TcGlobals) cattrs msg m =
| Some([ILAttribElem.String (Some featureName) ], _) when featureName = "RequiredMembers" ->
CompleteD
| _ ->
ErrorD (ObsoleteError(msg, m))
ErrorD (ObsoleteDiagnostic(true, "", msg, "", m))

let private extractILObsoleteAttributeInfo namedArgs =
let extractILAttribValueFrom name namedArgs =
match namedArgs with
| ExtractILAttributeNamedArg name (AttribElemStringArg v) -> v
| _ -> ""
let diagnosticId = extractILAttribValueFrom "DiagnosticId" namedArgs
let urlFormat = extractILAttribValueFrom "UrlFormat" namedArgs
(diagnosticId, urlFormat)

let private CheckILObsoleteAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m =
if isByrefLikeTyconRef then
CompleteD
else
let (AttribInfo(tref,_)) = g.attrib_SystemObsolete
match TryDecodeILAttribute tref cattrs with
// [<Obsolete>]
// [<Obsolete("Message")>]
// [<Obsolete("Message", true)>]
// [<Obsolete("Message", DiagnosticId = "DiagnosticId")>]
// [<Obsolete("Message", DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
// [<Obsolete(DiagnosticId = "DiagnosticId")>]
// [<Obsolete(DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
// [<Obsolete("Message", true, DiagnosticId = "DiagnosticId")>]
// [<Obsolete("Message", true, DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
// Constructors deciding on IsError and Message properties.
| Some ([ attribElement ], namedArgs) ->
let diagnosticId, urlFormat = extractILObsoleteAttributeInfo namedArgs
let msg =
match attribElement with
| ILAttribElem.String (Some msg) -> msg
| ILAttribElem.String None
| _ -> ""

WarnD (ObsoleteDiagnostic(false, diagnosticId, msg, urlFormat, m))
| Some ([ILAttribElem.String (Some msg); ILAttribElem.Bool isError ], namedArgs) ->
let diagnosticId, urlFormat = extractILObsoleteAttributeInfo namedArgs
if isError then
if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) then
CheckCompilerFeatureRequiredAttribute g cattrs msg m
else
ErrorD (ObsoleteDiagnostic(true, diagnosticId, msg, urlFormat, m))
else
WarnD (ObsoleteDiagnostic(false, diagnosticId, msg, urlFormat, m))
// Only DiagnosticId, UrlFormat
| Some (_, namedArgs) ->
let diagnosticId, urlFormat = extractILObsoleteAttributeInfo namedArgs
WarnD(ObsoleteDiagnostic(false, diagnosticId, "", urlFormat, m))
// No arguments
| None -> CompleteD

/// Check IL attributes for 'ObsoleteAttribute', returning errors and warnings as data
let private CheckILAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m =
let (AttribInfo(tref,_)) = g.attrib_SystemObsolete
match TryDecodeILAttribute tref cattrs with
| Some ([ILAttribElem.String (Some msg) ], _) when not isByrefLikeTyconRef ->
WarnD(ObsoleteWarning(msg, m))
| Some ([ILAttribElem.String (Some msg); ILAttribElem.Bool isError ], _) when not isByrefLikeTyconRef ->
if isError then
if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) then
CheckCompilerFeatureRequiredAttribute g cattrs msg m
else
ErrorD (ObsoleteError(msg, m))
else
WarnD (ObsoleteWarning(msg, m))
| Some ([ILAttribElem.String None ], _) when not isByrefLikeTyconRef ->
WarnD(ObsoleteWarning("", m))
| Some _ when not isByrefLikeTyconRef ->
WarnD(ObsoleteWarning("", m))
| _ ->
CompleteD
trackErrors {
do! CheckILObsoleteAttributes g isByrefLikeTyconRef cattrs m
}

let langVersionPrefix = "--langversion:preview"

let private extractObsoleteAttributeInfo namedArgs =
let extractILAttribValueFrom name namedArgs =
match namedArgs with
| ExtractAttribNamedArg name (AttribStringArg v) -> v
| _ -> ""
let diagnosticId = extractILAttribValueFrom "DiagnosticId" namedArgs
let urlFormat = extractILAttribValueFrom "UrlFormat" namedArgs
(diagnosticId, urlFormat)

let private CheckObsoleteAttributes g attribs m =
trackErrors {
match TryFindFSharpAttribute g g.attrib_SystemObsolete attribs with
// [<Obsolete>]
// [<Obsolete("Message")>]
// [<Obsolete("Message", true)>]
// [<Obsolete("Message", DiagnosticId = "DiagnosticId")>]
// [<Obsolete("Message", DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
// [<Obsolete(DiagnosticId = "DiagnosticId")>]
// [<Obsolete(DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
// [<Obsolete("Message", true, DiagnosticId = "DiagnosticId")>]
// [<Obsolete("Message", true, DiagnosticId = "DiagnosticId", UrlFormat = "UrlFormat")>]
// Constructors deciding on IsError and Message properties.
| Some(Attrib(unnamedArgs= [ AttribStringArg s ]; propVal= namedArgs)) ->
let diagnosticId, urlFormat = extractObsoleteAttributeInfo namedArgs
do! WarnD(ObsoleteDiagnostic(false, diagnosticId, s, urlFormat, m))
| Some(Attrib(unnamedArgs= [ AttribStringArg s; AttribBoolArg(isError) ]; propVal= namedArgs)) ->
let diagnosticId, urlFormat = extractObsoleteAttributeInfo namedArgs
if isError then
do! ErrorD (ObsoleteDiagnostic(true, diagnosticId, s, urlFormat, m))
else
do! WarnD (ObsoleteDiagnostic(false, diagnosticId, s, urlFormat, m))
// Only DiagnosticId, UrlFormat
| Some(Attrib(propVal= namedArgs)) ->
let diagnosticId, urlFormat = extractObsoleteAttributeInfo namedArgs
do! WarnD(ObsoleteDiagnostic(false, diagnosticId, "", urlFormat, m))
| None -> ()
}

let private CheckCompilerMessageAttribute g attribs m =
trackErrors {
match TryFindFSharpAttribute g g.attrib_CompilerMessageAttribute attribs with
| Some(Attrib(unnamedArgs= [ AttribStringArg s ; AttribInt32Arg n ]; propVal= namedArgs)) ->
let msg = UserCompilerMessage(s, n, m)
let isError =
match namedArgs with
| ExtractAttribNamedArg "IsError" (AttribBoolArg v) -> v
| _ -> false
// If we are using a compiler that supports nameof then error 3501 is always suppressed.
// See attribute on FSharp.Core 'nameof'
if n = 3501 then
()
elif isError && (not g.compilingFSharpCore || n <> 1204) then
do! ErrorD msg
else
do! WarnD msg
| _ ->
()
}

let private CheckExperimentalAttribute g attribs m =
trackErrors {
match TryFindFSharpAttribute g g.attrib_ExperimentalAttribute attribs with
| Some(Attrib(unnamedArgs= [ AttribStringArg(s) ])) ->
let isExperimentalAttributeDisabled (s:string) =
if g.compilingFSharpCore then
true
else
g.langVersion.IsPreviewEnabled && (s.IndexOf(langVersionPrefix, StringComparison.OrdinalIgnoreCase) >= 0)
if not (isExperimentalAttributeDisabled s) then
do! WarnD(Experimental(s, m))
| Some _ ->
do! WarnD(Experimental(FSComp.SR.experimentalConstruct (), m))
| _ ->
()
}

let private CheckUnverifiableAttribute g attribs m =
trackErrors {
match TryFindFSharpAttribute g g.attrib_UnverifiableAttribute attribs with
| Some _ ->
do! WarnD(PossibleUnverifiableCode(m))
| _ -> ()
}

/// Check F# attributes for 'ObsoleteAttribute', 'CompilerMessageAttribute' and 'ExperimentalAttribute',
/// returning errors and warnings as data
let CheckFSharpAttributes (g:TcGlobals) attribs m =
if isNil attribs then CompleteD
else
trackErrors {
match TryFindFSharpAttribute g g.attrib_SystemObsolete attribs with
| Some(Attrib(_, _, [ AttribStringArg s ], _, _, _, _)) ->
do! WarnD(ObsoleteWarning(s, m))
| Some(Attrib(_, _, [ AttribStringArg s; AttribBoolArg(isError) ], _, _, _, _)) ->
if isError then
do! ErrorD (ObsoleteError(s, m))
else
do! WarnD (ObsoleteWarning(s, m))
| Some _ ->
do! WarnD(ObsoleteWarning("", m))
| None ->
()

match TryFindFSharpAttribute g g.attrib_CompilerMessageAttribute attribs with
| Some(Attrib(_, _, [ AttribStringArg s ; AttribInt32Arg n ], namedArgs, _, _, _)) ->
let msg = UserCompilerMessage(s, n, m)
let isError =
match namedArgs with
| ExtractAttribNamedArg "IsError" (AttribBoolArg v) -> v
| _ -> false
// If we are using a compiler that supports nameof then error 3501 is always suppressed.
// See attribute on FSharp.Core 'nameof'
if n = 3501 then
()
elif isError && (not g.compilingFSharpCore || n <> 1204) then
do! ErrorD msg
else
do! WarnD msg
| _ ->
()

match TryFindFSharpAttribute g g.attrib_ExperimentalAttribute attribs with
| Some(Attrib(_, _, [ AttribStringArg(s) ], _, _, _, _)) ->
let isExperimentalAttributeDisabled (s:string) =
if g.compilingFSharpCore then
true
else
g.langVersion.IsPreviewEnabled && (s.IndexOf(langVersionPrefix, StringComparison.OrdinalIgnoreCase) >= 0)
if not (isExperimentalAttributeDisabled s) then
do! WarnD(Experimental(s, m))
| Some _ ->
do! WarnD(Experimental(FSComp.SR.experimentalConstruct (), m))
| _ ->
()

match TryFindFSharpAttribute g g.attrib_UnverifiableAttribute attribs with
| Some _ ->
do! WarnD(PossibleUnverifiableCode(m))
| _ ->
()
do! CheckObsoleteAttributes g attribs m
do! CheckCompilerMessageAttribute g attribs m
do! CheckExperimentalAttribute g attribs m
do! CheckUnverifiableAttribute g attribs m
}

#if !NO_TYPEPROVIDERS
/// Check a list of provided attributes for 'ObsoleteAttribute', returning errors and warnings as data
let private CheckProvidedAttributes (g: TcGlobals) m (provAttribs: Tainted<IProvidedCustomAttributeProvider>) =
let (AttribInfo(tref, _)) = g.attrib_SystemObsolete
match provAttribs.PUntaint((fun a -> a.GetAttributeConstructorArgs(provAttribs.TypeProvider.PUntaintNoFailure(id), tref.FullName)), m) with
| Some ([ Some (:? string as msg) ], _) -> WarnD(ObsoleteWarning(msg, m))
| Some ([ Some (:? string as msg) ], _) -> WarnD(ObsoleteDiagnostic(false, "", msg, "", m))
| Some ([ Some (:? string as msg); Some (:?bool as isError) ], _) ->
if isError then
ErrorD (ObsoleteError(msg, m))
ErrorD (ObsoleteDiagnostic(true, "", msg, "", m))
else
WarnD (ObsoleteWarning(msg, m))
WarnD (ObsoleteDiagnostic(false, "", msg, "", m))
| Some ([ None ], _) ->
WarnD(ObsoleteWarning("", m))
WarnD(ObsoleteDiagnostic(false, "", "", "", m))
| Some _ ->
WarnD(ObsoleteWarning("", m))
WarnD(ObsoleteDiagnostic(false, "", "", "", m))
| None ->
CompleteD
#endif
Expand Down
9 changes: 6 additions & 3 deletions src/Compiler/Checking/AttributeChecking.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Text
open FSharp.Compiler.TypedTree

exception ObsoleteWarning of string * range

exception ObsoleteError of string * range
exception ObsoleteDiagnostic of
isError: bool *
diagnosticId: string *
message: string *
urlFormat: string *
range: range

type AttribInfo =
| FSAttribInfo of TcGlobals * Attrib
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/PostInferenceChecks.fs
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ let WarnOnWrongTypeForAccess (cenv: cenv) env objName valAcc m ty =
if isLessAccessible tyconAcc valAcc then
let errorText = FSComp.SR.chkTypeLessAccessibleThanType(tcref.DisplayName, (objName())) |> snd
let warningText = errorText + Environment.NewLine + FSComp.SR.tcTypeAbbreviationsCheckedAtCompileTime()
warning(AttributeChecking.ObsoleteWarning(warningText, m))
warning(AttributeChecking.ObsoleteDiagnostic(false, "", warningText, "", m))

CheckTypeDeep cenv (visitType, None, None, None, None) cenv.g env NoInfo ty

Expand Down
11 changes: 4 additions & 7 deletions src/Compiler/Driver/CompilerDiagnostics.fs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,7 @@ type Exception with
| IntfImplInExtrinsicAugmentation m
| ValueRestriction(_, _, _, _, m)
| LetRecUnsound(_, _, m)
| ObsoleteError(_, m)
| ObsoleteWarning(_, m)
| ObsoleteDiagnostic(_, _, _, _, m)
| Experimental(_, m)
| PossibleUnverifiableCode m
| UserCompilerMessage(_, _, m)
Expand Down Expand Up @@ -266,7 +265,7 @@ type Exception with
| UnresolvedOverloading _ -> 41
| LibraryUseOnly _ -> 42
| ErrorFromAddingConstraint _ -> 43
| ObsoleteWarning _ -> 44
| ObsoleteDiagnostic(isError = false) -> 44
| ReservedKeyword _ -> 46
| SelfRefObjCtor _ -> 47
| VirtualAugmentationOnNullValuedType _ -> 48
Expand Down Expand Up @@ -327,7 +326,7 @@ type Exception with
| UnresolvedConversionOperator _ -> 93

// avoid 94-100 for safety
| ObsoleteError _ -> 101
| ObsoleteDiagnostic(isError = true) -> 101
#if !NO_TYPEPROVIDERS
| TypeProviders.ProvidedTypeResolutionNoRange _
| TypeProviders.ProvidedTypeResolution _ -> 103
Expand Down Expand Up @@ -1790,9 +1789,7 @@ type Exception with

| ValNotLocal _ -> os.AppendString(ValNotLocalE().Format)

| ObsoleteError(s, _)

| ObsoleteWarning(s, _) ->
| ObsoleteDiagnostic(message = s) ->
os.AppendString(Obsolete1E().Format)

if s <> "" then
Expand Down
Loading

0 comments on commit cddbb7a

Please sign in to comment.