diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index 7db99de0b38..a0fb7f9b951 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -12,6 +12,7 @@ * Fix discriminated union initialization. ([#PR 16661](https://github.com/dotnet/fsharp/pull/16661)) * Allow calling method with both Optional and ParamArray. ([#PR 16688](https://github.com/dotnet/fsharp/pull/16688), [suggestions #1120](https://github.com/fsharp/fslang-suggestions/issues/1120)) * Fix release inline optimization, which leads to MethodAccessException if used with `assembly:InternalsVisibleTo`` attribute. ([Issue #16105](https://github.com/dotnet/fsharp/issues/16105), ([PR #16737](https://github.com/dotnet/fsharp/pull/16737)) +* Enforce AttributeTargets on let values and functions. ([PR #16692](https://github.com/dotnet/fsharp/pull/16692)) ### Added diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index d1880b4dd85..f39dd172561 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -8,7 +8,8 @@ ### Fixed * Allow extension methods without type attribute work for types from imported assemblies. ([PR #16368](https://github.com/dotnet/fsharp/pull/16368)) +* Enforce AttributeTargets on let values and functions. ([PR #16692](https://github.com/dotnet/fsharp/pull/16692)) ### Changed -* Lower interpolated strings to string concatenation. ([PR #16556](https://github.com/dotnet/fsharp/pull/16556)) \ No newline at end of file +* Lower interpolated strings to string concatenation. ([PR #16556](https://github.com/dotnet/fsharp/pull/16556)) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 19f3a32a345..c30f8e1630b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,9 +1,9 @@ - + https://github.com/dotnet/source-build-reference-packages - 539af5d8ae183d4fe61e8b2f8f4a8505c8a765a7 + 62fb9a85e5c4af657b0014fd6d6588c139d0bb4f diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 89268e1ee6e..3e3e90a72fe 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -10636,8 +10636,7 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt | ModuleOrMemberBinding, SynBindingKind.StandaloneExpression, _ -> Some(".cctor") | _, _, _ -> envinner.eCallerMemberName - let envinner = {envinner with eCallerMemberName = callerName } - + let envinner = { envinner with eCallerMemberName = callerName } let attrTgt = declKind.AllowedAttribTargets memberFlagsOpt let isFixed, rhsExpr, overallPatTy, overallExprTy = @@ -10873,6 +10872,16 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt errorR(Error(FSComp.SR.tcLiteralCannotBeInline(), mBinding)) if not (isNil declaredTypars) then errorR(Error(FSComp.SR.tcLiteralCannotHaveGenericParameters(), mBinding)) + + if g.langVersion.SupportsFeature(LanguageFeature.EnforceAttributeTargetsOnFunctions) && memberFlagsOpt.IsNone && not attrs.IsEmpty then + let rhsIsFunction = isFunTy g overallPatTy + let lhsIsFunction = isFunTy g overallExprTy + let attrTgt = + match rhsIsFunction, lhsIsFunction with + | false, false when declaredTypars.IsEmpty -> AttributeTargets.Field ||| AttributeTargets.Property ||| AttributeTargets.ReturnValue + | _, _ -> AttributeTargets.Method ||| AttributeTargets.ReturnValue + + TcAttributesWithPossibleTargets false cenv env attrTgt attrs |> ignore CheckedBindingInfo(inlineFlag, valAttribs, xmlDoc, tcPatPhase2, explicitTyparInfo, nameToPrelimValSchemeMap, rhsExprChecked, argAndRetAttribs, overallPatTy, mBinding, debugPoint, isCompGen, literalValue, isFixed), tpenv diff --git a/src/Compiler/Checking/TailCallChecks.fs b/src/Compiler/Checking/TailCallChecks.fs index c26683e3da9..ce6ab702bdc 100644 --- a/src/Compiler/Checking/TailCallChecks.fs +++ b/src/Compiler/Checking/TailCallChecks.fs @@ -725,12 +725,7 @@ let CheckModuleBinding cenv (isRec: bool) (TBind _ as bind) = // warn for non-rec functions which have the attribute if cenv.g.langVersion.SupportsFeature LanguageFeature.WarningWhenTailCallAttrOnNonRec then - let isNotAFunction = - match bind.Var.ValReprInfo with - | Some info -> info.HasNoArgs - | _ -> false - - if (not isRec || isNotAFunction) && cenv.g.HasTailCallAttrib bind.Var.Attribs then + if not isRec && cenv.g.HasTailCallAttrib bind.Var.Attribs then warning (Error(FSComp.SR.chkTailCallAttrOnNonRec (), bind.Var.Range)) // Check if a let binding to the result of a rec expression is not inside the rec expression diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 1fef46084d0..a1086629fbe 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1594,6 +1594,7 @@ featureWarningIndexedPropertiesGetSetSameType,"Indexed properties getter and set featureChkTailCallAttrOnNonRec,"Raises warnings if the 'TailCall' attribute is used on non-recursive functions." featureUnionIsPropertiesVisible,"Union case test properties" featureBooleanReturningAndReturnTypeDirectedPartialActivePattern,"Boolean-returning and return-type-directed partial active patterns" +featureEnforceAttributeTargetsOnFunctions,"Enforce AttributeTargets on functions" featureLowerInterpolatedStringToConcat,"Optimizes interpolated strings in certain cases, by lowering to concatenation" 3354,tcNotAFunctionButIndexerNamedIndexingNotYetEnabled,"This value supports indexing, e.g. '%s.[index]'. The syntax '%s[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation." 3354,tcNotAFunctionButIndexerIndexingNotYetEnabled,"This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation." diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs index b780d91ca74..d6ae83ada6e 100644 --- a/src/Compiler/Facilities/AsyncMemoize.fs +++ b/src/Compiler/Facilities/AsyncMemoize.fs @@ -534,6 +534,15 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T } + member _.TryGet(key: 'TKey, predicate: 'TVersion -> bool) : 'TValue option = + let versionsAndJobs = cache.GetAll(key) + + versionsAndJobs + |> Seq.tryPick (fun (version, job) -> + match predicate version, job with + | true, Completed(completed, _) -> Some completed + | _ -> None) + member _.Clear() = cache.Clear() member _.Clear predicate = cache.Clear predicate diff --git a/src/Compiler/Facilities/AsyncMemoize.fsi b/src/Compiler/Facilities/AsyncMemoize.fsi index a34588e7af8..1cce68cf999 100644 --- a/src/Compiler/Facilities/AsyncMemoize.fsi +++ b/src/Compiler/Facilities/AsyncMemoize.fsi @@ -69,6 +69,8 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T member Get': key: 'TKey * computation: NodeCode<'TValue> -> NodeCode<'TValue> + member TryGet: key: 'TKey * predicate: ('TVersion -> bool) -> 'TValue option + member Event: IEvent member OnEvent: ((JobEvent * (string * 'TKey * 'TVersion) -> unit) -> unit) diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 66547a12e29..6e2d91bc6cd 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -85,6 +85,7 @@ type LanguageFeature = | WarningIndexedPropertiesGetSetSameType | WarningWhenTailCallAttrOnNonRec | BooleanReturningAndReturnTypeDirectedPartialActivePattern + | EnforceAttributeTargetsOnFunctions | LowerInterpolatedStringToConcat /// LanguageVersion management @@ -198,6 +199,7 @@ type LanguageVersion(versionText) = LanguageFeature.WarningWhenTailCallAttrOnNonRec, previewVersion LanguageFeature.UnionIsPropertiesVisible, previewVersion LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern, previewVersion + LanguageFeature.EnforceAttributeTargetsOnFunctions, previewVersion LanguageFeature.LowerInterpolatedStringToConcat, previewVersion ] @@ -342,6 +344,7 @@ type LanguageVersion(versionText) = | LanguageFeature.WarningWhenTailCallAttrOnNonRec -> FSComp.SR.featureChkTailCallAttrOnNonRec () | LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern -> FSComp.SR.featureBooleanReturningAndReturnTypeDirectedPartialActivePattern () + | LanguageFeature.EnforceAttributeTargetsOnFunctions -> FSComp.SR.featureEnforceAttributeTargetsOnFunctions () | LanguageFeature.LowerInterpolatedStringToConcat -> FSComp.SR.featureLowerInterpolatedStringToConcat () /// Get a version string associated with the given feature. diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 582c191ac8a..4888479d867 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -76,6 +76,7 @@ type LanguageFeature = | WarningIndexedPropertiesGetSetSameType | WarningWhenTailCallAttrOnNonRec | BooleanReturningAndReturnTypeDirectedPartialActivePattern + | EnforceAttributeTargetsOnFunctions | LowerInterpolatedStringToConcat /// LanguageVersion management diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs index d66847b5c17..d0af1284f14 100644 --- a/src/Compiler/Service/BackgroundCompiler.fs +++ b/src/Compiler/Service/BackgroundCompiler.fs @@ -179,6 +179,10 @@ type internal IBackgroundCompiler = fileName: string * options: FSharpProjectOptions * sourceText: ISourceText option * userOpName: string -> (FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash) option + abstract member TryGetRecentCheckResultsForFile: + fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> + (FSharpParseFileResults * FSharpCheckFileResults) option + abstract member BeforeBackgroundFileCheck: IEvent abstract member FileChecked: IEvent @@ -1174,6 +1178,16 @@ type internal BackgroundCompiler | None -> None | None -> None + member _.TryGetRecentCheckResultsForFile(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) = + projectSnapshot.ProjectSnapshot.SourceFiles + |> List.tryFind (fun f -> f.FileName = fileName) + |> Option.bind (fun (f: FSharpFileSnapshot) -> + let options = projectSnapshot.ToOptions() + let sourceText = f.GetSource() |> Async.AwaitTask |> Async.RunSynchronously + + self.TryGetRecentCheckResultsForFile(fileName, options, Some sourceText, userOpName) + |> Option.map (fun (parseFileResults, checkFileResults, _hash) -> (parseFileResults, checkFileResults))) + /// Parse and typecheck the whole project (the implementation, called recursively as project graph is evaluated) member private _.ParseAndCheckProjectImpl(options, userOpName) = node { @@ -1732,3 +1746,11 @@ type internal BackgroundCompiler userOpName: string ) : (FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash) option = self.TryGetRecentCheckResultsForFile(fileName, options, sourceText, userOpName) + + member _.TryGetRecentCheckResultsForFile + ( + fileName: string, + projectSnapshot: FSharpProjectSnapshot, + userOpName: string + ) : (FSharpParseFileResults * FSharpCheckFileResults) option = + self.TryGetRecentCheckResultsForFile(fileName, projectSnapshot, userOpName) diff --git a/src/Compiler/Service/BackgroundCompiler.fsi b/src/Compiler/Service/BackgroundCompiler.fsi index cd7c163a0d1..fff6324be35 100644 --- a/src/Compiler/Service/BackgroundCompiler.fsi +++ b/src/Compiler/Service/BackgroundCompiler.fsi @@ -169,6 +169,10 @@ type internal IBackgroundCompiler = fileName: string * options: FSharpProjectOptions * sourceText: ISourceText option * userOpName: string -> (FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash) option + abstract TryGetRecentCheckResultsForFile: + fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> + (FSharpParseFileResults * FSharpCheckFileResults) option + abstract BeforeBackgroundFileCheck: IEvent abstract FileChecked: IEvent diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index 7ab252ef73b..76d9705890e 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -345,6 +345,12 @@ type internal ProjectSnapshotBase<'T when 'T :> IFileSnapshot>(projectCore: Proj member this.FileKey(fileName: string) = this.UpTo(fileName).LastFileKey member this.FileKey(index: FileIndex) = this.UpTo(index).LastFileKey + member this.FileKeyWithExtraFileSnapshotVersion(fileName: string) = + let fileKey = this.FileKey fileName + let fileSnapshot = this.SourceFiles |> Seq.find (fun f -> f.FileName = fileName) + + fileKey.WithExtraVersion(fileSnapshot.Version |> Md5Hasher.toString) + /// Project snapshot with filenames and versions given as initial input and internal ProjectSnapshot = ProjectSnapshotBase @@ -394,10 +400,10 @@ and internal ProjectCore let commandLineOptions = lazy (seq { + yield! OtherOptions + for r in ReferencesOnDisk do $"-r:{r.Path}" - - yield! OtherOptions } |> Seq.toList) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index e85488e7738..c5ecfba812f 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -307,7 +307,7 @@ type internal CompilerCaches(sizeFactor: int) = this.AssemblyData.Clear(shouldClear) this.SemanticClassification.Clear(snd >> shouldClear) this.ItemKeyStore.Clear(snd >> shouldClear) - this.ScriptClosure.Clear(snd >> shouldClear) // Todo check if correct predicate + this.ScriptClosure.Clear(snd >> shouldClear) type internal TransparentCompiler ( @@ -1472,9 +1472,8 @@ type internal TransparentCompiler let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: ProjectSnapshot) = caches.ParseAndCheckFileInProject.Get( - projectSnapshot.FileKey fileName, + projectSnapshot.FileKeyWithExtraFileSnapshotVersion fileName, node { - use _ = Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |] @@ -1605,6 +1604,29 @@ type internal TransparentCompiler } ) + let TryGetRecentCheckResultsForFile + ( + fileName: string, + projectSnapshot: FSharpProjectSnapshot, + userOpName: string + ) : (FSharpParseFileResults * FSharpCheckFileResults) option = + ignore userOpName + + let cacheKey = + projectSnapshot.ProjectSnapshot.FileKeyWithExtraFileSnapshotVersion fileName + + let version = cacheKey.GetVersion() + + let parseFileResultsAndcheckFileAnswer = + caches.ParseAndCheckFileInProject.TryGet( + cacheKey.GetKey(), + (fun (_fullVersion, fileContentVersion) -> fileContentVersion = (snd version)) + ) + + match parseFileResultsAndcheckFileAnswer with + | Some(parseFileResults, FSharpCheckFileAnswer.Succeeded checkFileResults) -> Some(parseFileResults, checkFileResults) + | _ -> None + let ComputeProjectExtras (bootstrapInfo: BootstrapInfo) (projectSnapshot: ProjectSnapshotWithSources) = caches.ProjectExtras.Get( projectSnapshot.SignatureKey, @@ -2356,3 +2378,11 @@ type internal TransparentCompiler userOpName: string ) : (FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash) option = backgroundCompiler.TryGetRecentCheckResultsForFile(fileName, options, sourceText, userOpName) + + member this.TryGetRecentCheckResultsForFile + ( + fileName: string, + projectSnapshot: FSharpProjectSnapshot, + userOpName: string + ) : (FSharpParseFileResults * FSharpCheckFileResults) option = + TryGetRecentCheckResultsForFile(fileName, projectSnapshot, userOpName) diff --git a/src/Compiler/Service/TransparentCompiler.fsi b/src/Compiler/Service/TransparentCompiler.fsi index 9aa5929566c..8e581872d84 100644 --- a/src/Compiler/Service/TransparentCompiler.fsi +++ b/src/Compiler/Service/TransparentCompiler.fsi @@ -118,7 +118,7 @@ type internal CompilerCaches = member ParseAndCheckAllFilesInProject: AsyncMemoizeDisabled member ParseAndCheckFileInProject: - AsyncMemoize<(string * (string * string)), string, (FSharpParseFileResults * FSharpCheckFileAnswer)> + AsyncMemoize<(string * (string * string)), string * string, (FSharpParseFileResults * FSharpCheckFileAnswer)> member ParseAndCheckProject: AsyncMemoize<(string * string), string, FSharpCheckProjectResults> diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 94dce6286b5..103c84e63cf 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -338,6 +338,10 @@ type FSharpChecker let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.TryGetRecentCheckResultsForFile(fileName, options, sourceText, userOpName) + member _.TryGetRecentCheckResultsForFile(fileName: string, projectSnapshot: FSharpProjectSnapshot, ?userOpName: string) = + let userOpName = defaultArg userOpName "Unknown" + backgroundCompiler.TryGetRecentCheckResultsForFile(fileName, projectSnapshot, userOpName) + member _.Compile(argv: string[], ?userOpName: string) = let _userOpName = defaultArg userOpName "Unknown" use _ = Activity.start "FSharpChecker.Compile" [| Activity.Tags.userOpName, _userOpName |] diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi index cb8272b0f69..71e0f51df3d 100644 --- a/src/Compiler/Service/service.fsi +++ b/src/Compiler/Service/service.fsi @@ -422,6 +422,11 @@ type public FSharpChecker = fileName: string * options: FSharpProjectOptions * ?sourceText: ISourceText * ?userOpName: string -> (FSharpParseFileResults * FSharpCheckFileResults (* hash *) * int64) option + [] + member TryGetRecentCheckResultsForFile: + fileName: string * projectSnapshot: FSharpProjectSnapshot * ?userOpName: string -> + (FSharpParseFileResults * FSharpCheckFileResults) option + /// This function is called when the entire environment is known to have changed for reasons not encoded in the ProjectOptions of any project/compilation. member InvalidateAll: unit -> unit diff --git a/src/Compiler/Utilities/LruCache.fs b/src/Compiler/Utilities/LruCache.fs index c75ed1d88cf..7b06292c2e2 100644 --- a/src/Compiler/Utilities/LruCache.fs +++ b/src/Compiler/Utilities/LruCache.fs @@ -198,21 +198,27 @@ type internal LruCache<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'TVers /// Returns an option of a value for given key and version, and also a list of all other versions for given key member this.GetAll(key, version) = - this.TryGet(key, version), + let others = + this.GetAll(key) |> Seq.filter (fun (ver, _val) -> ver <> version) |> Seq.toList + this.TryGet(key, version), others + + /// Returns a list of version * value pairs for a given key. The strongly held value is first in the list. + member _.GetAll(key: 'TKey) : ('TVersion * 'TValue) seq = match dictionary.TryGetValue key with | false, _ -> [] | true, versionDict -> versionDict.Values - |> Seq.map (fun node -> node.Value) - |> Seq.filter (p24 >> ((<>) version)) + |> Seq.map (_.Value) + |> Seq.sortBy (function + | _, _, _, Strong _ -> 0 + | _ -> 1) |> Seq.choose (function | _, ver, _, Strong v -> Some(ver, v) | _, ver, _, Weak r -> match r.TryGetTarget() with | true, x -> Some(ver, x) | _ -> None) - |> Seq.toList member _.Remove(key, version) = match dictionary.TryGetValue key with diff --git a/src/Compiler/Utilities/LruCache.fsi b/src/Compiler/Utilities/LruCache.fsi index d9aefd2a240..eb2880047d7 100644 --- a/src/Compiler/Utilities/LruCache.fsi +++ b/src/Compiler/Utilities/LruCache.fsi @@ -33,6 +33,9 @@ type internal LruCache<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'TVers /// Returns an option of a value for given key and version, and also a list of all other versions for given key member GetAll: key: 'TKey * version: 'TVersion -> 'TValue option * ('TVersion * 'TValue) list + /// Returns a list of version * value pairs for a given key. The strongly held value is first in the list. + member GetAll: key: 'TKey -> ('TVersion * 'TValue) seq + member GetValues: unit -> (string * 'TVersion * 'TValue) seq member Remove: key: 'TKey -> unit diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 27098c6bd1e..d4142d783fa 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -292,6 +292,11 @@ literál float32 bez tečky + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides Vyvolá chyby pro přepsání jiných než virtuálních členů diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index c89e0988f8e..fa0904ef50f 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -292,6 +292,11 @@ punktloses float32-Literal + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides Löst Fehler für Außerkraftsetzungen nicht virtueller Member aus. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index de54c17c1f3..2d5ada63574 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -292,6 +292,11 @@ literal float32 sin punto + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides Genera errores para invalidaciones de miembros no virtuales diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 17807523602..da3c6f4b9b6 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -292,6 +292,11 @@ littéral float32 sans point + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides Déclenche des erreurs pour les remplacements de membres non virtuels diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 1661484a63c..010e34a81a2 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -292,6 +292,11 @@ valore letterale float32 senza punti + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides Genera errori per gli override dei membri non virtuali diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index a5a04b7c1b0..8a92ac2ea9e 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -292,6 +292,11 @@ ドットなしの float32 リテラル + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides 仮想メンバー以外のオーバーライドに対してエラーを発生させます diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index d419bd0d99b..51778bd4145 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -292,6 +292,11 @@ 점이 없는 float32 리터럴 + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides 비가상 멤버 재정의에 대한 오류 발생 diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 65d582f3796..a8a3f05ba9a 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -292,6 +292,11 @@ bezkropkowy literał float32 + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides Zgłasza błędy w przypadku przesłonięć elementów innych niż wirtualne diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 93af3d22e75..1f62f9a3d04 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -292,6 +292,11 @@ literal float32 sem ponto + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides Gera erros para substituições de membros não virtuais diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index b13f061163b..64ce92b6125 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -292,6 +292,11 @@ литерал float32 без точки + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides Вызывает ошибки при переопределениях невиртуальных элементов diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index ad43bfe169b..d77dfd672ec 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -292,6 +292,11 @@ noktasız float32 sabit değeri + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides Sanal olmayan üyelerde geçersiz kılmalar için hatalar oluştur diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index d7013ad94e7..5393d25202a 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -292,6 +292,11 @@ 无点 float32 文本 + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides 引发非虚拟成员替代的错误 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 902612c1b64..f75fc155fde 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -292,6 +292,11 @@ 無點號的 float32 常值 + + Enforce AttributeTargets on functions + Enforce AttributeTargets on functions + + Raises errors for non-virtual members overrides 引發非虛擬成員覆寫的錯誤 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs index cddee9f80ab..c7861ee3e56 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs @@ -94,6 +94,147 @@ module CustomAttributes_AttributeUsage = (Error 842, Line 24, Col 7, Line 24, Col 36, "This attribute is not valid for use on this language element") (Error 842, Line 29, Col 15, Line 29, Col 47, "This attribute is not valid for use on this language element") ] + + // SOURCE=E_AttributeTargetIsField01.fs # E_AttributeTargetIsField01.fs + [] + let ``E_AttributeTargetIsField01_fs`` compilation = + compilation + |> withLangVersion80 + |> withOptions ["--nowarn:25"] + |> verifyCompile + |> shouldSucceed + + // SOURCE=E_AttributeTargetIsField01.fs # E_AttributeTargetIsField01.fs + [] + let ``E_AttributeTargetIsField01_fs preview`` compilation = + compilation + |> withLangVersionPreview + |> withOptions ["--nowarn:25"] + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 842, Line 9, Col 3, Line 9, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 12, Col 3, Line 12, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 15, Col 3, Line 15, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 18, Col 3, Line 18, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 21, Col 3, Line 21, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 24, Col 3, Line 24, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 27, Col 3, Line 27, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 30, Col 3, Line 30, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 33, Col 3, Line 33, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 36, Col 3, Line 36, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 39, Col 3, Line 39, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 42, Col 3, Line 42, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 45, Col 3, Line 45, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 49, Col 3, Line 49, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 56, Col 3, Line 56, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 64, Col 3, Line 64, Col 12, "This attribute is not valid for use on this language element") + (Error 842, Line 66, Col 7, Line 66, Col 16, "This attribute is not valid for use on this language element") + ] + + // SOURCE=E_AttributeTargetIsField02.fs # E_AttributeTargetIsField02.fs + [] + let ``E_AttributeTargetIsField02_fs`` compilation = + compilation + |> withLangVersion80 + |> withOptions ["--nowarn:25"] + |> verifyCompile + |> shouldSucceed + + // SOURCE=E_AttributeTargetIsField02.fs # E_AttributeTargetIsField02.fs + [] + let ``E_AttributeTargetIsField02_fs preview`` compilation = + compilation + |> withLangVersionPreview + |> withOptions ["--nowarn:25"] + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 842, Line 11, Col 6, Line 11, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 14, Col 6, Line 14, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 17, Col 6, Line 17, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 19, Col 10, Line 19, Col 19, "This attribute is not valid for use on this language element") + (Error 842, Line 21, Col 6, Line 21, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 24, Col 6, Line 24, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 27, Col 6, Line 27, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 30, Col 6, Line 30, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 33, Col 6, Line 33, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 36, Col 6, Line 36, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 39, Col 6, Line 39, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 42, Col 6, Line 42, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 45, Col 6, Line 45, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 49, Col 6, Line 49, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 56, Col 6, Line 56, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 64, Col 6, Line 64, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 66, Col 10, Line 66, Col 19, "This attribute is not valid for use on this language element") + (Error 842, Line 68, Col 6, Line 68, Col 15, "This attribute is not valid for use on this language element") + ] + + // SOURCE=E_AttributeTargetIsMethod02.fs # E_AttributeTargetIsMethod02.fs + [] + let ``E_AttributeTargetIsMethod02_fs`` compilation = + compilation + |> withLangVersion80 + |> withOptions ["--nowarn:25"] + |> verifyCompile + |> shouldSucceed + + // SOURCE=E_AttributeTargetIsMethod02.fs # E_AttributeTargetIsMethod02.fs + [] + let ``E_AttributeTargetIsMethod02_fs preview`` compilation = + compilation + |> withLangVersionPreview + |> withOptions ["--nowarn:25"] + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 842, Line 9, Col 3, Line 9, Col 13, "This attribute is not valid for use on this language element") + (Error 842, Line 12, Col 3, Line 12, Col 13, "This attribute is not valid for use on this language element") + (Error 842, Line 15, Col 3, Line 15, Col 13, "This attribute is not valid for use on this language element") + (Error 842, Line 18, Col 3, Line 18, Col 13, "This attribute is not valid for use on this language element") + (Error 842, Line 21, Col 3, Line 21, Col 13, "This attribute is not valid for use on this language element") + (Error 842, Line 24, Col 3, Line 24, Col 13, "This attribute is not valid for use on this language element") + (Error 842, Line 26, Col 7, Line 26, Col 17, "This attribute is not valid for use on this language element") + (Error 842, Line 28, Col 3, Line 28, Col 13, "This attribute is not valid for use on this language element") + (Error 842, Line 31, Col 3, Line 31, Col 13, "This attribute is not valid for use on this language element") + (Error 842, Line 34, Col 3, Line 34, Col 13, "This attribute is not valid for use on this language element") + (Error 842, Line 39, Col 3, Line 39, Col 13, "This attribute is not valid for use on this language element") + ] + + // SOURCE=E_AttributeTargetIsMethod03.fs # E_AttributeTargetIsMethod03.fs + [] + let ``E_AttributeTargetIsMethod03_fs`` compilation = + compilation + |> withLangVersion80 + |> withOptions ["--nowarn:25"] + |> verifyCompile + |> shouldSucceed + + // SOURCE=E_AttributeTargetIsMethod03.fs # E_AttributeTargetIsMethod03.fs + [] + let ``E_AttributeTargetIsMethod03_fs preview`` compilation = + compilation + |> withLangVersionPreview + |> withOptions ["--nowarn:25"] + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 842, Line 12, Col 6, Line 12, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 15, Col 6, Line 15, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 18, Col 6, Line 18, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 20, Col 10, Line 20, Col 20, "This attribute is not valid for use on this language element") + (Error 842, Line 22, Col 6, Line 22, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 25, Col 6, Line 25, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 28, Col 6, Line 28, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 31, Col 6, Line 31, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 34, Col 6, Line 34, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 37, Col 6, Line 37, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 39, Col 10, Line 39, Col 20, "This attribute is not valid for use on this language element") + (Error 842, Line 41, Col 6, Line 41, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 44, Col 6, Line 44, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 47, Col 6, Line 47, Col 16, "This attribute is not valid for use on this language element") + (Error 842, Line 52, Col 6, Line 52, Col 16, "This attribute is not valid for use on this language element") + ] // SOURCE=E_ConditionalAttribute.fs SCFLAGS="--test:ErrorRanges" # E_ConditionalAttribute.fs [] diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsField01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsField01.fs new file mode 100644 index 00000000000..1e3e48516c9 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsField01.fs @@ -0,0 +1,67 @@ +// This tests that AttributeTargets.Field is not allowed in let function bindings + +open System + +[] +type FieldOnlyAttribute() = + inherit Attribute() + +[] // Should fail +let func1 () = "someFunction" + +[] // Should fail +let func2 a = a + 1 + +[] // Should fail +let func3 (a, b) = a + b + +[] // Should fail +let func4 (a: int) : int = a + 1 + +[] // Should fail +let func5 a b = [ a; b ] + +[] // Should fail +let func6<'a> = "someTypedFunction" + +[] // Should fail +let func7<'a> (x : 'a) = "someTypedFunction2" + +[] // Should fail +let func8 = fun x -> x + +[] // Should fail +let func9 = id + +[] // Should fail +let __func10<'a> = false + +[] // Should fail +let __func11<'a> : bool = false + +[] // Should fail +let (|Bool|_|) = function "true" -> Some true | "false" -> Some false | _ -> None + +[] // Should fail +[] +let (|BoolExpr2|_|) = function "true" -> ValueSome true | "false" -> ValueSome false | _ -> ValueNone + +[] // Should fail +let (|BoolExpr3|_|) x = + match x with + | "true" -> Some true + | "false" -> Some false + | _ -> None + +[] // Should fail +[] +let (|BoolExpr4|_|) x = + match x with + | "true" -> ValueSome true + | "false" -> ValueSome false + | _ -> ValueNone + +[] // Should fail +let rec func12() = 0 +and [] func13() = [] // Should fail + diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsField02.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsField02.fs new file mode 100644 index 00000000000..c7ba6dda24f --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsField02.fs @@ -0,0 +1,69 @@ +// This tests that AttributeTargets.Field is not allowed in class let function bindings + +open System +open System.Diagnostics + +[] +type FieldOnlyAttribute() = + inherit Attribute() + +type TestClass() = + [] // Should fail + static let func1() = "someFunction" + + [] // Should fail + static let rec func2() = "someFunction" + + []// Should fail + static let rec func3() = "someFunction" + and [] fun4() = "someFunction" // Should fail + + [] // Should fail + let func5 () = "someFunction" + + [] // Should fail + let func6 a = a + 1 + + [] // Should fail + let func7 (a, b) = a + b + + [] // Should fail + let func8 (a: int) : int = a + 1 + + [] // Should fail + let func9 a b = [ a; b ] + + [] // Should fail + let func10 = fun x -> x + + [] // Should fail + let func11 = id + + [] // Should fail + let (|Bool|_|) = function "true" -> Some true | "false" -> Some false | _ -> None + + [] // Should fail + [] + let (|BoolExpr2|_|) = function "true" -> ValueSome true | "false" -> ValueSome false | _ -> ValueNone + + [] // Should fail + let (|BoolExpr3|_|) x = + match x with + | "true" -> Some true + | "false" -> Some false + | _ -> None + + [] // Should fail + [] + let (|BoolExpr4|_|) x = + match x with + | "true" -> ValueSome true + | "false" -> ValueSome false + | _ -> ValueNone + + [] // Should fail + let rec func12() = 0 + and [] func13() = [] // Should fail + + [] // Should fail + let rec func14() = 0 \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsMethod02.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsMethod02.fs new file mode 100644 index 00000000000..8687a9b1d0c --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsMethod02.fs @@ -0,0 +1,40 @@ +// This tests that AttributeTargets.Method is not allowed in let bound values + +open System + +[] +type MethodOnlyAttribute() = + inherit Attribute() + +[] // Should fail +let val1 = "someValue" + +[] // Should fail +let i, j, k = (1, 2, 3) + +[] // Should fail +let val2 = nameof(MethodOnlyAttribute) + +[] // Should fail +let rec val3 = nameof(val2) + +[] // Should fail +let ``val4`` = "someValue" + +[] // Should fail +let rec val5 = 0 +and [] val6 = [] // Should fail + +[] // Should fail +let (a :: _) = [] + +[] // Should fail +let (d, e) as val7 = 1, 2 + +[] // Should fail +let 1 = 0 + +type X = { X: int } + +[] // Should fail +let { X = _ } = { X = 1 } diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsMethod03.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsMethod03.fs new file mode 100644 index 00000000000..c60ecae32b2 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsMethod03.fs @@ -0,0 +1,54 @@ +// This tests that AttributeTargets.Method is not allowed in class let bound values + +open System +open System.Diagnostics + +[] +type MethodOnlyAttribute() = + inherit Attribute() + +type TestClass() = + + [] // Should fail + static let val1 = "someValue" + + [] // Should fail + static let rec val2 = "someValue" + + [] // Should fail + static let rec val3 = "someValue" + and [] val4 = "someValue" // Should fail + + [] // Should fail + let val5 = "someValue" + + [] // Should fail + let i, j, k = (1, 2, 3) + + [] // Should fail + let val5 = nameof(MethodOnlyAttribute) + + [] // Should fail + let rec val6 = nameof(val5) + + [] // Should fail + let ``val7`` = "someValue" + + [] // Should fail + let rec val8 = 0 + and [] val9 = [] // Should fail + + [] // Should fail + let (a :: _) = [] + + [] // Should fail + let (d, e) as foo = 1, 2 + + [] // Should fail + let 1 = 0 + + type X = { X: int } + + [] // Should fail + let { X = _ } = { X = 1 } + diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TailCallAttribute.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TailCallAttribute.fs index 56572879715..9d34b2466e6 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TailCallAttribute.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TailCallAttribute.fs @@ -1440,7 +1440,7 @@ namespace N ] [] - let ``Warn about attribute on non-recursive let-bound value`` () = + let ``Error about attribute on non-recursive let-bound value`` () = """ namespace N @@ -1453,18 +1453,10 @@ namespace N |> withLangVersionPreview |> compile |> shouldFail - |> withResults [ - { Error = Warning 3861 - Range = { StartLine = 7 - StartColumn = 13 - EndLine = 7 - EndColumn = 18 } - Message = - "The TailCall attribute should only be applied to recursive functions." } - ] + |> withSingleDiagnostic (Error 842, Line 6, Col 11, Line 6, Col 19, "This attribute is not valid for use on this language element") [] - let ``Warn about attribute on recursive let-bound value`` () = + let ``Error about attribute on recursive let-bound value`` () = """ namespace N @@ -1477,15 +1469,7 @@ namespace N |> withLangVersionPreview |> compile |> shouldFail - |> withResults [ - { Error = Warning 3861 - Range = { StartLine = 7 - StartColumn = 17 - EndLine = 7 - EndColumn = 37 } - Message = - "The TailCall attribute should only be applied to recursive functions." } - ] + |> withSingleDiagnostic (Error 842, Line 6, Col 11, Line 6, Col 19, "This attribute is not valid for use on this language element") [] let ``Warn about self-defined attribute`` () = // is the analysis available for users of older FSharp.Core versions diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs index 2adb305a2ea..3a8730043a3 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs @@ -646,10 +646,12 @@ let fuzzingTest seed (project: SyntheticProject) = task { } +(* This gets in the way of insertions too often now, uncomment when stable. [] [] [] [] +*) let Fuzzing signatureFiles = let seed = System.Random().Next() @@ -896,6 +898,52 @@ let ``LoadClosure for script is recomputed after changes`` () = |> Map Assert.Equal([Weakened; Requested; Started; Finished; Weakened; Requested; Started; Finished], closureComputations["FileFirst.fs"]) + +[] +let ``TryGetRecentCheckResultsForFile returns None before first call to ParseAndCheckFileInProject`` () = + let project = SyntheticProject.Create( + sourceFile "First" []) + + ProjectWorkflowBuilder(project) { + clearCache + tryGetRecentCheckResults "First" expectNone + } |> ignore + +[] +let ``TryGetRecentCheckResultsForFile returns result after first call to ParseAndCheckFileInProject`` () = + let project = SyntheticProject.Create( + sourceFile "First" [] ) + + ProjectWorkflowBuilder(project) { + tryGetRecentCheckResults "First" expectSome + } |> ignore + +[] +let ``TryGetRecentCheckResultsForFile returns no result after edit`` () = + let project = SyntheticProject.Create( + sourceFile "First" []) + + ProjectWorkflowBuilder(project) { + tryGetRecentCheckResults "First" expectSome + updateFile "First" updatePublicSurface + tryGetRecentCheckResults "First" expectNone + checkFile "First" expectOk + tryGetRecentCheckResults "First" expectSome + } |> ignore + +[] +let ``TryGetRecentCheckResultsForFile returns result after edit of other file`` () = + let project = SyntheticProject.Create( + sourceFile "First" [], + sourceFile "Second" ["First"]) + + ProjectWorkflowBuilder(project) { + tryGetRecentCheckResults "First" expectSome + tryGetRecentCheckResults "Second" expectSome + updateFile "First" updatePublicSurface + tryGetRecentCheckResults "First" expectNone + tryGetRecentCheckResults "Second" expectSome // file didn't change so we still want to get the recent result + } |> ignore [] let ``Background compiler and Transparent compiler return the same options`` () = diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index 69fb762ea84..3c4b22f76c1 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -2079,6 +2079,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Mi FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]],System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]] get_BeforeBackgroundFileCheck() FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]],System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]] get_FileChecked() FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]],System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]] get_FileParsed() +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] TryGetRecentCheckResultsForFile(System.String, FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults,System.Int64]] TryGetRecentCheckResultsForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParsingOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]] GetParsingOptionsFromCommandLineArgs(Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) FSharp.Compiler.CodeAnalysis.FSharpChecker: System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParsingOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]] GetParsingOptionsFromCommandLineArgs(Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index 69fb762ea84..3c4b22f76c1 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -2079,6 +2079,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Mi FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]],System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]] get_BeforeBackgroundFileCheck() FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]],System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]] get_FileChecked() FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]],System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions]] get_FileParsed() +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] TryGetRecentCheckResultsForFile(System.String, FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults,System.Int64]] TryGetRecentCheckResultsForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParsingOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]] GetParsingOptionsFromCommandLineArgs(Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) FSharp.Compiler.CodeAnalysis.FSharpChecker: System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParsingOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]] GetParsingOptionsFromCommandLineArgs(Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean]) diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index 2157d8fb7fe..998f2bd201d 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -754,7 +754,13 @@ module ProjectOperations = |> Seq.toArray Assert.Equal<(string * int * int * int)[]>(expected |> Seq.sort |> Seq.toArray, actual) - + + let expectNone x = + if Option.isSome x then failwith "expected None, but was Some" + + let expectSome x = + if Option.isNone x then failwith "expected Some, but was None" + let rec saveProject (p: SyntheticProject) generateSignatureFiles checker = async { Directory.CreateDirectory(p.ProjectDir) |> ignore @@ -1346,6 +1352,28 @@ type ProjectWorkflowBuilder exn $"Compilation failed with exit code {exitCode}" |> raise return ctx } + + [] + member this.TryGetRecentCheckResults(workflow: Async, fileId: string, expected) = + async { + let! ctx = workflow + let project, file = ctx.Project.FindInAllProjects fileId + let fileName = project.ProjectDir ++ file.FileName + let options = project.GetProjectOptions checker + let! snapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot ctx.Project) + let r = checker.TryGetRecentCheckResultsForFile(fileName, snapshot) + expected r + + match r with + | Some(parseFileResults, checkFileResults) -> + let signature = getSignature(parseFileResults, FSharpCheckFileAnswer.Succeeded(checkFileResults)) + match ctx.Signatures.TryFind(fileId) with + | Some priorSignature -> Assert.Equal(priorSignature, signature) + | None -> () + | None -> () + + return ctx + } /// Execute a set of operations on a given synthetic project. /// The project is saved to disk and type checked at the start. diff --git a/tests/service/ProjectAnalysisTests.fs b/tests/service/ProjectAnalysisTests.fs index 266ec0d900b..c375f1c0392 100644 --- a/tests/service/ProjectAnalysisTests.fs +++ b/tests/service/ProjectAnalysisTests.fs @@ -4751,17 +4751,17 @@ type TestRecord = { B : int } module Test = [)>] - let withType = 0 + let withType() = 0 [>)>] - let withGenericType = 0 + let withGenericType() = 0 [)>] - let withTupleType = 0 + let withTupleType() = 0 [ int>)>] - let withFuncType = 0 + let withFuncType() = 0 [; typeof |])>] - let withTypeArray = 0 + let withTypeArray() = 0 [] - let withIntArray = 0 + let withIntArray() = 0 module NestedModule = type NestedRecordType = { B : int } @@ -5462,6 +5462,65 @@ type A(i:int) = | Some decl -> failwithf "unexpected declaration %A" decl | None -> failwith "declaration list is empty" +[] +[] +[] +let ``TryGetRecentCheckResultsForFile called with snapshot returns cached result after ParseAndCheckFile`` useTransparentCompiler = + let fileName1 = Path.ChangeExtension(tryCreateTemporaryFileName (), ".fs") + let base2 = tryCreateTemporaryFileName () + let dllName = Path.ChangeExtension(base2, ".dll") + let projFileName = Path.ChangeExtension(base2, ".fsproj") + let fileSource1Text = """ +type A(i:int) = + member x.Value = i +""" + let fileSource1 = SourceText.ofString fileSource1Text + FileSystem.OpenFileForWriteShim(fileName1).Write(fileSource1Text) + + let fileNames = [|fileName1|] + let args = mkProjectCommandLineArgs (dllName, []) + let checker = FSharpChecker.Create(useTransparentCompiler=useTransparentCompiler) + let options = { checker.GetProjectOptionsFromCommandLineArgs (projFileName, args) with SourceFiles = fileNames } + let snapshot = FSharpProjectSnapshot.FromOptions(options, DocumentSource.FileSystem) |> Async.RunImmediate + + let rbefore = checker.TryGetRecentCheckResultsForFile(fileName1, snapshot) + match rbefore with + | Some(fileResults, checkFileResults) -> failwith "cached results before ParseAndCheckFileInProject was called" + | None -> () + + checker.ParseAndCheckFileInProject(fileName1, snapshot) |> Async.RunImmediate + |> function + | _, FSharpCheckFileAnswer.Succeeded(res) -> () + | _ -> failwithf "Parsing aborted unexpectedly..." + + let rafterCheckResults = checker.TryGetRecentCheckResultsForFile(fileName1, snapshot) + match rafterCheckResults with + | Some(fileResults, checkFileResults) -> () + | None -> failwith "no results from TryGetRecentCheckResultsForFile" + + let fileSource1TextEdited = """ +type A(i:int) = + member x.Value = i + member x.Value2 = 23 +""" + let fileSource1Edited = SourceText.ofString fileSource1TextEdited + FileSystem.OpenFileForWriteShim(fileName1).Write(fileSource1TextEdited) + let snapshotAfterFileEdit = FSharpProjectSnapshot.FromOptions(options, DocumentSource.FileSystem) |> Async.RunImmediate + + let rafterEditBefore2ndCheckResults = checker.TryGetRecentCheckResultsForFile(fileName1, snapshotAfterFileEdit) + match rafterEditBefore2ndCheckResults with + | Some(fileResults, checkFileResults) -> failwith "stale cache results from TryGetRecentCheckResultsForFile after edit" + | None -> () + + checker.ParseAndCheckFileInProject(fileName1, snapshotAfterFileEdit) |> Async.RunImmediate + |> function + | _, FSharpCheckFileAnswer.Succeeded(res) -> () + | _ -> failwithf "Parsing aborted unexpectedly..." + + let rafterEditAfter2ndCheckResults = checker.TryGetRecentCheckResultsForFile(fileName1, snapshotAfterFileEdit) + match rafterEditAfter2ndCheckResults with + | Some(fileResults, checkFileResults) -> () + | None -> failwith "no results from TryGetRecentCheckResultsForFile" [] []